diff --git a/client/package-lock.json b/client/package-lock.json index 78eba7d..01ac000 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -5727,6 +5727,11 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, + "get-youtube-id": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-youtube-id/-/get-youtube-id-1.0.1.tgz", + "integrity": "sha512-5yidLzoLXbtw82a/Wb7LrajkGn29BM6JuLWeHyNfzOGp1weGyW4+7eMz6cP23+etqj27VlOFtq8fFFDMLq/FXQ==" + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -7058,6 +7063,11 @@ } } }, + "load-script": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", + "integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ=" + }, "loader-fs-cache": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz", @@ -9923,6 +9933,11 @@ } } }, + "sister": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sister/-/sister-3.0.2.tgz", + "integrity": "sha512-p19rtTs+NksBRKW9qn0UhZ8/TUI9BPw9lmtHny+Y3TinWlOa9jWh9xB0AtPSdmOy49NJJJSSe0Ey4C7h0TrcYA==" + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -11314,6 +11329,15 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, + "vue-youtube": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/vue-youtube/-/vue-youtube-1.4.0.tgz", + "integrity": "sha512-PCyfGAouSt6rTX0GLUzpdX2XC52zYf7a9mUhdp53jeDlPoU40hpsvyV3Zg2+947pvbv27ORcmtzm2fqO08kh9Q==", + "requires": { + "get-youtube-id": "^1.0.0", + "youtube-player": "^5.4.0" + } + }, "vuex": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.5.1.tgz", @@ -12328,6 +12352,31 @@ "dev": true } } + }, + "youtube-player": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/youtube-player/-/youtube-player-5.5.2.tgz", + "integrity": "sha512-ZGtsemSpXnDky2AUYWgxjaopgB+shFHgXVpiJFeNB5nWEugpW1KWYDaHKuLqh2b67r24GtP6HoSW5swvf0fFIQ==", + "requires": { + "debug": "^2.6.6", + "load-script": "^1.0.0", + "sister": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } } } } diff --git a/client/package.json b/client/package.json index f02698d..9f9157e 100644 --- a/client/package.json +++ b/client/package.json @@ -13,6 +13,7 @@ "register-service-worker": "^1.7.1", "vue": "^2.6.11", "vue-router": "^3.2.0", + "vue-youtube": "^1.4.0", "vuex": "^3.4.0" }, "devDependencies": { diff --git a/client/src/components/Player.vue b/client/src/components/Player.vue new file mode 100644 index 0000000..78715fe --- /dev/null +++ b/client/src/components/Player.vue @@ -0,0 +1,13 @@ + + + + + + + diff --git a/client/src/main.js b/client/src/main.js index 6d3fe40..6e1a96a 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -4,11 +4,13 @@ import './registerServiceWorker' import router from './router' import store from './store' import Buefy from 'buefy' +import VueYoutube from 'vue-youtube' import 'buefy/dist/buefy.css' - // import './assets/style.scss' + Vue.use(Buefy) +Vue.use(VueYoutube) Vue.config.productionTip = false new Vue({ diff --git a/client/src/store/roomModule.js b/client/src/store/roomModule.js index 7a0f27c..e2714f0 100644 --- a/client/src/store/roomModule.js +++ b/client/src/store/roomModule.js @@ -3,7 +3,16 @@ const state = { roomStatus: { roomName: '', roomCode: '', - current: '', + player: { + timeCode: 0, + playing: true + }, + current: { + link: '', + title: '', + votes: 0, + voters: [] + }, playlist: [] } } @@ -23,6 +32,35 @@ const actions = { }, setAdmin ({ commit }) { commit('SET_ADMIN') + }, + vote ({ commit, dispatch, state }, { link, isPositive, voterName }) { + console.log('vote on ' + link + ' (' + isPositive + ') by ' + voterName) + if (isPositive) { + commit('ADD_VOTE', { + link: link, + voterName: voterName + }) + } else { + commit('REMOVE_VOTE', { + link: link, + voterName: voterName + }) + } + dispatch('rtc/broadcast', { message: state.roomStatus, type: 'status' }, { root: true }) + }, + setCurrent ({ commit, dispatch }, { playerStatus, timeCode }) { + switch (playerStatus) { + case 0: + commit('CURRENT_END') + break + case 1: + commit('CURRENT_PLAY', timeCode) + break + case 2: + commit('CURRENT_PAUSE', timeCode) + break + } + dispatch('rtc/broadcast', { message: state.roomStatus, type: 'status' }, { root: true }) } } @@ -39,8 +77,58 @@ const mutations = { SET_ADMIN (state) { state.admin = true }, - BROADCAST_ROOMSTATUS (state) { + ADD_VOTE (state, { link, voterName }) { + var play = state.roomStatus.playlist.find(play => play.link === link) + if (play === undefined) { + play = { + link: link, + votes: 1, + voters: [ + voterName + ] + } + if (state.roomStatus.current.votes === 0) state.roomStatus.current = play + else state.roomStatus.playlist.push(play) + } else { + play.votes++ + play.voters.push(voterName) + } + }, + REMOVE_VOTE (state, { link, voterName }) { + var play = state.roomStatus.playlist.find(play => play.link === link) + play.votes-- + const index = play.voters.indexOf(voterName) + if (index > -1) { + play.voters.splice(index, 1) + } + if (play.vote === 0) { + const index = state.roomStatus.playlist.indexOf(play) + if (index > -1) { + state.roomStatus.playlist.splice(index, 1) + } + } + }, + CURRENT_END (state) { + if (state.roomStatus.playlist.length === 0) { + state.roomStatus.current.link = '' + state.roomStatus.current.title = '' + state.roomStatus.current.votes = 0 + state.roomStatus.current.voters = [] + } else { + state.roomStatus.playlist.sort((a, b) => { + return b.votes - a.votes + }) + state.roomStatus.current = state.roomStatus.playlist.shift() + } + }, + CURRENT_PAUSE (state, timeCode) { + state.roomStatus.player.playing = false + state.roomStatus.player.timeCode = timeCode + }, + CURRENT_PLAY (state, timeCode) { + state.roomStatus.player.playing = true + state.roomStatus.player.timeCode = timeCode } } diff --git a/client/src/store/rtcModule.js b/client/src/store/rtcModule.js index d08dadf..3e96b26 100644 --- a/client/src/store/rtcModule.js +++ b/client/src/store/rtcModule.js @@ -39,8 +39,8 @@ const actions = { leave ({ commit }) { commit('LEAVE') }, - broadcast ({ commit }, message) { - commit('BROADCAST', message) + broadcast ({ commit }, { message, type }) { + commit('BROADCAST', { message: message, type: type }) } } @@ -79,6 +79,7 @@ const mutations = { var peer = state.peers.find(peer => peer.name === target) peer.dataChannel = peer.connection.createDataChannel('dataChannel') + peer.dataChannel.onmessage = handleDataChannelMessage peer.dataChannel.onopen = handleDataChannelStateChangeEvent peer.dataChannel.onclose = handleDataChannelStateChangeEvent @@ -127,9 +128,14 @@ const mutations = { }) state.peers = {} }, - BROADCAST (state, message) { + BROADCAST (state, { message, type }) { + const data = JSON.stringify({ + type: type, + message: message + }) + console.log('[RTC] broadcast message ' + data) state.peers.forEach(peer => { - peer.dataChannel.send(message) + peer.dataChannel.send(data) }) } } @@ -167,17 +173,19 @@ function handleDataChannelCallback (event) { peer.dataChannel.onopen = handleDataChannelStateChangeEvent peer.dataChannel.onclose = handleDataChannelStateChangeEvent - store.dispatch('rtc/broadcast', store.state.room.roomStatus) + store.dispatch('rtc/broadcast', { message: store.state.room.roomStatus, type: 'status' }) } function handleDataChannelMessage (event) { console.log('[RTC] data channel message ' + event.data) - var data = event.data + var data = JSON.parse(event.data) + console.log('[RTC] data channel message type ' + data.type) switch (data.type) { case 'status': store.dispatch('room/setRoomStatus', data.message) break case 'vote': + store.dispatch('room/vote', { link: data.message.link, isPositive: data.message.isPositive, voterName: data.message.voterName }) break } } diff --git a/client/src/views/Room.vue b/client/src/views/Room.vue index 7b5a712..bc43fd6 100644 --- a/client/src/views/Room.vue +++ b/client/src/views/Room.vue @@ -4,7 +4,19 @@