Merge branch 'listening-start' into 'develop'
Fix #1060: Added a new radio based on another user listenings Closes #1060 See merge request funkwhale/funkwhale!1067
This commit is contained in:
commit
8700e1b6f8
|
@ -0,0 +1 @@
|
||||||
|
Added a new radio based on another user listenings (#1060)
|
|
@ -42,6 +42,7 @@ import { WebSocketBridge } from 'django-channels'
|
||||||
import GlobalEvents from '@/components/utils/global-events'
|
import GlobalEvents from '@/components/utils/global-events'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import locales from './locales'
|
import locales from './locales'
|
||||||
|
import {getClientOnlyRadio} from '@/radios'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
|
@ -138,6 +139,11 @@ export default {
|
||||||
id: 'sidebarPendingReviewRequestCount',
|
id: 'sidebarPendingReviewRequestCount',
|
||||||
handler: this.incrementPendingReviewRequestsCountInSidebar
|
handler: this.incrementPendingReviewRequestsCountInSidebar
|
||||||
})
|
})
|
||||||
|
this.$store.commit('ui/addWebsocketEventHandler', {
|
||||||
|
eventName: 'Listen',
|
||||||
|
id: 'handleListen',
|
||||||
|
handler: this.handleListen
|
||||||
|
})
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
let self = this
|
let self = this
|
||||||
|
@ -175,6 +181,10 @@ export default {
|
||||||
eventName: 'user_request.created',
|
eventName: 'user_request.created',
|
||||||
id: 'sidebarPendingReviewRequestCount',
|
id: 'sidebarPendingReviewRequestCount',
|
||||||
})
|
})
|
||||||
|
this.$store.commit('ui/removeWebsocketEventHandler', {
|
||||||
|
eventName: 'Listen',
|
||||||
|
id: 'handleListen',
|
||||||
|
})
|
||||||
this.disconnect()
|
this.disconnect()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -190,6 +200,14 @@ export default {
|
||||||
incrementPendingReviewRequestsCountInSidebar (event) {
|
incrementPendingReviewRequestsCountInSidebar (event) {
|
||||||
this.$store.commit('ui/incrementNotifications', {type: 'pendingReviewRequests', value: event.pending_count})
|
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 () {
|
async fetchNodeInfo () {
|
||||||
let response = await axios.get('instance/nodeinfo/2.0/')
|
let response = await axios.get('instance/nodeinfo/2.0/')
|
||||||
this.$store.commit('instance/nodeinfo', response.data)
|
this.$store.commit('instance/nodeinfo', response.data)
|
||||||
|
|
|
@ -251,6 +251,8 @@ export default {
|
||||||
progressInterval: null,
|
progressInterval: null,
|
||||||
maxPreloaded: 3,
|
maxPreloaded: 3,
|
||||||
preloadDelay: 15,
|
preloadDelay: 15,
|
||||||
|
listenDelay: 15,
|
||||||
|
listeningRecorded: null,
|
||||||
soundsCache: [],
|
soundsCache: [],
|
||||||
soundId: null,
|
soundId: null,
|
||||||
playTimeout: null,
|
playTimeout: null,
|
||||||
|
@ -477,6 +479,13 @@ export default {
|
||||||
this.getSound(toPreload)
|
this.getSound(toPreload)
|
||||||
this.nextTrackPreloaded = true
|
this.nextTrackPreloaded = true
|
||||||
}
|
}
|
||||||
|
if (t > this.listenDelay || d - t < 30) {
|
||||||
|
let onlyTrack = this.$store.state.queue.tracks.length === 1
|
||||||
|
if (this.listeningRecorded != this.currentTrack) {
|
||||||
|
this.listeningRecorded = this.currentTrack
|
||||||
|
this.$store.dispatch('player/trackListened', this.currentTrack)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
seek (step) {
|
seek (step) {
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
<tags-list label-classes="tiny" :truncate-size="20" :limit="2" :show-more="false" :tags="object.track.tags"></tags-list>
|
<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">
|
<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>
|
<span class="right floated"><human-date :date="object.creation_date" /></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,10 +8,12 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
import lodash from '@/lodash'
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
customRadioId: {required: false},
|
customRadioId: {required: false},
|
||||||
type: {type: String, required: false},
|
type: {type: String, required: false},
|
||||||
|
clientOnly: {type: Boolean, default: false},
|
||||||
objectId: {default: null}
|
objectId: {default: null}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -19,7 +21,12 @@ export default {
|
||||||
if (this.running) {
|
if (this.running) {
|
||||||
this.$store.dispatch('radios/stop')
|
this.$store.dispatch('radios/stop')
|
||||||
} else {
|
} 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) {
|
if (!state.running) {
|
||||||
return false
|
return false
|
||||||
} else {
|
} 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]
|
||||||
|
}
|
|
@ -127,7 +127,6 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
trackEnded ({dispatch, rootState}, track) {
|
trackEnded ({dispatch, rootState}, track) {
|
||||||
dispatch('trackListened', track)
|
|
||||||
let queueState = rootState.queue
|
let queueState = rootState.queue
|
||||||
if (queueState.currentIndex === queueState.tracks.length - 1) {
|
if (queueState.currentIndex === queueState.tracks.length - 1) {
|
||||||
// we've reached last track of queue, trigger a reload
|
// we've reached last track of queue, trigger a reload
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import logger from '@/logging'
|
import logger from '@/logging'
|
||||||
|
|
||||||
|
import {getClientOnlyRadio} from '@/radios'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: {
|
state: {
|
||||||
|
@ -42,11 +44,17 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
start ({commit, dispatch}, {type, objectId, customRadioId}) {
|
start ({commit, dispatch}, {type, objectId, customRadioId, clientOnly}) {
|
||||||
var params = {
|
var params = {
|
||||||
radio_type: type,
|
radio_type: type,
|
||||||
related_object_id: objectId,
|
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) => {
|
return axios.post('radios/sessions/', params).then((response) => {
|
||||||
logger.default.info('Successfully started radio ', type)
|
logger.default.info('Successfully started radio ', type)
|
||||||
|
@ -57,7 +65,10 @@ export default {
|
||||||
logger.default.error('Error while starting radio', type)
|
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('current', null)
|
||||||
commit('running', false)
|
commit('running', false)
|
||||||
},
|
},
|
||||||
|
@ -71,6 +82,9 @@ export default {
|
||||||
var params = {
|
var params = {
|
||||||
session: state.current.session
|
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) => {
|
return axios.post('radios/tracks/', params).then((response) => {
|
||||||
logger.default.info('Adding track to queue from radio')
|
logger.default.info('Adding track to queue from radio')
|
||||||
let append = dispatch('queue/append', {track: response.data.track}, {root: true})
|
let append = dispatch('queue/append', {track: response.data.track}, {root: true})
|
||||||
|
|
|
@ -31,6 +31,7 @@ export default {
|
||||||
'mutation.updated': {},
|
'mutation.updated': {},
|
||||||
'report.created': {},
|
'report.created': {},
|
||||||
'user_request.created': {},
|
'user_request.created': {},
|
||||||
|
'Listen': {},
|
||||||
},
|
},
|
||||||
pageTitle: null,
|
pageTitle: null,
|
||||||
routePreferences: {
|
routePreferences: {
|
||||||
|
|
|
@ -43,6 +43,9 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</h1>
|
</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 class="ui small hidden divider"></div>
|
||||||
<div v-if="$store.getters['ui/layoutVersion'] === 'large'">
|
<div v-if="$store.getters['ui/layoutVersion'] === 'large'">
|
||||||
<rendered-description
|
<rendered-description
|
||||||
|
@ -82,6 +85,7 @@ import { mapState } from "vuex"
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import ReportMixin from '@/components/mixins/Report'
|
import ReportMixin from '@/components/mixins/Report'
|
||||||
|
import RadioButton from "@/components/radios/Button"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [ReportMixin],
|
mixins: [ReportMixin],
|
||||||
|
@ -89,6 +93,9 @@ export default {
|
||||||
username: {type: String, required: true},
|
username: {type: String, required: true},
|
||||||
domain: {type: String, required: false, default: null},
|
domain: {type: String, required: false, default: null},
|
||||||
},
|
},
|
||||||
|
components: {
|
||||||
|
RadioButton,
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
object: null,
|
object: null,
|
||||||
|
|
|
@ -136,7 +136,6 @@ describe('store/player', () => {
|
||||||
payload: {test: 'track'},
|
payload: {test: 'track'},
|
||||||
params: {rootState: {queue: {currentIndex: 0, tracks: [1, 2]}}},
|
params: {rootState: {queue: {currentIndex: 0, tracks: [1, 2]}}},
|
||||||
expectedActions: [
|
expectedActions: [
|
||||||
{ type: 'trackListened', payload: {test: 'track'} },
|
|
||||||
{ type: 'queue/next', payload: null, options: {root: true} }
|
{ type: 'queue/next', payload: null, options: {root: true} }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@ -147,7 +146,6 @@ describe('store/player', () => {
|
||||||
payload: {test: 'track'},
|
payload: {test: 'track'},
|
||||||
params: {rootState: {queue: {currentIndex: 1, tracks: [1, 2]}}},
|
params: {rootState: {queue: {currentIndex: 1, tracks: [1, 2]}}},
|
||||||
expectedActions: [
|
expectedActions: [
|
||||||
{ type: 'trackListened', payload: {test: 'track'} },
|
|
||||||
{ type: 'radios/populateQueue', payload: null, options: {root: true} },
|
{ type: 'radios/populateQueue', payload: null, options: {root: true} },
|
||||||
{ type: 'queue/next', payload: null, options: {root: true} }
|
{ type: 'queue/next', payload: null, options: {root: true} }
|
||||||
]
|
]
|
||||||
|
|
|
@ -58,6 +58,7 @@ describe('store/radios', () => {
|
||||||
it('stop', () => {
|
it('stop', () => {
|
||||||
return testAction({
|
return testAction({
|
||||||
action: store.actions.stop,
|
action: store.actions.stop,
|
||||||
|
params: {state: {}},
|
||||||
expectedMutations: [
|
expectedMutations: [
|
||||||
{ type: 'current', payload: null },
|
{ type: 'current', payload: null },
|
||||||
{ type: 'running', payload: false }
|
{ type: 'running', payload: false }
|
||||||
|
|
Loading…
Reference in New Issue