work on logs, timetable, stats

This commit is contained in:
bkfox 2019-09-08 01:39:40 +02:00
parent 2d21ab2434
commit c68e21ee57
71 changed files with 19683 additions and 710 deletions

View File

@ -12,7 +12,7 @@ __all__ = ['ArticleAdmin']
@admin.register(Article)
class ArticleAdmin(PageAdmin):
list_display = PageAdmin.list_display + ('program',)
list_filter = ('program',)
list_filter = PageAdmin.list_filter + ('program',)
search_fields = PageAdmin.search_fields + ['program__title']
# TODO: readonly field

View File

@ -49,7 +49,7 @@ class DiffusionInline(DiffusionBaseAdmin, admin.TabularInline):
@admin.register(Episode)
class EpisodeAdmin(PageAdmin):
list_display = PageAdmin.list_display + ('program',)
list_filter = ('program',)
list_filter = PageAdmin.list_filter + ('program',)
search_fields = PageAdmin.search_fields + ['program__title']
readonly_fields = ('program',)

View File

@ -24,10 +24,9 @@ class PageAdmin(admin.ModelAdmin):
list_display = ('cover_thumb', 'title', 'status', 'category')
list_display_links = ('cover_thumb', 'title')
list_editable = ('status', 'category')
list_filter = ('status', 'category')
prepopulated_fields = {"slug": ("title",)}
change_form_template = 'admin/aircox/page_change_form.html'
search_fields = ['title', 'category__title']
fieldsets = [
('', {
@ -39,6 +38,8 @@ class PageAdmin(admin.ModelAdmin):
}),
]
change_form_template = 'admin/aircox/page_change_form.html'
def cover_thumb(self, obj):
return mark_safe('<img src="{}"/>'.format(obj.cover.icons['64'])) \
if obj.cover else ''

View File

@ -3,6 +3,8 @@ import datetime
from django.utils.safestring import mark_safe
from django.urls.converters import StringConverter
from .utils import str_to_date
class PagePathConverter(StringConverter):
""" Match path for pages, including surrounding slashes. """
@ -39,8 +41,7 @@ class DateConverter:
regex = r'[0-9]{4}/[0-9]{2}/[0-9]{2}'
def to_python(self, value):
value = value.split('/')
return datetime.date(int(value[0]), int(value[1]), int(value[2]))
return str_to_date(value)
def to_url(self, value):
return '{:04d}/{:02d}/{:02d}'.format(value.year, value.month,

View File

@ -221,6 +221,7 @@ class Log(models.Model):
def related(self):
return self.diffusion or self.sound or self.track
# FIXME: required????
@property
def local_date(self):
"""
@ -230,6 +231,12 @@ class Log(models.Model):
"""
return tz.localtime(self.date, tz.get_current_timezone())
# prepare for the future on crash + ease the use in merged lists with
# diffusions
@property
def start(self):
return self.date
def __str__(self):
return '#{} ({}, {}, {})'.format(
self.pk, self.get_type_display(),

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,159 @@
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["admin"],{
/******/ (function(modules) { // webpackBootstrap
/******/ // install a JSONP callback for chunk loading
/******/ function webpackJsonpCallback(data) {
/******/ var chunkIds = data[0];
/******/ var moreModules = data[1];
/******/ var executeModules = data[2];
/******/
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0, resolves = [];
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ resolves.push(installedChunks[chunkId][0]);
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/ for(moduleId in moreModules) {
/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
/******/ modules[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(parentJsonpFunction) parentJsonpFunction(data);
/******/
/******/ while(resolves.length) {
/******/ resolves.shift()();
/******/ }
/******/
/******/ // add entry modules from loaded chunk to deferred list
/******/ deferredModules.push.apply(deferredModules, executeModules || []);
/******/
/******/ // run deferred modules when all chunks ready
/******/ return checkDeferredModules();
/******/ };
/******/ function checkDeferredModules() {
/******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i];
/******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; j++) {
/******/ var depId = deferredModule[j];
/******/ if(installedChunks[depId] !== 0) fulfilled = false;
/******/ }
/******/ if(fulfilled) {
/******/ deferredModules.splice(i--, 1);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ }
/******/ }
/******/
/******/ return result;
/******/ }
/******/
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // object to store loaded and loading chunks
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ // Promise = chunk loading, 0 = chunk loaded
/******/ var installedChunks = {
/******/ "admin": 0
/******/ };
/******/
/******/ var deferredModules = [];
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
/******/ var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
/******/ jsonpArray.push = webpackJsonpCallback;
/******/ jsonpArray = jsonpArray.slice();
/******/ for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
/******/ var parentJsonpFunction = oldJsonpFunction;
/******/
/******/
/******/ // add entry module to deferred list
/******/ deferredModules.push(["./assets/admin/index.js","vendor"]);
/******/ // run deferred modules when ready
/******/ return checkDeferredModules();
/******/ })
/************************************************************************/
/******/ ({
/***/ "./assets/admin/admin.scss":
/*!*********************************!*\
@ -19,8 +174,175 @@ eval("// extracted by mini-css-extract-plugin\n\n//# sourceURL=webpack:///./asse
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var _admin_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./admin.scss */ \"./assets/admin/admin.scss\");\n/* harmony import */ var _admin_scss__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_admin_scss__WEBPACK_IMPORTED_MODULE_0__);\n\n\n\n\n\n//# sourceURL=webpack:///./assets/admin/index.js?");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n/* harmony import */ var _admin_scss__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./admin.scss */ \"./assets/admin/admin.scss\");\n/* harmony import */ var _admin_scss__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_admin_scss__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _statistics_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./statistics.vue */ \"./assets/admin/statistics.vue\");\n/* harmony import */ var public__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! public */ \"./assets/public/index.js\");\n\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-statistics', _statistics_vue__WEBPACK_IMPORTED_MODULE_2__[\"default\"])\n\n\n\n\n\n\n\n\n//# sourceURL=webpack:///./assets/admin/index.js?");
/***/ }),
/***/ "./assets/admin/statistics.vue":
/*!*************************************!*\
!*** ./assets/admin/statistics.vue ***!
\*************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _statistics_vue_vue_type_template_id_47005a51___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./statistics.vue?vue&type=template&id=47005a51& */ \"./assets/admin/statistics.vue?vue&type=template&id=47005a51&\");\n/* harmony import */ var _statistics_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./statistics.vue?vue&type=script&lang=js& */ \"./assets/admin/statistics.vue?vue&type=script&lang=js&\");\n/* empty/unused harmony star reexport *//* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(\n _statistics_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n _statistics_vue_vue_type_template_id_47005a51___WEBPACK_IMPORTED_MODULE_0__[\"render\"],\n _statistics_vue_vue_type_template_id_47005a51___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"],\n false,\n null,\n null,\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"assets/admin/statistics.vue\"\n/* harmony default export */ __webpack_exports__[\"default\"] = (component.exports);\n\n//# sourceURL=webpack:///./assets/admin/statistics.vue?");
/***/ }),
/***/ "./assets/admin/statistics.vue?vue&type=script&lang=js&":
/*!**************************************************************!*\
!*** ./assets/admin/statistics.vue?vue&type=script&lang=js& ***!
\**************************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_vue_loader_lib_index_js_vue_loader_options_statistics_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib??vue-loader-options!./statistics.vue?vue&type=script&lang=js& */ \"./node_modules/vue-loader/lib/index.js?!./assets/admin/statistics.vue?vue&type=script&lang=js&\");\n/* empty/unused harmony star reexport */ /* harmony default export */ __webpack_exports__[\"default\"] = (_node_modules_vue_loader_lib_index_js_vue_loader_options_statistics_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__[\"default\"]); \n\n//# sourceURL=webpack:///./assets/admin/statistics.vue?");
/***/ }),
/***/ "./assets/admin/statistics.vue?vue&type=template&id=47005a51&":
/*!********************************************************************!*\
!*** ./assets/admin/statistics.vue?vue&type=template&id=47005a51& ***!
\********************************************************************/
/*! exports provided: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_statistics_vue_vue_type_template_id_47005a51___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../node_modules/vue-loader/lib??vue-loader-options!./statistics.vue?vue&type=template&id=47005a51& */ \"./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/admin/statistics.vue?vue&type=template&id=47005a51&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_statistics_vue_vue_type_template_id_47005a51___WEBPACK_IMPORTED_MODULE_0__[\"render\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_statistics_vue_vue_type_template_id_47005a51___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"]; });\n\n\n\n//# sourceURL=webpack:///./assets/admin/statistics.vue?");
/***/ }),
/***/ "./assets/public/app.js":
/*!******************************!*\
!*** ./assets/public/app.js ***!
\******************************/
/*! exports provided: app, default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"app\", function() { return app; });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n\n\n\nvar app = null;\n/* harmony default export */ __webpack_exports__[\"default\"] = (app);\n\nfunction loadApp() {\n app = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n el: '#app',\n delimiters: [ '[[', ']]' ],\n })\n}\n\nwindow.addEventListener('load', loadApp);\n\n\n\n\n\n//# sourceURL=webpack:///./assets/public/app.js?");
/***/ }),
/***/ "./assets/public/index.js":
/*!********************************!*\
!*** ./assets/public/index.js ***!
\********************************/
/*! no exports provided */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/all.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/all.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/fontawesome.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var buefy_dist_buefy_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! buefy/dist/buefy.css */ \"./node_modules/buefy/dist/buefy.css\");\n/* harmony import */ var buefy_dist_buefy_css__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(buefy_dist_buefy_css__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./app */ \"./assets/public/app.js\");\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./styles.scss */ \"./assets/public/styles.scss\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_styles_scss__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _player_vue__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./player.vue */ \"./assets/public/player.vue\");\n/**\n * This module includes code available for both the public website and\n * administration interface)\n */\n//-- vendor\n\n\n\n\n\n\n\n//-- aircox\n\n\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-player', _player_vue__WEBPACK_IMPORTED_MODULE_7__[\"default\"])\n\n\nwindow.aircox = {\n app: _app__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n LiveInfo: _liveInfo__WEBPACK_IMPORTED_MODULE_5__[\"default\"],\n}\n\n\n\n//# sourceURL=webpack:///./assets/public/index.js?");
/***/ }),
/***/ "./assets/public/liveInfo.js":
/*!***********************************!*\
!*** ./assets/public/liveInfo.js ***!
\***********************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (class {\n constructor(url, timeout) {\n this.url = url;\n this.timeout = timeout;\n this.promise = null;\n this.items = [];\n }\n\n drop() {\n this.promise = null;\n }\n\n fetch() {\n const promise = fetch(this.url).then(response =>\n response.ok ? response.json()\n : Promise.reject(response)\n ).then(data => {\n this.items = data;\n return this.items\n })\n\n this.promise = promise;\n return promise;\n }\n\n refresh() {\n const promise = this.fetch();\n promise.then(data => {\n if(promise != this.promise)\n return [];\n\n window.setTimeout(() => this.refresh(), this.timeout*1000)\n })\n return promise\n }\n});\n\n\n//# sourceURL=webpack:///./assets/public/liveInfo.js?");
/***/ }),
/***/ "./assets/public/player.vue":
/*!**********************************!*\
!*** ./assets/public/player.vue ***!
\**********************************/
/*! exports provided: default, State */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./player.vue?vue&type=template&id=42a56ec9& */ \"./assets/public/player.vue?vue&type=template&id=42a56ec9&\");\n/* harmony import */ var _player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./player.vue?vue&type=script&lang=js& */ \"./assets/public/player.vue?vue&type=script&lang=js&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return _player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"State\"]; });\n\n/* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(\n _player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n _player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__[\"render\"],\n _player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"],\n false,\n null,\n null,\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"assets/public/player.vue\"\n/* harmony default export */ __webpack_exports__[\"default\"] = (component.exports);\n\n//# sourceURL=webpack:///./assets/public/player.vue?");
/***/ }),
/***/ "./assets/public/player.vue?vue&type=script&lang=js&":
/*!***********************************************************!*\
!*** ./assets/public/player.vue?vue&type=script&lang=js& ***!
\***********************************************************/
/*! exports provided: default, State */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib??vue-loader-options!./player.vue?vue&type=script&lang=js& */ \"./node_modules/vue-loader/lib/index.js?!./assets/public/player.vue?vue&type=script&lang=js&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return _node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__[\"State\"]; });\n\n /* harmony default export */ __webpack_exports__[\"default\"] = (_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__[\"default\"]); \n\n//# sourceURL=webpack:///./assets/public/player.vue?");
/***/ }),
/***/ "./assets/public/player.vue?vue&type=template&id=42a56ec9&":
/*!*****************************************************************!*\
!*** ./assets/public/player.vue?vue&type=template&id=42a56ec9& ***!
\*****************************************************************/
/*! exports provided: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../node_modules/vue-loader/lib??vue-loader-options!./player.vue?vue&type=template&id=42a56ec9& */ \"./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/public/player.vue?vue&type=template&id=42a56ec9&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__[\"render\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"]; });\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?");
/***/ }),
/***/ "./assets/public/styles.scss":
/*!***********************************!*\
!*** ./assets/public/styles.scss ***!
\***********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
eval("// extracted by mini-css-extract-plugin\n\n//# sourceURL=webpack:///./assets/public/styles.scss?");
/***/ }),
/***/ "./node_modules/vue-loader/lib/index.js?!./assets/admin/statistics.vue?vue&type=script&lang=js&":
/*!****************************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib??vue-loader-options!./assets/admin/statistics.vue?vue&type=script&lang=js& ***!
\****************************************************************************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n\n\nconst splitReg = new RegExp(`,\\s*`, 'g');\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n data() {\n return {\n counts: {},\n }\n },\n\n methods: {\n update() {\n const items = this.$el.querySelectorAll('input[name=\"data\"]:checked')\n const counts = {};\n\n console.log(items)\n for(var item of items)\n if(item.value)\n for(var tag of item.value.split(splitReg))\n counts[tag.trim()] = (counts[tag.trim()] || 0) + 1;\n this.counts = counts;\n console.log('counts', this.counts)\n }\n },\n\n mounted() {\n this.$refs.form.addEventListener('change', () => this.update())\n this.update()\n }\n});\n\n\n//# sourceURL=webpack:///./assets/admin/statistics.vue?./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
/***/ "./node_modules/vue-loader/lib/index.js?!./assets/public/player.vue?vue&type=script&lang=js&":
/*!*************************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib??vue-loader-options!./assets/public/player.vue?vue&type=script&lang=js& ***!
\*************************************************************************************************************/
/*! exports provided: State, default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return State; });\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst State = {\n paused: 0,\n playing: 1,\n loading: 2,\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n data() {\n return {\n state: State.paused,\n liveInfo: new _liveInfo__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.liveInfoUrl, this.liveInfoTimeout),\n }\n },\n\n props: {\n buttonTitle: String,\n liveInfoUrl: String,\n liveInfoTimeout: { type: Number, default: 5},\n src: String,\n },\n\n computed: {\n paused() { return this.state == State.paused; },\n playing() { return this.state == State.playing; },\n loading() { return this.state == State.loading; },\n\n onAir() {\n return this.liveInfo.items && this.liveInfo.items[0];\n },\n\n buttonStyle() {\n if(!this.onAir)\n return;\n return { backgroundImage: `url(${this.onAir.cover})` }\n }\n },\n\n methods: {\n load(src) {\n const audio = this.$refs.audio;\n audio.src = src;\n audio.load()\n },\n\n play(src) {\n if(src)\n this.load(src);\n this.$refs.audio.play().catch(e => console.error(e))\n },\n\n pause() {\n this.$refs.audio.pause()\n },\n\n toggle() {\n if(this.paused)\n this.play()\n else\n this.pause()\n },\n\n onChange(event) {\n const audio = this.$refs.audio;\n this.state = audio.paused ? State.paused : State.playing;\n },\n },\n\n mounted() {\n this.liveInfo.refresh()\n },\n\n destroyed() {\n this.liveInfo.drop()\n },\n});\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/admin/statistics.vue?vue&type=template&id=47005a51&":
/*!**************************************************************************************************************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./assets/admin/statistics.vue?vue&type=template&id=47005a51& ***!
\**************************************************************************************************************************************************************************************************/
/*! exports provided: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"form\",\n { ref: \"form\" },\n [_vm._t(\"default\", null, { counts: _vm.counts })],\n 2\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./assets/admin/statistics.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/public/player.vue?vue&type=template&id=42a56ec9&":
/*!***********************************************************************************************************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./assets/public/player.vue?vue&type=template&id=42a56ec9& ***!
\***********************************************************************************************************************************************************************************************/
/*! exports provided: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"media\" }, [\n _c(\"div\", { staticClass: \"media-left\" }, [\n _c(\n \"div\",\n {\n staticClass: \"button\",\n attrs: { title: _vm.buttonTitle, \"aria-label\": _vm.buttonTitle },\n on: {\n click: function($event) {\n return _vm.toggle()\n }\n }\n },\n [\n _vm.playing\n ? _c(\"span\", { staticClass: \"fas fa-pause\" })\n : _c(\"span\", { staticClass: \"fas fa-play\" })\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"audio\",\n {\n ref: \"audio\",\n on: {\n playing: _vm.onChange,\n ended: _vm.onChange,\n pause: _vm.onChange\n }\n },\n [_vm._t(\"sources\")],\n 2\n )\n ]),\n _vm._v(\" \"),\n _vm.onAir && _vm.onAir.cover\n ? _c(\"div\", { staticClass: \"media-left media-cover\" }, [\n _c(\"img\", { staticClass: \"cover\", attrs: { src: _vm.onAir.cover } })\n ])\n : _vm._e(),\n _vm._v(\" \"),\n _vm.onAir && _vm.onAir.type == \"track\"\n ? _c(\n \"div\",\n { staticClass: \"media-content\" },\n [_vm._t(\"track\", null, { onAir: _vm.onAir, liveInfo: _vm.liveInfo })],\n 2\n )\n : _vm.onAir && _vm.onAir.type == \"diffusion\"\n ? _c(\n \"div\",\n { staticClass: \"media-content\" },\n [\n _vm._t(\"diffusion\", null, {\n onAir: _vm.onAir,\n liveInfo: _vm.liveInfo\n })\n ],\n 2\n )\n : _c(\"div\", { staticClass: \"media-content\" }, [_vm._t(\"empty\")], 2)\n ])\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options");
/***/ })
}]);
/******/ });

