Initial SyncLoungePlus support

Also fixed a stack of connection logic and temporarily disabled normal connections via request.
This commit is contained in:
samcm 2017-12-25 00:02:12 +11:00
parent ab36a3fbf5
commit ef80db6f30
8 changed files with 240 additions and 145 deletions

View File

@ -24,7 +24,7 @@
</v-toolbar>
<v-content v-bind:style="mainStyle">
<v-container class="ma-0 pa-3" align-start v-bind:style="containerStyle" style="height: 100%" fluid>
<v-flex xs12 v-if="loading || !plex.gotDevices">
<v-flex xs12 v-if="(loading || !plex.gotDevices) && route.meta.protected">
<v-container fill-height>
<v-layout justify-center align-center wrap row class="pt-4 text-xs-center">
<v-flex xs8 md4>
@ -119,7 +119,12 @@
},
mounted: async function () {
// Verify route changes
chrome.runtime.sendMessage('mlmjjfdcbemagmnjahllphjnohbmhcnf', { command: 'heartbeat' }, (response) => {
console.log(response)
if (response) {
this.$store.commit('SET_EXTAVAILABLE', true)
}
})
if (this.$route.query.ptserver && this.$route.query.ptroom) {
console.log('We should auto join')
// Looks like a valid request...
@ -133,6 +138,12 @@
this.snackbarMsg = msg
this.snackbar = true
})
window.EventBus.$on('PLAYBACK_CHANGE', (ratingKey) => {
// this.$store.dispatch('PLAYBACK_CHANGE', ratingKey)
})
window.EventBus.$on('NEW_TIMELINE', (timeline) => {
this.$store.dispatch('NEW_TIMELINE', timeline)
})
if (window['localStorage'].getItem('plexuser') == null) {
console.log('User isnt signed in - sending to signin')
this.$router.push('/signin')
@ -144,7 +155,11 @@
}
console.log('Logging in to Plex.Tv')
let plexstorage = JSON.parse(window['localStorage'].getItem('plexuser'))
await this.$store.dispatch('PLEX_LOGIN_TOKEN', plexstorage.authToken)
try {
await this.$store.dispatch('PLEX_LOGIN_TOKEN', plexstorage.authToken)
} catch (e) {
this.$router.push('/signin')
}
this.loading = false
},
@ -164,7 +179,10 @@
},
libraryCache: function () {
return this.$store.getters.getLibraryCache
},
},
extAvailable: function () {
return this.$store.getters.getExtAvailable
},
crumbs: function () {
if (this.$route.path.indexOf('browse') === -1) {
return []

View File

@ -145,8 +145,8 @@
}
},
watch: {
chosenClient: function () {
if (this.chosenClient) {
chosenClient: function (to, from) {
if (this.chosenClient && !from) {
this.$router.push('/joinroom')
}
}

View File

@ -2,7 +2,7 @@
<v-layout wrap row ckass="pt-2 pa-4" justify-center>
<v-flex xs12 md8>
<v-card style="background: rgba(0,0,0,0.3)" class="pa-4">
<h1 class="white--text center-text pa-4">Sign in to Plex.tv</h1>
<h1 :style="fontSizes.largest" class="center-text pa-4">Sign in to Plex.tv</h1>
<div v-if="!pin">
<v-layout wrap row style="position:relative">
<v-flex xs12 md4 offset-md4>
@ -13,7 +13,7 @@
</v-layout>
</div>
<div v-if="token" class="center-text" style="font-size:400%">
<v-icon class="green--text text--darken-2" style="font-size: 64px">done</v-icon>
<v-icon x-large class="green--text text--darken-2" style="font-size: 64px">done</v-icon>
<h3 class="white--text">
Signed in!
</h3>
@ -21,11 +21,11 @@
<div v-if="pin && !token">
<v-layout wrap row flex class="pt-4">
<v-flex xs12 md6 offset-md3>
<h1 class="center-text" style="color:white !important; background-color: rgba(128, 128, 128, 0.2); letter-spacing:1px">{{ pin }}</h1>
<h1 :style="fontSizes.largest" class="center-text" color="primary" style="color:white !important; background-color: rgba(128, 128, 128, 0.2); letter-spacing:1px">{{ pin }}</h1>
<v-layout wrap row flex class="pt-4">
<v-flex xs4 offset-xs4 >
<v-btn v-clipboard="pin" v-on:click.native="sendNotification()" primary class="pt-orange" style="width:100%">
<v-icon class="mr-2">content_copy</v-icon>
<v-btn v-clipboard="pin" v-on:click.native="sendNotification()" primary class="primary" style="width:100%">
<v-icon class="mr-2">content_copy</v-icon>
Copy
</v-btn>
</v-flex>
@ -95,8 +95,8 @@
this.$http.post('https://plex.tv/pins.xml', null, {
headers: {
'X-Plex-Device': 'Web',
'X-Plex-Device-Name': 'PlexTogether',
'X-Plex-Product': 'PlexTogether',
'X-Plex-Device-Name': 'SyncLounge',
'X-Plex-Product': 'SyncLounge',
'X-Plex-Version': '1.2',
'X-Plex-Platform': sBrowser,
'X-Plex-Platform-Version': '',
@ -107,7 +107,7 @@
if (!err) {
this.pin = result.pin.code[0]
this.ID = result.pin.id[0]._
let checker = setInterval(function () {
let checker = setInterval(() => {
var options = {
url: 'https://plex.tv/pins/' + result.pin.id[0]._ + '.xml',
headers: {
@ -130,14 +130,14 @@
if (!err) {
if (result.pin.auth_token[0] != null && result.pin.auth_token[0].length > 1) {
console.log('GOT TOKEN!', this)
that.token = result.pin.auth_token[0]
this.token = result.pin.auth_token[0]
let jsonObj = {
authToken: this.token
}
storage.setItem('plexuser', JSON.stringify(jsonObj))
await that.$store.dispatch('PLEX_LOGIN_TOKEN', token)
setTimeout(function () {
that.$router.push('/sync')
await this.$store.dispatch('PLEX_LOGIN_TOKEN', this.token)
setTimeout(() => {
this.$router.push('/browse')
}, 2500)
clearInterval(checker)
}

View File

@ -74,18 +74,29 @@ Vue.mixin({
plexserver: function () {
return this.plex.servers[this.$route.params.machineIdentifier]
},
route: function () {
return this.$route
},
fontSizes: function () {
var w = Math.round(Math.max(document.documentElement.clientWidth, window.innerWidth || 0))
var h = Math.round(Math.max(document.documentElement.clientHeight, window.innerHeight || 0))
let maxPx = 94
let maxRes = 3000
return {
largest: { 'font-size': ((w / maxRes) * maxPx) + 'px' }
largest: { 'font-size': ((w / maxRes) * maxPx) + 'px' },
medium: { 'font-size': ((w / maxRes) * maxPx) * 0.6 + 'px' }
}
}
}
})
// var data = { type: "FROM_PAGE", text: "Hello from the webpage!", callback: (res) => {
// console.log('Result callback!', res)
// }};
// window.postMessage(data, "*");
router.beforeEach((to, from, next) => {
console.log('Route change', to, this, store)
if (to.matched.some(record => record.meta.protected)) {
@ -112,7 +123,9 @@ router.beforeEach((to, from, next) => {
console.log('Valid route change!')
next()
} else {
next() // make sure to always call next()!
if (!to.meta.protected) {
return next() // make sure to always call next()!
}
router.push('/browse')
}
})

View File

@ -15,14 +15,13 @@ export default new Router({
base: '/ptweb/',
routes: [
{ path: '/', meta: { protected: true } },
{ path: '/signin', component: signin },
{ path: '/signout', component: signout },
{ path: '/join', component: join },
{ path: '/clientselect', component: require('../components/application/walkthrough.vue') },
{ path: '/joinroom', component: require('../components/application/joinroom.vue') },
{ path: '/signin', meta: { noload: true }, component: signin },
{ path: '/signout', meta: { noload: true }, component: signout },
{ path: '/join', meta: { noload: true }, component: join },
{ path: '/clientselect', meta: { noload: false }, component: require('../components/application/walkthrough.vue') },
{ path: '/joinroom', meta: { noload: false }, component: require('../components/application/joinroom.vue') },
{ path: '/player', meta: { protected: true }, component: require('../components/application/ptplayer.vue') },
{ path: '/browse', meta: { protected: true }, name: 'browse', component: require('../components/application/plexbrowser.vue') },
{ path: '/browse/:machineIdentifier', meta: { protected: true }, name: 'server', component: require('../components/application/plexbrowser/plexserver.vue'), },

View File

@ -76,6 +76,8 @@ const state = {
autoJoinPassword: null,
shortLink: null,
webapp_socket: _webapp_socket,
extAvailable: false,
lastRatingKey: null,
// SETTINGS
DARKMODE: JSON.parse(getSetting('DARKMODE')),
CLIENTPOLLINTERVAL: getSetting('CLIENTPOLLINTERVAL'),
@ -91,77 +93,9 @@ const state = {
}
const mutations = {
SET_CHOSENCLIENT (state, client) {
async function playbackChange (ratingKey) {
// console.log('Playback change!', ratingKey)
if (ratingKey != null) {
// Playing something different!
let server = state.plex.servers[state.chosenClient.lastTimelineObject.machineIdentifier]
state.LASTSERVER = state.chosenClient.lastTimelineObject.machineIdentifier
window['localStorage'].setItem('LASTSERVER', state.chosenClient.lastTimelineObject.machineIdentifier)
if (!server) {
return
}
// Fetch our metadata from this server
// console.log('Loading content metadata from store ' + ratingKey)
server.getMediaByRatingKey(ratingKey.replace('/library/metadata/', '')).then((data) => {
let metadata = data.MediaContainer.Metadata[0]
if (!metadata) {
return
}
if (metadata.type == 'movie') {
sendNotification('Now Playing: ' + metadata.title + ' from ' + state.plex.servers[metadata.machineIdentifier].name)
}
if (metadata.type == 'episode') {
sendNotification('Now Playing: ' + metadata.grandparentTitle + ' S' + metadata.parentIndex + 'E' + metadata.index + ' from ' + state.plex.servers[metadata.machineIdentifier].name)
}
state.chosenClient.clientPlayingMetadata = metadata
var w = Math.round(Math.max(document.documentElement.clientWidth, window.innerWidth || 0));
var h = Math.round(Math.max(document.documentElement.clientHeight, window.innerHeight || 0));
state.background = state.plex.servers[metadata.machineIdentifier].getUrlForLibraryLoc(metadata.thumb, w / 4, h / 4, 4)
})
} else {
let thumb = await state.plex.getRandomThumb(state.plex)
if (thumb) {
state.background = thumb
}
state.chosenClient.clientPlayingMetadata = null
}
}
function newTimeline (timeline) {
// console.log('Got timeline')
// Lets send this to our PTServer
state.ourClientResponseTime = timeline.lastResponseTime
let title = null
let rawTitle = null
if (state.chosenClient.clientPlayingMetadata) {
let metadata = state.chosenClient.clientPlayingMetadata
rawTitle = metadata.title
if (metadata.type == 'episode') {
title = metadata.grandparentTitle + ' - ' + metadata.title + ' S' + metadata.parentIndex + '-' + 'E' + metadata.index
} else {
title = metadata.title
}
}
let end_obj = {
time: timeline.time,
maxTime: timeline.duration,
title: title,
rawTitle: rawTitle,
playerState: timeline.state,
clientResponseTime: state.chosenClient.lastResponseTime
}
let time = -1
let maxTime = -1
let playerState = null
let showName = null
if (state.synclounge._socket) {
state.synclounge._socket.pollStartTime = (new Date).getTime()
state.synclounge._socket.emit('poll', end_obj)
}
}
// Set up our client poller
function clientPoller (time) {
@ -191,8 +125,6 @@ const mutations = {
if (state.chosenClient == null) {
return
}
state.chosenClient.events.on('new_timeline', newTimeline)
state.chosenClient.events.on('playback_change', playbackChange)
state.chosenClientTimeSet = (new Date).getTime()
clientPoller(state.chosenClientTimeSet)
state.chosenClient.getTimeline(function (timeline) {})
@ -298,6 +230,14 @@ const mutations = {
},
SET_HOSTPTSERVERRESPONSETIME (state, value) {
state.stats.hostPTServerResponseTime = value
},
SET_EXTAVAILABLE (state, value) {
state.extAvailable = value
},
SET_VALUE (state, data) {
let [ key, value ] = data
console.log('Setting state', key, 'to', value)
state[key] = value
}
}
const getters = {
@ -368,6 +308,9 @@ const getters = {
},
getSettingLASTSERVER: state => {
return state.LASTSERVER
},
getExtAvailable: state => {
return state.extAvailable
}
}
const actions = {
@ -375,7 +318,89 @@ const actions = {
setTimeout(() => {
commit('INCREMENT')
}, 200)
}
},
async PLAYBACK_CHANGE ({ commit, state, dispatch }, data) {
console.log('Playback change!', state.chosenClient)
let [ client, ratingKey, mediaContainer ] = data
if (ratingKey) {
// Playing something different!
console.log(mediaContainer)
let server = state.plex.servers[mediaContainer.machineIdentifier]
state.LASTSERVER = mediaContainer.machineIdentifier
window['localStorage'].setItem('LASTSERVER', mediaContainer.machineIdentifier)
if (!server) {
console.log('Playing off a server we do not have access to')
return
}
// Fetch our metadata from this server
// console.log('Loading content metadata from store ' + ratingKey)
server.getMediaByRatingKey(ratingKey.replace('/library/metadata/', '')).then((data) => {
console.log('Metadata:', data)
let metadata = data.MediaContainer.Metadata[0]
if (!metadata) {
return
}
if (metadata.type == 'movie') {
sendNotification('Now Playing: ' + metadata.title + ' from ' + state.plex.servers[metadata.machineIdentifier].name)
}
if (metadata.type == 'episode') {
sendNotification('Now Playing: ' + metadata.grandparentTitle + ' S' + metadata.parentIndex + 'E' + metadata.index + ' from ' + state.plex.servers[metadata.machineIdentifier].name)
}
state.chosenClient.clientPlayingMetadata = metadata
var w = Math.round(Math.max(document.documentElement.clientWidth, window.innerWidth || 0));
var h = Math.round(Math.max(document.documentElement.clientHeight, window.innerHeight || 0));
state.background = state.plex.servers[metadata.machineIdentifier].getUrlForLibraryLoc(metadata.thumb, w / 4, h / 4, 4)
})
} else {
let thumb = await state.plex.getRandomThumb(state.plex)
if (thumb) {
state.background = thumb
}
state.chosenClient.clientPlayingMetadata = null
}
},
NEW_TIMELINE ({ commit, state, dispatch }, data) {
// return true
let [ client, timeline, mediaContainer ] = data
// console.log(state)
if (!state.chosenClient || (client.clientIdentifier !== state.chosenClient.clientIdentifier)) {
console.log('Invalid client')
return false
}
if (state.lastRatingKey !== timeline.ratingKey) {
commit('SET_VALUE', ['lastRatingKey', timeline.ratingKey])
dispatch('PLAYBACK_CHANGE', [ client, timeline.ratingKey, timeline])
}
// state.ourClientResponseTime = timeline.lastResponseTime
let title = null
let rawTitle = null
if (state.chosenClient.clientPlayingMetadata) {
let metadata = state.chosenClient.clientPlayingMetadata
rawTitle = metadata.title
if (metadata.type == 'episode') {
title = metadata.grandparentTitle + ' - ' + metadata.title + ' S' + metadata.parentIndex + '-' + 'E' + metadata.index
} else {
title = metadata.title
}
}
let end_obj = {
time: timeline.time,
maxTime: timeline.duration,
title: title,
rawTitle: rawTitle,
playerState: timeline.state,
clientResponseTime: state.chosenClient.lastResponseTime
}
let time = -1
let maxTime = -1
let playerState = null
let showName = null
if (state.synclounge._socket) {
state.synclounge._socket.pollStartTime = (new Date).getTime()
state.synclounge._socket.emit('poll', end_obj)
}
},
}

View File

@ -173,7 +173,8 @@ export default {
PLEX_ADD_CLIENT: ({ state, commit, dispatch }, client) => {
commit('PLEX_CLIENT_SET', client)
commit('PLEX_CLIENT_SET_VALUE', [client, 'commit', commit])
commit('PLEX_CLIENT_SET_VALUE', [client, 'commit', commit])
commit('PLEX_CLIENT_SET_VALUE', [client, 'dispatch', dispatch])
},
PLEX_ADD_SERVER: ({ state, commit, dispatch }, server) => {
commit('PLEX_SERVER_SET', server)

View File

@ -44,6 +44,9 @@ module.exports = function PlexClient () {
this.eventbus = window.EventBus // Assigned early on - we will use this to communicate with the PT Player
this.commit = null
this.dispatch = null
let previousTimeline = {}
this.setValue = function (key, value) {
this[key] = value
@ -88,7 +91,9 @@ module.exports = function PlexClient () {
if (!connection) {
return reject('No connection specified')
}
var query = 'type=video&X-Plex-Device-Name=SyncLounge&'
var query = ''
Object.assign(params, { type: 'video', 'X-Plex-Device-Name': 'SyncLounge'})
// console.log(params)
for (let key in params) {
query += encodeURIComponent(key) + '=' + encodeURIComponent(params[key]) + '&'
}
@ -100,21 +105,49 @@ module.exports = function PlexClient () {
var _url = connection.uri + command + '?' + query
this.setValue('commandId', this.commandId + 1)
var options = PlexAuth.getClientApiOptions(_url, this.clientIdentifier, this.uuid, 5000)
console.log('sending api request', options)
request(options, (error, response, body) => {
// console.log('response data', response)
if (error) {
return reject(error)
} else {
parseXMLString(body, function (err, result) {
if (err || (response.statusCode != 200 && response.statusCode != 201)) {
return reject(err)
// console.log('sending api request', options)
chrome.runtime.sendMessage('mlmjjfdcbemagmnjahllphjnohbmhcnf', {
command: 'client',
data: {
url: _url,
query: params,
options: options
},
client_command: command,
query: query
}, (response) => {
// console.log('SyncLoungePlus response', response)
if (response) {
parseXMLString(response, (err, result) => {
resolve(result)
if (command === '/player/timeline/poll') {
this.updateTimelineObject(result)
}
return resolve(result)
})
}
return
})
} else {
// request(options, (error, response, body) => {
// // console.log('response data', response)
// if (error) {
// return reject(error)
// } else {
// parseXMLString(body, function (err, result) {
// if (err || (response.statusCode != 200 && response.statusCode != 201)) {
// return reject(err)
// }
// return resolve(result)
// })
// }
// })
}
})
}
if ((new Date().getTime() - this.lastSubscribe) > 29000) {
// We need to subscribe first!
@ -152,10 +185,9 @@ module.exports = function PlexClient () {
}
this.updateTimelineObject = function (result) {
this.setValue('lastTimelineObject', result)
this.lastTimelineObject = result
this.events.emit('new_timeline', result)
// this.events.emit('new_timeline', result)
// console.log('New timeline', result)
// Check if we are the SLPlayer
if (this.clientIdentifier === 'PTPLAYER9PLUS10') {
// SLPLAYER
@ -190,40 +222,47 @@ module.exports = function PlexClient () {
// Valid timeline data
// Standard player
let timelines = result.MediaContainer.Timeline
let videoTimeline = null
let videoTimeline = {}
for (let i = 0; i < timelines.length; i++) {
let _timeline = timelines[i]['$']
if (_timeline.type == 'video'){
videoTimeline = _timeline
}
if ((_timeline.state && _timeline.state != 'stopped') || i == (timelines.length - 1)) {
this.events.emit('new_timeline', timelines[i]['$'])
var clonetimeline = this.lastTimelineObject
this.lastTimelineObject = timelines[i]['$']
this.setValue('lastTimelineObject', timelines[i]['$'])
if (!this.oldTimelineObject) {
// First time we've got data!
if (!this.lastTimelineObject.ratingKey) {
this.events.emit('playback_change', null)
} else {
this.events.emit('playback_change', this.lastTimelineObject.ratingKey)
}
this.setValue('oldTimelineObject', timelines[i]['$'])
// this.oldTimelineObject = timelines[i]['$']
return timelines[i]['$']
console.log('Does', videoTimeline.ratingKey + ' equal ' + previousTimeline.ratingKey)
if (videoTimeline.ratingKey !== previousTimeline.ratingKey) {
window.EventBus.$emit('PLAYBACK_CHANGE', [this, videoTimeline.ratingKey, result.MediaContainer])
}
this.setValue('oldTimelineObject', clonetimeline)
this.oldTimelineObject = clonetimeline
if (this.oldTimelineObject.ratingKey != result.ratingKey) {
if (!this.lastTimelineObject.ratingKey) {
this.events.emit('playback_change', null)
} else {
this.events.emit('playback_change', result.ratingKey)
}
}
return timelines[i]['$']
}
// if ((_timeline.state && _timeline.state != 'stopped') || i == (timelines.length - 1)) {
// this.events.emit('new_timeline', timelines[i]['$'])
// var clonetimeline = this.lastTimelineObject
// this.lastTimelineObject = timelines[i]['$']
// this.setValue('lastTimelineObject', timelines[i]['$'])
// if (!this.oldTimelineObject) {
// // First time we've got data!
// if (!this.lastTimelineObject.ratingKey) {
// this.events.emit('playback_change', null)
// } else {
// this.events.emit('playback_change', this.lastTimelineObject.ratingKey)
// }
// this.setValue('oldTimelineObject', timelines[i]['$'])
// // this.oldTimelineObject = timelines[i]['$']
// return timelines[i]['$']
// }
// this.setValue('oldTimelineObject', clonetimeline)
// this.oldTimelineObject = clonetimeline
// if (this.oldTimelineObject.ratingKey != result.ratingKey) {
// if (!this.lastTimelineObject.ratingKey) {
// this.events.emit('playback_change', null)
// } else {
// this.events.emit('playback_change', result.ratingKey)
// }
// }
// return timelines[i]['$']
// }
}
window.EventBus.$emit('NEW_TIMELINE', [this, videoTimeline, result.MediaContainer])
previousTimeline = videoTimeline
// this.setValue('lastTimelineObject', videoTimeline)
return videoTimeline
}
this.pressPlay = function (callback) {