From cd63646f391030d083c6ce6de250dcbf177d1e9b Mon Sep 17 00:00:00 2001 From: Eliot Berriot <contact@eliotberriot.com> Date: Wed, 25 Mar 2020 22:24:31 +0100 Subject: [PATCH] Fix #1060: Added a new radio based on another user listenings --- changes/changelog.d/1060.feature | 1 + front/src/App.vue | 18 ++++++++ front/src/components/audio/track/Widget.vue | 2 +- front/src/components/radios/Button.vue | 11 ++++- front/src/radios.js | 51 +++++++++++++++++++++ front/src/store/radios.js | 20 ++++++-- front/src/store/ui.js | 1 + front/src/views/auth/ProfileBase.vue | 7 +++ front/tests/unit/specs/store/player.spec.js | 2 - front/tests/unit/specs/store/radios.spec.js | 1 + 10 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 changes/changelog.d/1060.feature create mode 100644 front/src/radios.js diff --git a/changes/changelog.d/1060.feature b/changes/changelog.d/1060.feature new file mode 100644 index 0000000000..245a6be0ce --- /dev/null +++ b/changes/changelog.d/1060.feature @@ -0,0 +1 @@ +Added a new radio based on another user listenings (#1060) diff --git a/front/src/App.vue b/front/src/App.vue index b572b1bcd0..6252198e27 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -42,6 +42,7 @@ import { WebSocketBridge } from 'django-channels' import GlobalEvents from '@/components/utils/global-events' import moment from 'moment' import locales from './locales' +import {getClientOnlyRadio} from '@/radios' export default { name: 'app', @@ -138,6 +139,11 @@ export default { id: 'sidebarPendingReviewRequestCount', handler: this.incrementPendingReviewRequestsCountInSidebar }) + this.$store.commit('ui/addWebsocketEventHandler', { + eventName: 'Listen', + id: 'handleListen', + handler: this.handleListen + }) }, mounted () { let self = this @@ -175,6 +181,10 @@ export default { eventName: 'user_request.created', id: 'sidebarPendingReviewRequestCount', }) + this.$store.commit('ui/removeWebsocketEventHandler', { + eventName: 'Listen', + id: 'handleListen', + }) this.disconnect() }, methods: { @@ -190,6 +200,14 @@ export default { incrementPendingReviewRequestsCountInSidebar (event) { this.$store.commit('ui/incrementNotifications', {type: 'pendingReviewRequests', value: event.pending_count}) }, + handleListen (event) { + if (this.$store.state.radios.current && this.$store.state.radios.running) { + let current = this.$store.state.radios.current + if (current.clientOnly && current.type === 'account') { + getClientOnlyRadio(current).handleListen(current, event, this.$store) + } + } + }, async fetchNodeInfo () { let response = await axios.get('instance/nodeinfo/2.0/') this.$store.commit('instance/nodeinfo', response.data) diff --git a/front/src/components/audio/track/Widget.vue b/front/src/components/audio/track/Widget.vue index 6895a87127..945db6a167 100644 --- a/front/src/components/audio/track/Widget.vue +++ b/front/src/components/audio/track/Widget.vue @@ -29,7 +29,7 @@ <tags-list label-classes="tiny" :truncate-size="20" :limit="2" :show-more="false" :tags="object.track.tags"></tags-list> <div class="extra" v-if="isActivity"> - <span class="left floated">@{{ object.user.username }}</span> + <router-link class="left floated" :to="{name: 'profile.overview', params: {username: object.user.username}}">@{{ object.user.username }}</router-link> <span class="right floated"><human-date :date="object.creation_date" /></span> </div> </div> diff --git a/front/src/components/radios/Button.vue b/front/src/components/radios/Button.vue index f335a65962..7e1ff40c50 100644 --- a/front/src/components/radios/Button.vue +++ b/front/src/components/radios/Button.vue @@ -8,10 +8,12 @@ <script> +import lodash from '@/lodash' export default { props: { customRadioId: {required: false}, type: {type: String, required: false}, + clientOnly: {type: Boolean, default: false}, objectId: {default: null} }, methods: { @@ -19,7 +21,12 @@ export default { if (this.running) { this.$store.dispatch('radios/stop') } else { - this.$store.dispatch('radios/start', {type: this.type, objectId: this.objectId, customRadioId: this.customRadioId}) + this.$store.dispatch('radios/start', { + type: this.type, + objectId: this.objectId, + customRadioId: this.customRadioId, + clientOnly: this.clientOnly, + }) } } }, @@ -30,7 +37,7 @@ export default { if (!state.running) { return false } else { - return current.type === this.type && current.objectId === this.objectId && current.customRadioId === this.customRadioId + return current.type === this.type && lodash.isEqual(current.objectId, this.objectId) && current.customRadioId === this.customRadioId } } } diff --git a/front/src/radios.js b/front/src/radios.js new file mode 100644 index 0000000000..b10937fb9f --- /dev/null +++ b/front/src/radios.js @@ -0,0 +1,51 @@ +import axios from "axios" +import logger from '@/logging' + +// import axios from 'axios' + +const RADIOS = { + // some radios are client side only, so we have to implement the populateQueue + // method by hand + account: { + offset: 1, + populateQueue({current, dispatch, playNow}) { + let params = {scope: `actor:${current.objectId.fullUsername}`, ordering: '-creation_date', page_size: 1, page: this.offset} + axios.get('history/listenings', {params}).then((response) => { + let latest = response.data.results[0] + if (!latest) { + logger.default.error('No more tracks') + dispatch('stop') + } + this.offset += 1 + let append = dispatch('queue/append', {track: latest.track}, {root: true}) + if (playNow) { + append.then(() => { + dispatch('queue/last', null, {root: true}) + }) + } + }, (error) => { + logger.default.error('Error while fetching listenings', error) + dispatch('stop') + }) + }, + stop () { + this.offset = 1 + }, + handleListen (current, event, store) { + // XXX: handle actors from other pods + if (event.actor.local_id === current.objectId.username) { + axios.get(`tracks/${event.object.local_id}`).then((response) => { + if (response.data.uploads.length > 0) { + store.dispatch('queue/append', {track: response.data, index: store.state.queue.currentIndex + 1}) + this.offset += 1 + } + }, (error) => { + logger.default.error('Cannot retrieve track info', error) + }) + } + } + } +} +export function getClientOnlyRadio({type}) { + return RADIOS[type] +} diff --git a/front/src/store/radios.js b/front/src/store/radios.js index 6eb06566ff..d07ad59cbc 100644 --- a/front/src/store/radios.js +++ b/front/src/store/radios.js @@ -1,6 +1,8 @@ import axios from 'axios' import logger from '@/logging' +import {getClientOnlyRadio} from '@/radios' + export default { namespaced: true, state: { @@ -42,11 +44,17 @@ export default { } }, actions: { - start ({commit, dispatch}, {type, objectId, customRadioId}) { + start ({commit, dispatch}, {type, objectId, customRadioId, clientOnly}) { var params = { radio_type: type, related_object_id: objectId, - custom_radio: customRadioId + custom_radio: customRadioId, + } + if (clientOnly) { + commit('current', {type, objectId, customRadioId, clientOnly}) + commit('running', true) + dispatch('populateQueue', true) + return } return axios.post('radios/sessions/', params).then((response) => { logger.default.info('Successfully started radio ', type) @@ -57,7 +65,10 @@ export default { logger.default.error('Error while starting radio', type) }) }, - stop ({commit}) { + stop ({commit, state}) { + if (state.current && state.current.clientOnly) { + getClientOnlyRadio(state.current).stop() + } commit('current', null) commit('running', false) }, @@ -71,6 +82,9 @@ export default { var params = { session: state.current.session } + if (state.current.clientOnly) { + return getClientOnlyRadio(state.current).populateQueue({current: state.current, dispatch, state, rootState, playNow}) + } return axios.post('radios/tracks/', params).then((response) => { logger.default.info('Adding track to queue from radio') let append = dispatch('queue/append', {track: response.data.track}, {root: true}) diff --git a/front/src/store/ui.js b/front/src/store/ui.js index 0c16f2b451..5c6ca20de4 100644 --- a/front/src/store/ui.js +++ b/front/src/store/ui.js @@ -31,6 +31,7 @@ export default { 'mutation.updated': {}, 'report.created': {}, 'user_request.created': {}, + 'Listen': {}, }, pageTitle: null, routePreferences: { diff --git a/front/src/views/auth/ProfileBase.vue b/front/src/views/auth/ProfileBase.vue index cb70b66ae7..702d3b870d 100644 --- a/front/src/views/auth/ProfileBase.vue +++ b/front/src/views/auth/ProfileBase.vue @@ -43,6 +43,9 @@ </div> </template> </h1> + <div class="ui center aligned text"> + <radio-button type="account" :object-id="{username: object.preferred_username, fullUsername: object.full_username}" :client-only="true"></radio-button> + </div> <div class="ui small hidden divider"></div> <div v-if="$store.getters['ui/layoutVersion'] === 'large'"> <rendered-description @@ -82,6 +85,7 @@ import { mapState } from "vuex" import axios from 'axios' import ReportMixin from '@/components/mixins/Report' +import RadioButton from "@/components/radios/Button" export default { mixins: [ReportMixin], @@ -89,6 +93,9 @@ export default { username: {type: String, required: true}, domain: {type: String, required: false, default: null}, }, + components: { + RadioButton, + }, data () { return { object: null, diff --git a/front/tests/unit/specs/store/player.spec.js b/front/tests/unit/specs/store/player.spec.js index 13a3fd7630..c3f1c4583f 100644 --- a/front/tests/unit/specs/store/player.spec.js +++ b/front/tests/unit/specs/store/player.spec.js @@ -136,7 +136,6 @@ describe('store/player', () => { payload: {test: 'track'}, params: {rootState: {queue: {currentIndex: 0, tracks: [1, 2]}}}, expectedActions: [ - { type: 'trackListened', payload: {test: 'track'} }, { type: 'queue/next', payload: null, options: {root: true} } ] }) @@ -147,7 +146,6 @@ describe('store/player', () => { payload: {test: 'track'}, params: {rootState: {queue: {currentIndex: 1, tracks: [1, 2]}}}, expectedActions: [ - { type: 'trackListened', payload: {test: 'track'} }, { type: 'radios/populateQueue', payload: null, options: {root: true} }, { type: 'queue/next', payload: null, options: {root: true} } ] diff --git a/front/tests/unit/specs/store/radios.spec.js b/front/tests/unit/specs/store/radios.spec.js index ff14f6145c..512b0fc3f4 100644 --- a/front/tests/unit/specs/store/radios.spec.js +++ b/front/tests/unit/specs/store/radios.spec.js @@ -58,6 +58,7 @@ describe('store/radios', () => { it('stop', () => { return testAction({ action: store.actions.stop, + params: {state: {}}, expectedMutations: [ { type: 'current', payload: null }, { type: 'running', payload: false } -- GitLab