View File

@ -1,12 +1,12 @@
<?xml version="1.0" standalone="no"?>
<!--
Font Awesome Free 5.9.0 by @fontawesome - https://fontawesome.com
Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<metadata>
Created by FontForge 20190112 at Tue Jun 4 15:16:44 2019
Created by FontForge 20190801 at Thu Aug 22 14:41:09 2019
By Robert Madole
Copyright (c) Font Awesome
</metadata>
@ -22,8 +22,8 @@ Copyright (c) Font Awesome
descent="-64"
bbox="-0.200195 -66.9505 641.5 448.3"
underline-thickness="25"
underline-position="-51"
unicode-range="U+0020-F842"
underline-position="-50"
unicode-range="U+0020-F89E"
/>
<missing-glyph />
<glyph glyph-name="twitter-square" unicode="&#xf081;"
@ -2462,22 +2462,20 @@ l-10.9004 20.5996h37.5l54.9004 -109.9zM243.7 134.2c29.7998 0 50.2002 21.5 50.200
c-11.7998 0 -26.2998 -0.0996094 -39.3994 -0.599609c-29.1006 -0.900391 -47.2002 -6.2002 -47.2002 -25.2998c0 -12.4004 9.90039 -25.8008 35 -25.8008c33.7002 0 51.5996 18.4004 51.5996 48.4004zM32.7002 179.9c3.5 -58.3008 79.2002 -57.4004 91.2002 -21.6006
h33.0996c-6.40039 -34.3994 -43 -46.0996 -74.4004 -46.0996c-57.1992 0 -82.5 31.5 -82.5 74c0 46.7998 26.2002 77.5996 83 77.5996c45.3008 0 78.4004 -23.7002 78.4004 -75.3994v-8.5h-128.8zM127.7 201.3c-2.2998 54.7002 -87.5 56.6006 -94.4004 0h94.4004z" />
<glyph glyph-name="keybase" unicode="&#xf4f5;"
d="M195.21 17.2998c0 -9.8252 -7.97461 -17.7998 -17.7998 -17.7998c-9.82617 0 -17.7998 7.97461 -17.7998 17.7998c0 9.82617 7.97363 17.7998 17.7998 17.7998c9.80371 -0.0214844 17.7783 -7.99609 17.7998 -17.7998zM288 35.2002
c9.80371 -0.0224609 17.7783 -7.99609 17.7998 -17.7998c0 -9.82617 -7.97461 -17.8008 -17.7998 -17.8008s-17.7998 7.97461 -17.7998 17.8008c0 9.8252 7.97461 17.7998 17.7998 17.7998zM430.3 71.2002c0 -38.9004 -7.59961 -73.9004 -22.2002 -103h-27.2998
c23.5 38.7002 30.5 94.7998 22.4004 134.3c-16.1006 -29.5 -52.1006 -38.5996 -85.9004 -28.7998c-127.8 37.5 -192.5 -19.7002 -234.6 -50.2998l18.8994 59.2998l-39.8994 -42.2998c3.95605 -21.9639 17.9336 -54.3545 31.2002 -72.3008h-28.79
c-8.1543 13.2822 -18.0996 36.2646 -22.2002 51.3008l-23.7998 -25.2002c0 74.8994 -5.5 147.6 61.5 215.2c16.4688 16.7402 47.4248 37.6621 69.0996 46.6992c-6.7998 13.5 -9.5 29.2002 -7.7998 46l-19.9102 1.2002c-16.918 1.05371 -30.6484 15.666 -30.6484 32.6172
c0 0.492188 0.0214844 1.29102 0.0488281 1.7832v0.0996094l1.59961 26.2002c1.10449 16.7988 15.665 30.5078 32.5 30.5996c1.2998 0 -0.299805 0.100586 28.2002 -1.69922c7.65918 -0.414062 17.873 -5.52148 22.7998 -11.4004c7.11035 10.4004 14.5 20.5 24.6104 34.5
l20.5996 -12.0996c-13.5996 -29 -9.09961 -36.2002 -9 -36.3008c3.90039 0 13.9004 0.5 32.4004 -5.69922c28.8379 -9.54883 52.2422 -41.9512 52.2422 -72.3291c0 -8.61914 -2.75195 -22.0469 -6.14258 -29.9717c19 -6.09961 51.2998 -19.8994 82.4004 -51.7998
c36.5996 -37.5996 57.6992 -87.3994 57.6992 -136.6h-0.00976562zM146 325.9c2.80762 8.47461 8.67578 21.6455 13.0996 29.3994c0.100586 2 2.2002 13.1006 -7.7998 13.7998c-28.5 1.80078 -26.2998 1.60059 -26.7002 1.60059h-0.0429688
c-4.47754 0 -8.31152 -3.62891 -8.55664 -8.10059l-1.59961 -26.1992c-0.00683594 -0.121094 -0.0117188 -0.318359 -0.0117188 -0.439453c0 -4.48633 3.63379 -8.36719 8.11133 -8.66113zM171.8 264.1c4.50488 -7.35938 14.4951 -16.3193 22.2998 -20
c0 21.2002 28.5 41.9004 52.8008 17.5l8.39941 -10.2998c20.7998 18.7998 19.4004 45.2998 12.1006 60.9004c-13.8008 29.0996 -46.9004 32 -54.3008 31.7002c-0.319336 -0.015625 -0.837891 -0.0283203 -1.15723 -0.0283203c-9.09863 0 -19.1973 6.86719 -22.542 15.3281
c-13.6904 -21.2002 -37.1904 -62.5 -17.5908 -95.1006h-0.00976562zM254.7 195.7l-19.7002 -16.1006c-0.900391 -0.738281 -1.63086 -2.2832 -1.63086 -3.44727c0 -0.890625 0.461914 -2.16797 1.03125 -2.85254l8.89941 -10.8994
c0.742188 -0.896484 2.28809 -1.62305 3.45117 -1.62305c0.887695 0 2.16406 0.458008 2.84863 1.02246l19.6006 16l5.5 -6.7998c4.89941 -6 13.7998 1.40039 9 7.2998c-63.6006 78.2998 -41.5 51.1006 -55.2998 68.1006c-4.7002 6 -13.9004 -1.40039 -9 -7.30078
c1.89941 -2.2998 18.3994 -22.5996 19.7998 -24.2998l-9.60059 -7.89941c-4.59961 -3.80078 2.60059 -13.3008 7.40039 -9.40039l9.7002 8zM373.11 170c-16.9004 23.7002 -42.6006 46.7002 -73.4004 60.4004c-6.18359 2.73633 -16.4434 6.58887 -22.9004 8.59961
c-1.64355 -1.83789 -4.51074 -4.61523 -6.39941 -6.2002l31.8994 -39.2002c3.70605 -4.54102 6.71289 -12.9834 6.71289 -18.8447c0 -7.78906 -4.88867 -18.1172 -10.9121 -23.0547c-1.30078 -1.10059 -13.1006 -10.7002 -29 -4.90039
c-2.90039 -2.2998 -10.1006 -9.89941 -22.2002 -9.89941h-0.0419922c-7.46777 0 -17.3496 4.70312 -22.0586 10.5l-8.89941 10.8994c-3.5293 4.33984 -6.39355 12.4014 -6.39355 17.9951c0 2.49121 0.624023 6.43555 1.39355 8.80469
c-3.83398 4.43945 -6.94531 12.8018 -6.94531 18.667c0 3.26172 1.05078 8.33984 2.34473 11.333c-7.19922 1.30078 -26.6992 6.2002 -42.6992 21.4004c-55.8008 -20.7002 -88 -64.4004 -101.301 -91.2002c-14.8994 -30.2002 -18.7998 -60.8994 -19.8994 -90.2002
c8.2002 8.7002 -3.90039 -4.09961 114 120.9l-29.9004 -93.5996c57.7998 31.0996 124 36 197.4 14.3994c23.5996 -6.89941 45.0996 -1.59961 56 13.9004c11.0996 15.5996 8.5 37.7002 -6.7998 59.2998zM128.61 340.9l1 15.5996l15.5996 -1l-1 -15.5996z" />
d="M286.17 29c9.93652 0 18 -8.06445 18 -18s-8.06348 -18 -18 -18c-9.93555 0 -18 8.06445 -18 18s8.06445 18 18 18zM398.09 176.6c22.9102 -33.46 35.9102 -72.3398 35.9102 -110.92c0 -31.6797 -5 -60.6797 -14.5996 -86.2295
c-3.04004 -8.0498 -10.9502 -12.7197 -18.3701 -11.1504c-6.83984 1.24023 -11.1201 9.28027 -8.60059 15.7402c11.1904 28.71 14.8799 58.3398 14.8799 81.6396c-0.0517578 7.91797 -1.30566 20.6543 -2.7998 28.4307
c-0.649414 -1.06055 -1.12988 -2.2207 -1.84961 -3.2207c-17.29 -24.5293 -50.54 -33.8896 -84.7402 -23.8398c-78.8701 23.1699 -178.02 3.81055 -236.25 -38.5898l24.6602 74.1104l-46.8203 -59.8301c2.04297 -15.3486 9.10352 -39.1504 15.7598 -53.1299
c6.25 -13.1904 0.460938 -18.2402 -3.75 -20.1104c-4.76953 -2.12012 -13.8594 -2.7998 -19.6396 7.33008c-5.43652 9.81641 -11.96 26.6436 -14.5596 37.5596l-23.3203 -29.7998v33.6406c0 55.7695 0 125.109 62.6504 188.409c11.4258 11.5684 32.1631 27.4902 46.29 35.54
l-8.93066 0.540039c-27.8799 1.64062 -49.2402 24.8506 -47.6299 51.8506l2.36035 36.6797c0 -6.24023 0.139648 45.8799 50.75 45.8799c2.05957 0 -0.470703 0.120117 41.0596 -2.33008c2.31641 -0.15625 6.03027 -0.71582 8.29004 -1.25
c7.41992 11.3398 15.6504 22.8301 24.3398 34.8906l5.48047 7.55957l22.8994 -13.5195c-11.29 -24 -10 -33 -9.39941 -35c9.08008 0.229492 20 -1.6709 32.4102 -5.77051c29.6523 -9.84375 53.7188 -43.1914 53.7188 -74.4355
c0 -8.5127 -2.61621 -21.8154 -5.83887 -29.6943c6.18652 -2.13965 12.3135 -4.56348 18.3799 -7.27051c47.8896 -21.2598 77.7598 -59.0898 87.2598 -73.71zM142.37 319.42c1.55664 5.42773 4.69336 14.0156 7 19.1699l-29.1104 1.73047
c0.610352 -0.0507812 -12.2598 0.849609 -13.2598 -11.3203l-2.41016 -36.6602c-0.00585938 -0.143555 -0.0107422 -0.376953 -0.0107422 -0.520508c0 -6.50293 5.27344 -12 11.7705 -12.2695l22.3809 -1.33984c-0.380859 3.10645 -0.689453 8.16797 -0.689453 11.2969
c0 2.28809 0.165039 5.99414 0.369141 8.27344l-13.1299 0.779297l1.38965 21.79zM290.79 147.24c2.06152 1.58789 3.73438 4.9873 3.73438 7.58887c0 1.80273 -0.893555 4.42383 -1.99414 5.85059l-81.0898 96.3203c-1.71484 1.99023 -5.23828 3.60547 -7.86523 3.60547
c-1.99023 0 -4.87305 -1.00098 -6.43555 -2.23535c-2.05957 -1.58398 -3.73242 -4.97949 -3.73242 -7.57812c0 -1.7998 0.892578 -4.41699 1.99316 -5.8418c0.0898438 -0.140625 18.5996 -22.1406 18.5996 -22.1406l-16.9102 -13.29
c-1.59473 -1.22266 -2.88867 -3.8457 -2.88867 -5.85547c0 -1.37988 0.680664 -3.38867 1.51855 -4.48438c0.0800781 -0.109375 2.52246 -3.07324 3.7998 -4.5293c1.27832 -1.45703 3.8877 -2.63867 5.8252 -2.63867c1.4707 0 3.60547 0.734375 4.76562 1.63867
l17.0898 13.4492l14.1396 -16.7393l-34.5703 -27.1807c-1.58398 -1.22266 -2.86914 -3.83984 -2.86914 -5.84082c0 -1.38574 0.685547 -3.40039 1.5293 -4.49902l15.7803 -18.6396c1.33594 -1.55176 4.08203 -2.81055 6.12988 -2.81055
c1.54492 0 3.78516 0.775391 5 1.73047l34.4199 27l9.68066 -11.4902c1.7334 -1.98242 5.27832 -3.5918 7.91211 -3.5918c1.98438 0 4.86816 0.986328 6.4375 2.20215zM187.44 29c9.93555 0 18 -8.06445 18 -18s-8.06445 -18 -18 -18c-9.93652 0 -18 8.06445 -18 18
s8.06348 18 18 18z" />
<glyph glyph-name="mastodon" unicode="&#xf4f6;"
d="M433 268.89c0 0 0.799805 -71.6992 -9 -121.5c-6.23047 -31.5996 -55.1104 -66.1992 -111.23 -72.8994c-20.0996 -2.40039 -93.1191 -14.2002 -178.75 6.7002v-0.339844c0 -3.75977 0.40332 -9.83496 0.900391 -13.5605c6.62988 -49.5996 49.2197 -52.5996 89.6299 -54
c40.8105 -1.2998 77.1201 10.0996 77.1201 10.0996l1.7002 -36.8994s-28.5098 -15.2998 -79.3203 -18.1006c-28.0098 -1.59961 -62.8193 0.700195 -103.33 11.4004c-112.229 29.7002 -105.63 173.4 -105.63 289.1c0 97.2002 63.7197 125.7 63.7197 125.7
@ -3438,5 +3436,14 @@ c0 7.7207 7 14.6104 20.4102 14.6104c14.0898 0 20.79 -8.4502 20.79 -18.3496h30.70
c17.2598 -6.15039 21.9102 -10.4004 21.9102 -19.4795c0 -15.2002 -19.1309 -14.2305 -19.4707 -14.2305c-20.3994 0 -25.6494 9.09961 -25.6494 21.9004h-30.7998l-0.180664 -0.560547c-0.679688 -31.3203 28.3799 -45.2197 56.6299 -45.2197
c29.9805 0 51.1201 13.5498 51.1201 38.29zM276.68 215.79c0 25.2998 -18.4297 45.46 -53.4199 45.46h-51.7793v-138.18h32.1699v47.3594h19.6094c30.25 0 53.4199 15.9502 53.4199 45.3604zM297.94 123l49.0596 138.22h-31.0898l-47.9102 -138.22h29.9404zM404.46 261.22
h-31.0898l-47.9102 -138.22h29.9404z" />
<glyph glyph-name="cotton-bureau" unicode="&#xf89e;" horiz-adv-x="512"
d="M474.31 117.59h25.1807c-25.7998 -109.78 -111.4 -173.59 -239.67 -173.59c-154.63 -0.339844 -247.82 92.8604 -247.82 248.18c0 154.63 93 247.82 247.82 247.82c128.399 0 214.06 -63.5098 240.18 -173.61h-25.2598
c-24.8506 95.6104 -99.9199 148.811 -214.69 148.811c-141.85 0 -223.2 -81.3799 -223.2 -223.2c0 -137.93 76.6699 -218 211.101 -223v49.2002c0 48.1602 -26.5498 74.3896 -74.5498 74.3896c-62.1309 0 -99.4004 37.2803 -99.4004 99.4102
c0 61.3701 36.5195 98.2803 97.3799 99.0596c30.7402 64.6504 144.24 69.3203 177.24 0c60.8496 -0.779297 97.3799 -37.6895 97.3799 -99.0596c0 -62.0098 -37.2002 -99.21 -99.2002 -99.21c-47.9795 0 -74.3896 -26.3896 -74.3896 -74.3896v-49.1602
c107.67 3.75977 178.24 56.5 201.899 148.35zM357 265.67c3.7998 -21.0801 11.2695 -104.2 -71.79 -120.75c12.2598 -17.7402 32.9805 -27.3301 61.5898 -27.3301c47.9697 0 74.4004 26.4102 74.4004 74.4102c0 44.6699 -22.8301 70.2197 -64.2002 73.6699zM275.32 168.31
c72.7803 9.89062 58.5 86.9102 56.2295 97c-72.5596 -10 -58.6895 -86.6592 -56.2295 -97zM260 316l-0.179688 -0.259766c-28.3008 0 -49.1602 -9.66016 -61.5703 -27.3506c28.3701 -5.44922 49.3701 -20.5898 61.5996 -43.4492
c12.2305 22.8594 33.2305 37.9697 61.5908 43.4492c-12.4404 17.9404 -32.8301 27.6104 -61.4404 27.6104zM188.48 265.28h0.239258c-2.75 -10.0498 -16.1602 -87.1602 56.25 -97c2.41992 10.1895 16.6807 86.4297 -56.4893 97zM173.2 117.59l0.330078 0.0302734
c28.2998 0 49 9.66992 61.1396 27.2998c-73.0303 14.2197 -78.4004 83.5498 -71.6504 120.75c-41.3594 -3.66992 -64.2197 -29.3096 -64.2197 -73.6699c0 -48.0098 26.4004 -74.4102 74.4004 -74.4102zM226.41 105.2h0.269531
c14.4902 -7.60059 25.5605 -19.3301 33.5605 -33.8301c6.36523 12.2188 21.4092 27.374 33.5801 33.8301c-14.4902 8.00977 -26.0508 19.0596 -33.8203 33.5498c-6.4248 -12.1094 -21.4736 -27.1396 -33.5898 -33.5498z" />
</font>
</defs></svg>

