diff --git a/channelInfo.py b/channelInfo.py index 829f02c..e5ca0d3 100644 --- a/channelInfo.py +++ b/channelInfo.py @@ -239,5 +239,12 @@ channels = { "cHasData": True, "cPrimaryColor": "#000000", "cSecondaryColor": "#E2001A" + }, + "all": { + "shortname": "all", + "stationname": "Alle", + "cHasData": True, + "cPrimaryColor": "black", + "cSecondaryColor": "white" } } diff --git a/server.py b/server.py index 13b9fdb..43cd8c2 100644 --- a/server.py +++ b/server.py @@ -8,6 +8,12 @@ from app import app from models import * +def add_cors(response): + header = response.headers + header['Access-Control-Allow-Origin'] = '*' + return response + + def query_to_response(query, limit=10, key=False, sort=False, offset=None, list=None, **kwargs): """ @@ -83,9 +89,10 @@ def popular(channel): start, end = get_range(date, date_type) get = Play.select(Play.song, fn.Count(SQL('*')).alias("count")) \ .join(Channel).switch(Play).join(Song) \ - .where((Song.show == 0) & (Channel.shortname == channel) & ( - Play.time.between(start, end))) \ - .group_by(Play.song).order_by(SQL('count').desc()) + .where((Song.show == 0) & (Play.time.between(start, end))) + if channel != "all": + get = get.where(Channel.shortname == channel) + get = get.group_by(Play.song).order_by(SQL('count').desc()) if request.args.get('offset'): get = get.offset(int(request.args.get('offset'))) return query_to_response(get, extra_attrs=["count"], exclude=[Play.channel, Play.time, Play.id], key="song.id", @@ -98,8 +105,10 @@ def plays(channel, song_id): start, end = get_range(date, date_type) get = Play.select(Play.time) \ .join(Channel) \ - .where((Play.song == song_id) & (Channel.shortname == channel) & (Play.time.between(start, end))) \ - .order_by(Play.time.desc()) + .where((Play.song == song_id) & (Play.time.between(start, end))) + if channel != "all": + get = get.where(Channel.shortname == channel) + get = get.order_by(Play.time.desc()) return query_to_response(get, exclude=[Play.channel, Play.song, Play.id], list="time", limit=False) @@ -109,9 +118,12 @@ def details(channel, song_id): .where(Song.id == song_id) date, date_type = get_dates_from_request() start, end = get_range(date, date_type) - count = Play.select().join(Channel).where( - (Play.song == song_id) & (Channel.shortname == channel) & (Play.time.between(start, end)) - ).count() + get = Play.select().join(Channel).where( + (Play.song == song_id) & (Play.time.between(start, end)) + ) + if channel != "all": + get = get.where(Channel.shortname == channel) + count = get.count() response = jsonify({"order": -1, "count": count, "song": model_to_dict(get.get())}) if __name__ == '__main__': response.headers.add('Access-Control-Allow-Origin', '*') @@ -120,4 +132,5 @@ def details(channel, song_id): if __name__ == '__main__': app.debug = True + app.after_request(add_cors) app.run() diff --git a/web/List.vue b/web/List.vue index f99c8e0..84ae19d 100644 --- a/web/List.vue +++ b/web/List.vue @@ -128,13 +128,13 @@ }, props: ["channel"], computed: { - channelData: function () { + channelData: function() { return this.channels[this.channel]; }, - momentDate: function () { + momentDate: function() { return moment(this.date); }, - popular: function () { + popular: function() { function compare(a, b) { if (a.order < b.order) return -1; @@ -149,22 +149,24 @@ }, methods: { - getChannels: function () { - let vm = this; + getChannels: function() { axios.get(baseURL, { params: {} }) - .then(function (response) { - vm.channels = response.data; - document.title = "Radiostats - " + vm.channels[vm.channel].stationname; - vm.getPopular(); + .then(response => { + const all = response.data["all"]; + this.channels = response.data; + delete response.data["all"]; + response.data["all"]=all; + document.title = "Radiostats - " + this.channels[this.channel].stationname; + this.getPopular(); }) - .catch(function (error) { - vm.httpError = error; + .catch(error => { + this.httpError = error; }); }, - getPopular: function () { + getPopular: function() { this.offset = 0; this.showMore = true; this.httpError = false; @@ -201,40 +203,38 @@ } }) - .catch(function (error) { - vm.httpError = error; + .catch(error => { + this.httpError = error; }); }, - getAdditional: function () { - let vm = this; - + getAdditional: function() { axios.get(baseURL + this.channel, { params: { - offset: vm.offset, - date: vm.momentDate.format("YYYY-MM-DD"), - dateType: vm.dateType + offset: this.offset, + date: this.momentDate.format("YYYY-MM-DD"), + dateType: this.dateType } }) - .then(function (response) { - vm.offset += 10; - vm.songs = Object.assign({}, vm.songs, response.data); + .then(response => { + this.offset += 10; + this.songs = Object.assign({}, this.songs, response.data); if (Object.keys(response.data).length < 10) { - vm.showMore = false; + this.showMore = false; } }) - .catch(function (error) { - vm.httpError = error; + .catch(error => { + this.httpError = error; }); }, - icon: function (id) { + icon: function(id) { if (id === "fm4" || id === "oe3" || id === "kht") { return id + ".svg"; } else { return id + ".png"; } }, - updateSelection: function () { + updateSelection: function() { let from, to; let date = moment(this.date); if (this.dateType !== "alltime") { @@ -251,7 +251,7 @@ "to": to.toDate(), }; }, - formatDate: function () { + formatDate: function() { switch (this.dateType) { case "day": return "am " + this.momentDate.format("D. MMMM"); @@ -263,10 +263,10 @@ return "im gesamten Zeitraum"; } }, - toogleVisibility: function () { + toogleVisibility: function() { this.showDate = !this.showDate; }, - toogleDetails: function ($event, songId) { + toogleDetails: function($event, songId) { if (this.$route.name !== "DetailView" || this.$route.params.songId !== songId) { this.$router.replace({name: 'DetailView', params: {channel: this.channel, songId: songId}}); } else { @@ -275,24 +275,24 @@ } }, watch: { - channel: function () { + channel: function() { document.title = "Radiostats - " + this.channelData.stationname; this.getPopular(); }, - '$route.name': function (id) { + '$route.name': function(id) { document.title = "Radiostats - " + this.channelData.stationname; }, - dateType: function () { + dateType: function() { this.updateSelection(); this.getPopular(); }, - date: function () { + date: function() { this.updateSelection(); this.getPopular(); } }, - mounted: function () { + mounted: function() { this.getChannels(); this.updateSelection(); } @@ -314,20 +314,24 @@ header { padding: 2.5rem; transition: color .2s, background-color .2s; + h2, div { font-weight: bold; text-align: center; margin: 0; } + div { cursor: pointer; font-size: 3.0rem; line-height: 1.3; + svg { fill: currentColor; width: 32px; height: 18.66px; transition: transform .3s; + &.disabled { transform: rotate(-90deg); @@ -351,19 +355,23 @@ margin: 10px 10px; } } + a { /*border-bottom: solid 5px;*/ &.router-link-active { border-bottom: solid 5px; } + display: block; + img { margin-bottom: 5px; display: block; width: 40px; height: 40px; transition: filter .2s; + &.noData:not(:hover) { filter: grayscale(0.7); } @@ -373,12 +381,14 @@ table { margin: 0; + img, .imgPlaceholder { width: 36px; height: 36px; background-color: #eee; display: block; } + tr.clickable { cursor: pointer; } @@ -390,6 +400,7 @@ text-align: center; cursor: pointer; transition: background-color .2s; + &:hover { background-color: #eee; } @@ -410,6 +421,7 @@ margin-right: 0; margin-left: auto; } + @media (max-width: 700px) { > div { .vdp-datepicker { @@ -425,10 +437,12 @@ display: flex; flex-direction: row; align-items: center; + > div { width: 50%; padding: 0 15px !important; } + @media (max-width: 700px) { flex-direction: column; > div { diff --git a/web/icons/all.png b/web/icons/all.png new file mode 100644 index 0000000..ee1e411 Binary files /dev/null and b/web/icons/all.png differ diff --git a/web/main.js b/web/main.js index e29a4fe..88cca7c 100644 --- a/web/main.js +++ b/web/main.js @@ -5,11 +5,13 @@ import router from './routes'; import MatomoTracker from './MatomoTracker'; import {init, Integrations} from '@sentry/browser'; -init({ - dsn: 'https://91af780499634f98a17afe160c6ace89@sentry.lw1.at/12', - integrations: [new Integrations.Vue({Vue})], - release: COMMIT_HASH -}); +if (process.env.NODE_ENV === "production") { + init({ + dsn: 'https://91af780499634f98a17afe160c6ace89@sentry.lw1.at/12', + integrations: [new Integrations.Vue({Vue})], + release: COMMIT_HASH + }); +} Vue.use(VueHead); let matomo = new MatomoTracker;