Router finished + slplayer fixes
This commit is contained in:
parent
d53ce90745
commit
41e72204b4
20
src/App.vue
20
src/App.vue
|
@ -13,7 +13,7 @@
|
|||
</v-navigation-drawer>
|
||||
<v-toolbar app fixed>
|
||||
<v-toolbar-side-icon @click="drawer = !drawer"></v-toolbar-side-icon>
|
||||
<v-toolbar-title class="white--text">SyncLounge</v-toolbar-title>
|
||||
<v-toolbar-title class="white--text"> SyncLounge </v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-toolbar-items>
|
||||
<img class="ma-2" style="height:48px; width: 48px" v-bind:src="logo"/>
|
||||
|
@ -162,7 +162,10 @@
|
|||
},
|
||||
itemCache: function () {
|
||||
return this.$store.getters.getItemCache
|
||||
},
|
||||
},
|
||||
libraryCache: function () {
|
||||
return this.$store.getters.getLibraryCache
|
||||
},
|
||||
crumbs: function () {
|
||||
if (this.$route.path.indexOf('browse') === -1) {
|
||||
return []
|
||||
|
@ -173,6 +176,13 @@
|
|||
} catch (e) {
|
||||
return 'Loading..'
|
||||
}
|
||||
}
|
||||
const getLibrary = (id) => {
|
||||
try {
|
||||
return this.libraryCache[this.$route.params.machineIdentifier][id]
|
||||
} catch (e) {
|
||||
return 'Loading..'
|
||||
}
|
||||
}
|
||||
let data = [{
|
||||
text: 'Home',
|
||||
|
@ -187,7 +197,7 @@
|
|||
},
|
||||
sectionId: () => {
|
||||
return {
|
||||
text: this.$route.params.sectionId,
|
||||
text: getLibrary(this.$route.params.sectionId),
|
||||
to: '/browse/' + this.$route.params.machineIdentifier + '/' + this.$route.params.sectionId
|
||||
}
|
||||
},
|
||||
|
@ -197,7 +207,7 @@
|
|||
to = '/browse/' + this.$route.params.machineIdentifier + '/' + this.$route.params.sectionId
|
||||
+ '/tv/' + this.$route.params.grandparentKey + '/' + this.$route.params.parentKey
|
||||
} else {
|
||||
'/browse/' + this.$route.params.machineIdentifier + '/' + this.$route.params.sectionId
|
||||
to = '/browse/' + this.$route.params.machineIdentifier + '/' + this.$route.params.sectionId
|
||||
+ '/tv/' + this.$route.params.parentKey
|
||||
}
|
||||
return {
|
||||
|
@ -283,7 +293,7 @@
|
|||
mainStyle: function() {
|
||||
if (this.$store.getters.getBackground != null){
|
||||
return {
|
||||
'background-image': 'url('+this.$store.getters.getBackground+')',
|
||||
'background-image': 'url(' + this.$store.getters.getBackground + ')',
|
||||
'background-repeat': 'no-repeat',
|
||||
'background-size': 'cover',
|
||||
'background-position': 'center'
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<v-toolbar-item class="hidden-sm-and-down">
|
||||
<img style="height:70%;width:auto" v-bind:src="logo"/>
|
||||
</v-toolbar-item>
|
||||
<v-toolbar-item class="hidden-sm-and-down" v-for="link in links" :href="link.href" :target="link.target">{{ link.title }}</v-toolbar-item>
|
||||
<v-toolbar-item class="hidden-sm-and-down" v-for="link in links" :href="link.href" :key="link.href" :target="link.target">{{ link.title }}</v-toolbar-item>
|
||||
</v-toolbar-items>
|
||||
</v-toolbar>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div ref="root">
|
||||
<v-layout v-if="!contents" row >
|
||||
<v-flex xs12 style="position:relative">
|
||||
<v-progress-circular style="left: 50%; top:50%" v-bind:size="60" indeterminate class="amber--text"></v-progress-circular>
|
||||
|
@ -8,7 +8,7 @@
|
|||
<div v-if="contents">
|
||||
<v-card v-if="contents" horizontal :img="getArtUrl" style="height: 80vh" class="darken-2 white--text">
|
||||
<div style="background-color: rgba(0, 0, 0, 0.4); height: 100%">
|
||||
<v-container style="background-color: rgba(0, 0, 0, 0.8)" fill-height>
|
||||
<v-container style="background-color: rgba(0, 0, 0, 0.8); height: 100%" fluid>
|
||||
<v-layout row wrap v-if="contents.type == 'episode'">
|
||||
<v-flex md9 sm12 style="height 100%" class="mt-4 pa-1 pl-0">
|
||||
<h3 style="font-weight:bold"> {{ contents.grandparentTitle }}</h3>
|
||||
|
@ -33,17 +33,17 @@
|
|||
</v-flex>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout justify-center align-start row wrap v-if="contents.type == 'movie'">
|
||||
<v-flex md3 class="hidden-sm-and-down pa-4">
|
||||
<v-layout justify-center align-center row wrap v-if="contents.type == 'movie'">
|
||||
<v-flex md3 class="pa-4">
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12>
|
||||
<v-flex xs12 md12>
|
||||
<v-card-media
|
||||
:src="thumb"
|
||||
height="30vh"
|
||||
contain
|
||||
></v-card-media>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="text-xs-center">
|
||||
<v-flex xs8 md12 class="text-xs-center hidden-sm-and-down ">
|
||||
<div v-if="playable">
|
||||
<v-btn block v-if="playable && contents.Media.length == 1 && (contents.viewOffset == 0 || !contents.viewOffset)" v-on:click.native="playMedia(contents)" class="primary white--text">
|
||||
<v-icon> play_arrow </v-icon>
|
||||
|
@ -59,11 +59,11 @@
|
|||
</v-flex>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
<v-flex md9 sm12>
|
||||
<h1 style="font-size: 72px">{{ contents.title }}</h1>
|
||||
<v-flex md9 sm12>
|
||||
<h1 :style="fontSizes.largest">{{ contents.title }}</h1>
|
||||
<h2>{{ contents.year }}</h2>
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12 sm6 style="opacity:0.5">
|
||||
<v-flex xs12 md6 style="opacity:0.5">
|
||||
{{ length }}
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6>
|
||||
|
@ -73,12 +73,26 @@
|
|||
<v-chip v-if="contents.studio" color="grey darken-2" small label> {{ contents.studio }}</v-chip>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="text-xs-center hidden-md-and-up ">
|
||||
<div v-if="playable">
|
||||
<v-btn block v-if="playable && contents.Media.length == 1 && (contents.viewOffset == 0 || !contents.viewOffset)" v-on:click.native="playMedia(contents)" class="primary white--text">
|
||||
<v-icon> play_arrow </v-icon>
|
||||
</v-btn>
|
||||
<v-btn block v-else @click.native.stop="dialog = true" class="primary white--text">
|
||||
<v-icon> play_arrow </v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<span v-if="!playable" class="pa-2" >Now playing on {{ chosenClient.name }} from {{ server.name }}</span>
|
||||
<v-btn v-if="!playable" style="background-color: #cc3f3f" v-on:click.native="pressStop()" class="white--text">
|
||||
<v-icon></v-icon> Stop
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
<p class="pt-3" style="font-style: italic"> {{ contents.summary }} </p>
|
||||
<v-layout row wrap class="hidden-sm-and-down" justify-start align-start v-if="contents.type === 'movie'">
|
||||
<v-flex lg3 xl2 v-if="contents.Role && contents.Role.length > 0">
|
||||
<v-subheader class="white--text"> Featuring </v-subheader>
|
||||
<div v-for="actor in contents.Role.slice(0, 6)" :key="actor.tag">
|
||||
{{ actor.tag }} <span style="opacity:0.7;font-size:80%"> {{actor.role}} </span>
|
||||
{{ actor.tag }} <span style="opacity:0.7;font-size:80%"> {{ actor.role }} </span>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex lg3 xl2 v-if="contents.Director && contents.Director.length > 0">
|
||||
|
@ -159,6 +173,23 @@
|
|||
</div>
|
||||
</v-flex>
|
||||
</v-layout> -->
|
||||
<v-divider></v-divider>
|
||||
<div v-if="subsetParentData(6).length >= 0 && contents.type == 'episode' && playable" style="background: rgba(0,0,0,0.3)">
|
||||
<v-subheader>Also in Season {{ contents.parentIndex }} of {{ contents.grandparentTitle }}</v-subheader>
|
||||
<v-layout v-if="parentData" row wrap justify-start>
|
||||
<v-flex xs6 md2 xl2 lg2 class="pb-3" v-for="ep in subsetParentData(6)" :key="ep.key">
|
||||
<plexthumb bottomOnly :content="ep" :img="getLittleThumb(ep)" :class="{highlightBorder: ep.index == contents.index}" style="margin:15%" :server="server" type="thumb" spoilerFilter></plexthumb>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
<div v-if="relatedItems.length > 0" style="background: rgba(0,0,0,0.3)">
|
||||
<v-subheader>Related Movies</v-subheader>
|
||||
<v-layout row wrap justify-start>
|
||||
<v-flex xs4 md2 class="ma-1" v-for="movie in relatedItems" :key="movie.key">
|
||||
<plexthumb :content="movie" :img="getLittleThumb(movie)" style="margin:15%" :server="server" type="thumb"></plexthumb>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
</v-container>
|
||||
<!-- <v-card-actions class="pa-4" >
|
||||
<v-spacer></v-spacer>
|
||||
|
@ -178,23 +209,7 @@
|
|||
<v-icon></v-icon> Stop
|
||||
</v-btn>
|
||||
</v-card-actions> -->
|
||||
<v-divider></v-divider>
|
||||
<div v-if="subsetParentData(6).length >= 0 && contents.type == 'episode' && playable" style="background: rgba(0,0,0,0.3)">
|
||||
<v-subheader>Also in Season {{ contents.parentIndex }} of {{ contents.grandparentTitle }}</v-subheader>
|
||||
<v-layout v-if="parentData" row wrap justify-start>
|
||||
<v-flex xs6 md2 xl2 lg2 class="pb-3" v-for="ep in subsetParentData(6)" :key="ep.key">
|
||||
<plexthumb bottomOnly :content="ep" :img="getLittleThumb(ep)" :class="{highlightBorder: ep.index == contents.index}" style="margin:15%" :server="server" type="thumb" spoilerFilter @contentSet="setContent(ep)"></plexthumb>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
<div v-if="relatedItems.length > 0 && contents.type == 'movies'" style="background: rgba(0,0,0,0.3)">
|
||||
<v-subheader>Related Movies</v-subheader>
|
||||
<v-layout row wrap justify-start>
|
||||
<v-flex xs6 md2 xl2 lg2 class="pb-3" v-for="ep in relatedItems" :key="ep.key">
|
||||
<plexthumb bottomOnly :content="ep" :img="getLittleThumb(ep)" :class="{highlightBorder: ep.index == contents.index}" style="margin:15%" :server="server" type="thumb" @contentSet="setContent(ep)"></plexthumb>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</v-card>
|
||||
</div>
|
||||
|
@ -217,7 +232,7 @@
|
|||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs4>
|
||||
<v-btn class="primary white--text" @click.native.stop="playMedia(content,index)">
|
||||
<v-btn class="primary white--text" @click.native.stop="playMedia(contents, index)">
|
||||
Play
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
|
@ -239,29 +254,7 @@
|
|||
created () {
|
||||
// Hit the PMS endpoing /library/sections
|
||||
var that = this
|
||||
console.log('Loading content metadata: ' + this.ratingKey)
|
||||
this.server.getMediaByRatingKey(this.ratingKey).then(async (result) => {
|
||||
if (result) {
|
||||
this.contents = result
|
||||
if (result.type == 'episode'){
|
||||
this.server.getSeriesChildren(result.parentKey + '/children', 0, 500, 1).then((res) => {
|
||||
if (res){
|
||||
this.parentData = res
|
||||
}
|
||||
})
|
||||
}
|
||||
if (result.type == 'movie'){
|
||||
try {
|
||||
this.related = await this.server.getRelated(this.ratingKey, 12)
|
||||
} catch (e) {
|
||||
console.log('Unable to fetch related content for', this.ratingKey, 'Error:', e )
|
||||
}
|
||||
}
|
||||
this.setBackground()
|
||||
} else {
|
||||
this.status = 'Error loading libraries!'
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
@ -284,12 +277,17 @@
|
|||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
this.getNewData()
|
||||
this.fullheight = this.$refs.root.offsetHeight
|
||||
this.fullwidth = this.$refs.root.offsetWidth
|
||||
},
|
||||
beforeDestroy () {
|
||||
|
||||
},
|
||||
watch: {
|
||||
ratingKey: function () {
|
||||
this.getNewData()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
plex () {
|
||||
|
@ -347,7 +345,7 @@
|
|||
this.related.MediaContainer.Hub[0].Metadata.forEach((item) => {
|
||||
items.push(item)
|
||||
})
|
||||
return items
|
||||
return items.slice(0, 4)
|
||||
},
|
||||
getArtUrl () {
|
||||
var w = Math.round(Math.max(document.documentElement.clientWidth, window.innerWidth || 0));
|
||||
|
@ -383,6 +381,32 @@
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
getNewData () {
|
||||
console.log('Loading content metadata: ' + this.ratingKey)
|
||||
this.server.getMediaByRatingKey(this.ratingKey).then(async (result) => {
|
||||
if (result) {
|
||||
this.contents = result.MediaContainer.Metadata[0]
|
||||
if (this.contents.type == 'episode'){
|
||||
this.server.getSeriesChildren(result.parentKey + '/children', 0, 500, 1).then((res) => {
|
||||
if (res){
|
||||
this.parentData = res
|
||||
}
|
||||
})
|
||||
}
|
||||
if (this.contents.type == 'movie'){
|
||||
try {
|
||||
console.log('Fetching related')
|
||||
this.related = await this.server.getRelated(this.ratingKey, 12)
|
||||
} catch (e) {
|
||||
console.log('Unable to fetch related content for', this.ratingKey, 'Error:', e )
|
||||
}
|
||||
}
|
||||
this.setBackground()
|
||||
} else {
|
||||
this.status = 'Error loading libraries!'
|
||||
}
|
||||
})
|
||||
},
|
||||
setContent (content) {
|
||||
this.$router.push('/browse/' + this.serverId + '/' + content.ratingKey)
|
||||
},
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
<v-progress-circular style="left: 50%; top:50%" v-bind:size="60" indeterminate class="amber--text"></v-progress-circular>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div v-if="!browsingContent && contents" class="mt-3" style="height:90vh; overflow-y:scroll ">
|
||||
<v-layout class="row" row wrap>
|
||||
<v-flex xs4 md3 lg1 class="pb-3" v-for="content in contents.MediaContainer.Metadata" :key="content.key">
|
||||
<div v-if="!browsingContent && contents" class="mt-3 mx-auto" style="height:90vh; overflow-y:scroll ">
|
||||
<v-layout class="row" row wrap justify-start>
|
||||
<v-flex xs4 md3 lg1 class="ma-3" v-for="content in contents.MediaContainer.Metadata" :key="content.key">
|
||||
<plexthumb :content="content" :server="server" type="thumb" style="margin:7%" @contentSet="setContent(content)"></plexthumb>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</v-flex>
|
||||
</v-layout>
|
||||
<div v-if="contents" class="mt-3">
|
||||
<v-flex xs12 style="background: rgba(0, 0, 0, .4);">
|
||||
<v-flex xs12 style="background: rgba(0, 0, 0, .4);">
|
||||
<v-card class="darken-2 white--text" :img="getArtUrl">
|
||||
<v-container style="background:rgba(0,0,0,0.6)" class="pa-3 ma-0" fluid grid-list-lg>
|
||||
<v-layout row style="height:100%">
|
||||
|
@ -20,13 +20,13 @@
|
|||
</v-flex>
|
||||
<v-flex xs12 md9 class="ma-2">
|
||||
<div>
|
||||
<h3 > {{ contents.parentTitle }}</h3>
|
||||
<h1 style="font-size: 72px"> {{ contents.parentTitle }}</h1>
|
||||
<h3 style="font-weight:bold">{{ contents.title }}</h3>
|
||||
<p> {{ getSeasons }} - {{ contents.parentYear }} </p>
|
||||
<v-divider></v-divider>
|
||||
<p style="font-style: italic" class="pt-3; overflow: hidden"> {{ contents.summary }} </p>
|
||||
<div>
|
||||
<v-chip v-for="genre in genres" :key="genre.tag" label>
|
||||
<v-chip v-for="genre in genres" :key="genre.tag" label color="grey">
|
||||
{{ genre.tag }}
|
||||
</v-chip>
|
||||
</div>
|
||||
|
|
|
@ -25,10 +25,25 @@
|
|||
{{ content.Media.length }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div :style="{ 'height': bottomCalculatedHeight }" style="background: rgba(0, 0, 0, .8);position:absolute; bottom: 0; width:100%">
|
||||
</div>
|
||||
<v-container fill-height fluid class="pa-0" style="background: linear-gradient(to top, rgba(0, 0, 0, 5), rgba(0, 0, 0, 00)); background-position-y:bottom; background-repeat:no-repeat; background-size:100% 60%; max-width:100%">
|
||||
<v-layout row wrap justify-end align-end>
|
||||
<v-flex xs12>
|
||||
<v-progress-linear style="width:100%" class="pa-0 mb-1 ma-0 pt-content-progress" v-if="showProgressBar" height="2" :value="unwatchedPercent"></v-progress-linear>
|
||||
<v-layout align-end row wrap class="text-xs-left pa-1" style="max-width: 100%">
|
||||
<v-flex xs12 v-if="!onlyBottom" style="max-width: 100%">
|
||||
<div class="truncate" style="font-size:1rem">{{ getTitle(content) }}</div>
|
||||
</v-flex>
|
||||
<v-flex xs12 style="font-size:0.8rem" ref="bottomText">
|
||||
<div class="truncate soft-text">{{ getUnder(content) }}</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
<!-- <div :style="{ 'height': bottomCalculatedHeight }" style="background: rgba(0, 0, 0, .8);position:absolute; bottom: 0; width:100%">
|
||||
<div class="ma-0">
|
||||
<v-progress-linear style="position:absolute; top:0; width:100%" class="pa-0 ma-0 pt-content-progress" v-if="showProgressBar" height="2" :value="unwatchedPercent"></v-progress-linear>
|
||||
<v-progress-linear style="position:absolute; top:0; width:100%" class="pa-0 ma-0 pt-content-progress" v-if="showProgressBar" height="2" :value="unwatchedPercent"></v-progress-linear>
|
||||
<v-layout row wrap class="text-xs-left" style="margin:0; margin-left:3px; display:block; max-width:100%; height:100%">
|
||||
<v-flex v-if="!onlyBottom" xs12 style="height:50%" :style="topTextStyle" ref="topText" class="pa-0 ma-0 ml-1 mt-1">
|
||||
<div class="truncate" style="font-size:1rem">{{ getTitle(content) }}</div>
|
||||
|
@ -38,7 +53,7 @@
|
|||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
<template>
|
||||
<div style="width:100%; max-height: calc(100vh - 64px)">
|
||||
<videoplayer v-if="playingMetadata && chosenServer && chosenQuality && ready"
|
||||
@playerMounted="playerMounted()"
|
||||
@timelineUpdate="timelineUpdate"
|
||||
@playbackEnded="stopPlayback()"
|
||||
@playerMounted="playerMounted()"
|
||||
@timelineUpdate="timelineUpdate"
|
||||
@playbackEnded="stopPlayback()"
|
||||
|
||||
:metadata="playingMetadata"
|
||||
:server="chosenServer"
|
||||
:src="getSourceByLabel(chosenQuality)"
|
||||
:initUrl="getSourceByLabel(chosenQuality).initUrl"
|
||||
:params="getSourceByLabel(chosenQuality).params"
|
||||
:initialOffset="playertime"
|
||||
:createdAt="playerCreatedAt"
|
||||
:metadata="playingMetadata"
|
||||
:server="chosenServer"
|
||||
:src="getSourceByLabel(chosenQuality)"
|
||||
:initUrl="getSourceByLabel(chosenQuality).initUrl"
|
||||
:params="getSourceByLabel(chosenQuality).params"
|
||||
:initialOffset="playertime"
|
||||
:createdAt="playerCreatedAt"
|
||||
></videoplayer>
|
||||
<v-dialog v-model="dialog">
|
||||
<v-card>
|
||||
<v-card-title>Playback Settings </v-card-title>
|
||||
<v-card-text>
|
||||
|
||||
<v-card-text>
|
||||
<v-select
|
||||
v-model="chosenQuality"
|
||||
:items="qualitiesSelect"
|
||||
|
@ -68,10 +67,11 @@
|
|||
<v-btn primary v-on:click.native.stop="dialog = !dialog">Playback Settings</v-btn>
|
||||
</v-flex>
|
||||
<v-flex md2>
|
||||
<v-btn error v-on:click.native="stopPlayback()">Stop playback</v-btn>
|
||||
<router-link to="/browse">
|
||||
<v-btn error v-on:click.native="stopPlayback()">Stop playback</v-btn>
|
||||
</router-link>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -79,7 +79,7 @@
|
|||
// CSS imports
|
||||
|
||||
var request = require('request')
|
||||
var parseXMLString = require('xml2js').parseString;
|
||||
var parseXMLString = require('xml2js').parseString
|
||||
// Components
|
||||
import videoplayer from './ptplayer/videoplayer.vue'
|
||||
|
||||
|
@ -91,7 +91,19 @@
|
|||
created () {
|
||||
},
|
||||
mounted: function () {
|
||||
var that = this
|
||||
|
||||
// Check if we have params
|
||||
if (this.$route.query.start) {
|
||||
// We need to auto play
|
||||
let query = this.$route.query
|
||||
this.chosenKey = query.key.replace('/library/metadata/', '')
|
||||
this.chosenMediaIndex = query.mediaIndex || 0
|
||||
this.chosenServer = this.plex.servers[query.chosenServer]
|
||||
this.playertime = query.offset
|
||||
let oldtime = this.playertime
|
||||
let oldkey = this.chosenKey
|
||||
let checkers = 0
|
||||
}
|
||||
|
||||
// Similuate a real plex client
|
||||
this.eventbus.$on('command', (data) => {
|
||||
|
@ -148,31 +160,6 @@
|
|||
})
|
||||
return
|
||||
}
|
||||
if (data.command == '/player/playback/playMedia') {
|
||||
this.chosenKey = data.params.key.replace('/library/metadata/', '')
|
||||
this.chosenMediaIndex = data.params.mediaIndex || 0
|
||||
this.chosenServer = this.plex.servers[data.params.machineIdentifier]
|
||||
this.playertime = data.params.offset
|
||||
let oldtime = this.playertime
|
||||
let oldkey = this.chosenKey
|
||||
let checkers = 0
|
||||
|
||||
let tick = setInterval(() => {
|
||||
console.log('Checking..')
|
||||
if (Math.abs(parseInt(this.playertime) - parseInt(oldtime) ) > 1000) {
|
||||
console.log('STARTED PLAYING!')
|
||||
clearInterval(tick)
|
||||
return data.callback(true)
|
||||
}
|
||||
checkers++
|
||||
if (checkers > 300 || oldkey != this.chosenKey) {
|
||||
console.log('Timeout reached on playMedia')
|
||||
// It has been 30 seconds since - fail
|
||||
clearInterval(tick)
|
||||
return data.callback(false)
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
console.log('Unable to process the remote control command ' + data.command)
|
||||
})
|
||||
|
||||
|
@ -221,7 +208,7 @@
|
|||
chosenQuality: function () {
|
||||
this.changedPlaying(false)
|
||||
//console.log('Our new preferred quality is now ' + this.chosenQuality )
|
||||
this.$store.commit('setSettingPTPLAYERQUALITY',this.chosenQuality)
|
||||
this.$store.commit('setSettingPTPLAYERQUALITY', this.chosenQuality)
|
||||
},
|
||||
chosenMediaIndex: function () {
|
||||
this.chosenSubtitleIndex = 0
|
||||
|
@ -450,7 +437,7 @@
|
|||
stopPlayback () {
|
||||
console.log('Stopped Playback')
|
||||
this.$store.commit('SET_DECISIONBLOCKED', false)
|
||||
request(this.getSourceByLabel(this.chosenQuality).stopUrl, function (error, response, body) {})
|
||||
request(this.getSourceByLabel(this.chosenQuality).stopUrl, (error, response, body) => {})
|
||||
this.playerstatus = 'stopped'
|
||||
this.sessionId = this.generateGuid()
|
||||
this.xplexsession = this.generateGuid()
|
||||
|
@ -462,23 +449,22 @@
|
|||
var that = this
|
||||
this.ready = false
|
||||
this.$store.commit('SET_DECISIONBLOCKED', false)
|
||||
//console.log('Changed what we are meant to be playing!')
|
||||
console.log('Changed what we are meant to be playing!', changeItem)
|
||||
if (!this.chosenKey || !this.chosenServer) {
|
||||
this.playerstatus = 'stopped'
|
||||
this.playerMetadata = null
|
||||
return
|
||||
}
|
||||
|
||||
function req () {
|
||||
that.sources = that.generateSources()
|
||||
request(that.getSourceByLabel(that.chosenQuality).initUrl, function (error, response, body) {
|
||||
parseXMLString(body, function (err, result) {
|
||||
const req = () => {
|
||||
this.sources = this.generateSources()
|
||||
request(this.getSourceByLabel(this.chosenQuality).initUrl, (error, response, body) => {
|
||||
parseXMLString(body, (err, result) => {
|
||||
if (err) {
|
||||
that.ready = false
|
||||
this.ready = false
|
||||
}
|
||||
that.ready = true
|
||||
that.transcodeSessionMetadata = result
|
||||
|
||||
this.ready = true
|
||||
this.transcodeSessionMetadata = result
|
||||
})
|
||||
if (!error) {
|
||||
|
||||
|
@ -487,15 +473,15 @@
|
|||
}
|
||||
|
||||
if (this.playingMetadata) {
|
||||
request(this.getSourceByLabel(this.chosenQuality).stopUrl, function (error, response, body) {
|
||||
request(this.getSourceByLabel(this.chosenQuality).stopUrl, (error, response, body) => {
|
||||
// We dont need to know what this resulted in
|
||||
})
|
||||
}
|
||||
if (changeItem) {
|
||||
if (changeItem || !this.playingMetadata) {
|
||||
this.playingMetadata = null
|
||||
this.chosenServer.getMediaByRatingKey(this.chosenKey, function (result) {
|
||||
//console.log(result)
|
||||
that.playingMetadata = result
|
||||
this.chosenServer.getMediaByRatingKey(this.chosenKey).then((result) => {
|
||||
console.log(result)
|
||||
this.playingMetadata = result.MediaContainer.Metadata[0]
|
||||
req()
|
||||
})
|
||||
} else {
|
||||
|
@ -526,7 +512,7 @@
|
|||
session: this.sessionId,
|
||||
'X-Plex-Product': 'SyncLounge',
|
||||
'X-Plex-Version': '3.4.1',
|
||||
'X-Plex-Client-Identifier': 'SyncLoungeWeb',
|
||||
'X-Plex-Client-Identifier': 'SyncLounge',
|
||||
'X-Plex-Platform': this.browser,
|
||||
'X-Plex-Platform-Version': '57.0',
|
||||
'X-Plex-Device': 'Windows',
|
||||
|
@ -587,7 +573,7 @@
|
|||
'X-Plex-Chunked': 1,
|
||||
'X-Plex-Product': 'SyncLounge',
|
||||
'X-Plex-Version': '3.4.1',
|
||||
'X-Plex-Client-Identifier': 'SyncLoungePlayer',
|
||||
'X-Plex-Client-Identifier': 'SyncLounge',
|
||||
'X-Plex-Platform': 'SyncLounge',
|
||||
'X-Plex-Platform-Version': '57.0',
|
||||
'X-Plex-Device': 'HTML TV App',
|
||||
|
@ -616,7 +602,7 @@
|
|||
'timeout': 1,
|
||||
'X-Plex-Product': 'SyncLounge',
|
||||
'X-Plex-Version': '3.4.1',
|
||||
'X-Plex-Client-Identifier': 'SyncLoungePlayer',
|
||||
'X-Plex-Client-Identifier': 'SyncLounge',
|
||||
'X-Plex-Platform': that.browser,
|
||||
'X-Plex-Platform-Version': '57.0',
|
||||
'X-Plex-Device': 'Windows',
|
||||
|
@ -653,7 +639,6 @@
|
|||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
|
||||
return s4() + s4() + s4() + s4();
|
||||
},
|
||||
getBrowser () {
|
||||
|
|
|
@ -318,13 +318,13 @@
|
|||
|
||||
this.player.currentTime(this.initialOffset / 1000)
|
||||
|
||||
player.on(['waiting', 'pause'], function () {
|
||||
that.isPlaying = 'paused';
|
||||
});
|
||||
player.on(['waiting', 'pause'], () => {
|
||||
this.isPlaying = 'paused';
|
||||
})
|
||||
|
||||
player.on('playing', function () {
|
||||
that.isPlaying = 'playing';
|
||||
});
|
||||
player.on('playing', () => {
|
||||
this.isPlaying = 'playing';
|
||||
})
|
||||
|
||||
// Setup our intervals for pinging the transcoder and timelines
|
||||
function send () {
|
||||
|
@ -335,7 +335,7 @@
|
|||
if (!that.player || !that.metadata) {
|
||||
return
|
||||
}
|
||||
var query = '';
|
||||
var query = ''
|
||||
let params = {
|
||||
hasMDE: 1,
|
||||
ratingKey: that.metadata.ratingKey,
|
||||
|
@ -362,14 +362,14 @@
|
|||
timeout: 2000,
|
||||
url: url
|
||||
}
|
||||
request(url, function (error, response, body) {
|
||||
request(url, (error, response, body) => {
|
||||
if (!error) {
|
||||
// console.log('Succesfully sent Player status to PMS')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.ticker = setInterval(function () {
|
||||
this.ticker = setInterval(() => {
|
||||
// Tell the PMS instance of our status
|
||||
send()
|
||||
}, 10000)
|
||||
|
|
25
src/main.js
25
src/main.js
|
@ -34,6 +34,22 @@ Vue.config.productionTip = false
|
|||
|
||||
// Our Event bus
|
||||
window.EventBus = new Vue()
|
||||
window.EventBus.$on('command', (data) => {
|
||||
if (data.command === '/player/playback/playMedia') {
|
||||
router.push(
|
||||
{
|
||||
path: '/player',
|
||||
query: {
|
||||
start: true,
|
||||
key: data.params.key.replace('/library/metadata/', ''),
|
||||
mediaIndex: data.params.mediaIndex || 0,
|
||||
chosenServer: data.params.machineIdentifier,
|
||||
playertime: data.params.offset
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
Vue.mixin({
|
||||
computed: {
|
||||
|
@ -57,6 +73,15 @@ Vue.mixin({
|
|||
},
|
||||
plexserver: function () {
|
||||
return this.plex.servers[this.$route.params.machineIdentifier]
|
||||
},
|
||||
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' }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -21,7 +21,7 @@ export default new Router({
|
|||
{ path: '/clientselect', component: require('../components/application/walkthrough.vue') },
|
||||
{ path: '/joinroom', component: require('../components/application/joinroom.vue') },
|
||||
|
||||
{ path: '/player', component: require('../components/application/ptplayer.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') },
|
||||
|
|
15
src/store.js
15
src/store.js
|
@ -93,7 +93,7 @@ const state = {
|
|||
const mutations = {
|
||||
SET_CHOSENCLIENT (state, client) {
|
||||
async function playbackChange (ratingKey) {
|
||||
console.log('Playback change!', ratingKey)
|
||||
// console.log('Playback change!', ratingKey)
|
||||
if (ratingKey != null) {
|
||||
// Playing something different!
|
||||
let server = state.plex.servers[state.chosenClient.lastTimelineObject.machineIdentifier]
|
||||
|
@ -103,8 +103,9 @@ const mutations = {
|
|||
return
|
||||
}
|
||||
// Fetch our metadata from this server
|
||||
console.log('Loading content metadata from store ' + ratingKey)
|
||||
server.getMediaByRatingKey(ratingKey.replace('/library/metadata/', ''), function (metadata) {
|
||||
// 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
|
||||
}
|
||||
|
@ -129,7 +130,7 @@ const mutations = {
|
|||
}
|
||||
|
||||
function newTimeline (timeline) {
|
||||
console.log('Got timeline')
|
||||
// console.log('Got timeline')
|
||||
// Lets send this to our PTServer
|
||||
state.ourClientResponseTime = timeline.lastResponseTime
|
||||
let title = null
|
||||
|
@ -156,9 +157,9 @@ const mutations = {
|
|||
let playerState = null
|
||||
let showName = null
|
||||
|
||||
if (state.plextogether._socket) {
|
||||
state.plextogether._socket.pollStartTime = (new Date).getTime()
|
||||
state.plextogether._socket.emit('poll', end_obj)
|
||||
if (state.synclounge._socket) {
|
||||
state.synclounge._socket.pollStartTime = (new Date).getTime()
|
||||
state.synclounge._socket.emit('poll', end_obj)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
export default {
|
||||
getItemCache: (state) => {
|
||||
return state.itemCache
|
||||
},
|
||||
getLibraryCache: (state) => {
|
||||
return state.libraryCache
|
||||
}
|
||||
};
|
||||
|
|
|
@ -137,7 +137,7 @@ module.exports = function PlexClient () {
|
|||
return false
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
// console.log(e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ module.exports = function PlexServer () {
|
|||
request(options, (error, response, body) => {
|
||||
if (!error) {
|
||||
let parsed = JSON.parse(body)
|
||||
console.log('Metadata request result', parsed)
|
||||
this.handleMetadata(parsed)
|
||||
return resolve(parsed)
|
||||
}
|
||||
|
@ -138,8 +139,17 @@ module.exports = function PlexServer () {
|
|||
|
||||
this.getMediaByRatingKey = async function (ratingKey) {
|
||||
//This function hits the PMS and returns the item at the ratingKey
|
||||
let data = await this.hitApi('/library/metadata/' + ratingKey, {})
|
||||
return this.handleMetadata(data)
|
||||
try {
|
||||
let data = await this.hitApi('/library/metadata/' + ratingKey, {})
|
||||
if (data && data.MediaContainer.librarySectionID) {
|
||||
this.commit('SET_LIBRARYCACHE', [data.MediaContainer.librarySectionID, this.clientIdentifier, data.MediaContainer.librarySectionTitle])
|
||||
}
|
||||
return data
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return false
|
||||
}
|
||||
// return this.handleMetadata(data)
|
||||
}
|
||||
this.markWatchedByRatingKey = function (ratingKey) {
|
||||
return this.hitApi('/:/scrobble', {
|
||||
|
@ -175,19 +185,31 @@ module.exports = function PlexServer () {
|
|||
throw new Error(e)
|
||||
}
|
||||
}
|
||||
this.getAllLibraries = function () {
|
||||
return this.hitApi('/library/sections', {})
|
||||
this.getAllLibraries = async function () {
|
||||
try {
|
||||
let data = await this.hitApi('/library/sections', {})
|
||||
console.log('Library data', data)
|
||||
if (data && data.MediaContainer) {
|
||||
data.MediaContainer.Directory.forEach((library) => {
|
||||
this.commit('SET_LIBRARYCACHE', [library.key, this.clientIdentifier, library.title ])
|
||||
})
|
||||
}
|
||||
return data
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
this.getLibraryContents = async function (key, start, size) {
|
||||
try {
|
||||
let data = await this.hitApi('/library/sections/' + key + '/all', {
|
||||
'X-Plex-Container-Start': start,
|
||||
'X-Plex-Container-Size': size
|
||||
'X-Plex-Container-Size': size,
|
||||
'excludeAllLeaves': 1
|
||||
})
|
||||
for (let i = 0; i < data.MediaContainer.Metadata.length; i++) {
|
||||
data.MediaContainer.Metadata[i].librarySectionID = key
|
||||
this.commit('SET_ITEMCACHE', [data.MediaContainer.Metadata[i].ratingKey,
|
||||
data.MediaContainer.Metadata[i]])
|
||||
// this.commit('SET_ITEMCACHE', [data.MediaContainer.Metadata[i].ratingKey,
|
||||
// data.MediaContainer.Metadata[i]])
|
||||
}
|
||||
return data
|
||||
} catch (e) {
|
||||
|
@ -250,36 +272,21 @@ module.exports = function PlexServer () {
|
|||
}
|
||||
|
||||
this.handleMetadata = function (result) {
|
||||
if (result != null) {
|
||||
if (result._children) {
|
||||
// Old Server version compatibility
|
||||
for (var i in result._children) {
|
||||
var res = result._children[i]
|
||||
if (res._elementType == 'Directory' || res._elementType == 'Media' || res._elementType == 'Video') {
|
||||
res.machineIdentifier = this.clientIdentifier
|
||||
return res
|
||||
if (result) {
|
||||
if (result.MediaContainer && result.MediaContainer.Metadata && result.MediaContainer.Metadata.length > 0) {
|
||||
for (let i = 0; i < result.MediaContainer.Metadata.length; i++) {
|
||||
result.MediaContainer.Metadata[i].machineIdentifier = this.clientIdentifier
|
||||
if (result.MediaContainer.Metadata[i].ratingKey) {
|
||||
this.commit('SET_ITEMCACHE', [result.MediaContainer.Metadata[i].ratingKey,
|
||||
result.MediaContainer.Metadata[i]])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// New Server compatibility
|
||||
if (result.MediaContainer && result.MediaContainer.Metadata && result.MediaContainer.Metadata.length > 0) {
|
||||
for (let i = 0; i < result.MediaContainer.Metadata.length; i++) {
|
||||
result.MediaContainer.Metadata[i].machineIdentifier = this.clientIdentifier
|
||||
if (result.MediaContainer.Metadata[i].ratingKey) {
|
||||
this.commit('SET_ITEMCACHE', [result.MediaContainer.Metadata[i].ratingKey,
|
||||
result.MediaContainer.Metadata[i]])
|
||||
}
|
||||
}
|
||||
return
|
||||
} else {
|
||||
if (result.MediaContainer.ratingKey) {
|
||||
this.commit('SET_ITEMCACHE', [result.MediaContainer.ratingKey, result.MediaContainer])
|
||||
}
|
||||
return
|
||||
if (result.MediaContainer.ratingKey) {
|
||||
this.commit('SET_ITEMCACHE', [result.MediaContainer.ratingKey, result.MediaContainer])
|
||||
}
|
||||
return result.MediaContainer.Metadata[0]
|
||||
}
|
||||
return null
|
||||
return result.MediaContainer.Metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,10 +41,20 @@ export default {
|
|||
state.clients[client.clientIdentifier].chosenConnection = connection
|
||||
},
|
||||
SET_ITEMCACHE: (state, data) => {
|
||||
// return
|
||||
let [ratingKey, newData] = data
|
||||
if (!state.itemCache[newData.machineIdentifier]) {
|
||||
state.itemCache[newData.machineIdentifier] = {}
|
||||
}
|
||||
state.itemCache[newData.machineIdentifier][ratingKey] = newData
|
||||
},
|
||||
SET_LIBRARYCACHE: (state, data) => {
|
||||
// return
|
||||
console.log('Setting library cache', data)
|
||||
let [id, machineIdentifier, newData] = data
|
||||
if (!state.libraryCache[machineIdentifier]) {
|
||||
state.libraryCache[machineIdentifier] = {}
|
||||
}
|
||||
state.libraryCache[machineIdentifier][id] = newData
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@ export default {
|
|||
servers: {},
|
||||
|
||||
itemCache: {},
|
||||
libraryCache: {},
|
||||
|
||||
chosenClient: null,
|
||||
|
||||
|
|
Loading…
Reference in New Issue