Before

Width:  |  Height:  |  Size: 674 KiB

After

Width:  |  Height:  |  Size: 675 KiB

View File

@ -1,12 +1,12 @@
<?xml version="1.0" standalone="no"?>
<!--
Font Awesome Free 5.9.0 by @fontawesome - https://fontawesome.com
Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<metadata>
Created by FontForge 20190112 at Tue Jun 4 15:16:44 2019
Created by FontForge 20190801 at Thu Aug 22 14:41:09 2019
By Robert Madole
Copyright (c) Font Awesome
</metadata>
@ -22,7 +22,7 @@ Copyright (c) Font Awesome
descent="-64"
bbox="-0.0663408 -64.0662 640.01 448.1"
underline-thickness="25"
underline-position="-51"
underline-position="-50"
unicode-range="U+0020-F5C8"
/>
<missing-glyph />

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 141 KiB

View File

@ -1,12 +1,12 @@
<?xml version="1.0" standalone="no"?>
<!--
Font Awesome Free 5.9.0 by @fontawesome - https://fontawesome.com
Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<metadata>
Created by FontForge 20190112 at Tue Jun 4 15:16:44 2019
Created by FontForge 20190801 at Thu Aug 22 14:41:09 2019
By Robert Madole
Copyright (c) Font Awesome
</metadata>
@ -22,7 +22,7 @@ Copyright (c) Font Awesome
descent="-64"
bbox="-0.983398 -64.9834 640.104 448.427"
underline-thickness="25"
underline-position="-51"
underline-position="-50"
unicode-range="U+0020-F897"
/>
<missing-glyph />

Before

Width:  |  Height:  |  Size: 820 KiB

After

Width:  |  Height:  |  Size: 820 KiB

View File

@ -10,7 +10,7 @@
/******/ var moduleId, chunkId, i = 0, resolves = [];
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(installedChunks[chunkId]) {
/******/ if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ resolves.push(installedChunks[chunkId][0]);
/******/ }
/******/ installedChunks[chunkId] = 0;
@ -148,278 +148,117 @@
/******/
/******/
/******/ // add entry module to deferred list
/******/ deferredModules.push(["./assets/index.js","vendor","admin"]);
/******/ deferredModules.push(["./assets/public/index.js","vendor"]);
/******/ // run deferred modules when ready
/******/ return checkDeferredModules();
/******/ })
/************************************************************************/
/******/ ({
/***/ "./assets/index.js":
/*!*************************!*\
!*** ./assets/index.js ***!
\*************************/
/*! no exports provided */
/*! all exports used */
/***/ "./assets/public/app.js":
/*!******************************!*\
!*** ./assets/public/app.js ***!
\******************************/
/*! exports provided: app, default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/all.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/all.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/fontawesome.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./js */ \"./assets/js/index.js\");\n/* harmony import */ var _vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./vue */ \"./assets/vue/index.js\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./styles.scss */ \"./assets/styles.scss\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_styles_scss__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _admin__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./admin */ \"./assets/admin/index.js\");\n\n\n\n\n\n\n\n// import './noscript.scss';\n\n\n\n\n//# sourceURL=webpack:///./assets/index.js?");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"app\", function() { return app; });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n\n\n\nvar app = null;\n/* harmony default export */ __webpack_exports__[\"default\"] = (app);\n\nfunction loadApp() {\n app = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n el: '#app',\n delimiters: [ '[[', ']]' ],\n })\n}\n\nwindow.addEventListener('load', loadApp);\n\n\n\n\n\n//# sourceURL=webpack:///./assets/public/app.js?");
/***/ }),
/***/ "./assets/js/app.js":
/*!**************************!*\
!*** ./assets/js/app.js ***!
\**************************/
/*! exports provided: app */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* unused harmony export app */\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n/* harmony import */ var buefy__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! buefy */ \"./node_modules/buefy/dist/buefy.js\");\n/* harmony import */ var buefy__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(buefy__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(buefy__WEBPACK_IMPORTED_MODULE_1___default.a);\n\nvar app = null;\n\nfunction loadApp() {\n app = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n el: '#app',\n delimiters: [ '[[', ']]' ],\n })\n}\n\n\nwindow.addEventListener('load', loadApp);\n\n\n\n\n//# sourceURL=webpack:///./assets/js/app.js?");
/***/ }),
/***/ "./assets/js/index.js":
/*!****************************!*\
!*** ./assets/js/index.js ***!
\****************************/
/***/ "./assets/public/index.js":
/*!********************************!*\
!*** ./assets/public/index.js ***!
\********************************/
/*! no exports provided */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./app */ \"./assets/js/app.js\");\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./liveInfo */ \"./assets/js/liveInfo.js\");\n\n\n\n\n\n\n//# sourceURL=webpack:///./assets/js/index.js?");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/all.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/all.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/fontawesome.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var buefy_dist_buefy_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! buefy/dist/buefy.css */ \"./node_modules/buefy/dist/buefy.css\");\n/* harmony import */ var buefy_dist_buefy_css__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(buefy_dist_buefy_css__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./app */ \"./assets/public/app.js\");\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./styles.scss */ \"./assets/public/styles.scss\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_styles_scss__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _player_vue__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./player.vue */ \"./assets/public/player.vue\");\n/**\n * This module includes code available for both the public website and\n * administration interface)\n */\n//-- vendor\n\n\n\n\n\n\n\n//-- aircox\n\n\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-player', _player_vue__WEBPACK_IMPORTED_MODULE_7__[\"default\"])\n\n\nwindow.aircox = {\n app: _app__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n LiveInfo: _liveInfo__WEBPACK_IMPORTED_MODULE_5__[\"default\"],\n}\n\n\n\n//# sourceURL=webpack:///./assets/public/index.js?");
/***/ }),
/***/ "./assets/js/liveInfo.js":
/*!*******************************!*\
!*** ./assets/js/liveInfo.js ***!
\*******************************/
/***/ "./assets/public/liveInfo.js":
/*!***********************************!*\
!*** ./assets/public/liveInfo.js ***!
\***********************************/
/*! exports provided: default */
/*! exports used: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("\n/* harmony default export */ __webpack_exports__[\"a\"] = (class {\n constructor(url, timeout) {\n this.url = url;\n this.timeout = timeout;\n this.promise = null;\n this.items = [];\n }\n\n drop() {\n this.promise = null;\n }\n\n fetch() {\n const promise = fetch(this.url).then(response =>\n response.ok ? response.json()\n : Promise.reject(response)\n ).then(data => {\n this.items = data;\n return this.items\n })\n\n this.promise = promise;\n return promise;\n }\n\n refresh() {\n const promise = this.fetch();\n promise.then(data => {\n if(promise != this.promise)\n return [];\n\n window.setTimeout(() => this.refresh(), this.timeout*1000)\n })\n return promise\n }\n});\n\n\n//# sourceURL=webpack:///./assets/js/liveInfo.js?");
eval("__webpack_require__.r(__webpack_exports__);\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (class {\n constructor(url, timeout) {\n this.url = url;\n this.timeout = timeout;\n this.promise = null;\n this.items = [];\n }\n\n drop() {\n this.promise = null;\n }\n\n fetch() {\n const promise = fetch(this.url).then(response =>\n response.ok ? response.json()\n : Promise.reject(response)\n ).then(data => {\n this.items = data;\n return this.items\n })\n\n this.promise = promise;\n return promise;\n }\n\n refresh() {\n const promise = this.fetch();\n promise.then(data => {\n if(promise != this.promise)\n return [];\n\n window.setTimeout(() => this.refresh(), this.timeout*1000)\n })\n return promise\n }\n});\n\n\n//# sourceURL=webpack:///./assets/public/liveInfo.js?");
/***/ }),
/***/ "./assets/styles.scss":
/*!****************************!*\
!*** ./assets/styles.scss ***!
\****************************/
/***/ "./assets/public/player.vue":
/*!**********************************!*\
!*** ./assets/public/player.vue ***!
\**********************************/
/*! exports provided: default, State */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./player.vue?vue&type=template&id=42a56ec9& */ \"./assets/public/player.vue?vue&type=template&id=42a56ec9&\");\n/* harmony import */ var _player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./player.vue?vue&type=script&lang=js& */ \"./assets/public/player.vue?vue&type=script&lang=js&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return _player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"State\"]; });\n\n/* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(\n _player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n _player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__[\"render\"],\n _player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"],\n false,\n null,\n null,\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"assets/public/player.vue\"\n/* harmony default export */ __webpack_exports__[\"default\"] = (component.exports);\n\n//# sourceURL=webpack:///./assets/public/player.vue?");
/***/ }),
/***/ "./assets/public/player.vue?vue&type=script&lang=js&":
/*!***********************************************************!*\
!*** ./assets/public/player.vue?vue&type=script&lang=js& ***!
\***********************************************************/
/*! exports provided: default, State */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib??vue-loader-options!./player.vue?vue&type=script&lang=js& */ \"./node_modules/vue-loader/lib/index.js?!./assets/public/player.vue?vue&type=script&lang=js&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return _node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__[\"State\"]; });\n\n /* harmony default export */ __webpack_exports__[\"default\"] = (_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__[\"default\"]); \n\n//# sourceURL=webpack:///./assets/public/player.vue?");
/***/ }),
/***/ "./assets/public/player.vue?vue&type=template&id=42a56ec9&":
/*!*****************************************************************!*\
!*** ./assets/public/player.vue?vue&type=template&id=42a56ec9& ***!
\*****************************************************************/
/*! exports provided: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../node_modules/vue-loader/lib??vue-loader-options!./player.vue?vue&type=template&id=42a56ec9& */ \"./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/public/player.vue?vue&type=template&id=42a56ec9&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__[\"render\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_template_id_42a56ec9___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"]; });\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?");
/***/ }),
/***/ "./assets/public/styles.scss":
/*!***********************************!*\
!*** ./assets/public/styles.scss ***!
\***********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
eval("// extracted by mini-css-extract-plugin\n\n//# sourceURL=webpack:///./assets/styles.scss?");
eval("// extracted by mini-css-extract-plugin\n\n//# sourceURL=webpack:///./assets/public/styles.scss?");
/***/ }),
/***/ "./assets/vue/index.js":
/*!*****************************!*\
!*** ./assets/vue/index.js ***!
\*****************************/
/*! exports provided: Player, Tab, Tabs */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n/* harmony import */ var _player_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./player.vue */ \"./assets/vue/player.vue\");\n/* harmony import */ var _tab_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./tab.vue */ \"./assets/vue/tab.vue\");\n/* harmony import */ var _tabs_vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./tabs.vue */ \"./assets/vue/tabs.vue\");\n\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-player', _player_vue__WEBPACK_IMPORTED_MODULE_1__[/* default */ \"a\"]);\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-tab', _tab_vue__WEBPACK_IMPORTED_MODULE_2__[/* default */ \"a\"]);\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-tabs', _tabs_vue__WEBPACK_IMPORTED_MODULE_3__[/* default */ \"a\"]);\n\n\n\n\n\n\n//# sourceURL=webpack:///./assets/vue/index.js?");
/***/ }),
/***/ "./assets/vue/player.vue":
/*!*******************************!*\
!*** ./assets/vue/player.vue ***!
\*******************************/
/*! exports provided: default, State */
/*! exports used: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var _player_vue_vue_type_template_id_2882cef8___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./player.vue?vue&type=template&id=2882cef8& */ \"./assets/vue/player.vue?vue&type=template&id=2882cef8&\");\n/* harmony import */ var _player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./player.vue?vue&type=script&lang=js& */ \"./assets/vue/player.vue?vue&type=script&lang=js&\");\n/* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__[/* default */ \"a\"])(\n _player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[/* default */ \"a\"],\n _player_vue_vue_type_template_id_2882cef8___WEBPACK_IMPORTED_MODULE_0__[/* render */ \"a\"],\n _player_vue_vue_type_template_id_2882cef8___WEBPACK_IMPORTED_MODULE_0__[/* staticRenderFns */ \"b\"],\n false,\n null,\n null,\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"assets/vue/player.vue\"\n/* harmony default export */ __webpack_exports__[\"a\"] = (component.exports);\n\n//# sourceURL=webpack:///./assets/vue/player.vue?");
/***/ }),
/***/ "./assets/vue/player.vue?vue&type=script&lang=js&":
/*!********************************************************!*\
!*** ./assets/vue/player.vue?vue&type=script&lang=js& ***!
\********************************************************/
/*! exports provided: default, State */
/*! exports used: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var _node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib??vue-loader-options!./player.vue?vue&type=script&lang=js& */ \"./node_modules/vue-loader/lib/index.js?!./assets/vue/player.vue?vue&type=script&lang=js&\");\n /* harmony default export */ __webpack_exports__[\"a\"] = (_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__[/* default */ \"a\"]); \n\n//# sourceURL=webpack:///./assets/vue/player.vue?");
/***/ }),
/***/ "./assets/vue/player.vue?vue&type=template&id=2882cef8&":
/*!**************************************************************!*\
!*** ./assets/vue/player.vue?vue&type=template&id=2882cef8& ***!
\**************************************************************/
/*! exports provided: render, staticRenderFns */
/*! exports used: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_template_id_2882cef8___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../node_modules/vue-loader/lib??vue-loader-options!./player.vue?vue&type=template&id=2882cef8& */ \"./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/vue/player.vue?vue&type=template&id=2882cef8&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_template_id_2882cef8___WEBPACK_IMPORTED_MODULE_0__[\"a\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_player_vue_vue_type_template_id_2882cef8___WEBPACK_IMPORTED_MODULE_0__[\"b\"]; });\n\n\n\n//# sourceURL=webpack:///./assets/vue/player.vue?");
/***/ }),
/***/ "./assets/vue/tab.vue":
/*!****************************!*\
!*** ./assets/vue/tab.vue ***!
\****************************/
/*! exports provided: default */
/*! exports used: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var _tab_vue_vue_type_template_id_65401e0e___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./tab.vue?vue&type=template&id=65401e0e& */ \"./assets/vue/tab.vue?vue&type=template&id=65401e0e&\");\n/* harmony import */ var _tab_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tab.vue?vue&type=script&lang=js& */ \"./assets/vue/tab.vue?vue&type=script&lang=js&\");\n/* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__[/* default */ \"a\"])(\n _tab_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[/* default */ \"a\"],\n _tab_vue_vue_type_template_id_65401e0e___WEBPACK_IMPORTED_MODULE_0__[/* render */ \"a\"],\n _tab_vue_vue_type_template_id_65401e0e___WEBPACK_IMPORTED_MODULE_0__[/* staticRenderFns */ \"b\"],\n false,\n null,\n null,\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"assets/vue/tab.vue\"\n/* harmony default export */ __webpack_exports__[\"a\"] = (component.exports);\n\n//# sourceURL=webpack:///./assets/vue/tab.vue?");
/***/ }),
/***/ "./assets/vue/tab.vue?vue&type=script&lang=js&":
/*!*****************************************************!*\
!*** ./assets/vue/tab.vue?vue&type=script&lang=js& ***!
\*****************************************************/
/*! exports provided: default */
/*! exports used: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var _node_modules_vue_loader_lib_index_js_vue_loader_options_tab_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib??vue-loader-options!./tab.vue?vue&type=script&lang=js& */ \"./node_modules/vue-loader/lib/index.js?!./assets/vue/tab.vue?vue&type=script&lang=js&\");\n /* harmony default export */ __webpack_exports__[\"a\"] = (_node_modules_vue_loader_lib_index_js_vue_loader_options_tab_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__[/* default */ \"a\"]); \n\n//# sourceURL=webpack:///./assets/vue/tab.vue?");
/***/ }),
/***/ "./assets/vue/tab.vue?vue&type=template&id=65401e0e&":
/*!***********************************************************!*\
!*** ./assets/vue/tab.vue?vue&type=template&id=65401e0e& ***!
\***********************************************************/
/*! exports provided: render, staticRenderFns */
/*! exports used: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_tab_vue_vue_type_template_id_65401e0e___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../node_modules/vue-loader/lib??vue-loader-options!./tab.vue?vue&type=template&id=65401e0e& */ \"./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/vue/tab.vue?vue&type=template&id=65401e0e&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_tab_vue_vue_type_template_id_65401e0e___WEBPACK_IMPORTED_MODULE_0__[\"a\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_tab_vue_vue_type_template_id_65401e0e___WEBPACK_IMPORTED_MODULE_0__[\"b\"]; });\n\n\n\n//# sourceURL=webpack:///./assets/vue/tab.vue?");
/***/ }),
/***/ "./assets/vue/tabs.vue":
/*!*****************************!*\
!*** ./assets/vue/tabs.vue ***!
\*****************************/
/*! exports provided: default */
/*! exports used: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var _tabs_vue_vue_type_template_id_466f44d5___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./tabs.vue?vue&type=template&id=466f44d5& */ \"./assets/vue/tabs.vue?vue&type=template&id=466f44d5&\");\n/* harmony import */ var _tabs_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tabs.vue?vue&type=script&lang=js& */ \"./assets/vue/tabs.vue?vue&type=script&lang=js&\");\n/* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__[/* default */ \"a\"])(\n _tabs_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[/* default */ \"a\"],\n _tabs_vue_vue_type_template_id_466f44d5___WEBPACK_IMPORTED_MODULE_0__[/* render */ \"a\"],\n _tabs_vue_vue_type_template_id_466f44d5___WEBPACK_IMPORTED_MODULE_0__[/* staticRenderFns */ \"b\"],\n false,\n null,\n null,\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"assets/vue/tabs.vue\"\n/* harmony default export */ __webpack_exports__[\"a\"] = (component.exports);\n\n//# sourceURL=webpack:///./assets/vue/tabs.vue?");
/***/ }),
/***/ "./assets/vue/tabs.vue?vue&type=script&lang=js&":
/*!******************************************************!*\
!*** ./assets/vue/tabs.vue?vue&type=script&lang=js& ***!
\******************************************************/
/*! exports provided: default */
/*! exports used: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var _node_modules_vue_loader_lib_index_js_vue_loader_options_tabs_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib??vue-loader-options!./tabs.vue?vue&type=script&lang=js& */ \"./node_modules/vue-loader/lib/index.js?!./assets/vue/tabs.vue?vue&type=script&lang=js&\");\n /* harmony default export */ __webpack_exports__[\"a\"] = (_node_modules_vue_loader_lib_index_js_vue_loader_options_tabs_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__[/* default */ \"a\"]); \n\n//# sourceURL=webpack:///./assets/vue/tabs.vue?");
/***/ }),
/***/ "./assets/vue/tabs.vue?vue&type=template&id=466f44d5&":
/*!************************************************************!*\
!*** ./assets/vue/tabs.vue?vue&type=template&id=466f44d5& ***!
\************************************************************/
/*! exports provided: render, staticRenderFns */
/*! exports used: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_tabs_vue_vue_type_template_id_466f44d5___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../node_modules/vue-loader/lib??vue-loader-options!./tabs.vue?vue&type=template&id=466f44d5& */ \"./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/vue/tabs.vue?vue&type=template&id=466f44d5&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_tabs_vue_vue_type_template_id_466f44d5___WEBPACK_IMPORTED_MODULE_0__[\"a\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_tabs_vue_vue_type_template_id_466f44d5___WEBPACK_IMPORTED_MODULE_0__[\"b\"]; });\n\n\n\n//# sourceURL=webpack:///./assets/vue/tabs.vue?");
/***/ }),
/***/ "./node_modules/vue-loader/lib/index.js?!./assets/vue/player.vue?vue&type=script&lang=js&":
/*!**********************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib??vue-loader-options!./assets/vue/player.vue?vue&type=script&lang=js& ***!
\**********************************************************************************************************/
/***/ "./node_modules/vue-loader/lib/index.js?!./assets/public/player.vue?vue&type=script&lang=js&":
/*!*************************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib??vue-loader-options!./assets/public/player.vue?vue&type=script&lang=js& ***!
\*************************************************************************************************************/
/*! exports provided: State, default */
/*! exports used: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* unused harmony export State */\n/* harmony import */ var js_liveInfo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! js/liveInfo */ \"./assets/js/liveInfo.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst State = {\n paused: 0,\n playing: 1,\n loading: 2,\n}\n\n/* harmony default export */ __webpack_exports__[\"a\"] = ({\n data() {\n return {\n state: State.paused,\n liveInfo: new js_liveInfo__WEBPACK_IMPORTED_MODULE_0__[/* default */ \"a\"](this.liveInfoUrl, this.liveInfoTimeout),\n }\n },\n\n props: {\n buttonTitle: String,\n liveInfoUrl: String,\n liveInfoTimeout: { type: Number, default: 5},\n src: String,\n },\n\n computed: {\n paused() { return this.state == State.paused; },\n playing() { return this.state == State.playing; },\n loading() { return this.state == State.loading; },\n\n onAir() {\n return this.liveInfo.items && this.liveInfo.items[0];\n },\n\n buttonStyle() {\n if(!this.onAir)\n return;\n return { backgroundImage: `url(${this.onAir.cover})` }\n }\n },\n\n methods: {\n load(src) {\n const audio = this.$refs.audio;\n audio.src = src;\n audio.load()\n },\n\n play(src) {\n if(src)\n this.load(src);\n this.$refs.audio.play().catch(e => console.error(e))\n },\n\n pause() {\n this.$refs.audio.pause()\n },\n\n toggle() {\n if(this.paused)\n this.play()\n else\n this.pause()\n },\n\n onChange(event) {\n const audio = this.$refs.audio;\n this.state = audio.paused ? State.paused : State.playing;\n },\n },\n\n mounted() {\n this.liveInfo.refresh()\n },\n\n destroyed() {\n this.liveInfo.drop()\n },\n});\n\n\n\n//# sourceURL=webpack:///./assets/vue/player.vue?./node_modules/vue-loader/lib??vue-loader-options");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return State; });\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst State = {\n paused: 0,\n playing: 1,\n loading: 2,\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n data() {\n return {\n state: State.paused,\n liveInfo: new _liveInfo__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.liveInfoUrl, this.liveInfoTimeout),\n }\n },\n\n props: {\n buttonTitle: String,\n liveInfoUrl: String,\n liveInfoTimeout: { type: Number, default: 5},\n src: String,\n },\n\n computed: {\n paused() { return this.state == State.paused; },\n playing() { return this.state == State.playing; },\n loading() { return this.state == State.loading; },\n\n onAir() {\n return this.liveInfo.items && this.liveInfo.items[0];\n },\n\n buttonStyle() {\n if(!this.onAir)\n return;\n return { backgroundImage: `url(${this.onAir.cover})` }\n }\n },\n\n methods: {\n load(src) {\n const audio = this.$refs.audio;\n audio.src = src;\n audio.load()\n },\n\n play(src) {\n if(src)\n this.load(src);\n this.$refs.audio.play().catch(e => console.error(e))\n },\n\n pause() {\n this.$refs.audio.pause()\n },\n\n toggle() {\n if(this.paused)\n this.play()\n else\n this.pause()\n },\n\n onChange(event) {\n const audio = this.$refs.audio;\n this.state = audio.paused ? State.paused : State.playing;\n },\n },\n\n mounted() {\n this.liveInfo.refresh()\n },\n\n destroyed() {\n this.liveInfo.drop()\n },\n});\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
/***/ "./node_modules/vue-loader/lib/index.js?!./assets/vue/tab.vue?vue&type=script&lang=js&":
/*!*******************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib??vue-loader-options!./assets/vue/tab.vue?vue&type=script&lang=js& ***!
\*******************************************************************************************************/
/*! exports provided: default */
/*! exports used: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("//\n//\n//\n//\n//\n//\n//\n\n/* harmony default export */ __webpack_exports__[\"a\"] = ({\n props: {\n value: { default: undefined },\n },\n\n methods: {\n select() {\n this.$parent.selectTab(this);\n },\n\n onclick(event) {\n this.select();\n /*if(event.target.href != document.location)\n window.history.pushState(\n { url: event.target.href },\n event.target.innerText + ' - ' + document.title,\n event.target.href\n ) */\n }\n }\n});\n\n\n//# sourceURL=webpack:///./assets/vue/tab.vue?./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
/***/ "./node_modules/vue-loader/lib/index.js?!./assets/vue/tabs.vue?vue&type=script&lang=js&":
/*!********************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib??vue-loader-options!./assets/vue/tabs.vue?vue&type=script&lang=js& ***!
\********************************************************************************************************/
/*! exports provided: default */
/*! exports used: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n/* harmony default export */ __webpack_exports__[\"a\"] = ({\n props: {\n default: { default: null },\n },\n\n data() {\n return {\n value: this.default,\n }\n },\n\n computed: {\n tab() {\n const vnode = this.$slots.default && this.$slots.default.find(\n elm => elm.child && elm.child.value == this.value\n );\n return vnode && vnode.child;\n }\n },\n\n methods: {\n selectTab(tab) {\n const value = tab.value;\n if(this.value === value)\n return;\n\n this.value = value;\n this.$emit('select', {target: this, value: value, tab: tab});\n },\n },\n});\n\n\n//# sourceURL=webpack:///./assets/vue/tabs.vue?./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/vue/player.vue?vue&type=template&id=2882cef8&":
/*!********************************************************************************************************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./assets/vue/player.vue?vue&type=template&id=2882cef8& ***!
\********************************************************************************************************************************************************************************************/
/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/public/player.vue?vue&type=template&id=42a56ec9&":
/*!***********************************************************************************************************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./assets/public/player.vue?vue&type=template&id=42a56ec9& ***!
\***********************************************************************************************************************************************************************************************/
/*! exports provided: render, staticRenderFns */
/*! exports used: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"media\" }, [\n _c(\"div\", { staticClass: \"media-left\" }, [\n _c(\n \"div\",\n {\n staticClass: \"button\",\n attrs: { title: _vm.buttonTitle, \"aria-label\": _vm.buttonTitle },\n on: {\n click: function($event) {\n return _vm.toggle()\n }\n }\n },\n [\n _vm.playing\n ? _c(\"span\", { staticClass: \"fas fa-pause\" })\n : _c(\"span\", { staticClass: \"fas fa-play\" })\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"audio\",\n {\n ref: \"audio\",\n on: {\n playing: _vm.onChange,\n ended: _vm.onChange,\n pause: _vm.onChange\n }\n },\n [_vm._t(\"sources\")],\n 2\n )\n ]),\n _vm._v(\" \"),\n _vm.onAir && _vm.onAir.cover\n ? _c(\"div\", { staticClass: \"media-left media-cover\" }, [\n _c(\"img\", { staticClass: \"cover\", attrs: { src: _vm.onAir.cover } })\n ])\n : _vm._e(),\n _vm._v(\" \"),\n _vm.onAir && _vm.onAir.type == \"track\"\n ? _c(\n \"div\",\n { staticClass: \"media-content\" },\n [_vm._t(\"track\", null, { onAir: _vm.onAir, liveInfo: _vm.liveInfo })],\n 2\n )\n : _vm.onAir && _vm.onAir.type == \"diffusion\"\n ? _c(\n \"div\",\n { staticClass: \"media-content\" },\n [\n _vm._t(\"diffusion\", null, {\n onAir: _vm.onAir,\n liveInfo: _vm.liveInfo\n })\n ],\n 2\n )\n : _c(\"div\", { staticClass: \"media-content\" }, [_vm._t(\"empty\")], 2)\n ])\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./assets/vue/player.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/vue/tab.vue?vue&type=template&id=65401e0e&":
/*!*****************************************************************************************************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./assets/vue/tab.vue?vue&type=template&id=65401e0e& ***!
\*****************************************************************************************************************************************************************************************/
/*! exports provided: render, staticRenderFns */
/*! exports used: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"li\",\n {\n class: { \"is-active\": _vm.$parent.value == _vm.value },\n on: {\n click: function($event) {\n $event.preventDefault()\n return _vm.onclick($event)\n }\n }\n },\n [_vm._t(\"default\")],\n 2\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./assets/vue/tab.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./assets/vue/tabs.vue?vue&type=template&id=466f44d5&":
/*!******************************************************************************************************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./assets/vue/tabs.vue?vue&type=template&id=466f44d5& ***!
\******************************************************************************************************************************************************************************************/
/*! exports provided: render, staticRenderFns */
/*! exports used: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n [\n _c(\"div\", { staticClass: \"tabs is-centered is-medium\" }, [\n _c(\"ul\", [_vm._t(\"tabs\", null, { value: _vm.value })], 2)\n ]),\n _vm._v(\" \"),\n _vm._t(\"default\", null, { value: _vm.value })\n ],\n 2\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./assets/vue/tabs.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"media\" }, [\n _c(\"div\", { staticClass: \"media-left\" }, [\n _c(\n \"div\",\n {\n staticClass: \"button\",\n attrs: { title: _vm.buttonTitle, \"aria-label\": _vm.buttonTitle },\n on: {\n click: function($event) {\n return _vm.toggle()\n }\n }\n },\n [\n _vm.playing\n ? _c(\"span\", { staticClass: \"fas fa-pause\" })\n : _c(\"span\", { staticClass: \"fas fa-play\" })\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"audio\",\n {\n ref: \"audio\",\n on: {\n playing: _vm.onChange,\n ended: _vm.onChange,\n pause: _vm.onChange\n }\n },\n [_vm._t(\"sources\")],\n 2\n )\n ]),\n _vm._v(\" \"),\n _vm.onAir && _vm.onAir.cover\n ? _c(\"div\", { staticClass: \"media-left media-cover\" }, [\n _c(\"img\", { staticClass: \"cover\", attrs: { src: _vm.onAir.cover } })\n ])\n : _vm._e(),\n _vm._v(\" \"),\n _vm.onAir && _vm.onAir.type == \"track\"\n ? _c(\n \"div\",\n { staticClass: \"media-content\" },\n [_vm._t(\"track\", null, { onAir: _vm.onAir, liveInfo: _vm.liveInfo })],\n 2\n )\n : _vm.onAir && _vm.onAir.type == \"diffusion\"\n ? _c(\n \"div\",\n { staticClass: \"media-content\" },\n [\n _vm._t(\"diffusion\", null, {\n onAir: _vm.onAir,\n liveInfo: _vm.liveInfo\n })\n ],\n 2\n )\n : _c(\"div\", { staticClass: \"media-content\" }, [_vm._t(\"empty\")], 2)\n ])\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options");
/***/ })

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,12 +1,67 @@
{% extends "admin/base_site.html" %}
{% load i18n %}
{% load i18n aircox %}
{% block content %}{{ block.super }}
<table class="table">
{# TODO: date subtitle #}
<a-statistics>
<template v-slot:default="{counts}">
<table class="table is-hoverable is-fullwidth">
<thead>
<tr>
<th>{% trans "time" %}</th>
<th>{% trans "episode" %}</th>
<th>{% trans "track" %}</th>
<th>{% trans "tags" %}</th>
</tr>
</thead>
<tbody>
{% for object in object_list %}
{% with object|get_tracks as tracks %}
{% for track in tracks %}
<tr>
{% if forloop.first %}
<td rowspan="{{ tracks|length }}">{{ object.start|time:"H:i" }}</td>
<td rowspan="{{ tracks|length }}">{{ object.episode|default:"" }}</td>
{% endif %}
</table>
{% if not object|is_diffusion %}
{% with track as object %}
<td>{% include "aircox/track_item.html" %}</td>
{% endwith %}
{% with track.tags.all|join:', ' as tags %}
<td>
{% if tags %}
<label class="checkbox">
<input type="checkbox" checked value="{{ tags|escape }}" name="data">
{{ tags }}
</label>
{% endif %}
</td>
{% endwith %}
{% else %}
{% endif %}
{% endfor %}
<tr>
{% endwith %}
{% endfor %}
</tbody>
<tfoot>
<tr>
<td class="is-size-6">{% trans "Totals" %}</td>
<td colspan="100">
<div class="columns is-size-6">
<span v-for="(count, tag) in counts" class="column">
<b>[[ tag ]]</b>
[[ count ]]
</span>
</div>
</td>
</tr>
</tfoot>
</table>
</template>
</a-statistics>
{% endblock %}

View File

@ -8,6 +8,9 @@
<link rel="stylesheet" type="text/css" href="{% static "aircox/main.css" %}">
<link rel="stylesheet" type="text/css" href="{% static "aircox/admin.css" %}">
<script src="{% static "aircox/vendor.js" %}"></script>
<script src="{% static "aircox/admin.js" %}"></script>
{% block extrastyle %}{% endblock %}
{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}">{% endif %}
@ -26,7 +29,7 @@
data-admin-utc-offset="{% now "Z" %}">
<!-- Container -->
<div id="container">
<div id="app">
{% if not is_popup %}
<!-- Header -->
@ -59,16 +62,16 @@
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item has-dropdown is-hoverable">
<a href="#" class="navbar-link">{% trans "Tools" %}</a>
<div class="navbar-dropdown is-boxed is-right">
<a href="{% url 'admin:tools-stats' %}" class="navbar-item">{% trans "Statistics" %}</a>
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item has-dropdown is-hoverable">
<a href="{% url "admin:auth_user_change" user.pk %}" class="navbar-link">
{% firstof user.get_short_name user.get_username %}

View File

@ -14,10 +14,10 @@ Context:
<link rel="icon" href="{% thumbnail site.favicon 32x32 crop %}" />
{% block assets %}
<link rel="stylesheet" type="text/css" href="{% static "aircox/main.css" %}"/>
<link rel="stylesheet" type="text/css" href="{% static "aircox/vendor.css" %}"/>
<script src="{% static "aircox/main.js" %}"></script>
<link rel="stylesheet" type="text/css" href="{% static "aircox/main.css" %}"/>
<script src="{% static "aircox/vendor.js" %}"></script>
<script src="{% static "aircox/main.js" %}"></script>
{% endblock %}
<title>
@ -55,14 +55,19 @@ Context:
{% block header %}
<h1 class="title is-1">{% block title %}{% endblock %}</h1>
<h3 class="subtitle is-3 columns">
{% block subtitle %}
{% if parent %}
<a href="{{ parent.get_absolute_url }}" class="column">
&#10092; {{ parent.title }}</a></li>
{% endif %}
{% endblock %}
<h3 class="subtitle is-3">
{% block subtitle %}{% endblock %}
</h3>
<div class="columns is-size-4">
{% block header_meta %}
{% if parent %}
<a href="{{ parent.get_absolute_url }}" class="column">
&#10092; {{ parent.title }}</a></li>
{% endif %}
{% endblock %}
</div>
{% endblock %}
</header>

View File

@ -0,0 +1,44 @@
{% extends "aircox/page.html" %}
{% load i18n aircox %}
{% block title %}
{% with station.name as station %}
{% blocktrans %}Today on {{ station }}{% endblocktrans %}
{% endwith %}
{% endblock %}
{% block subtitle %}{{ date|date:"l d F Y" }}{% endblock %}
{% block main %}{{ block.super }}
<div class="columns">
{% with True as hide_schedule %}
<section class="column">
<div id="timetable-{{ date|date:"Y-m-d" }}">
{% for diffusion in object_list %}
<div class="columns">
<div class="column is-one-fifth has-text-right">
<time datetime="{{ diffusion.start|date:"c" }}">
{{ diffusion.start|date:"H:i" }} - {{ diffusion.end|date:"H:i" }}
</time>
</div>
<div class="column">
{% with diffusion.episode as object %}
{% include "aircox/episode_item.html" %}
{% endwith %}
</div>
</div>
{% endfor %}
</div>
</section>
{% endwith %}
<nav class="column menu is-one-third-desktop" role="menu">
{% with "diffusion-list" as url_name %}
{% include "aircox/widgets/dates_menu.html" %}
{% endwith %}
</nav>
</div>
{% endblock %}

View File

@ -1,62 +0,0 @@
{% extends "aircox/page.html" %}
{% load i18n aircox %}
{% block title %}
{% with station.name as station %}
{% blocktrans %}This week's shows... {% endblocktrans %}
{% endwith %}
{% endblock %}
{% block subtitle %}
<div class="column">
{% blocktrans %}From <b>{{ start }}</b> to <b>{{ end }}</b>{% endblocktrans %}
</div>
{% endblock %}
{% block main %}{{ block.super }}
{% with True as hide_schedule %}
<section>
{% unique_id "timetable" as timetable_id %}
<a-tabs default="{{ date }}">
<template v-slot:tabs="scope" noscript="hidden">
<li><a href="{% url "timetable" date=prev_date %}">&#10092; {% trans "Before" %}</a></li>
{% for day in by_date.keys %}
<a-tab value="{{ day }}">
<a href="{% url "timetable" date=day %}">
{{ day|date:"D. d" }}
</a>
</a-tab>
{% endfor %}
<li>
<a href="{% url "timetable" date=next_date %}">{% trans "After" %} &#10093;</a>
</li>
</template>
<template v-slot:default="{value}">
{% for day, diffusions in by_date.items %}
<noscript><h4 class="subtitle is-4">{{ day|date:"l d F Y" }}</h4></noscript>
<div id="{{timetable_id}}-{{ day|date:"Y-m-d" }}" v-if="value == '{{ day }}'">
{% for diffusion in diffusions %}
<div class="columns">
<div class="column is-one-fifth has-text-right">
<time datetime="{{ diffusion.start|date:"c" }}">
{{ diffusion.start|date:"H:i" }} - {{ diffusion.end|date:"H:i" }}
</time>
</div>
<div class="column">
{% with diffusion.episode as object %}
{% include "aircox/episode_item.html" %}
{% endwith %}
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</template>
</a-tabs>
</section>
{% endwith %}
{% endblock %}

View File

@ -16,13 +16,8 @@ for design review.
{% endwith %}
{% endwith %}
{% else %}
{% with object.track as track %}
<span class="has-text-info is-size-5">&#9836;</span>
<span>{{ track.title }}</span>
<span class="has-text-grey-dark has-text-weight-light">
&mdash; {{ track.artist }}
{% if track.info %}(<i>{{ track.info }}</i>){% endif %}
</span>
{% with object.track as object %}
{% include "aircox/track_item.html" %}
{% endwith %}
{% endif %}

View File

@ -1,31 +1,20 @@
{% extends "aircox/page.html" %}
{% load i18n aircox %}
{% load i18n humanize aircox %}
{% block title %}
{% trans "Logs" %}
{% with station.name as station %}
{% blocktrans %}That happened on {{ station }}{% endblocktrans %}
{% endwith %}
{% endblock %}
{% block subtitle %}{{ date|date:"l d F Y" }}{% endblock %}
{% block main %}
<section class="section">
{% if dates %}
<nav class="tabs is-medium is-centered" aria-label="{% trans "Other days' logs" %}">
<ul>
{% for day in dates %}
<li {% if day == date %}class="is-active"{% endif %}>
<a href="{% url "logs" date=day %}">
{{ day|date:"d b" }}
</a>
</li>
{% if forloop.last and day > min_date %}
<li>...</li>
{% endif %}
{% endfor %}
</ul>
</nav>
{% endif %}
<div class="columns">
<section class="section column">
{# <h4 class="subtitle size-4">{{ date }}</h4> #}
{% with True as hide_schedule %}
<table class="table is-striped is-hoverable is-fullwidth has-background-transparent">
@ -48,5 +37,13 @@
</table>
{% endwith %}
</section>
<nav class="column menu is-one-third-desktop" role="menu">
{% with "logs" as url_name %}
{% include "aircox/widgets/dates_menu.html" %}
{% endwith %}
</nav>
</div>
{% endblock %}

View File

@ -6,12 +6,11 @@ Context:
- page: page
{% endcomment %}
{% block subtitle %}
{{ block.super }}
{% if page.category %}
{% block header_meta %}{{ block.super }}
<span class="column has-text-right">{{ object.category.title }}</span>
{% endif %}
{% endblock %}
{% endif %}
{% block main %}
@ -51,7 +50,9 @@ Context:
{% for field in comment_form %}
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label">{{ field.label_tag }}</label>
<label class="label">
{{ field.label_tag }}
</label>
</div>
<div class="field-body">
<div class="field">

View File

@ -4,9 +4,8 @@
<br>
<div class="box is-fullwidth is-fixed-bottom is-paddingless player"
aria-role="{% trans "player" %}"
aria-description="{% trans "audio player used to listen to streams and podcasts" %}"
>
role="{% trans "player" %}"
aria-description="{% trans "audio player used to listen to the radio" %}">
<noscript>
<audio src="{{ audio_streams.0 }}" controls>
{% for stream in audio_streams %}
@ -18,7 +17,7 @@
<a-player ref="player" src="{{ audio_streams.0 }}"
live-info-url="{% url "api-live" %}" :live-info-timeout="15"
button-title="{% trans "Play/pause audio" %}">
button-title="{% trans "Play or pause audio" %}">
<template v-slot:sources>
{% for stream in audio_streams %}
<source src="{{ stream }}" />

View File

@ -16,7 +16,7 @@
<nav class="pagination is-centered">
<ul class="pagination-list">
<li>
<a href="{% url "diffusion-list" parent_slug=program.slug %}"
<a href="{% url "episode-list" parent_slug=program.slug %}"
class="pagination-link"
aria-label="{% trans "Show all program's diffusions" %}">
{% trans "More shows" %}

View File

@ -0,0 +1,12 @@
{% comment %}
Context:
- object: track to render
{% endcomment %}
<span class="has-text-info is-size-5">&#9836;</span>
<span>{{ track.title }}</span>
<span class="has-text-grey-dark has-text-weight-light">
&mdash; {{ track.artist }}
{% if track.info %}(<i>{{ track.info }}</i>){% endif %}
</span>

View File

@ -0,0 +1,48 @@
{% comment %}
Render a navigation menu for dates
Context:
- url_name: url name
- date: current date
- input_type: date input type
- dates: dates to display as a list of `(date|None, title|None)`.
An empty date results to a title or a separator
{% endcomment %}
{% load i18n humanize %}
<nav class="menu is-one-third-desktop " role="menu"
aria-label="{% trans "pick a date" %}">
<p class="menu-label">{% trans "Pick a date" %}</p>
<form action="{% url url_name %}" method="GET"
aria-label="{% trans "Jump to date" %}">
<div class="field has-addons">
<div class="control has-icons-left">
<span class="icon is-small is-left"><span class="far fa-calendar"></span></span>
<input type="{{ date_input|default:"date" }}" class="input date"
name="date" value="{{ date|date:"Y-m-d" }}">
</div>
<div class="control">
<button class="button is-primary">{% trans "Go" %}</button>
</div>
</div>
</form>
<ul class="menu-list">
{% for day, title in dates %}
{% if not day %}
{% if title %}
</ul>
<p class="menu-label">{{ title }}</p>
<ul class="menu-list">
{% else %}<hr class="dropdown-divider">{% endif %}
{% else %}
<li><a href="{% url url_name date=day %}" {% if day == date %}class="is-active"{% endif %}>
{% if title %}{{ title }}{% else %}{{ day|naturalday:"l d" }}{% endif %}
</a></li>
{% endif %}
{% endfor %}
</ul>
</nav>

View File

@ -2,7 +2,7 @@ import random
from django import template
from aircox.models import Page, Diffusion
from aircox.models import Page, Diffusion, Log
random.seed()
register = template.Library()
@ -24,15 +24,21 @@ def do_update_query(obj, **kwargs):
obj.pop(k)
return obj
@register.filter(name='is_diffusion')
def do_is_diffusion(obj):
return isinstance(obj, Diffusion)
@register.simple_tag(name='unique_id')
def do_unique_id(prefix=''):
value = str(random.random()).replace('.', '')
return prefix + '_' + value if prefix else value
@register.filter(name='get_tracks')
def do_get_tracks(obj):
""" Get a list of track for the provided log, diffusion, or episode """
if isinstance(obj, Log):
return (obj.track,)
if isinstance(obj, Diffusion):
obj = obj.episode
return obj.track_set.all()
@register.simple_tag(name='nav_items', takes_context=True)
@ -42,3 +48,12 @@ def do_nav_items(context, menu, **kwargs):
for item in station.navitem_set.filter(menu=menu)]
# FIXME: used?
@register.simple_tag(name='unique_id')
def do_unique_id(prefix=''):
value = str(random.random()).replace('.', '')
return prefix + '_' + value if prefix else value

View File

@ -19,7 +19,7 @@ register_converter(WeekConverter, 'week')
api = [
path('live/', views.api.LiveAPIView.as_view(), name='api-live'),
path('logs/', views.api.LogListAPIView.as_view(), name='api-live'),
]
@ -40,18 +40,18 @@ urls = [
path(_('programs/<slug:slug>/'),
views.ProgramDetailView.as_view(), name='program-detail'),
path(_('programs/<slug:parent_slug>/episodes/'),
views.EpisodeListView.as_view(), name='diffusion-list'),
views.EpisodeListView.as_view(), name='episode-list'),
path(_('programs/<slug:parent_slug>/articles/'),
views.ArticleListView.as_view(), name='article-list'),
path(_('episodes/'),
views.EpisodeListView.as_view(), name='diffusion-list'),
views.EpisodeListView.as_view(), name='episode-list'),
path(_('episodes/<slug:slug>/'),
views.EpisodeDetailView.as_view(), name='episode-detail'),
path(_('week/'),
views.TimetableView.as_view(), name='timetable'),
path(_('week/<week:date>/'),
views.TimetableView.as_view(), name='timetable'),
views.DiffusionListView.as_view(), name='diffusion-list'),
path(_('week/<date:date>/'),
views.DiffusionListView.as_view(), name='diffusion-list'),
path(_('logs/'), views.LogListView.as_view(), name='logs'),
path(_('logs/<date:date>/'), views.LogListView.as_view(), name='logs'),

View File

@ -20,6 +20,19 @@ def redirect(url):
raise Redirect(url)
def str_to_date(value, sep='/'):
"""
Return a date from the provided `value` string, formated as "yyyy/mm/dd"
(or "dd/mm/yyyy" if `reverse` is True).
Raises ValueError for incorrect value format.
"""
value = value.split(sep)[:3]
if len(value) < 3:
return ValueError('incorrect date format')
return datetime.date(int(value[0]), int(value[1]), int(value[2]))
def date_range(date, delta=None, **delta_kwargs):
"""
Return a range of provided date such as `[date-delta, date+delta]`.

View File

@ -2,7 +2,7 @@ from . import api, admin
from .article import ArticleDetailView, ArticleListView
from .base import BaseView
from .episode import EpisodeDetailView, EpisodeListView, TimetableView
from .episode import EpisodeDetailView, EpisodeListView, DiffusionListView
from .log import LogListView
from .page import PageDetailView, PageListView
from .program import ProgramDetailView

View File

@ -10,7 +10,7 @@ from django.utils.translation import ugettext_lazy as _
from django.views.generic import ListView
from ..models import Program
from .log import BaseLogListView
from .log import LogListView
class BaseAdminView(LoginRequiredMixin, UserPassesTestMixin):
@ -25,20 +25,13 @@ class BaseAdminView(LoginRequiredMixin, UserPassesTestMixin):
return super().get_context_data(**kwargs)
class StatisticsView(BaseAdminView, BaseLogListView, ListView):
class StatisticsView(BaseAdminView, LogListView, ListView):
template_name = 'admin/aircox/statistics.html'
title = _('Statistics')
date = None
def get_queryset(self):
return super().get_queryset().today(self.date)
def get_diffusions_queryset(self):
return super().get_diffusions_queryset().today(self.date)
def get(self, request, *args, date=None, **kwargs):
self.date = datetime.date.today() if date is None else date
return super().get(request, *args, date=date, **kwargs)
def get_object_list(self, logs, *_):
return super().get_object_list(logs, True)
class AdminSite(admin.AdminSite):

View File

@ -4,9 +4,10 @@ from django.utils import timezone as tz
from rest_framework.generics import ListAPIView
from ..utils import str_to_date
from ..models import Log
from ..serializers import LogInfo, LogInfoSerializer
from .log import BaseLogListView
from .log import LogListMixin
class BaseAPIView:
@ -18,28 +19,30 @@ class BaseAPIView:
return super().get_queryset().station(self.station)
class LiveAPIView(BaseLogListView, BaseAPIView, ListAPIView):
class LogListAPIView(LogListMixin, BaseAPIView, ListAPIView):
"""
Return logs list, including diffusions. By default return logs of
the last 30 minutes.
Available GET parameters:
- "date": return logs for a specified date (
- "full": (staff user only) don't merge diffusion and logs
"""
serializer_class = LogInfoSerializer
min_date = None
queryset = Log.objects.all()
def get(self, *args, **kwargs):
self.min_date = tz.now() - tz.timedelta(minutes=20)
self.date = self.get_date()
if self.date is None:
self.min_date = tz.now() - tz.timedelta(minutes=30)
return super().get(*args, **kwargs)
def get_object_list(self, logs, full):
return [LogInfo(obj) for obj in super().get_object_list(logs, full)]
def get_serializer(self, queryset, *args, **kwargs):
queryset = Log.merge_diffusions(self.get_queryset(),
self.get_diffusions_queryset())
queryset = [LogInfo(obj) for obj in queryset]
return super().get_serializer(queryset, *args, **kwargs)
def get_queryset(self):
return super().get_queryset().after(self.min_date)
def get_diffusions_queryset(self):
return super().get_diffusions_queryset().after(self.min_date)
# Monitoring
full = bool(self.request.GET.get('full'))
return super().get_serializer(self.get_object_list(queryset, full),
*args, **kwargs)

View File

@ -1,5 +1,6 @@
from ..models import Article, Program
from .page import ParentMixin, PageDetailView, PageListView
from .mixins import ParentMixin
from .page import PageDetailView, PageListView
__all__ = ['ArticleDetailView', 'ArticleListView']

View File

@ -2,15 +2,16 @@ from collections import OrderedDict
import datetime
from django.views.generic import ListView
from django.utils.translation import ugettext as _
from ..converters import WeekConverter
from ..models import Diffusion, Episode, Program, Sound
from .base import BaseView
from .program import ProgramPageDetailView
from .page import ParentMixin, PageListView
from .page import PageListView
from .mixins import GetDateMixin, ParentMixin
__all__ = ['EpisodeDetailView', 'EpisodeListView', 'TimetableView']
__all__ = ['EpisodeDetailView', 'EpisodeListView', 'DiffusionListView']
class EpisodeDetailView(ProgramPageDetailView):
@ -32,7 +33,6 @@ class EpisodeDetailView(ProgramPageDetailView):
class EpisodeListView(ParentMixin, PageListView):
model = Episode
template_name = 'aircox/diffusion_list.html'
item_template_name = 'aircox/episode_item.html'
show_headline = True
@ -40,44 +40,35 @@ class EpisodeListView(ParentMixin, PageListView):
fk_parent = 'program'
class TimetableView(BaseView, ListView):
class DiffusionListView(GetDateMixin, BaseView, ListView):
""" View for timetables """
template_name_suffix = '_timetable'
model = Diffusion
# ordering = ('start',)
date = None
start = None
end = None
def get_date(self):
date = super().get_date()
return date if date is not None else datetime.date.today()
def get_queryset(self):
self.date = self.kwargs.get('date') or datetime.date.today()
self.start = self.date - datetime.timedelta(days=self.date.weekday())
self.end = self.start + datetime.timedelta(days=7)
return super().get_queryset().range(self.start, self.end) \
.order_by('start')
return super().get_queryset().today(self.date).order_by('start')
def get_context_data(self, **kwargs):
# regoup by dates
by_date = OrderedDict()
date = self.start
while date < self.end:
by_date[date] = []
date += datetime.timedelta(days=1)
for diffusion in self.object_list:
if diffusion.date not in by_date:
continue
by_date[diffusion.date].append(diffusion)
return super().get_context_data(
by_date=by_date,
date=self.date,
start=self.start,
end=self.end - datetime.timedelta(days=1),
prev_date=self.start - datetime.timedelta(days=1),
next_date=self.end + datetime.timedelta(days=1),
**kwargs
)
today = datetime.date.today()
start = self.date - datetime.timedelta(days=self.date.weekday())
dates = [
(today, None),
(today - datetime.timedelta(days=1), None),
(today + datetime.timedelta(days=1), None),
(today - datetime.timedelta(days=7), _('next week')),
(today + datetime.timedelta(days=7), _('last week')),
(None, None)
] + [
(date, date.strftime('%A %d'))
for date in (start + datetime.timedelta(days=i)
for i in range(0, 7)) if date != today
]
return super().get_context_data(date=self.date, dates=dates, **kwargs)

View File

@ -5,56 +5,61 @@ from django.views.generic import ListView
from ..models import Diffusion, Log
from .base import BaseView
from .mixins import GetDateMixin
__all__ = ['BaseLogListView', 'LogListView']
__all__ = ['LogListMixin', 'LogListView']
class BaseLogListView:
class LogListMixin(GetDateMixin):
model = Log
date = None
def get_date(self):
date, today = super().get_date(), datetime.date.today()
if date is not None and not self.request.user.is_staff:
return min(date, today)
return date
def get_queryset(self):
# only get logs for tracks: log for diffusion will be retrieved
# by the diffusions' queryset.
return super().get_queryset().on_air().filter(track__isnull=False)
qs = super().get_queryset().on_air().filter(track__isnull=False)
return qs.today(self.date) if self.date is not None else \
qs.after(self.min_date) if self.min_date is not None else qs
def get_diffusions_queryset(self):
return Diffusion.objects.station(self.station).on_air()
qs = Diffusion.objects.station(self.station).on_air()
return qs.today(self.date) if self.date is not None else \
qs.after(self.min_date) if self.min_date is not None else qs
def get_object_list(self, logs, full=False):
"""
Return diffusions merged to the provided logs queryset. If
`full`, sort items by date without merging.
"""
diffs = self.get_diffusions_queryset()
if self.request.user.is_staff and full:
return sorted(list(logs) + list(diffs), key=lambda obj: obj.start)
return Log.merge_diffusions(logs, diffs)
class LogListView(BaseView, BaseLogListView, ListView):
date = None
max_age = 10
min_date = None
def get(self, request, *args, **kwargs):
today = datetime.date.today()
self.min_date = today - datetime.timedelta(days=self.max_age)
self.date = min(max(self.min_date, self.kwargs['date']), today) \
if 'date' in self.kwargs else today
return super().get(request, *args, **kwargs)
def get_queryset(self):
return super().get_queryset().today(self.date)
def get_diffusions_queryset(self):
return super().get_diffusions_queryset().today(self.date)
class LogListView(BaseView, LogListMixin, ListView):
"""
Return list of logs for the provided date (from `kwargs` or
`request.GET`, defaults to today).
"""
def get_date(self):
date, today = super().get_date(), datetime.date.today()
return today if date is None else min(date, today)
def get_context_data(self, **kwargs):
today = datetime.date.today()
max_date = min(max(self.date + datetime.timedelta(days=3),
self.min_date + datetime.timedelta(days=6)), today)
return super().get_context_data(
date=self.date,
min_date=self.min_date,
dates=(date for date in (
max_date - datetime.timedelta(days=i)
for i in range(0, 7)) if date >= self.min_date),
object_list=Log.merge_diffusions(self.object_list,
self.get_diffusions_queryset()),
**kwargs
)
kwargs.update({
'date': self.date,
'dates': ((today - datetime.timedelta(days=i), None)
for i in range(0, 7)),
'object_list': self.get_object_list(self.object_list),
})
return super().get_context_data(**kwargs)

67
aircox/views/mixins.py Normal file
View File

@ -0,0 +1,67 @@
from django.shortcuts import get_object_or_404
from ..utils import str_to_date
__all__ = ['GetDateMixin', 'ParentMixin']
class GetDateMixin:
"""
Mixin offering utils to get date by `request.GET` or
`kwargs['date']`
"""
date = None
def get_date(self):
if 'date' in self.request.GET:
return str_to_date(self.request.GET['date'], '-')
return self.kwargs['date'] if 'date' in self.kwargs else None
def get(self, *args, **kwargs):
self.date = self.get_date()
return super().get(*args, **kwargs)
class ParentMixin:
"""
Optional parent page for a list view. Parent is fetched and passed to the
template context when `parent_model` is provided (queryset is filtered by
parent page in such case).
"""
parent_model = None
""" Parent model """
parent_url_kwarg = 'parent_slug'
""" Url lookup argument """
parent_field = 'slug'
""" Parent field for url lookup """
fk_parent = 'page'
""" Page foreign key to the parent """
parent = None
""" Parent page object """
def get_parent(self, request, *args, **kwargs):
if self.parent_model is None or self.parent_url_kwarg not in kwargs:
return
lookup = {self.parent_field: kwargs[self.parent_url_kwarg]}
return get_object_or_404(
self.parent_model.objects.select_related('cover'), **lookup)
def get(self, request, *args, **kwargs):
self.parent = self.get_parent(request, *args, **kwargs)
return super().get(request, *args, **kwargs)
def get_queryset(self):
if self.parent is not None:
lookup = {self.fk_parent: self.parent}
return super().get_queryset().filter(**lookup)
return super().get_queryset()
def get_context_data(self, **kwargs):
parent = kwargs.setdefault('parent', self.parent)
if parent is not None:
kwargs.setdefault('cover', parent.cover)
return super().get_context_data(**kwargs)

View File

@ -12,49 +12,7 @@ from ..utils import Redirect
from .base import BaseView
__all__ = ['ParentMixin', 'PageDetailView', 'PageListView']
class ParentMixin:
"""
Optional parent page for a list view. Parent is fetched and passed to the
template context when `parent_model` is provided (queryset is filtered by
parent page in such case).
"""
parent_model = None
""" Parent model """
parent_url_kwarg = 'parent_slug'
""" Url lookup argument """
parent_field = 'slug'
""" Parent field for url lookup """
fk_parent = 'page'
""" Page foreign key to the parent """
parent = None
""" Parent page object """
def get_parent(self, request, *args, **kwargs):
if self.parent_model is None or self.parent_url_kwarg not in kwargs:
return
lookup = {self.parent_field: kwargs[self.parent_url_kwarg]}
return get_object_or_404(
self.parent_model.objects.select_related('cover'), **lookup)
def get(self, request, *args, **kwargs):
self.parent = self.get_parent(request, *args, **kwargs)
return super().get(request, *args, **kwargs)
def get_queryset(self):
if self.parent is not None:
lookup = {self.fk_parent: self.parent}
return super().get_queryset().filter(**lookup)
return super().get_queryset()
def get_context_data(self, **kwargs):
parent = kwargs.setdefault('parent', self.parent)
if parent is not None:
kwargs.setdefault('cover', parent.cover)
return super().get_context_data(**kwargs)
__all__ = ['PageDetailView', 'PageListView']
# TODO: pagination: in template, only a limited number of pages displayed

View File

@ -1,3 +1,13 @@
import Vue from 'vue';
import './admin.scss';
import Statistics from './statistics.vue';
Vue.component('a-statistics', Statistics)
import 'public';

View File

@ -0,0 +1,39 @@
<template>
<form ref="form">
<slot :counts="counts"></slot>
</form>
</template>
<script>
const splitReg = new RegExp(`,\s*`, 'g');
export default {
data() {
return {
counts: {},
}
},
methods: {
update() {
const items = this.$el.querySelectorAll('input[name="data"]:checked')
const counts = {};
console.log(items)
for(var item of items)
if(item.value)
for(var tag of item.value.split(splitReg))
counts[tag.trim()] = (counts[tag.trim()] || 0) + 1;
this.counts = counts;
console.log('counts', this.counts)
}
},
mounted() {
this.$refs.form.addEventListener('change', () => this.update())
this.update()
}
}
</script>

View File

@ -1,10 +0,0 @@
import '@fortawesome/fontawesome-free/css/all.min.css';
import '@fortawesome/fontawesome-free/css/fontawesome.min.css';
import './js';
import './vue';
import './styles.scss';
// import './noscript.scss';
import './admin';

View File

@ -1,4 +0,0 @@
import app from './app';
import LiveInfo from './liveInfo';

View File

@ -1,6 +0,0 @@
/**[noscript="hidden"] {
display: none;
}*/

View File

@ -1,9 +1,8 @@
import Vue from 'vue';
import Buefy from 'buefy';
Vue.use(Buefy);
export var app = null;
export default app;
function loadApp() {
app = new Vue({
@ -12,7 +11,7 @@ function loadApp() {
})
}
window.addEventListener('load', loadApp);

28
assets/public/index.js Normal file
View File

@ -0,0 +1,28 @@
/**
* This module includes code available for both the public website and
* administration interface)
*/
//-- vendor
import Vue from 'vue';
import '@fortawesome/fontawesome-free/css/all.min.css';
import '@fortawesome/fontawesome-free/css/fontawesome.min.css';
import 'buefy/dist/buefy.css';
//-- aircox
import app from './app';
import LiveInfo from './liveInfo';
import './styles.scss';
import Player from './player.vue';
Vue.component('a-player', Player)
window.aircox = {
app: app,
LiveInfo: LiveInfo,
}

View File

@ -26,7 +26,7 @@
<script>
import LiveInfo from 'js/liveInfo';
import LiveInfo from './liveInfo';
export const State = {
paused: 0,

View File

@ -1,28 +0,0 @@
<template>
<div>
<a-tabs class="tabs" @select="value = $event.value;">
<template v-slot:default><slot name="tabs" :value="value"/></template>
</a-tabs>
<slot :value="value"></slot>
</div>
</template>
<script>
import Tabs from './tabs.vue';
export default {
props: ['default'],
data() {
return {
value: this.default,
}
},
components: {
'a-tabs': Tabs,
}
}
</script>

View File

@ -1,13 +0,0 @@
import Vue from 'vue';
import Player from './player.vue';
import Tab from './tab.vue';
import Tabs from './tabs.vue';
Vue.component('a-player', Player);
Vue.component('a-tab', Tab);
Vue.component('a-tabs', Tabs);
export {Player, Tab, Tabs};

View File

@ -1,31 +0,0 @@
<template>
<li @click.prevent="onclick"
:class="{'is-active': $parent.value == value}">
<slot></slot>
</li>
</template>
<script>
export default {
props: {
value: { default: undefined },
},
methods: {
select() {
this.$parent.selectTab(this);
},
onclick(event) {
this.select();
/*if(event.target.href != document.location)
window.history.pushState(
{ url: event.target.href },
event.target.innerText + ' - ' + document.title,
event.target.href
) */
}
}
}
</script>

View File

@ -1,45 +0,0 @@
<template>
<div>
<div class="tabs is-centered is-medium">
<ul><slot name="tabs" :value="value" /></ul>
</div>
<slot :value="value"/>
</div>
</template>
<script>
export default {
props: {
default: { default: null },
},
data() {
return {
value: this.default,
}
},
computed: {
tab() {
const vnode = this.$slots.default && this.$slots.default.find(
elm => elm.child && elm.child.value == this.value
);
return vnode && vnode.child;
}
},
methods: {
selectTab(tab) {
const value = tab.value;
if(this.value === value)
return;
this.value = value;
this.$emit('select', {target: this, value: value, tab: tab});
},
},
}
</script>

View File

@ -6,24 +6,24 @@
"author": "bkfox",
"license": "AGPL",
"devDependencies": {
"@fortawesome/fontawesome-free": "^5.8.2",
"@fortawesome/fontawesome-free": "^5.10.2",
"bulma": "^0.7.5",
"css-loader": "^2.1.1",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^3.0.1",
"mini-css-extract-plugin": "^0.5.0",
"node-sass": "^4.12.0",
"sass-loader": "^7.1.0",
"sass-loader": "^7.3.1",
"style-loader": "^0.23.1",
"ttf-loader": "^1.0.2",
"vue-loader": "^15.7.0",
"vue-loader": "^15.7.1",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.32.2",
"webpack-cli": "^3.3.2"
"webpack": "^4.39.3",
"webpack-cli": "^3.3.8"
},
"dependencies": {
"buefy": "^0.7.8",
"buefy": "^0.7.10",
"vue": "^2.6.10"
}
}

View File

@ -8,7 +8,10 @@ const VueLoaderPlugin = require('vue-loader/lib/plugin');
module.exports = (env, argv) => Object({
context: __dirname,
entry: './assets/index',
entry: {
main: './assets/public/index',
admin: './assets/admin/index',
},
output: {
path: path.resolve('aircox/static/aircox'),
@ -17,8 +20,8 @@ module.exports = (env, argv) => Object({
},
optimization: {
usedExports: true,
concatenateModules: argv.mode == 'production' ? true : false,
//usedExports: true,
// concatenateModules: argv.mode == 'production' ? true : false,
splitChunks: {
cacheGroups: {
@ -29,12 +32,12 @@ module.exports = (env, argv) => Object({
test: /[\\/]node_modules[\\/]/,
},
admin: {
/*admin: {
name: 'admin',
chunks: 'initial',
enforce: true,
enforce: false,
test: /assets[\\/]admin[\\/]/,
},
},*/
/*noscript: {
name: 'noscript',
@ -82,13 +85,10 @@ module.exports = (env, argv) => Object({
resolve: {
alias: {
js: path.resolve(__dirname, 'assets/js'),
vue: 'vue/dist/vue.esm.browser.js',
// buefy: 'buefy/dist/buefy.js',
},
modules: [
'assets/js',
'assets/vue',
'./assets',
'./node_modules',
],
extensions: ['.js', '.vue', '.css', '.scss', '.styl', '.ttf']