vue lint
This commit is contained in:
parent
c2a3b0b2b5
commit
063aefc48e
13
.eslintrc.js
13
.eslintrc.js
|
@ -1,13 +1,24 @@
|
|||
// Inspired by https://stackoverflow.com/questions/60187885/how-to-configure-vue-cli-4-with-eslint-airbnb-rules-typescript-stylelint-f
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: ['plugin:vue/essential', '@vue/airbnb'],
|
||||
extends: ['plugin:vue/recommended', '@vue/airbnb'],
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
ecmaVersion: 2020,
|
||||
},
|
||||
rules: {
|
||||
'class-methods-use-this': 0,
|
||||
'max-len': [
|
||||
'error',
|
||||
{
|
||||
code: 100,
|
||||
ignoreComments: true,
|
||||
ignoreUrls: true,
|
||||
},
|
||||
],
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
|
||||
|
|
185
src/App.vue
185
src/App.vue
|
@ -1,57 +1,93 @@
|
|||
<template>
|
||||
<v-app dark style="height:100%">
|
||||
<leftsidebar></leftsidebar>
|
||||
<rightsidebar></rightsidebar>
|
||||
<v-app
|
||||
dark
|
||||
style="height:100%"
|
||||
>
|
||||
<leftsidebar />
|
||||
<rightsidebar />
|
||||
|
||||
<v-app-bar app scroll-off-screen :scroll-threshold="1" style="z-index: 5">
|
||||
<v-app-bar-nav-icon @click="SET_LEFT_SIDEBAR_OPEN"></v-app-bar-nav-icon>
|
||||
<a href="https://synclounge.tv" target="_blank">
|
||||
<v-app-bar
|
||||
app
|
||||
scroll-off-screen
|
||||
:scroll-threshold="1"
|
||||
style="z-index: 5"
|
||||
>
|
||||
<v-app-bar-nav-icon @click="SET_LEFT_SIDEBAR_OPEN" />
|
||||
<a
|
||||
href="https://synclounge.tv"
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
class="ma-1 hidden-xs-only"
|
||||
style="height: 42px; width: auto; vertical-align: middle"
|
||||
v-bind:src="logos.light.long"
|
||||
/>
|
||||
:src="logos.light.long"
|
||||
>
|
||||
<img
|
||||
class="ma-1 hidden-sm-and-up"
|
||||
style="height: 42px; width: auto; vertical-align: middle"
|
||||
v-bind:src="logo"
|
||||
/>
|
||||
:src="logo"
|
||||
>
|
||||
</a>
|
||||
<nowplayingchip class="pl-4" v-if="showNowPlaying"></nowplayingchip>
|
||||
<v-spacer></v-spacer>
|
||||
<nowplayingchip
|
||||
v-if="showNowPlaying"
|
||||
class="pl-4"
|
||||
/>
|
||||
<v-spacer />
|
||||
<v-toolbar-items>
|
||||
<v-btn
|
||||
v-if="getShortLink != null"
|
||||
v-clipboard="getShortLink"
|
||||
color="primary"
|
||||
dark
|
||||
raised
|
||||
v-if="getShortLink != null"
|
||||
v-clipboard="getShortLink"
|
||||
@success="sendNotification()"
|
||||
>Invite</v-btn
|
||||
>
|
||||
<v-btn dark @click="goFullscreen" class="hidden-lg-and-up" icon>
|
||||
Invite
|
||||
</v-btn>
|
||||
<v-btn
|
||||
dark
|
||||
class="hidden-lg-and-up"
|
||||
icon
|
||||
@click="goFullscreen"
|
||||
>
|
||||
<v-icon>fullscreen</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-for="item in links"
|
||||
:key="item.title"
|
||||
small
|
||||
tag="a"
|
||||
class="hidden-sm-and-down"
|
||||
text
|
||||
:href="item.href"
|
||||
:target="item.target"
|
||||
>
|
||||
{{ item.title }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
small
|
||||
tag="a"
|
||||
class="hidden-sm-and-down"
|
||||
text
|
||||
v-for="item in links"
|
||||
:key="item.title"
|
||||
:href="item.href"
|
||||
:target="item.target"
|
||||
>{{ item.title }}</v-btn
|
||||
@click="donateDialog = true"
|
||||
>
|
||||
<v-btn small tag="a" class="hidden-sm-and-down" text @click="donateDialog = true"
|
||||
>Donate ♥</v-btn
|
||||
Donate ♥
|
||||
</v-btn>
|
||||
<v-icon
|
||||
v-if="showRightDrawerButton"
|
||||
class="clickable"
|
||||
@click="TOGGLE_RIGHT_SIDEBAR_OPEN"
|
||||
>
|
||||
<v-icon v-if="showRightDrawerButton" @click="TOGGLE_RIGHT_SIDEBAR_OPEN" class="clickable">{{
|
||||
isRightSidebarOpen ? 'last_page' : 'first_page'
|
||||
}}</v-icon>
|
||||
{{
|
||||
isRightSidebarOpen ? 'last_page' : 'first_page'
|
||||
}}
|
||||
</v-icon>
|
||||
</v-toolbar-items>
|
||||
</v-app-bar>
|
||||
<v-content v-bind:style="mainStyle" app>
|
||||
<v-content
|
||||
:style="mainStyle"
|
||||
app
|
||||
>
|
||||
<v-container
|
||||
class="ma-0 pa-0"
|
||||
align-start
|
||||
|
@ -59,26 +95,50 @@
|
|||
style="height: 100%; z-index: 250"
|
||||
fluid
|
||||
>
|
||||
<v-flex xs12 v-if="configError">
|
||||
<v-alert :dismissible="true" type="error" class="mt-0">{{ configError }}</v-alert>
|
||||
<v-flex
|
||||
v-if="configError"
|
||||
xs12
|
||||
>
|
||||
<v-alert
|
||||
:dismissible="true"
|
||||
type="error"
|
||||
class="mt-0"
|
||||
>
|
||||
{{ configError }}
|
||||
</v-alert>
|
||||
</v-flex>
|
||||
<v-flex xs12 v-if="(loading || (getPlex && !getPlex.gotDevices)) && route.protected">
|
||||
<v-flex
|
||||
v-if="(loading || (getPlex && !getPlex.gotDevices)) && route.protected"
|
||||
xs12
|
||||
>
|
||||
<v-container fill-height>
|
||||
<v-layout justify-center align-center wrap row class="pt-4 text-center">
|
||||
<v-flex xs8 md4>
|
||||
<v-layout
|
||||
justify-center
|
||||
align-center
|
||||
wrap
|
||||
row
|
||||
class="pt-4 text-center"
|
||||
>
|
||||
<v-flex
|
||||
xs8
|
||||
md4
|
||||
>
|
||||
<v-progress-circular
|
||||
indeterminate
|
||||
v-bind:size="60"
|
||||
:size="60"
|
||||
class="amber--text"
|
||||
></v-progress-circular>
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-flex>
|
||||
<div v-else :style="paddingStyle">
|
||||
<div
|
||||
v-else
|
||||
:style="paddingStyle"
|
||||
>
|
||||
<v-breadcrumbs
|
||||
:items="crumbs"
|
||||
v-if="crumbs && crumbs.length > 0"
|
||||
:items="crumbs"
|
||||
class="text-xs-left"
|
||||
style="justify-content: left"
|
||||
>
|
||||
|
@ -86,22 +146,37 @@
|
|||
<v-icon>chevron_right</v-icon>
|
||||
</template>
|
||||
<template v-slot:item="props">
|
||||
<v-breadcrumbs-item :to="props.item.to" :exact="true">{{
|
||||
props.item.text
|
||||
}}</v-breadcrumbs-item>
|
||||
<v-breadcrumbs-item
|
||||
:to="props.item.to"
|
||||
:exact="true"
|
||||
>
|
||||
{{
|
||||
props.item.text
|
||||
}}
|
||||
</v-breadcrumbs-item>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
<router-view></router-view>
|
||||
<router-view />
|
||||
</div>
|
||||
<v-snackbar color="green darken-2" bottom :timeout="4000" v-model="snackbar">
|
||||
<div style="text-align:center; width:100%">{{ snackbarMsg }}</div>
|
||||
<v-snackbar
|
||||
v-model="snackbar"
|
||||
color="green darken-2"
|
||||
bottom
|
||||
:timeout="4000"
|
||||
>
|
||||
<div style="text-align:center; width:100%">
|
||||
{{ snackbarMsg }}
|
||||
</div>
|
||||
</v-snackbar>
|
||||
<upnext></upnext>
|
||||
<v-dialog v-model="donateDialog" max-width="650px">
|
||||
<upnext />
|
||||
<v-dialog
|
||||
v-model="donateDialog"
|
||||
max-width="650px"
|
||||
>
|
||||
<donate
|
||||
:donateDialog="donateDialog"
|
||||
:onClose="() => (this.donateDialog = false)"
|
||||
></donate>
|
||||
:donate-dialog="donateDialog"
|
||||
:on-close="() => (this.donateDialog = false)"
|
||||
/>
|
||||
</v-dialog>
|
||||
</v-container>
|
||||
</v-content>
|
||||
|
@ -175,6 +250,14 @@ export default {
|
|||
fscreen.requestFullscreen(document.body);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
showRightDrawerButton() {
|
||||
// TODO: fix this is hacky
|
||||
if (this.showRightDrawerButton) {
|
||||
this.SET_RIGHT_SIDEBAR_OPEN(true);
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.configFetchPromise = this.fetchConfig();
|
||||
},
|
||||
|
@ -276,14 +359,6 @@ export default {
|
|||
|
||||
this.loading = false;
|
||||
},
|
||||
watch: {
|
||||
showRightDrawerButton() {
|
||||
// TODO: fix this is hacky
|
||||
if (this.showRightDrawerButton) {
|
||||
this.SET_RIGHT_SIDEBAR_OPEN(true);
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'getPlex',
|
||||
|
|
|
@ -1,30 +1,75 @@
|
|||
<template>
|
||||
<v-layout row wrap justify-center>
|
||||
<v-flex xs12 lg10 style="background: rgba(0,0,0,0.1); border-radius: 10px" class="pa-4">
|
||||
<v-layout row wrap justify-center>
|
||||
<v-flex xs12 md8 lg4 xl6>
|
||||
<img style="width:100%" v-bind:src="logo" />
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-center
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
lg10
|
||||
style="background: rgba(0,0,0,0.1); border-radius: 10px"
|
||||
class="pa-4"
|
||||
>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-center
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
md8
|
||||
lg4
|
||||
xl6
|
||||
>
|
||||
<img
|
||||
style="width:100%"
|
||||
:src="logo"
|
||||
>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-stepper
|
||||
style="background: rgba(0,0,0,0.3); border-radius: 20px"
|
||||
v-model="e1"
|
||||
style="background: rgba(0,0,0,0.3); border-radius: 20px"
|
||||
dark
|
||||
class="ma-4"
|
||||
>
|
||||
<v-stepper-header>
|
||||
<v-stepper-step step="1" :complete="true">Select a client</v-stepper-step>
|
||||
<v-divider></v-divider>
|
||||
<v-stepper-step step="2" :complete="false">Join a room</v-stepper-step>
|
||||
<v-divider></v-divider>
|
||||
<v-stepper-step step="3">Sync</v-stepper-step>
|
||||
<v-stepper-step
|
||||
step="1"
|
||||
:complete="true"
|
||||
>
|
||||
Select a client
|
||||
</v-stepper-step>
|
||||
<v-divider />
|
||||
<v-stepper-step
|
||||
step="2"
|
||||
:complete="false"
|
||||
>
|
||||
Join a room
|
||||
</v-stepper-step>
|
||||
<v-divider />
|
||||
<v-stepper-step step="3">
|
||||
Sync
|
||||
</v-stepper-step>
|
||||
</v-stepper-header>
|
||||
</v-stepper>
|
||||
<v-layout row wrap justify-center>
|
||||
<v-flex xs12 class="ml-4">
|
||||
<h2 class="text-xs-left">Connect to a SyncLounge room</h2>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-center
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
class="ml-4"
|
||||
>
|
||||
<h2 class="text-xs-left">
|
||||
Connect to a SyncLounge room
|
||||
</h2>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="ml-4">
|
||||
<v-flex
|
||||
xs12
|
||||
class="ml-4"
|
||||
>
|
||||
<p>
|
||||
It's time to connect to SyncLounge. From the list select a server which is closest to
|
||||
your location. Once you've chosen one that works for you it's time to create a room for
|
||||
|
@ -32,17 +77,23 @@
|
|||
</p>
|
||||
</v-flex>
|
||||
<v-flex
|
||||
v-if="!getConnected && this.GET_RECENT_ROOMS.length > 0"
|
||||
xs12
|
||||
class="nicelist pa-4"
|
||||
v-if="!getConnected && this.GET_RECENT_ROOMS.length > 0"
|
||||
style="color:white !important;"
|
||||
>
|
||||
<v-subheader>Recent Rooms</v-subheader>
|
||||
<v-list class="pa-0">
|
||||
<template v-for="(item, index) in GET_RECENT_ROOMS.slice(0, 3)">
|
||||
<v-list-item :key="index" @click="recentConnect(item)">
|
||||
<v-list-item
|
||||
:key="index"
|
||||
@click="recentConnect(item)"
|
||||
>
|
||||
<v-list-item-avatar>
|
||||
<img :src="logos.light.small" style="width: 32px; height: auto" />
|
||||
<img
|
||||
:src="logos.light.small"
|
||||
style="width: 32px; height: auto"
|
||||
>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{ item.name || item.server || 'Custom' }}</v-list-item-title>
|
||||
|
@ -52,8 +103,17 @@
|
|||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-tooltip top color="light-blue darken-4">
|
||||
<v-icon color="white" dark @click.stop="REMOVE_RECENT_ROOM(item)">close</v-icon>
|
||||
<v-tooltip
|
||||
top
|
||||
color="light-blue darken-4"
|
||||
>
|
||||
<v-icon
|
||||
color="white"
|
||||
dark
|
||||
@click.stop="REMOVE_RECENT_ROOM(item)"
|
||||
>
|
||||
close
|
||||
</v-icon>
|
||||
>Remove
|
||||
</v-tooltip>
|
||||
</v-list-item-action>
|
||||
|
@ -61,36 +121,80 @@
|
|||
</template>
|
||||
</v-list>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="nicelist pa-4" v-if="!getConnected" style="color:white !important">
|
||||
<v-flex
|
||||
v-if="!getConnected"
|
||||
xs12
|
||||
class="nicelist pa-4"
|
||||
style="color:white !important"
|
||||
>
|
||||
<v-subheader>Select a server</v-subheader>
|
||||
<v-layout row wrap justify-center align-center>
|
||||
<v-flex pa-2 xs12 md3 lg2 v-for="server in GET_SYNCLOUNGE_SERVERS" :key="server.url">
|
||||
<v-card height="300px" style="border-radius: 20px">
|
||||
<v-layout row wrap justify-start align-center style="height: 100%">
|
||||
<v-flex xs12 class="text-center pa-2" style="height: 80px">
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-center
|
||||
align-center
|
||||
>
|
||||
<v-flex
|
||||
v-for="server in GET_SYNCLOUNGE_SERVERS"
|
||||
:key="server.url"
|
||||
pa-2
|
||||
xs12
|
||||
md3
|
||||
lg2
|
||||
>
|
||||
<v-card
|
||||
height="300px"
|
||||
style="border-radius: 20px"
|
||||
>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-start
|
||||
align-center
|
||||
style="height: 100%"
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
class="text-center pa-2"
|
||||
style="height: 80px"
|
||||
>
|
||||
<img
|
||||
:src="server.image"
|
||||
style="max-height: 100%; vertical-align: middle; max-width: 80%; border-radius: 7px"
|
||||
/>
|
||||
>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="text-center">
|
||||
<v-flex
|
||||
xs12
|
||||
class="text-center"
|
||||
>
|
||||
<h2>{{ server.name }}</h2>
|
||||
<h4>{{ server.location }}</h4>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="text-center" v-if="server.url !== 'custom'">
|
||||
<v-flex
|
||||
v-if="server.url !== 'custom'"
|
||||
xs12
|
||||
class="text-center"
|
||||
>
|
||||
<div v-if="results[server.url]">
|
||||
<div v-if="results[server.url].alive">
|
||||
Ping:
|
||||
<span
|
||||
class="thick--text"
|
||||
:class="connectionQualityClass(results[server.url].latency)"
|
||||
>{{ results[server.url].latency }}ms</span
|
||||
>
|
||||
>{{ results[server.url].latency }}ms</span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="text-center red--text"
|
||||
>
|
||||
error
|
||||
</div>
|
||||
<div v-else class="text-center red--text">error</div>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="text-center">
|
||||
<v-flex
|
||||
xs12
|
||||
class="text-center"
|
||||
>
|
||||
<div v-if="server.url !== 'custom'">
|
||||
<div v-if="results[server.url]">
|
||||
<div v-if="results[server.url].alive">
|
||||
|
@ -99,23 +203,31 @@
|
|||
<span
|
||||
class="thick--text"
|
||||
:class="loadQualityClass(results[server.url].result)"
|
||||
>{{ results[server.url].result || 'Unknown' }}</span
|
||||
>
|
||||
>{{ results[server.url].result || 'Unknown' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="text-center red--text">error</div>
|
||||
<div
|
||||
v-else
|
||||
class="text-center red--text"
|
||||
>
|
||||
error
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 class="text-center pt-1 mt-4">
|
||||
<v-flex
|
||||
xs12
|
||||
class="text-center pt-1 mt-4"
|
||||
>
|
||||
<v-btn
|
||||
color="primary"
|
||||
:disabled="connectionPending"
|
||||
@click="serverSelected(server)"
|
||||
style="width: 80%; border-radius: 7px; margin: auto; position: absolute; bottom: 5px; left: 0; right: 0;"
|
||||
>Connect</v-btn
|
||||
@click="serverSelected(server)"
|
||||
>
|
||||
Connect
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-card>
|
||||
|
@ -126,69 +238,124 @@
|
|||
name="input-2"
|
||||
label="Custom Server"
|
||||
:value="GET_CUSTOM_SERVER_USER_INPUTTED_URL"
|
||||
@change="SET_CUSTOM_SERVER_USER_INPUTTED_URL"
|
||||
class="input-group pt-input"
|
||||
></v-text-field>
|
||||
<v-layout row wrap v-if="selectedServer.url == 'custom'">
|
||||
@change="SET_CUSTOM_SERVER_USER_INPUTTED_URL"
|
||||
/>
|
||||
<v-layout
|
||||
v-if="selectedServer.url == 'custom'"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex xs12>
|
||||
<v-btn
|
||||
class="pt-orange white--text pa-0 ma-0"
|
||||
color="primary"
|
||||
primary
|
||||
style="width:100%"
|
||||
v-on:click.native="attemptConnectCustom()"
|
||||
>Connect</v-btn
|
||||
@click.native="attemptConnectCustom()"
|
||||
>
|
||||
Connect
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout row wrap v-if="connectionPending && !serverError" class="pt-3">
|
||||
<v-layout
|
||||
v-if="connectionPending && !serverError"
|
||||
row
|
||||
wrap
|
||||
class="pt-3"
|
||||
>
|
||||
<v-flex xs12>
|
||||
<div style="width:100%;text-align:center">
|
||||
<v-progress-circular
|
||||
indeterminate
|
||||
v-bind:size="50"
|
||||
:size="50"
|
||||
class="amber--text"
|
||||
style="display:inline-block"
|
||||
></v-progress-circular>
|
||||
/>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout class="pt-3 text-center" row wrap v-if="serverError">
|
||||
<v-flex xs12 class="red--text">
|
||||
<v-icon class="red--text">info</v-icon>
|
||||
<v-layout
|
||||
v-if="serverError"
|
||||
class="pt-3 text-center"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
class="red--text"
|
||||
>
|
||||
<v-icon class="red--text">
|
||||
info
|
||||
</v-icon>
|
||||
{{ serverError }}
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
<v-flex xs12 v-if="getConnected" class="text-center">
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12 md6 offset-md3>
|
||||
<v-flex
|
||||
v-if="getConnected"
|
||||
xs12
|
||||
class="text-center"
|
||||
>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
md6
|
||||
offset-md3
|
||||
>
|
||||
<v-text-field
|
||||
v-model="room"
|
||||
origin="center center"
|
||||
:maxlength="25"
|
||||
name="input-2"
|
||||
label="Room name"
|
||||
:autofocus="true"
|
||||
v-on:keyup.enter.native="joinRoom()"
|
||||
v-model="room"
|
||||
></v-text-field>
|
||||
@keyup.enter.native="joinRoom()"
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex xs12 md6 offset-md3>
|
||||
<v-flex
|
||||
xs12
|
||||
md6
|
||||
offset-md3
|
||||
>
|
||||
<v-text-field
|
||||
v-model="password"
|
||||
transition="v-scale-transition"
|
||||
origin="center center"
|
||||
name="input-2"
|
||||
label="Room password"
|
||||
v-on:keyup.enter.native="joinRoom()"
|
||||
v-model="password"
|
||||
></v-text-field>
|
||||
@keyup.enter.native="joinRoom()"
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex xs12 md6 offset-md3>
|
||||
<v-btn block color="primary" v-on:click.native="joinRoom()">Join</v-btn>
|
||||
<v-flex
|
||||
xs12
|
||||
md6
|
||||
offset-md3
|
||||
>
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
@click.native="joinRoom()"
|
||||
>
|
||||
Join
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
<v-layout class="pt-3 text-center" row wrap v-if="roomError">
|
||||
<v-flex xs12 class="red--text">
|
||||
<v-icon class="red--text">info</v-icon>
|
||||
<v-layout
|
||||
v-if="roomError"
|
||||
class="pt-3 text-center"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
class="red--text"
|
||||
>
|
||||
<v-icon class="red--text">
|
||||
info
|
||||
</v-icon>
|
||||
{{ roomError }}
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
@ -206,8 +373,8 @@ import axios from 'axios';
|
|||
import { mapGetters, mapMutations, mapActions } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'Joinroom',
|
||||
props: ['object'],
|
||||
name: 'joinroom',
|
||||
data() {
|
||||
return {
|
||||
selectedServer: '',
|
||||
|
|
|
@ -3,28 +3,42 @@
|
|||
<div>
|
||||
<h4>Search</h4>
|
||||
<div>
|
||||
<v-layout class="mb-3" v-if="!selectedItem && !browsingServer" row wrap>
|
||||
<v-flex xs10 lg4>
|
||||
<v-layout
|
||||
v-if="!selectedItem && !browsingServer"
|
||||
class="mb-3"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
xs10
|
||||
lg4
|
||||
>
|
||||
<v-text-field
|
||||
id="testing"
|
||||
v-model="searchWord"
|
||||
name="searchInput"
|
||||
label="Search"
|
||||
:hint="searchStatus"
|
||||
id="testing"
|
||||
persistent-hint
|
||||
single-line
|
||||
prepend-icon="search"
|
||||
v-model="searchWord"
|
||||
></v-text-field>
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex xs2>
|
||||
<v-icon
|
||||
v-if="results.length > 0"
|
||||
v-on:click="results = []; searchWord = ''; searching = false"
|
||||
class="clickable red--text pt-3"
|
||||
>clear</v-icon>
|
||||
@click="results = []; searchWord = ''; searching = false"
|
||||
>
|
||||
clear
|
||||
</v-icon>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout row wrap v-if="searching || results.length > 0">
|
||||
<v-layout
|
||||
v-if="searching || results.length > 0"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-chip
|
||||
v-for="server in getPlex.servers"
|
||||
:key="server.machineIdentifier"
|
||||
|
@ -32,120 +46,190 @@
|
|||
class="green darken-3 white--text"
|
||||
>
|
||||
<v-avatar>
|
||||
<v-icon v-if="!heardBack(server)">clear</v-icon>
|
||||
<v-icon v-if="heardBack(server)">check_circle</v-icon>
|
||||
<v-icon v-if="!heardBack(server)">
|
||||
clear
|
||||
</v-icon>
|
||||
<v-icon v-if="heardBack(server)">
|
||||
check_circle
|
||||
</v-icon>
|
||||
</v-avatar>
|
||||
{{ server.name }}
|
||||
</v-chip>
|
||||
</v-layout>
|
||||
<v-progress-circular v-if="searching" indeterminate class="amber--text"></v-progress-circular>
|
||||
<v-progress-circular
|
||||
v-if="searching"
|
||||
indeterminate
|
||||
class="amber--text"
|
||||
/>
|
||||
<div v-if="results.length > 0">
|
||||
<v-layout v-if="filteredMovies && filteredMovies.length > 0" row wrap>
|
||||
<v-layout
|
||||
v-if="filteredMovies && filteredMovies.length > 0"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<!--Movies-->
|
||||
<v-flex xs12 lg12>
|
||||
<v-flex
|
||||
xs12
|
||||
lg12
|
||||
>
|
||||
<v-subheader>Movies ({{ filteredMovies.length }})</v-subheader>
|
||||
</v-flex>
|
||||
<v-flex
|
||||
v-for="movie in filteredMovies"
|
||||
:key="movie.key"
|
||||
xs6
|
||||
md3
|
||||
xl1
|
||||
lg1
|
||||
class="pb-3 ma-2"
|
||||
v-for="movie in filteredMovies"
|
||||
:key="movie.key"
|
||||
>
|
||||
<plexthumb
|
||||
:content="movie"
|
||||
:server="movie.server"
|
||||
showServer
|
||||
show-server
|
||||
search
|
||||
@contentSet="setContent(movie)"
|
||||
></plexthumb>
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout v-if="filteredShows && filteredShows.length > 0" row wrap>
|
||||
<v-layout
|
||||
v-if="filteredShows && filteredShows.length > 0"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<!--Shows-->
|
||||
<v-flex xs12 lg12>
|
||||
<v-flex
|
||||
xs12
|
||||
lg12
|
||||
>
|
||||
<v-subheader>TV Shows ({{ filteredShows.length }})</v-subheader>
|
||||
</v-flex>
|
||||
<v-flex xs6 md3 xl1 lg1 class="pb-3 ma-2" v-for="show in filteredShows" :key="show.key">
|
||||
<v-flex
|
||||
v-for="show in filteredShows"
|
||||
:key="show.key"
|
||||
xs6
|
||||
md3
|
||||
xl1
|
||||
lg1
|
||||
class="pb-3 ma-2"
|
||||
>
|
||||
<plexthumb
|
||||
:content="show"
|
||||
:server="show.server"
|
||||
showServer
|
||||
show-server
|
||||
search
|
||||
@contentSet="setContent(show)"
|
||||
></plexthumb>
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout v-if="filteredEpisodes && filteredEpisodes.length > 0" row wrap>
|
||||
<v-layout
|
||||
v-if="filteredEpisodes && filteredEpisodes.length > 0"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<!--Episodes-->
|
||||
<v-flex xs12 lg12>
|
||||
<v-flex
|
||||
xs12
|
||||
lg12
|
||||
>
|
||||
<v-subheader>TV Episodes ({{ filteredEpisodes.length }})</v-subheader>
|
||||
</v-flex>
|
||||
<v-flex
|
||||
v-for="episode in filteredEpisodes"
|
||||
:key="episode.key"
|
||||
xs6
|
||||
md3
|
||||
xl2
|
||||
lg2
|
||||
class="pb-3 ma-2"
|
||||
v-for="episode in filteredEpisodes"
|
||||
:key="episode.key"
|
||||
>
|
||||
<plexthumb
|
||||
:content="episode"
|
||||
:server="episode.server"
|
||||
showServer
|
||||
show-server
|
||||
type="art"
|
||||
search
|
||||
@contentSet="setContent(episode)"
|
||||
></plexthumb>
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
</div>
|
||||
<v-divider></v-divider>
|
||||
<div class="pt-4" v-if="GET_LASTSERVER && results.length == 0">
|
||||
<v-divider />
|
||||
<div
|
||||
v-if="GET_LASTSERVER && results.length == 0"
|
||||
class="pt-4"
|
||||
>
|
||||
<h4 v-if="subsetOnDeck().length > 0">
|
||||
Continue watching from {{ GET_LASTSERVER.name }}
|
||||
<span
|
||||
style="float:right; font-size:5rem; user-select: none;"
|
||||
>
|
||||
<v-icon
|
||||
@click="onDeckDown"
|
||||
style="margin-right: 15px;cursor: pointer"
|
||||
:style="onDeckDownStyle"
|
||||
@click="onDeckDown"
|
||||
>angle-left</v-icon>
|
||||
<v-icon @click="onDeckUp" :style="onDeckUpStyle" style="cursor: pointer">angle-right</v-icon>
|
||||
<v-icon
|
||||
:style="onDeckUpStyle"
|
||||
style="cursor: pointer"
|
||||
@click="onDeckUp"
|
||||
>angle-right</v-icon>
|
||||
</span>
|
||||
</h4>
|
||||
<v-layout v-if="onDeck" row justify-center>
|
||||
<v-flex xs12 md3 class="pb-3 pa-2" v-for="content in subsetOnDeck()" :key="content.key">
|
||||
<v-layout
|
||||
v-if="onDeck"
|
||||
row
|
||||
justify-center
|
||||
>
|
||||
<v-flex
|
||||
v-for="content in subsetOnDeck()"
|
||||
:key="content.key"
|
||||
xs12
|
||||
md3
|
||||
class="pb-3 pa-2"
|
||||
>
|
||||
<plexthumb
|
||||
:content="content"
|
||||
:server="GET_LASTSERVER"
|
||||
type="art"
|
||||
@contentSet="setContent(content)"
|
||||
></plexthumb>
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
<v-divider></v-divider>
|
||||
<div class="pt-4" v-if="results.length == 0">
|
||||
<h4>Browse
|
||||
<v-icon @click="PLEX_GET_DEVICES(true)" class="pl-2" small>refresh</v-icon>
|
||||
<v-divider />
|
||||
<div
|
||||
v-if="results.length == 0"
|
||||
class="pt-4"
|
||||
>
|
||||
<h4>
|
||||
Browse
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
small
|
||||
@click="PLEX_GET_DEVICES(true)"
|
||||
>
|
||||
refresh
|
||||
</v-icon>
|
||||
</h4>
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12 v-if="Object.keys(getPlex.servers).length === 0">
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
v-if="Object.keys(getPlex.servers).length === 0"
|
||||
xs12
|
||||
>
|
||||
<h5>No Plex Media Servers found. Make sure your server owner has shared their libraries with you!</h5>
|
||||
</v-flex>
|
||||
<v-flex
|
||||
v-for="server in getPlex.servers"
|
||||
:key="server.clientIdentifier"
|
||||
xs12
|
||||
lg4
|
||||
md6
|
||||
xl3
|
||||
v-for="server in getPlex.servers"
|
||||
:key="server.clientIdentifier"
|
||||
class="pa-2"
|
||||
>
|
||||
<router-link :to="'/browse/' + server.clientIdentifier">
|
||||
|
@ -157,21 +241,43 @@
|
|||
:title="server.name"
|
||||
>
|
||||
<v-container fill-height>
|
||||
<v-layout row justify-center align-center>
|
||||
<v-layout
|
||||
row
|
||||
justify-center
|
||||
align-center
|
||||
>
|
||||
<v-flex xs4>
|
||||
<v-img :src="logos.plex.standard" height="110px" contain></v-img>
|
||||
<v-img
|
||||
:src="logos.plex.standard"
|
||||
height="110px"
|
||||
contain
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex xs8 class="pl-2">
|
||||
<v-flex
|
||||
xs8
|
||||
class="pl-2"
|
||||
>
|
||||
<div>
|
||||
<h1 style="white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{ server.name }}</h1>
|
||||
<h4 style="opacity: 0.9">v{{ server.productVersion }}</h4>
|
||||
<h1 style="white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">
|
||||
{{ server.name }}
|
||||
</h1>
|
||||
<h4 style="opacity: 0.9">
|
||||
v{{ server.productVersion }}
|
||||
</h4>
|
||||
<div>Owned by {{ ownerOfServer(server) }}</div>
|
||||
<div v-if="!isConnectable(server)" class="red--text">Unable to connect</div>
|
||||
<div
|
||||
v-if="!isConnectable(server)"
|
||||
class="red--text"
|
||||
>
|
||||
Unable to connect
|
||||
</div>
|
||||
<div
|
||||
v-if="!isConnectable(server)"
|
||||
class="red--text"
|
||||
style="font-size: 10px"
|
||||
>Try disabling your adblocker</div>
|
||||
>
|
||||
Try disabling your adblocker
|
||||
</div>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
@ -192,10 +298,10 @@ import plexthumb from './plexbrowser/plexthumb.vue';
|
|||
const _ = require('lodash');
|
||||
|
||||
export default {
|
||||
name: 'Plexbrowser',
|
||||
components: {
|
||||
plexthumb,
|
||||
},
|
||||
name: 'plexbrowser',
|
||||
mounted() {
|
||||
this.updateOnDeck();
|
||||
},
|
||||
|
|
|
@ -1,57 +1,124 @@
|
|||
<template>
|
||||
<span>
|
||||
<span v-on:click="reset()" style="cursor: pointer !important"> {{ content.title }}<span
|
||||
v-if="browsingContent"
|
||||
> > </span> </span>
|
||||
<v-layout v-if="!contents && !browsingContent" 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>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div v-if="contents && !browsingContent" class="mt-3">
|
||||
<v-card horizontal height="25em" :img="getArtUrl">
|
||||
<v-card-row class="hidden-sm-and-down" :img="getThumb" height="100%"></v-card-row>
|
||||
<v-card-column style="background: rgba(0, 0, 0, .4)">
|
||||
<v-card-row height="11em" class="white--text">
|
||||
<v-card-text>
|
||||
<h3> {{ content.parentTitle }}</h3>
|
||||
<h6>{{ content.title }}</h6>
|
||||
<h4> {{content.year}} </h4>
|
||||
<p> {{ contents.MediaContainer.size }} tracks </p>
|
||||
</v-card-text>
|
||||
</v-card-row>
|
||||
<v-card-row actions class="pa-4" style="background: rgba(0,0,0,0.4)">
|
||||
<v-btn style="width:15%" v-on:click.native="playMedia(content)" raised large class="primary white--text">
|
||||
<v-icon light>play_arrow</v-icon> Play
|
||||
</v-btn>
|
||||
</v-card-row>
|
||||
</v-card-column>
|
||||
</v-card>
|
||||
<h4 class="mt-3"> Tracks </h4>
|
||||
<v-divider></v-divider>
|
||||
<div>
|
||||
<v-layout class="row mt-3" v-for="content in contents.MediaContainer.Metadata" :key="content" row wrap>
|
||||
<v-flex xs1 md1>
|
||||
<v-icon class="click-cursor" large light v-on:click="playMedia(content)">play_arrow</v-icon>
|
||||
</v-flex>
|
||||
<v-flex xs4 md3 class="click-cursor" v-on:click="playMedia(content)">
|
||||
<span class="soft-text">{{ content.index }}</span>. {{ content.title }}
|
||||
</v-flex>
|
||||
<v-flex xs4 md2>
|
||||
<span class="soft-text">{{ getDuration(content) }}</span>
|
||||
</v-flex>
|
||||
<v-flex md3>
|
||||
<span class="soft-text" v-for="media in content.Media" :key="media">
|
||||
{{ media.audioCodec }} ({{ media.audioChannels }}ch) <span v-if="content.Media.length > 1">,</span>
|
||||
</span>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
</div>
|
||||
<plexcontent v-if="browsingContent && browsingContent.type != 'show'" :content="browsingContent"
|
||||
:server="server" :library="library"
|
||||
></plexcontent>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
style="cursor: pointer !important"
|
||||
@click="reset()"
|
||||
> {{ content.title }}<span
|
||||
v-if="browsingContent"
|
||||
> > </span> </span>
|
||||
<v-layout
|
||||
v-if="!contents && !browsingContent"
|
||||
row
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
style="position:relative"
|
||||
>
|
||||
<v-progress-circular
|
||||
style="left: 50%; top:50%"
|
||||
:size="60"
|
||||
indeterminate
|
||||
class="amber--text"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div
|
||||
v-if="contents && !browsingContent"
|
||||
class="mt-3"
|
||||
>
|
||||
<v-card
|
||||
horizontal
|
||||
height="25em"
|
||||
:img="getArtUrl"
|
||||
>
|
||||
<v-card-row
|
||||
class="hidden-sm-and-down"
|
||||
:img="getThumb"
|
||||
height="100%"
|
||||
/>
|
||||
<v-card-column style="background: rgba(0, 0, 0, .4)">
|
||||
<v-card-row
|
||||
height="11em"
|
||||
class="white--text"
|
||||
>
|
||||
<v-card-text>
|
||||
<h3> {{ content.parentTitle }}</h3>
|
||||
<h6>{{ content.title }}</h6>
|
||||
<h4> {{ content.year }} </h4>
|
||||
<p> {{ contents.MediaContainer.size }} tracks </p>
|
||||
</v-card-text>
|
||||
</v-card-row>
|
||||
<v-card-row
|
||||
actions
|
||||
class="pa-4"
|
||||
style="background: rgba(0,0,0,0.4)"
|
||||
>
|
||||
<v-btn
|
||||
style="width:15%"
|
||||
raised
|
||||
large
|
||||
class="primary white--text"
|
||||
@click.native="playMedia(content)"
|
||||
>
|
||||
<v-icon light>play_arrow</v-icon> Play
|
||||
</v-btn>
|
||||
</v-card-row>
|
||||
</v-card-column>
|
||||
</v-card>
|
||||
<h4 class="mt-3"> Tracks </h4>
|
||||
<v-divider />
|
||||
<div>
|
||||
<v-layout
|
||||
v-for="content in contents.MediaContainer.Metadata"
|
||||
:key="content"
|
||||
class="row mt-3"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
xs1
|
||||
md1
|
||||
>
|
||||
<v-icon
|
||||
class="click-cursor"
|
||||
large
|
||||
light
|
||||
@click="playMedia(content)"
|
||||
>play_arrow</v-icon>
|
||||
</v-flex>
|
||||
<v-flex
|
||||
xs4
|
||||
md3
|
||||
class="click-cursor"
|
||||
@click="playMedia(content)"
|
||||
>
|
||||
<span class="soft-text">{{ content.index }}</span>. {{ content.title }}
|
||||
</v-flex>
|
||||
<v-flex
|
||||
xs4
|
||||
md2
|
||||
>
|
||||
<span class="soft-text">{{ getDuration(content) }}</span>
|
||||
</v-flex>
|
||||
<v-flex md3>
|
||||
<span
|
||||
v-for="media in content.Media"
|
||||
:key="media"
|
||||
class="soft-text"
|
||||
>
|
||||
{{ media.audioCodec }} ({{ media.audioChannels }}ch) <span v-if="content.Media.length > 1">,</span>
|
||||
</span>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
</div>
|
||||
<plexcontent
|
||||
v-if="browsingContent && browsingContent.type != 'show'"
|
||||
:content="browsingContent"
|
||||
:server="server"
|
||||
:library="library"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -70,22 +137,11 @@ humanizeDuration.languages.shortEn = {
|
|||
};
|
||||
|
||||
export default {
|
||||
props: ['library', 'server', 'content'],
|
||||
components: {
|
||||
plexcontent,
|
||||
plexthumb,
|
||||
},
|
||||
created() {
|
||||
// Hit the PMS endpoing /library/sections
|
||||
this.server.getSeriesContent(this.content.key, 0, 500, 1, (result) => {
|
||||
if (result) {
|
||||
this.contents = result;
|
||||
this.setBackground();
|
||||
} else {
|
||||
this.status = 'Error loading content!';
|
||||
}
|
||||
});
|
||||
},
|
||||
props: ['library', 'server', 'content'],
|
||||
data() {
|
||||
return {
|
||||
browsingContent: null,
|
||||
|
@ -94,15 +150,6 @@ export default {
|
|||
status: 'loading..',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
browsingContent() {
|
||||
if (!this.browsingContent) {
|
||||
this.$store.commit('SET_BACKGROUND', null);
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
beforeDestroy() {},
|
||||
computed: {
|
||||
getArtUrl() {
|
||||
const w = Math.round(Math.max(document.documentElement.clientWidth, window.innerWidth || 0));
|
||||
|
@ -128,6 +175,26 @@ export default {
|
|||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
browsingContent() {
|
||||
if (!this.browsingContent) {
|
||||
this.$store.commit('SET_BACKGROUND', null);
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Hit the PMS endpoing /library/sections
|
||||
this.server.getSeriesContent(this.content.key, 0, 500, 1, (result) => {
|
||||
if (result) {
|
||||
this.contents = result;
|
||||
this.setBackground();
|
||||
} else {
|
||||
this.status = 'Error loading content!';
|
||||
}
|
||||
});
|
||||
},
|
||||
mounted() {},
|
||||
beforeDestroy() {},
|
||||
methods: {
|
||||
setContent(content) {
|
||||
this.browsingContent = content;
|
||||
|
|
|
@ -1,42 +1,107 @@
|
|||
<template>
|
||||
<span>
|
||||
<span v-on:click="reset()" style="cursor: pointer !important"> {{ content.title }}<span
|
||||
v-if="browsingContent"
|
||||
> > </span> </span>
|
||||
<v-layout v-if="!contents && !browsingContent" 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>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div v-if="contents && !browsingContent" class="mt-3">
|
||||
<v-card horizontal height="25em" :img="getArtUrl">
|
||||
<v-card-row class="hidden-sm-and-down" :img="getThumb" height="100%"></v-card-row>
|
||||
<v-card-column style="background: rgba(0, 0, 0, .4)">
|
||||
<v-card-row height="11em" class="white--text">
|
||||
<v-card-text>
|
||||
<h3> {{ content.title }}</h3>
|
||||
<p> {{ contents.MediaContainer.summary }} </p>
|
||||
</v-card-text>
|
||||
</v-card-row>
|
||||
<v-card-row actions>
|
||||
<v-chip v-for="genre in content.Genre" :key="genre" v-tooltip:top="{ html: 'Genre' }" label> {{ genre.tag }}</v-chip>
|
||||
<v-chip v-for="country in content.Country" :key="country" v-tooltip:top="{ html: 'Country' }"> {{ country.tag }}</v-chip>
|
||||
</v-card-row>
|
||||
</v-card-column>
|
||||
</v-card>
|
||||
<h4 class="mt-3"> Albums </h4>
|
||||
<v-divider></v-divider>
|
||||
<div>
|
||||
<v-layout class="row mt-3" row wrap>
|
||||
<v-flex xs6 md3 xl1 lg2 class="pb-3" v-for="content in contents.MediaContainer.Metadata" :key="content">
|
||||
<plexthumb :content="content" :server="server" type="thumb" fullTitle @contentSet="setContent(content)"></plexthumb>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
style="cursor: pointer !important"
|
||||
@click="reset()"
|
||||
> {{ content.title }}<span
|
||||
v-if="browsingContent"
|
||||
> > </span> </span>
|
||||
<v-layout
|
||||
v-if="!contents && !browsingContent"
|
||||
row
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
style="position:relative"
|
||||
>
|
||||
<v-progress-circular
|
||||
style="left: 50%; top:50%"
|
||||
:size="60"
|
||||
indeterminate
|
||||
class="amber--text"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div
|
||||
v-if="contents && !browsingContent"
|
||||
class="mt-3"
|
||||
>
|
||||
<v-card
|
||||
horizontal
|
||||
height="25em"
|
||||
:img="getArtUrl"
|
||||
>
|
||||
<v-card-row
|
||||
class="hidden-sm-and-down"
|
||||
:img="getThumb"
|
||||
height="100%"
|
||||
/>
|
||||
<v-card-column style="background: rgba(0, 0, 0, .4)">
|
||||
<v-card-row
|
||||
height="11em"
|
||||
class="white--text"
|
||||
>
|
||||
<v-card-text>
|
||||
<h3> {{ content.title }}</h3>
|
||||
<p> {{ contents.MediaContainer.summary }} </p>
|
||||
</v-card-text>
|
||||
</v-card-row>
|
||||
<v-card-row actions>
|
||||
<v-chip
|
||||
v-for="genre in content.Genre"
|
||||
:key="genre"
|
||||
v-tooltip:top="{ html: 'Genre' }"
|
||||
label
|
||||
> {{ genre.tag }}</v-chip>
|
||||
<v-chip
|
||||
v-for="country in content.Country"
|
||||
:key="country"
|
||||
v-tooltip:top="{ html: 'Country' }"
|
||||
> {{ country.tag }}</v-chip>
|
||||
</v-card-row>
|
||||
</v-card-column>
|
||||
</v-card>
|
||||
<h4 class="mt-3"> Albums </h4>
|
||||
<v-divider />
|
||||
<div>
|
||||
<v-layout
|
||||
class="row mt-3"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
v-for="content in contents.MediaContainer.Metadata"
|
||||
:key="content"
|
||||
xs6
|
||||
md3
|
||||
xl1
|
||||
lg2
|
||||
class="pb-3"
|
||||
>
|
||||
<plexthumb
|
||||
:content="content"
|
||||
:server="server"
|
||||
type="thumb"
|
||||
full-title
|
||||
@contentSet="setContent(content)"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
<plexalbum v-if="browsingContent && browsingContent.type == 'album'" :content="browsingContent" :server="server" :library="library"></plexalbum>
|
||||
<plexcontent v-if="browsingContent && browsingContent.type != 'album'" :content="browsingContent" :server="server" :library="library"></plexcontent>
|
||||
</span>
|
||||
</div>
|
||||
<plexalbum
|
||||
v-if="browsingContent && browsingContent.type == 'album'"
|
||||
:content="browsingContent"
|
||||
:server="server"
|
||||
:library="library"
|
||||
/>
|
||||
<plexcontent
|
||||
v-if="browsingContent && browsingContent.type != 'album'"
|
||||
:content="browsingContent"
|
||||
:server="server"
|
||||
:library="library"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -45,23 +110,12 @@ import plexalbum from './plexalbum';
|
|||
import plexthumb from './plexthumb.vue';
|
||||
|
||||
export default {
|
||||
props: ['library', 'server', 'content'],
|
||||
components: {
|
||||
plexcontent,
|
||||
plexthumb,
|
||||
plexalbum,
|
||||
},
|
||||
created() {
|
||||
// Hit the PMS endpoing /library/sections
|
||||
this.server.getSeriesContent(this.content.key, 0, 500, 1, (result) => {
|
||||
if (result) {
|
||||
this.contents = result;
|
||||
this.setBackground();
|
||||
} else {
|
||||
this.status = 'Error loading content!';
|
||||
}
|
||||
});
|
||||
},
|
||||
props: ['library', 'server', 'content'],
|
||||
data() {
|
||||
return {
|
||||
browsingContent: null,
|
||||
|
@ -70,15 +124,6 @@ export default {
|
|||
status: 'loading..',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
browsingContent() {
|
||||
if (!this.browsingContent) {
|
||||
this.$store.commit('SET_BACKGROUND', null);
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
beforeDestroy() {},
|
||||
computed: {
|
||||
getArtUrl() {
|
||||
const w = Math.round(Math.max(document.documentElement.clientWidth, window.innerWidth || 0));
|
||||
|
@ -100,6 +145,26 @@ export default {
|
|||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
browsingContent() {
|
||||
if (!this.browsingContent) {
|
||||
this.$store.commit('SET_BACKGROUND', null);
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Hit the PMS endpoing /library/sections
|
||||
this.server.getSeriesContent(this.content.key, 0, 500, 1, (result) => {
|
||||
if (result) {
|
||||
this.contents = result;
|
||||
this.setBackground();
|
||||
} else {
|
||||
this.status = 'Error loading content!';
|
||||
}
|
||||
});
|
||||
},
|
||||
mounted() {},
|
||||
beforeDestroy() {},
|
||||
methods: {
|
||||
setContent(content) {
|
||||
this.browsingContent = content;
|
||||
|
|
|
@ -1,13 +1,22 @@
|
|||
<template>
|
||||
<div ref="root" class="slcontent">
|
||||
<v-layout v-if="!contents" row>
|
||||
<v-flex xs12 style="position:relative">
|
||||
<div
|
||||
ref="root"
|
||||
class="slcontent"
|
||||
>
|
||||
<v-layout
|
||||
v-if="!contents"
|
||||
row
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
style="position:relative"
|
||||
>
|
||||
<v-progress-circular
|
||||
style="left: 50%; top:50%"
|
||||
v-bind:size="60"
|
||||
:size="60"
|
||||
indeterminate
|
||||
class="amber--text"
|
||||
></v-progress-circular>
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div v-if="contents">
|
||||
|
@ -19,65 +28,101 @@
|
|||
class="darken-2 white--text"
|
||||
>
|
||||
<div style=" height: 100%">
|
||||
<v-container style="background-color: rgba(0, 0, 0, 0.8); height: 100%" fluid>
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12 md3>
|
||||
<v-layout row wrap>
|
||||
<v-flex md12 class="pa-2">
|
||||
<v-img :src="thumb" height="30vh" contain></v-img>
|
||||
<v-container
|
||||
style="background-color: rgba(0, 0, 0, 0.8); height: 100%"
|
||||
fluid
|
||||
>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
md3
|
||||
>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
md12
|
||||
class="pa-2"
|
||||
>
|
||||
<v-img
|
||||
:src="thumb"
|
||||
height="30vh"
|
||||
contain
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex xs8 md12 class="text-center hidden-sm-and-down ">
|
||||
<v-flex
|
||||
xs8
|
||||
md12
|
||||
class="text-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)"
|
||||
block
|
||||
class="primary white--text"
|
||||
@click.native="playMedia(contents)"
|
||||
>
|
||||
<v-icon> play_arrow </v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
block
|
||||
v-else
|
||||
@click.native.stop="dialog = true"
|
||||
block
|
||||
class="primary white--text"
|
||||
@click.native.stop="dialog = true"
|
||||
>
|
||||
<v-icon> play_arrow </v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<div v-if="!playable" class="pa-2">
|
||||
<div
|
||||
v-if="!playable"
|
||||
class="pa-2"
|
||||
>
|
||||
Now playing on {{ chosenClient.name }} from {{ server.name }}
|
||||
</div>
|
||||
<v-btn
|
||||
v-if="!playable"
|
||||
style="background-color: #cc3f3f"
|
||||
v-on:click.native="pressStop()"
|
||||
class="white--text"
|
||||
@click.native="pressStop()"
|
||||
>
|
||||
<v-icon></v-icon> Stop
|
||||
<v-icon /> Stop
|
||||
</v-btn>
|
||||
<div v-if="!playable">
|
||||
<v-btn
|
||||
v-if="me.role !== 'host'"
|
||||
:disabled="manualSyncQueued"
|
||||
color="blue"
|
||||
v-on:click.native="doManualSync"
|
||||
v-if="me.role !== 'host'"
|
||||
>Manual sync</v-btn
|
||||
@click.native="doManualSync"
|
||||
>
|
||||
Manual sync
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
<v-flex xs12 md9 sm12 class="pa-2">
|
||||
<v-flex
|
||||
xs12
|
||||
md9
|
||||
sm12
|
||||
class="pa-2"
|
||||
>
|
||||
<h1>
|
||||
{{ title }}
|
||||
<span style="float: right">
|
||||
<v-menu>
|
||||
<v-btn icon class="ma-0 pa-0" dark>
|
||||
<v-btn
|
||||
icon
|
||||
class="ma-0 pa-0"
|
||||
dark
|
||||
>
|
||||
<v-icon>more_vert</v-icon>
|
||||
</v-btn>
|
||||
<v-list>
|
||||
|
@ -104,13 +149,27 @@
|
|||
contents.year
|
||||
}})
|
||||
</h4>
|
||||
<h2 v-if="contents.type === 'episode'">{{ contents.title }}</h2>
|
||||
<h3 v-else>{{ contents.year }}</h3>
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12 md6 style="opacity:0.5">
|
||||
<h2 v-if="contents.type === 'episode'">
|
||||
{{ contents.title }}
|
||||
</h2>
|
||||
<h3 v-else>
|
||||
{{ contents.year }}
|
||||
</h3>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
md6
|
||||
style="opacity:0.5"
|
||||
>
|
||||
{{ length }}
|
||||
</v-flex>
|
||||
<v-flex xs12 sm6>
|
||||
<v-flex
|
||||
xs12
|
||||
sm6
|
||||
>
|
||||
<div class="text-xs-right">
|
||||
<v-chip
|
||||
v-if="
|
||||
|
@ -120,41 +179,57 @@
|
|||
outlined
|
||||
left
|
||||
>
|
||||
{{ contents.Media[0].videoResolution.toUpperCase() }}</v-chip
|
||||
{{ contents.Media[0].videoResolution.toUpperCase() }}
|
||||
</v-chip>
|
||||
<v-chip
|
||||
v-if="contents.contentRating"
|
||||
color="grey darken-2"
|
||||
small
|
||||
label
|
||||
>
|
||||
<v-chip v-if="contents.contentRating" color="grey darken-2" small label>
|
||||
{{ contents.contentRating }}</v-chip
|
||||
>
|
||||
<v-chip v-if="contents.studio" color="grey darken-2" small label>
|
||||
{{ contents.studio }}</v-chip
|
||||
{{ contents.contentRating }}
|
||||
</v-chip>
|
||||
<v-chip
|
||||
v-if="contents.studio"
|
||||
color="grey darken-2"
|
||||
small
|
||||
label
|
||||
>
|
||||
{{ contents.studio }}
|
||||
</v-chip>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="text-center hidden-md-and-up ">
|
||||
<v-flex
|
||||
xs12
|
||||
class="text-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)"
|
||||
block
|
||||
class="primary white--text"
|
||||
@click.native="playMedia(contents)"
|
||||
>
|
||||
<v-icon> play_arrow </v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
block
|
||||
v-else
|
||||
@click.native.stop="dialog = true"
|
||||
block
|
||||
class="primary white--text"
|
||||
@click.native.stop="dialog = true"
|
||||
>
|
||||
<v-icon> play_arrow </v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<div v-else>
|
||||
<v-layout row wrap>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex xs12>
|
||||
<div class="pa-2">
|
||||
Now playing on {{ chosenClient.name }} from {{ server.name }}
|
||||
|
@ -164,66 +239,109 @@
|
|||
<v-btn
|
||||
block
|
||||
style="background-color: #cc3f3f"
|
||||
v-on:click.native="pressStop()"
|
||||
class="white--text"
|
||||
@click.native="pressStop()"
|
||||
>
|
||||
<v-icon></v-icon> Stop
|
||||
<v-icon /> Stop
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
<v-flex xs12>
|
||||
<v-btn
|
||||
v-if="me.role !== 'host'"
|
||||
block
|
||||
:disabled="manualSyncQueued"
|
||||
color="blue"
|
||||
v-on:click.native="doManualSync"
|
||||
v-if="me.role !== 'host'"
|
||||
>Manual sync</v-btn
|
||||
@click.native="doManualSync"
|
||||
>
|
||||
Manual sync
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
</v-flex>
|
||||
<div style="width: 100%">
|
||||
<p
|
||||
v-if="hidden"
|
||||
class="pt-3"
|
||||
style="font-style: italic"
|
||||
v-if="hidden"
|
||||
v-on:click="hiddenOverride = true"
|
||||
@click="hiddenOverride = true"
|
||||
>
|
||||
Summary automatically hidden for unwatched content. Click to unhide.
|
||||
</p>
|
||||
<p class="pt-3" style="font-style: italic" v-else>{{ contents.summary }}</p>
|
||||
<p
|
||||
v-else
|
||||
class="pt-3"
|
||||
style="font-style: italic"
|
||||
>
|
||||
{{ contents.summary }}
|
||||
</p>
|
||||
</div>
|
||||
<v-layout
|
||||
v-if="contents.type === 'movie'"
|
||||
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">
|
||||
<v-flex
|
||||
v-if="contents.Role && contents.Role.length > 0"
|
||||
lg3
|
||||
xl2
|
||||
>
|
||||
<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>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex lg3 xl2 v-if="contents.Director && contents.Director.length > 0">
|
||||
<v-subheader class="white--text"> Director </v-subheader>
|
||||
<div v-for="director in contents.Director.slice(0, 3)" :key="director.tag">
|
||||
<v-flex
|
||||
v-if="contents.Director && contents.Director.length > 0"
|
||||
lg3
|
||||
xl2
|
||||
>
|
||||
<v-subheader class="white--text">
|
||||
Director
|
||||
</v-subheader>
|
||||
<div
|
||||
v-for="director in contents.Director.slice(0, 3)"
|
||||
:key="director.tag"
|
||||
>
|
||||
{{ director.tag }}
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex lg3 xl2 v-if="contents.Producer && contents.Producer.length > 0">
|
||||
<v-subheader class="white--text"> Producers </v-subheader>
|
||||
<div v-for="producer in contents.Producer.slice(0, 3)" :key="producer.tag">
|
||||
<v-flex
|
||||
v-if="contents.Producer && contents.Producer.length > 0"
|
||||
lg3
|
||||
xl2
|
||||
>
|
||||
<v-subheader class="white--text">
|
||||
Producers
|
||||
</v-subheader>
|
||||
<div
|
||||
v-for="producer in contents.Producer.slice(0, 3)"
|
||||
:key="producer.tag"
|
||||
>
|
||||
{{ producer.tag }}
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex lg3 xl2 v-if="contents.Writer && contents.Writer.length > 0">
|
||||
<v-subheader class="white--text"> Writers </v-subheader>
|
||||
<div v-for="writer in contents.Writer.slice(0, 3)" :key="writer.tag">
|
||||
<v-flex
|
||||
v-if="contents.Writer && contents.Writer.length > 0"
|
||||
lg3
|
||||
xl2
|
||||
>
|
||||
<v-subheader class="white--text">
|
||||
Writers
|
||||
</v-subheader>
|
||||
<div
|
||||
v-for="writer in contents.Writer.slice(0, 3)"
|
||||
:key="writer.tag"
|
||||
>
|
||||
{{ writer.tag }}
|
||||
</div>
|
||||
</v-flex>
|
||||
|
@ -231,49 +349,68 @@
|
|||
</v-layout>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-divider></v-divider>
|
||||
<v-divider />
|
||||
<div
|
||||
v-if="subsetParentData(6).length >= 0 && contents.type == 'episode'"
|
||||
class="hidden-xs-only"
|
||||
>
|
||||
<v-subheader
|
||||
>Also in Season {{ contents.parentIndex }} of
|
||||
{{ contents.grandparentTitle }}</v-subheader
|
||||
<v-subheader>
|
||||
Also in Season {{ contents.parentIndex }} of
|
||||
{{ contents.grandparentTitle }}
|
||||
</v-subheader>
|
||||
<v-layout
|
||||
v-if="parentData"
|
||||
row
|
||||
wrap
|
||||
justify-start
|
||||
>
|
||||
<v-layout v-if="parentData" row wrap justify-start>
|
||||
<v-flex
|
||||
v-for="ep in subsetParentData(6)"
|
||||
:key="ep.key"
|
||||
xs6
|
||||
md2
|
||||
xl2
|
||||
lg2
|
||||
class="pb-3"
|
||||
v-for="ep in subsetParentData(6)"
|
||||
:key="ep.key"
|
||||
>
|
||||
<plexthumb
|
||||
bottomOnly
|
||||
bottom-only
|
||||
:content="ep"
|
||||
:img="getLittleThumb(ep)"
|
||||
:class="{ highlightBorder: ep.index === contents.index }"
|
||||
style="margin:3%"
|
||||
:server="server"
|
||||
spoilerFilter
|
||||
></plexthumb>
|
||||
spoiler-filter
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
<div v-if="relatedItems.length > 0">
|
||||
<v-subheader>Related Movies</v-subheader>
|
||||
<v-container fill-height fluid>
|
||||
<v-layout row wrap justify-space-around align-center>
|
||||
<v-flex xs4 md1 class="ma-1" v-for="movie in relatedItems" :key="movie.key">
|
||||
<v-container
|
||||
fill-height
|
||||
fluid
|
||||
>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-space-around
|
||||
align-center
|
||||
>
|
||||
<v-flex
|
||||
v-for="movie in relatedItems"
|
||||
:key="movie.key"
|
||||
xs4
|
||||
md1
|
||||
class="ma-1"
|
||||
>
|
||||
<plexthumb
|
||||
:content="movie"
|
||||
:img="getLittleThumb(movie)"
|
||||
style="margin:3%"
|
||||
:server="server"
|
||||
type="thumb"
|
||||
></plexthumb>
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
|
@ -289,18 +426,29 @@
|
|||
width="500px"
|
||||
>
|
||||
<v-card style="overflow: hidden">
|
||||
<v-card-title class="headline">Playback Settings</v-card-title>
|
||||
<v-card-title class="headline">
|
||||
Playback Settings
|
||||
</v-card-title>
|
||||
<v-checkbox
|
||||
v-if="contents.viewOffset && contents.viewOffset > 0"
|
||||
v-bind:label="'Resume from ' + getDuration(contents.viewOffset)"
|
||||
v-model="resumeFrom"
|
||||
:label="'Resume from ' + getDuration(contents.viewOffset)"
|
||||
color="orange lighten-2"
|
||||
class="pa-0 ma-0 ml-3"
|
||||
v-model="resumeFrom"
|
||||
></v-checkbox>
|
||||
<div v-for="(media, index) in contents.Media" :key="media.Part[0].key">
|
||||
<v-layout row wrap class="pa-2">
|
||||
/>
|
||||
<div
|
||||
v-for="(media, index) in contents.Media"
|
||||
:key="media.Part[0].key"
|
||||
>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
class="pa-2"
|
||||
>
|
||||
<v-flex xs8>
|
||||
<div class="pl-2">{{ media.videoResolution }}p {{ getDuration(media.duration) }}</div>
|
||||
<div class="pl-2">
|
||||
{{ media.videoResolution }}p {{ getDuration(media.duration) }}
|
||||
</div>
|
||||
<div class="pl-4 soft-text">
|
||||
<div>Video Codec: {{ media.videoCodec }} ({{ media.bitrate }}kbps)</div>
|
||||
<div>Audio Streams: {{ audioStreams(media.Part[0].Stream) }}</div>
|
||||
|
@ -308,7 +456,10 @@
|
|||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs4>
|
||||
<v-btn class="primary white--text" @click.native.stop="playMedia(contents, index)">
|
||||
<v-btn
|
||||
class="primary white--text"
|
||||
@click.native.stop="playMedia(contents, index)"
|
||||
>
|
||||
Play
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
|
@ -328,7 +479,6 @@ export default {
|
|||
components: {
|
||||
plexthumb,
|
||||
},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
browsingContent: null,
|
||||
|
@ -349,17 +499,6 @@ export default {
|
|||
eventbus: window.eventbus,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.getNewData();
|
||||
this.fullheight = this.$refs.root.offsetHeight;
|
||||
this.fullwidth = this.$refs.root.offsetWidth;
|
||||
},
|
||||
beforeDestroy() {},
|
||||
watch: {
|
||||
ratingKey() {
|
||||
this.getNewData();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
plex() {
|
||||
return this.$store.getters.getPlex;
|
||||
|
@ -471,6 +610,18 @@ export default {
|
|||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
ratingKey() {
|
||||
this.getNewData();
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getNewData();
|
||||
this.fullheight = this.$refs.root.offsetHeight;
|
||||
this.fullwidth = this.$refs.root.offsetWidth;
|
||||
},
|
||||
beforeDestroy() {},
|
||||
methods: {
|
||||
getNewData() {
|
||||
this.server.getMediaByRatingKey(this.ratingKey).then(async (result) => {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<template>
|
||||
<span ref="root">
|
||||
|
||||
</span>
|
||||
<span ref="root" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -17,6 +15,16 @@ export default {
|
|||
plexseries,
|
||||
plexcontent,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
contents: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
ratingKey() {
|
||||
return this.$route.params.ratingKey;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.server.getMediaByRatingKey(this.content.ratingKey).then((result) => {
|
||||
if (result) {
|
||||
|
@ -34,20 +42,10 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
contents: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
||||
},
|
||||
computed: {
|
||||
ratingKey() {
|
||||
return this.$route.params.ratingKey;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
|
|
|
@ -1,18 +1,58 @@
|
|||
<template>
|
||||
<span style="max-height: 90%">
|
||||
<v-layout v-if="!contents && !browsingContent" row justify-center align-start>
|
||||
<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>
|
||||
<v-layout
|
||||
v-if="!contents && !browsingContent"
|
||||
row
|
||||
justify-center
|
||||
align-start
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
style="position:relative"
|
||||
>
|
||||
<v-progress-circular
|
||||
style="left: 50%; top:50%"
|
||||
:size="60"
|
||||
indeterminate
|
||||
class="amber--text"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div v-if="!browsingContent && contents" class="mt-3" style="height:90vh; overflow-y: auto">
|
||||
<v-layout class="row" row wrap>
|
||||
<v-flex xs3 sm3 md1 lg1 class="ma-1" v-for="content in contents.MediaContainer.Metadata" :key="content.key">
|
||||
<plexthumb :content="content" :server="server" type="thumb" style="margin:7%" @contentSet="setContent(content)"></plexthumb>
|
||||
<div
|
||||
v-if="!browsingContent && contents"
|
||||
class="mt-3"
|
||||
style="height:90vh; overflow-y: auto"
|
||||
>
|
||||
<v-layout
|
||||
class="row"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
v-for="content in contents.MediaContainer.Metadata"
|
||||
:key="content.key"
|
||||
xs3
|
||||
sm3
|
||||
md1
|
||||
lg1
|
||||
class="ma-1"
|
||||
>
|
||||
<plexthumb
|
||||
:content="content"
|
||||
:server="server"
|
||||
type="thumb"
|
||||
style="margin:7%"
|
||||
@contentSet="setContent(content)"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout row>
|
||||
<v-flex xs12 v-if="contents && !browsingContent && !stopNewContent" v-observe-visibility="getMoreContent" justify-center>
|
||||
<v-flex
|
||||
v-if="contents && !browsingContent && !stopNewContent"
|
||||
v-observe-visibility="getMoreContent"
|
||||
xs12
|
||||
justify-center
|
||||
>
|
||||
Loading...
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
@ -30,7 +70,6 @@ import plexartist from './plexartist';
|
|||
const _ = require('lodash');
|
||||
|
||||
export default {
|
||||
props: ['library'],
|
||||
components: {
|
||||
plexcontent,
|
||||
plexseries,
|
||||
|
@ -38,10 +77,7 @@ export default {
|
|||
plexalbum,
|
||||
plexartist,
|
||||
},
|
||||
created() {
|
||||
// Hit the PMS endpoing /library/sections
|
||||
this.getMoreContent();
|
||||
},
|
||||
props: ['library'],
|
||||
data() {
|
||||
return {
|
||||
browsingContent: null,
|
||||
|
@ -55,16 +91,20 @@ export default {
|
|||
status: 'loading..',
|
||||
searchPhrase: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
||||
},
|
||||
computed: {
|
||||
server() {
|
||||
return this.plex.servers[this.$route.params.machineIdentifier];
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Hit the PMS endpoing /library/sections
|
||||
this.getMoreContent();
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
setContent(content) {
|
||||
|
|
|
@ -1,53 +1,118 @@
|
|||
<template>
|
||||
<span>
|
||||
<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>
|
||||
<v-layout
|
||||
v-if="!contents"
|
||||
row
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
style="position:relative"
|
||||
>
|
||||
<v-progress-circular
|
||||
style="left: 50%; top:50%"
|
||||
:size="60"
|
||||
indeterminate
|
||||
class="amber--text"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div v-else class="mt-3">
|
||||
<div
|
||||
v-else
|
||||
class="mt-3"
|
||||
>
|
||||
<v-flex xs12>
|
||||
<v-card class="darken-2 white--text" :img="getArtUrl">
|
||||
<v-container style="background: rgba(0, 0, 0, .6);" class="pa-0 ma-0" fluid grid-list-lg>
|
||||
<v-layout row style="height:100%">
|
||||
<v-flex xs12 md3 class="hidden-sm-and-down">
|
||||
<v-img
|
||||
:src="getThumb"
|
||||
class="ma-0 pa-0"
|
||||
height="25em"
|
||||
contain
|
||||
></v-img>
|
||||
</v-flex>
|
||||
<v-flex xs12 md9 style="position:relative" class="ma-2">
|
||||
<v-card
|
||||
class="darken-2 white--text"
|
||||
:img="getArtUrl"
|
||||
>
|
||||
<v-container
|
||||
style="background: rgba(0, 0, 0, .6);"
|
||||
class="pa-0 ma-0"
|
||||
fluid
|
||||
grid-list-lg
|
||||
>
|
||||
<v-layout
|
||||
row
|
||||
style="height:100%"
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
md3
|
||||
class="hidden-sm-and-down"
|
||||
>
|
||||
<v-img
|
||||
:src="getThumb"
|
||||
class="ma-0 pa-0"
|
||||
height="25em"
|
||||
contain
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex
|
||||
xs12
|
||||
md9
|
||||
style="position:relative"
|
||||
class="ma-2"
|
||||
>
|
||||
<div>
|
||||
<h1> {{ contents.MediaContainer.title1 }}</h1>
|
||||
<h3 style="font-weight:bold">{{ contents.MediaContainer.title2 }}</h3>
|
||||
<p> {{ contents.MediaContainer.size }} episodes </p>
|
||||
<v-divider />
|
||||
<p
|
||||
style="font-style: italic"
|
||||
class="pt-3; overflow: hidden"
|
||||
> {{ contents.summary }} </p>
|
||||
<div>
|
||||
<h1> {{ contents.MediaContainer.title1 }}</h1>
|
||||
<h3 style="font-weight:bold">{{ contents.MediaContainer.title2 }}</h3>
|
||||
<p> {{ contents.MediaContainer.size }} episodes </p>
|
||||
<v-divider></v-divider>
|
||||
<p style="font-style: italic" class="pt-3; overflow: hidden"> {{ contents.summary }} </p>
|
||||
<div>
|
||||
<div style="float:right" class="pa-4">
|
||||
<v-chip v-if="contents.MediaContainer.grandparentContentRating" label color="grey"> {{ contents.MediaContainer.grandparentContentRating }}</v-chip>
|
||||
<v-chip v-if="contents.MediaContainer.grandparentStudio" secondary color="grey"> {{ contents.MediaContainer.grandparentStudio }}</v-chip>
|
||||
</div>
|
||||
<div
|
||||
style="float:right"
|
||||
class="pa-4"
|
||||
>
|
||||
<v-chip
|
||||
v-if="contents.MediaContainer.grandparentContentRating"
|
||||
label
|
||||
color="grey"
|
||||
> {{ contents.MediaContainer.grandparentContentRating }}</v-chip>
|
||||
<v-chip
|
||||
v-if="contents.MediaContainer.grandparentStudio"
|
||||
secondary
|
||||
color="grey"
|
||||
> {{ contents.MediaContainer.grandparentStudio }}</v-chip>
|
||||
</div>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
<h4 class="mt-3"> Episodes </h4>
|
||||
<v-divider></v-divider>
|
||||
<div>
|
||||
<v-layout class="row mt-3" row wrap>
|
||||
<v-flex xs6 md2 class="pb-3" v-for="content in contents.MediaContainer.Metadata" :key="content.key">
|
||||
<plexthumb :content="content" :server="plexserver" type="thumb" style="margin:2%" fullTitle @contentSet="setContent(content)"></plexthumb>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
<h4 class="mt-3"> Episodes </h4>
|
||||
<v-divider />
|
||||
<div>
|
||||
<v-layout
|
||||
class="row mt-3"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
v-for="content in contents.MediaContainer.Metadata"
|
||||
:key="content.key"
|
||||
xs6
|
||||
md2
|
||||
class="pb-3"
|
||||
>
|
||||
<plexthumb
|
||||
:content="content"
|
||||
:server="plexserver"
|
||||
type="thumb"
|
||||
style="margin:2%"
|
||||
full-title
|
||||
@contentSet="setContent(content)"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -55,23 +120,11 @@ import plexcontent from './plexcontent';
|
|||
import plexthumb from './plexthumb.vue';
|
||||
|
||||
export default {
|
||||
props: ['library', 'server', 'content'],
|
||||
components: {
|
||||
plexcontent,
|
||||
plexthumb,
|
||||
},
|
||||
created() {
|
||||
// Hit the PMS endpoing /library/sections
|
||||
this.plexserver.getSeriesChildren(this.$route.params.ratingKey, 0, 500, 1, this.$route.params.sectionId)
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
this.contents = result;
|
||||
this.setBackground();
|
||||
} else {
|
||||
this.status = 'Error loading content!';
|
||||
}
|
||||
});
|
||||
},
|
||||
props: ['library', 'server', 'content'],
|
||||
data() {
|
||||
return {
|
||||
browsingContent: null,
|
||||
|
@ -80,15 +133,6 @@ export default {
|
|||
status: 'loading..',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
browsingContent() {
|
||||
if (!this.browsingContent) {
|
||||
this.$store.commit('SET_BACKGROUND', null);
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
beforeDestroy() {},
|
||||
computed: {
|
||||
getArtUrl() {
|
||||
const w = Math.round(Math.max(document.documentElement.clientWidth, window.innerWidth || 0));
|
||||
|
@ -105,6 +149,27 @@ export default {
|
|||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
browsingContent() {
|
||||
if (!this.browsingContent) {
|
||||
this.$store.commit('SET_BACKGROUND', null);
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Hit the PMS endpoing /library/sections
|
||||
this.plexserver.getSeriesChildren(this.$route.params.ratingKey, 0, 500, 1, this.$route.params.sectionId)
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
this.contents = result;
|
||||
this.setBackground();
|
||||
} else {
|
||||
this.status = 'Error loading content!';
|
||||
}
|
||||
});
|
||||
},
|
||||
mounted() {},
|
||||
beforeDestroy() {},
|
||||
methods: {
|
||||
setContent(content) {
|
||||
this.browsingContent = content;
|
||||
|
|
|
@ -1,44 +1,101 @@
|
|||
<template>
|
||||
<span>
|
||||
<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>
|
||||
<v-layout
|
||||
v-if="!contents"
|
||||
row
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
style="position:relative"
|
||||
>
|
||||
<v-progress-circular
|
||||
style="left: 50%; top:50%"
|
||||
:size="60"
|
||||
indeterminate
|
||||
class="amber--text"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div v-if="contents" class="mt-3">
|
||||
<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%">
|
||||
<v-flex xs12 md3 class="hidden-sm-and-down">
|
||||
<div
|
||||
v-if="contents"
|
||||
class="mt-3"
|
||||
>
|
||||
<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%"
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
md3
|
||||
class="hidden-sm-and-down"
|
||||
>
|
||||
<v-img
|
||||
:src="thumb"
|
||||
class="ma-0 pa-0 hidden-sm-and-down"
|
||||
height="25em"
|
||||
contain
|
||||
></v-img>
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex xs12 md9 class="ma-2">
|
||||
<v-flex
|
||||
xs12
|
||||
md9
|
||||
class="ma-2"
|
||||
>
|
||||
<div>
|
||||
<h1> {{ 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>
|
||||
<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 color="grey">
|
||||
<v-chip
|
||||
v-for="genre in genres"
|
||||
:key="genre.tag"
|
||||
label
|
||||
color="grey"
|
||||
>
|
||||
{{ genre.tag }}
|
||||
</v-chip>
|
||||
</div>
|
||||
<v-subheader class="white--text"> Featuring </v-subheader>
|
||||
<v-layout row wrap v-if="seriesData">
|
||||
<v-flex v-for="role in roles" :key="role.tag" xs12 md6 lg4>
|
||||
<v-layout
|
||||
v-if="seriesData"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
v-for="role in roles"
|
||||
:key="role.tag"
|
||||
xs12
|
||||
md6
|
||||
lg4
|
||||
>
|
||||
<v-chip style="border: none; background: none; color: white">
|
||||
<v-avatar>
|
||||
<img :src="role.thumb">
|
||||
</v-avatar>
|
||||
{{ role.tag }}
|
||||
<div style="opacity:0.7;font-size:80% " class="pa-2"> {{role.role}} </div>
|
||||
<div
|
||||
style="opacity:0.7;font-size:80% "
|
||||
class="pa-2"
|
||||
> {{ role.role }} </div>
|
||||
</v-chip>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
@ -49,9 +106,26 @@
|
|||
</v-card>
|
||||
</v-flex>
|
||||
<h4 class="mt-3"> Seasons </h4>
|
||||
<v-layout class="row" row wrap>
|
||||
<v-flex xs4 md2 xl1 lg1 class="pb-3" v-for="content in contents.Metadata" :key="content.key">
|
||||
<plexthumb :content="content" :server="plexserver" type="thumb" style="margin:7%"></plexthumb>
|
||||
<v-layout
|
||||
class="row"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
v-for="content in contents.Metadata"
|
||||
:key="content.key"
|
||||
xs4
|
||||
md2
|
||||
xl1
|
||||
lg1
|
||||
class="pb-3"
|
||||
>
|
||||
<plexthumb
|
||||
:content="content"
|
||||
:server="plexserver"
|
||||
type="thumb"
|
||||
style="margin:7%"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
|
@ -63,29 +137,11 @@ import plexseason from './plexseason.vue';
|
|||
import plexthumb from './plexthumb.vue';
|
||||
|
||||
export default {
|
||||
props: [],
|
||||
components: {
|
||||
plexseason,
|
||||
plexthumb,
|
||||
},
|
||||
created() {
|
||||
// Hit the PMS endpoing /library/sections
|
||||
this.plexserver.getSeriesChildren(this.$route.params.ratingKey, this.startingIndex, this.size, 1, this.$route.params.sectionId).then((result) => {
|
||||
if (result) {
|
||||
this.contents = result.MediaContainer;
|
||||
this.setBackground();
|
||||
} else {
|
||||
this.status = 'Error loading libraries!';
|
||||
}
|
||||
}).catch((e, data) => {
|
||||
});
|
||||
this.plexserver.getSeriesData(this.$route.params.ratingKey).then((res) => {
|
||||
if (res) {
|
||||
this.seriesData = res;
|
||||
}
|
||||
}).catch((e, data) => {
|
||||
});
|
||||
},
|
||||
props: [],
|
||||
data() {
|
||||
return {
|
||||
browsingContent: null,
|
||||
|
@ -96,12 +152,6 @@ export default {
|
|||
seriesData: null,
|
||||
status: 'loading..',
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
||||
},
|
||||
computed: {
|
||||
getArtUrl(object) {
|
||||
|
@ -132,6 +182,30 @@ export default {
|
|||
const h = Math.round(Math.max(document.documentElement.clientHeight, window.innerHeight || 0));
|
||||
return this.plexserver.getUrlForLibraryLoc(this.contents.thumb || this.contents.parentThumb || this.contents.grandparentThumb, w / 1, h / 1);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Hit the PMS endpoing /library/sections
|
||||
this.plexserver.getSeriesChildren(this.$route.params.ratingKey, this.startingIndex, this.size, 1, this.$route.params.sectionId).then((result) => {
|
||||
if (result) {
|
||||
this.contents = result.MediaContainer;
|
||||
this.setBackground();
|
||||
} else {
|
||||
this.status = 'Error loading libraries!';
|
||||
}
|
||||
}).catch((e, data) => {
|
||||
});
|
||||
this.plexserver.getSeriesData(this.$route.params.ratingKey).then((res) => {
|
||||
if (res) {
|
||||
this.seriesData = res;
|
||||
}
|
||||
}).catch((e, data) => {
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
setBackground() {
|
||||
|
|
|
@ -1,58 +1,174 @@
|
|||
<template>
|
||||
<span v-if="server">
|
||||
<v-layout v-if="!libraries && !browsingLibrary && !selectedItem" row align-center>
|
||||
<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>
|
||||
<v-layout
|
||||
v-if="!libraries && !browsingLibrary && !selectedItem"
|
||||
row
|
||||
align-center
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
style="position: relative"
|
||||
>
|
||||
<v-progress-circular
|
||||
style="left:50%; top:50%"
|
||||
:size="60"
|
||||
indeterminate
|
||||
class="amber--text"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div v-if="!browsingLibrary && !selectedItem && libraries" class="mt-3">
|
||||
<div v-if="!libraries && !browsingLibrary">
|
||||
<v-progress-circular active large></v-progress-circular>
|
||||
</div>
|
||||
<h4> Libraries </h4>
|
||||
<v-layout row wrap v-if="libraries && !browsingLibrary">
|
||||
<v-flex xs12 md3 xl2 lg2 v-for="library in filteredLibraries" class="pa-1" :key="library.name">
|
||||
<v-card v-on:click.native="setLibrary(library)" :img="getArtLibrary(library)" flat class="clickable text-center" style="max-width:100%; cursor: pointer; border-radius: 0px !important">
|
||||
<div style="position:relative; width:100%; background: rgba(0,0,0,0.4); height:8em" class="hidden-xs-only">
|
||||
<img style="height: 70%; display: block; margin-left: auto; margin-right: auto " :src="getThumb(library)" />
|
||||
</div>
|
||||
<div style="background: rgba(0,0,0,0.7); position:relative; width:100%;" class="text-center pa-1">
|
||||
<h2 class="truncate text-xs-left text-sm-center">{{ library.title }}</h2>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-divider v-if="subsetOnDeck(onDeckItemsPer).length > 0" class="mt-3 ma-2"></v-divider>
|
||||
<v-layout row wrap v-if="subsetOnDeck(onDeckItemsPer).length > 0">
|
||||
<v-flex xs6>
|
||||
<h4>On Deck</h4>
|
||||
</v-flex>
|
||||
<v-flex xs6>
|
||||
<span style="float:right; user-select: none;">
|
||||
<v-icon @click="onDeckDown" style="margin-right: 15px;cursor: pointer" :style="onDeckDownStyle">fa-angle-left</v-icon><v-icon @click="onDeckUp" :style="onDeckUpStyle" style="cursor: pointer">fa-angle-right</v-icon>
|
||||
</span>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout v-if="onDeck" row wrap>
|
||||
<v-flex xs12 sm6 md4 lg3 class="pb-3 pa-1" v-for="content in subsetOnDeck()" :key="content.key">
|
||||
<plexthumb :content="content" :server="server" type="art" @contentSet="setContent(content)"></plexthumb>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-divider v-if="subsetRecentlyAdded(recentItemsPer).length > 0" class="mt-3 ma-2"></v-divider>
|
||||
<v-layout row wrap v-if="subsetRecentlyAdded(recentItemsPer).length > 0">
|
||||
<v-flex xs6>
|
||||
<h4>Recently Added</h4>
|
||||
</v-flex>
|
||||
<v-flex xs6>
|
||||
<span style="float:right; user-select: none;"> <v-icon fa @click="recentlyAddedDown" style="margin-right: 15px;cursor: pointer;" :style="recentlyAddedDownStyle">fa-angle-left</v-icon><v-icon fa :style="recentlyAddedUpStyle" @click="recentlyAddedUp" style="cursor: pointer">fa-angle-right</v-icon>
|
||||
</span>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout v-if="recentlyAdded" class="row pt-2" row wrap justify-space-between>
|
||||
<v-flex xs4 sm2 md1 xl1 lg1 class="pb-3 pa-3" v-for="content in subsetRecentlyAdded(recentItemsPer)" :key="content.key">
|
||||
<plexthumb :content="content" :server="server" type="thumb" fullTitle locked @contentSet="setContent(content)"></plexthumb>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div
|
||||
v-if="!browsingLibrary && !selectedItem && libraries"
|
||||
class="mt-3"
|
||||
>
|
||||
<div v-if="!libraries && !browsingLibrary">
|
||||
<v-progress-circular
|
||||
active
|
||||
large
|
||||
/>
|
||||
</div>
|
||||
<h4> Libraries </h4>
|
||||
<v-layout
|
||||
v-if="libraries && !browsingLibrary"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
v-for="library in filteredLibraries"
|
||||
:key="library.name"
|
||||
xs12
|
||||
md3
|
||||
xl2
|
||||
lg2
|
||||
class="pa-1"
|
||||
>
|
||||
<v-card
|
||||
:img="getArtLibrary(library)"
|
||||
flat
|
||||
class="clickable text-center"
|
||||
style="max-width:100%; cursor: pointer; border-radius: 0px !important"
|
||||
@click.native="setLibrary(library)"
|
||||
>
|
||||
<div
|
||||
style="position:relative; width:100%; background: rgba(0,0,0,0.4); height:8em"
|
||||
class="hidden-xs-only"
|
||||
>
|
||||
<img
|
||||
style="height: 70%; display: block; margin-left: auto; margin-right: auto "
|
||||
:src="getThumb(library)"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
style="background: rgba(0,0,0,0.7); position:relative; width:100%;"
|
||||
class="text-center pa-1"
|
||||
>
|
||||
<h2 class="truncate text-xs-left text-sm-center">{{ library.title }}</h2>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-divider
|
||||
v-if="subsetOnDeck(onDeckItemsPer).length > 0"
|
||||
class="mt-3 ma-2"
|
||||
/>
|
||||
<v-layout
|
||||
v-if="subsetOnDeck(onDeckItemsPer).length > 0"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex xs6>
|
||||
<h4>On Deck</h4>
|
||||
</v-flex>
|
||||
<v-flex xs6>
|
||||
<span style="float:right; user-select: none;">
|
||||
<v-icon
|
||||
style="margin-right: 15px;cursor: pointer"
|
||||
:style="onDeckDownStyle"
|
||||
@click="onDeckDown"
|
||||
>fa-angle-left</v-icon><v-icon
|
||||
:style="onDeckUpStyle"
|
||||
style="cursor: pointer"
|
||||
@click="onDeckUp"
|
||||
>fa-angle-right</v-icon>
|
||||
</span>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout
|
||||
v-if="onDeck"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
v-for="content in subsetOnDeck()"
|
||||
:key="content.key"
|
||||
xs12
|
||||
sm6
|
||||
md4
|
||||
lg3
|
||||
class="pb-3 pa-1"
|
||||
>
|
||||
<plexthumb
|
||||
:content="content"
|
||||
:server="server"
|
||||
type="art"
|
||||
@contentSet="setContent(content)"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-divider
|
||||
v-if="subsetRecentlyAdded(recentItemsPer).length > 0"
|
||||
class="mt-3 ma-2"
|
||||
/>
|
||||
<v-layout
|
||||
v-if="subsetRecentlyAdded(recentItemsPer).length > 0"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex xs6>
|
||||
<h4>Recently Added</h4>
|
||||
</v-flex>
|
||||
<v-flex xs6>
|
||||
<span style="float:right; user-select: none;"> <v-icon
|
||||
fa
|
||||
style="margin-right: 15px;cursor: pointer;"
|
||||
:style="recentlyAddedDownStyle"
|
||||
@click="recentlyAddedDown"
|
||||
>fa-angle-left</v-icon><v-icon
|
||||
fa
|
||||
:style="recentlyAddedUpStyle"
|
||||
style="cursor: pointer"
|
||||
@click="recentlyAddedUp"
|
||||
>fa-angle-right</v-icon>
|
||||
</span>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout
|
||||
v-if="recentlyAdded"
|
||||
class="row pt-2"
|
||||
row
|
||||
wrap
|
||||
justify-space-between
|
||||
>
|
||||
<v-flex
|
||||
v-for="content in subsetRecentlyAdded(recentItemsPer)"
|
||||
:key="content.key"
|
||||
xs4
|
||||
sm2
|
||||
md1
|
||||
xl1
|
||||
lg1
|
||||
class="pb-3 pa-3"
|
||||
>
|
||||
<plexthumb
|
||||
:content="content"
|
||||
:server="server"
|
||||
type="thumb"
|
||||
full-title
|
||||
locked
|
||||
@contentSet="setContent(content)"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
|
@ -66,8 +182,6 @@ export default {
|
|||
components: {
|
||||
plexthumb,
|
||||
},
|
||||
created() {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
browsingLibrary: null,
|
||||
|
@ -82,25 +196,6 @@ export default {
|
|||
onDeckOffset: 0,
|
||||
recentlyAddedOffset: 0,
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
this.server.getAllLibraries().then((data) => {
|
||||
if (data) {
|
||||
this.libraries = data;
|
||||
} else {
|
||||
this.status = 'Error loading libraries!';
|
||||
}
|
||||
});
|
||||
this.server.getRecentlyAddedAll(0, 12).then((result) => {
|
||||
if (result) {
|
||||
this.recentlyAdded = result;
|
||||
this.setBackground();
|
||||
}
|
||||
});
|
||||
this.updateOnDeck();
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
||||
},
|
||||
computed: {
|
||||
recentItemsPer() {
|
||||
|
@ -170,6 +265,27 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
},
|
||||
created() {
|
||||
},
|
||||
async mounted() {
|
||||
this.server.getAllLibraries().then((data) => {
|
||||
if (data) {
|
||||
this.libraries = data;
|
||||
} else {
|
||||
this.status = 'Error loading libraries!';
|
||||
}
|
||||
});
|
||||
this.server.getRecentlyAddedAll(0, 12).then((result) => {
|
||||
if (result) {
|
||||
this.recentlyAdded = result;
|
||||
this.setBackground();
|
||||
}
|
||||
});
|
||||
this.updateOnDeck();
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
setContent(content) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div
|
||||
class="portrait"
|
||||
ref="root"
|
||||
class="portrait"
|
||||
style="cursor: pointer"
|
||||
@mouseover="hovering = true"
|
||||
@mouseout="hovering = false"
|
||||
|
@ -9,9 +9,9 @@
|
|||
<router-link :to="link">
|
||||
<v-card
|
||||
flat
|
||||
v-on:click.native="emitContentClicked(content)"
|
||||
class="grey darken-4 elevation-20"
|
||||
style="border-radius: 0px !important"
|
||||
@click.native="emitContentClicked(content)"
|
||||
>
|
||||
<v-img
|
||||
data-tilt
|
||||
|
@ -20,19 +20,23 @@
|
|||
:height="calculatedHeight"
|
||||
:src="getImg(content)"
|
||||
>
|
||||
<v-container class="pa-0 ma-0" fill-height fluid style="position:relative">
|
||||
<v-container
|
||||
class="pa-0 ma-0"
|
||||
fill-height
|
||||
fluid
|
||||
style="position:relative"
|
||||
>
|
||||
<v-layout>
|
||||
<v-flex xs12>
|
||||
<small
|
||||
class="ma-1"
|
||||
v-if="showServer !== undefined"
|
||||
class="ma-1"
|
||||
style="position:absolute; top:0;text-align:right;right:0;background: rgba(0, 0, 0, .5)"
|
||||
>
|
||||
{{ server.name }}</small
|
||||
>
|
||||
{{ server.name }}</small>
|
||||
<div
|
||||
class="pt-content-unwatched pt-orange unwatched"
|
||||
v-if="showUnwatchedFlag && showServer == undefined"
|
||||
class="pt-content-unwatched pt-orange unwatched"
|
||||
>
|
||||
<span class="pa-2 black--text">
|
||||
<span>
|
||||
|
@ -41,8 +45,8 @@
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
style="position:absolute; right:0; background-color: rgba(43, 43, 191, 0.8)"
|
||||
v-if="content.Media && content.Media.length != 1 && showServer == undefined"
|
||||
style="position:absolute; right:0; background-color: rgba(43, 43, 191, 0.8)"
|
||||
>
|
||||
<span class="pa-2 black--text">
|
||||
<span>
|
||||
|
@ -50,16 +54,26 @@
|
|||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<v-container fill-height fluid class="pa-0" style="max-width:100%">
|
||||
<v-layout row wrap justify-end align-end>
|
||||
<v-container
|
||||
fill-height
|
||||
fluid
|
||||
class="pa-0"
|
||||
style="max-width:100%"
|
||||
>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-end
|
||||
align-end
|
||||
>
|
||||
<v-flex xs12>
|
||||
<v-progress-linear
|
||||
v-if="showProgressBar"
|
||||
style="width:100%"
|
||||
class="pa-0 mb-0 ma-0 pt-content-progress"
|
||||
v-if="showProgressBar"
|
||||
height="1"
|
||||
:value="unwatchedPercent"
|
||||
></v-progress-linear>
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
|
@ -68,12 +82,33 @@
|
|||
</v-container>
|
||||
</v-img>
|
||||
</v-card>
|
||||
<v-layout align-end row wrap class="text-xs-left pa-1 white--text" style="max-width: 100%">
|
||||
<v-flex xs12 v-if="!bottomOnly" style="max-width: 100%">
|
||||
<div class="truncate" style="font-size:1rem">{{ getTitle(content) }}</div>
|
||||
<v-layout
|
||||
align-end
|
||||
row
|
||||
wrap
|
||||
class="text-xs-left pa-1 white--text"
|
||||
style="max-width: 100%"
|
||||
>
|
||||
<v-flex
|
||||
v-if="!bottomOnly"
|
||||
xs12
|
||||
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
|
||||
ref="bottomText"
|
||||
xs12
|
||||
style="font-size:0.8rem"
|
||||
>
|
||||
<div class="truncate soft-text">
|
||||
{{ getUnder(content) }}
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</router-link>
|
||||
|
@ -84,6 +119,7 @@
|
|||
import VanillaTilt from 'vanilla-tilt';
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
props: [
|
||||
'library',
|
||||
'showServer',
|
||||
|
@ -98,10 +134,6 @@ export default {
|
|||
'bottomOnly',
|
||||
'spoilerFilter',
|
||||
],
|
||||
components: {},
|
||||
created() {
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fullheight: null,
|
||||
|
@ -112,36 +144,6 @@ export default {
|
|||
hovering: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.fullheight = this.$refs.root.offsetHeight;
|
||||
// console.log(this.$refs)
|
||||
this.fullwidth = this.$refs.root.offsetWidth;
|
||||
if (this.$refs.topText) {
|
||||
this.toptextheight = this.$refs.topText.offsetHeight;
|
||||
}
|
||||
if (this.$refs.bottomText) {
|
||||
this.bottomtextheight = this.$refs.bottomText.offsetHeight;
|
||||
}
|
||||
if (this.type === 'thumb') {
|
||||
VanillaTilt.init(this.$refs.root, {
|
||||
reverse: true, // reverse the tilt direction
|
||||
max: 7, // max tilt rotation (degrees)
|
||||
perspective: 1000, // Transform perspective, the lower the more extreme the tilt gets.
|
||||
scale: 1.01, // 2 = 200%, 1.5 = 150%, etc..
|
||||
speed: 100, // Speed of the enter/exit transition
|
||||
transition: true, // Set a transition on enter/exit.
|
||||
axis: null, // What axis should be disabled. Can be X or Y.
|
||||
reset: true, // If the tilt effect has to be reset on exit.
|
||||
easing: 'cubic-bezier(.03,.98,.52,.99)', // Easing on enter/exit.
|
||||
glare: false, // if it should have a "glare" effect
|
||||
'max-glare': 0.15, // the maximum "glare" opacity (1 = 100%, 0.5 = 50%)
|
||||
'glare-prerender': false, // false = VanillaTilt creates the glare elements for you, otherwise
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
},
|
||||
computed: {
|
||||
plex() {
|
||||
return this.$store.getters.getPlex;
|
||||
|
@ -336,6 +338,39 @@ export default {
|
|||
return (this.content.viewedLeafCount / this.content.leafCount) * 100;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
},
|
||||
mounted() {
|
||||
this.fullheight = this.$refs.root.offsetHeight;
|
||||
// console.log(this.$refs)
|
||||
this.fullwidth = this.$refs.root.offsetWidth;
|
||||
if (this.$refs.topText) {
|
||||
this.toptextheight = this.$refs.topText.offsetHeight;
|
||||
}
|
||||
if (this.$refs.bottomText) {
|
||||
this.bottomtextheight = this.$refs.bottomText.offsetHeight;
|
||||
}
|
||||
if (this.type === 'thumb') {
|
||||
VanillaTilt.init(this.$refs.root, {
|
||||
reverse: true, // reverse the tilt direction
|
||||
max: 7, // max tilt rotation (degrees)
|
||||
perspective: 1000, // Transform perspective, the lower the more extreme the tilt gets.
|
||||
scale: 1.01, // 2 = 200%, 1.5 = 150%, etc..
|
||||
speed: 100, // Speed of the enter/exit transition
|
||||
transition: true, // Set a transition on enter/exit.
|
||||
axis: null, // What axis should be disabled. Can be X or Y.
|
||||
reset: true, // If the tilt effect has to be reset on exit.
|
||||
easing: 'cubic-bezier(.03,.98,.52,.99)', // Easing on enter/exit.
|
||||
glare: false, // if it should have a "glare" effect
|
||||
'max-glare': 0.15, // the maximum "glare" opacity (1 = 100%, 0.5 = 50%)
|
||||
'glare-prerender': false, // false = VanillaTilt creates the glare elements for you, otherwise
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
},
|
||||
methods: {
|
||||
emitContentClicked(content) {
|
||||
this.$emit('contentSet', content);
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
<template>
|
||||
<v-list-item :style="styleObj" class="pa-1">
|
||||
<v-list-item
|
||||
:style="styleObj"
|
||||
class="pa-1"
|
||||
>
|
||||
<v-list-item-avatar>
|
||||
<img class="clientLogo" :class="platformClass" :src="url" />
|
||||
<img
|
||||
class="clientLogo"
|
||||
:class="platformClass"
|
||||
:src="url"
|
||||
>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
|
@ -12,7 +19,9 @@
|
|||
:color="label[1]"
|
||||
small
|
||||
label
|
||||
>{{ label[0] }}</v-chip>
|
||||
>
|
||||
{{ label[0] }}
|
||||
</v-chip>
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ object.product }} - last seen {{ lastSeenAgo }}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
|
@ -23,9 +32,47 @@
|
|||
const moment = require('moment');
|
||||
|
||||
export default {
|
||||
name: 'Plexclient',
|
||||
props: ['object', 'selected', 'startup', 'sidebar'],
|
||||
name: 'plexclient',
|
||||
methods: {},
|
||||
data: () => ({
|
||||
platformMap: {
|
||||
android: 'android',
|
||||
'apple tv': 'atv',
|
||||
chrome: 'chrome',
|
||||
chromecast: 'chromecast',
|
||||
dlna: 'dlna',
|
||||
firefox: 'firefox',
|
||||
'internet explorer': 'ie',
|
||||
ios: 'ios',
|
||||
ipad: 'ios',
|
||||
iphone: 'ios',
|
||||
kodi: 'kodi',
|
||||
linux: 'linux',
|
||||
nexus: 'android',
|
||||
macos: 'macos',
|
||||
'microsoft edge': 'msedge',
|
||||
opera: 'opera',
|
||||
osx: 'macos',
|
||||
playstation: 'playstation',
|
||||
'plex home theater': 'plex',
|
||||
'plex media player': 'plex',
|
||||
plexamp: 'plexamp',
|
||||
plextogether: 'synclounge',
|
||||
roku: 'roku',
|
||||
safari: 'safari',
|
||||
samsung: 'samsung',
|
||||
synclounge: 'synclounge',
|
||||
tivo: 'tivo',
|
||||
tizen: 'samsung',
|
||||
tvos: 'atv',
|
||||
vizio: 'opera',
|
||||
wiiu: 'wiiu',
|
||||
windows: 'windows',
|
||||
'windows phone': 'wp',
|
||||
xbmc: 'xbmc',
|
||||
xbox: 'xbox',
|
||||
},
|
||||
}),
|
||||
computed: {
|
||||
tooltipMsg() {
|
||||
return `${this.object.name} running ${this.object.product} on ${this.object.device}`;
|
||||
|
@ -84,44 +131,6 @@ export default {
|
|||
};
|
||||
},
|
||||
},
|
||||
data: () => ({
|
||||
platformMap: {
|
||||
android: 'android',
|
||||
'apple tv': 'atv',
|
||||
chrome: 'chrome',
|
||||
chromecast: 'chromecast',
|
||||
dlna: 'dlna',
|
||||
firefox: 'firefox',
|
||||
'internet explorer': 'ie',
|
||||
ios: 'ios',
|
||||
ipad: 'ios',
|
||||
iphone: 'ios',
|
||||
kodi: 'kodi',
|
||||
linux: 'linux',
|
||||
nexus: 'android',
|
||||
macos: 'macos',
|
||||
'microsoft edge': 'msedge',
|
||||
opera: 'opera',
|
||||
osx: 'macos',
|
||||
playstation: 'playstation',
|
||||
'plex home theater': 'plex',
|
||||
'plex media player': 'plex',
|
||||
plexamp: 'plexamp',
|
||||
plextogether: 'synclounge',
|
||||
roku: 'roku',
|
||||
safari: 'safari',
|
||||
samsung: 'samsung',
|
||||
synclounge: 'synclounge',
|
||||
tivo: 'tivo',
|
||||
tizen: 'samsung',
|
||||
tvos: 'atv',
|
||||
vizio: 'opera',
|
||||
wiiu: 'wiiu',
|
||||
windows: 'windows',
|
||||
'windows phone': 'wp',
|
||||
xbmc: 'xbmc',
|
||||
xbox: 'xbox',
|
||||
},
|
||||
}),
|
||||
methods: {},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,35 +1,43 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="pt-1 text-xs-left">
|
||||
<h4 style="text-align:initial">Blocked Plex Servers</h4>
|
||||
<small
|
||||
>Used for autoplay functionality. Use this list to block SyncLounge from searching certain
|
||||
servers when attempting to autoplay content.</small
|
||||
>
|
||||
<h4 style="text-align:initial">
|
||||
Blocked Plex Servers
|
||||
</h4>
|
||||
<small>Used for autoplay functionality. Use this list to block SyncLounge from searching certain
|
||||
servers when attempting to autoplay content.</small>
|
||||
<v-select
|
||||
v-model="BLOCKEDSERVERS"
|
||||
label="Select"
|
||||
:items="localServersList"
|
||||
v-model="BLOCKEDSERVERS"
|
||||
item-value="id"
|
||||
item-text="name"
|
||||
multiple
|
||||
hint="Blocked Servers"
|
||||
persistent-hint
|
||||
></v-select>
|
||||
/>
|
||||
</div>
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12> </v-flex>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex xs12 />
|
||||
</v-layout>
|
||||
<v-divider></v-divider>
|
||||
<v-divider />
|
||||
<div class="pt-4 text-xs-left">
|
||||
<h4 style="text-align:initial">Change display name</h4>
|
||||
<v-checkbox label="Enabled" v-model="HIDEUSERNAME"></v-checkbox>
|
||||
<h4 style="text-align:initial">
|
||||
Change display name
|
||||
</h4>
|
||||
<v-checkbox
|
||||
v-model="HIDEUSERNAME"
|
||||
label="Enabled"
|
||||
/>
|
||||
<v-text-field
|
||||
v-if="HIDEUSERNAME"
|
||||
:value="GET_ALTUSERNAME"
|
||||
@change="SET_ALTUSERNAME"
|
||||
label="Alternative username"
|
||||
></v-text-field>
|
||||
@change="SET_ALTUSERNAME"
|
||||
/>
|
||||
<small>By default SyncLounge uses your Plex.tv username when you join a room.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -39,7 +47,7 @@
|
|||
import { mapGetters, mapMutations } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'plexsettings',
|
||||
name: 'Plexsettings',
|
||||
methods: {
|
||||
...mapMutations('settings', ['SET_HIDEUSERNAME', 'SET_ALTUSERNAME', 'SET_BLOCKEDSERVERS']),
|
||||
},
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
<template>
|
||||
<div style="width:100%; position: relative">
|
||||
<div style="position: relative" @mouseover="hovered = true" @mouseout="hovered = false">
|
||||
<div
|
||||
style="position: relative"
|
||||
@mouseover="hovered = true"
|
||||
@mouseout="hovered = false"
|
||||
>
|
||||
<videoplayer
|
||||
v-if="playingMetadata && chosenServer && GET_SLPLAYERQUALITY && ready"
|
||||
@playerMounted="playerMounted()"
|
||||
@timelineUpdate="timelineUpdate"
|
||||
@playbackEnded="stopPlayback()"
|
||||
:metadata="playingMetadata"
|
||||
:server="chosenServer"
|
||||
:src="getSourceByLabel(GET_SLPLAYERQUALITY)"
|
||||
:initUrl="getSourceByLabel(GET_SLPLAYERQUALITY).initUrl"
|
||||
:init-url="getSourceByLabel(GET_SLPLAYERQUALITY).initUrl"
|
||||
:params="getSourceByLabel(GET_SLPLAYERQUALITY).params"
|
||||
:initialOffset="offset"
|
||||
:createdAt="playerCreatedAt"
|
||||
></videoplayer>
|
||||
:initial-offset="offset"
|
||||
:created-at="playerCreatedAt"
|
||||
@playerMounted="playerMounted()"
|
||||
@timelineUpdate="timelineUpdate"
|
||||
@playbackEnded="stopPlayback()"
|
||||
/>
|
||||
<div v-if="playingMetadata && chosenServer">
|
||||
<transition name="fade">
|
||||
<div v-show="hovered">
|
||||
|
@ -27,10 +31,17 @@
|
|||
:src="thumbUrl"
|
||||
class="elevation-20"
|
||||
style="height: 80px; width: auto; vertical-align: middle; margin-left: auto; margin-right: auto;"
|
||||
/>
|
||||
>
|
||||
<v-flex class="pl-3">
|
||||
<v-container class="pa-0" fill-height>
|
||||
<v-layout column wrap justify-space-apart>
|
||||
<v-container
|
||||
class="pa-0"
|
||||
fill-height
|
||||
>
|
||||
<v-layout
|
||||
column
|
||||
wrap
|
||||
justify-space-apart
|
||||
>
|
||||
<v-flex>
|
||||
<h1>{{ getTitle(playingMetadata) }}</h1>
|
||||
</v-flex>
|
||||
|
@ -52,23 +63,36 @@
|
|||
>
|
||||
<v-flex class="text-xs-right pa-1">
|
||||
<div class="hidden-xs-only">
|
||||
<v-tooltip bottom color="accent" v-if="GET_ME && GET_ME.role !== 'host'">
|
||||
<v-tooltip
|
||||
v-if="GET_ME && GET_ME.role !== 'host'"
|
||||
bottom
|
||||
color="accent"
|
||||
>
|
||||
<v-icon
|
||||
color="white"
|
||||
class="clickable"
|
||||
:disabled="GET_MANUAL_SYNC_QUEUED"
|
||||
v-on:click="TRIGGER_MANUAL_SYNC"
|
||||
>compare_arrows</v-icon
|
||||
@click="TRIGGER_MANUAL_SYNC"
|
||||
>
|
||||
compare_arrows
|
||||
</v-icon>
|
||||
Manual Sync
|
||||
</v-tooltip>
|
||||
<v-icon color="white" class="clickable pl-3" v-on:click="dialog = !dialog"
|
||||
>settings</v-icon
|
||||
<v-icon
|
||||
color="white"
|
||||
class="clickable pl-3"
|
||||
@click="dialog = !dialog"
|
||||
>
|
||||
settings
|
||||
</v-icon>
|
||||
<router-link to="/browse">
|
||||
<v-icon color="white" class="pl-3" v-on:click.native="stopPlayback()"
|
||||
>close</v-icon
|
||||
<v-icon
|
||||
color="white"
|
||||
class="pl-3"
|
||||
@click.native="stopPlayback()"
|
||||
>
|
||||
close
|
||||
</v-icon>
|
||||
</router-link>
|
||||
</div>
|
||||
</v-flex>
|
||||
|
@ -79,28 +103,34 @@
|
|||
class="hoverBar"
|
||||
style="height: 120px; width: 100%; pointer-events: none; position: absolute; top: 0;"
|
||||
>
|
||||
<v-flex xs12> </v-flex>
|
||||
<v-flex xs12 />
|
||||
</v-layout>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
<div class="messages-wrapper" v-if="$vuetify.breakpoint.mdAndDown">
|
||||
<messages></messages>
|
||||
<div
|
||||
v-if="$vuetify.breakpoint.mdAndDown"
|
||||
class="messages-wrapper"
|
||||
>
|
||||
<messages />
|
||||
</div>
|
||||
<v-dialog v-model="dialog" width="350">
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
width="350"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title>Playback Settings </v-card-title>
|
||||
<v-card-text>
|
||||
<v-select
|
||||
:value="GET_SLPLAYERQUALITY"
|
||||
@input="changeQuality"
|
||||
:items="qualitiesSelect"
|
||||
item-text="text"
|
||||
item-value="id"
|
||||
persistent-hint
|
||||
label="Quality"
|
||||
hint="Select a different quality"
|
||||
></v-select>
|
||||
@input="changeQuality"
|
||||
/>
|
||||
<v-select
|
||||
v-model="chosenAudioTrackIndex"
|
||||
:select-text="'Default'"
|
||||
|
@ -110,30 +140,36 @@
|
|||
persistent-hint
|
||||
hint="Select a different audio track"
|
||||
:items="audioTrackSelect"
|
||||
></v-select>
|
||||
/>
|
||||
<v-select
|
||||
v-model="chosenSubtitleIndex"
|
||||
persistent-hint
|
||||
label="Subtitles"
|
||||
item-text="text"
|
||||
item-value="id"
|
||||
hint="Select a different subtitle track"
|
||||
v-model="chosenSubtitleIndex"
|
||||
:select-text="'Default'"
|
||||
:items="subtitleTrackSelect"
|
||||
></v-select>
|
||||
/>
|
||||
<v-select
|
||||
v-if="mediaIndexSelect.length > 1"
|
||||
v-model="chosenMediaIndex"
|
||||
persistent-hint
|
||||
item-text="text"
|
||||
item-value="id"
|
||||
hint="Select a different version of the content you're playing"
|
||||
v-model="chosenMediaIndex"
|
||||
label="Version"
|
||||
:items="mediaIndexSelect"
|
||||
></v-select>
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn class="blue--text darken-1" text @click.native="dialog = false">Close</v-btn>
|
||||
<v-btn
|
||||
class="blue--text darken-1"
|
||||
text
|
||||
@click.native="dialog = false"
|
||||
>
|
||||
Close
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
@ -144,15 +180,25 @@
|
|||
class="pa-3 hidden-sm-and-up"
|
||||
>
|
||||
<v-flex xs12>
|
||||
<v-layout row wrap>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<img
|
||||
:src="thumbUrl"
|
||||
class="elevation-20"
|
||||
style="height: 80px; width: auto; vertical-align: middle; margin-left: auto; margin-right: auto"
|
||||
/>
|
||||
>
|
||||
<v-flex class="pl-2">
|
||||
<v-container class="pa-0" fill-height>
|
||||
<v-layout column wrap justify-space-apart>
|
||||
<v-container
|
||||
class="pa-0"
|
||||
fill-height
|
||||
>
|
||||
<v-layout
|
||||
column
|
||||
wrap
|
||||
justify-space-apart
|
||||
>
|
||||
<v-flex>
|
||||
<h1>{{ getTitle(playingMetadata) }}</h1>
|
||||
</v-flex>
|
||||
|
@ -165,27 +211,40 @@
|
|||
</v-layout>
|
||||
</v-container>
|
||||
</v-flex>
|
||||
<v-layout row wrap class="">
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
class=""
|
||||
>
|
||||
<v-flex xs12>
|
||||
<v-btn
|
||||
v-if="GET_ME.role !== 'host'"
|
||||
block
|
||||
:disabled="GET_MANUAL_SYNC_QUEUED"
|
||||
color="blue"
|
||||
v-on:click.native="TRIGGER_MANUAL_SYNC"
|
||||
v-if="GET_ME.role !== 'host'"
|
||||
>Manual sync</v-btn
|
||||
@click.native="TRIGGER_MANUAL_SYNC"
|
||||
>
|
||||
Manual sync
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
<v-flex xs12>
|
||||
<v-btn block color="primary" v-on:click.native="dialog = !dialog"
|
||||
>Playback Settings</v-btn
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
@click.native="dialog = !dialog"
|
||||
>
|
||||
Playback Settings
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
<v-flex xs12>
|
||||
<router-link to="/browse">
|
||||
<v-btn block color="error" v-on:click.native="stopPlayback()"
|
||||
>Stop playback</v-btn
|
||||
<v-btn
|
||||
block
|
||||
color="error"
|
||||
@click.native="stopPlayback()"
|
||||
>
|
||||
Stop playback
|
||||
</v-btn>
|
||||
</router-link>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
@ -217,108 +276,11 @@ const request = require('request');
|
|||
const parseXMLString = require('xml2js').parseString;
|
||||
|
||||
export default {
|
||||
name: 'ptplayer',
|
||||
name: 'Ptplayer',
|
||||
components: {
|
||||
videoplayer,
|
||||
messages,
|
||||
},
|
||||
mounted() {
|
||||
// Check if we have params
|
||||
if (this.$route.query.start) {
|
||||
// We need to auto play
|
||||
const { query } = this.$route;
|
||||
this.chosenKey = query.key.replace('/library/metadata/', '');
|
||||
this.chosenMediaIndex = query.mediaIndex || 0;
|
||||
this.chosenServer = this.getPlex.servers[query.chosenServer];
|
||||
this.offset = query.playertime;
|
||||
}
|
||||
|
||||
// Similuate a real plex client
|
||||
this.commandListener = this.eventbus.$on('command', (data) => {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
if (data.command === '/player/timeline/poll') {
|
||||
const key = this.chosenKey;
|
||||
let ratingKey = null;
|
||||
if (key) {
|
||||
ratingKey = `/library/metadata/${key}`;
|
||||
}
|
||||
|
||||
let machineIdentifier = null;
|
||||
if (this.chosenServer) {
|
||||
machineIdentifier = this.chosenServer.clientIdentifier;
|
||||
}
|
||||
const playerdata = {
|
||||
key,
|
||||
ratingKey,
|
||||
time: this.playertime,
|
||||
type: 'video',
|
||||
machineIdentifier,
|
||||
duration: this.playerduration,
|
||||
state: this.playerstatus,
|
||||
};
|
||||
this.lastSentTimeline = playerdata;
|
||||
if (this.playertime) {
|
||||
this.eventbus.$emit('ptplayer-poll', (err, time) => {
|
||||
if (err) {
|
||||
return data.callback(this.playertime);
|
||||
}
|
||||
// let difference = Math.abs(time - this.playertime)
|
||||
// console.log('Poll time was out by', difference)
|
||||
playerdata.time = time;
|
||||
this.playertime = time;
|
||||
data.callback(playerdata);
|
||||
});
|
||||
} else {
|
||||
data.callback(playerdata);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (data.command === '/player/playback/play') {
|
||||
this.eventbus.$emit('player-press-play', (res) => data.callback(res));
|
||||
return;
|
||||
}
|
||||
if (data.command === '/player/playback/pause') {
|
||||
this.eventbus.$emit('player-press-pause', (res) => data.callback(res));
|
||||
return;
|
||||
}
|
||||
if (data.command === '/player/playback/playMedia') {
|
||||
this.chosenKey = data.params.key.replace('/library/metadata/', '');
|
||||
this.chosenMediaIndex = data.params.mediaIndex || 0;
|
||||
this.chosenServer = this.getPlex.servers[data.params.machineIdentifier];
|
||||
this.playertime = data.params.offset || this.$route.query.playertime || 0;
|
||||
this.offset = this.playertime;
|
||||
this.$nextTick(() => {
|
||||
this.changedPlaying(true);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (data.command === '/player/playback/stop') {
|
||||
this.ready = false;
|
||||
this.chosenKey = null;
|
||||
this.chosenServer = null;
|
||||
this.playerduration = null;
|
||||
this.playertime = 0;
|
||||
this.bufferedTile = null;
|
||||
this.playingMetadata = null;
|
||||
this.$router.push('/browse');
|
||||
return data.callback(true);
|
||||
}
|
||||
if (data.command === '/player/playback/seekTo') {
|
||||
this.eventbus.$emit('player-seek', {
|
||||
time: data.params.offset,
|
||||
soft: data.params.softSeek,
|
||||
callback: async (promise) => {
|
||||
await promise.catch(() => {
|
||||
data.callback(false);
|
||||
});
|
||||
data.callback(true);
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hovered: false,
|
||||
|
@ -444,6 +406,103 @@ export default {
|
|||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// Check if we have params
|
||||
if (this.$route.query.start) {
|
||||
// We need to auto play
|
||||
const { query } = this.$route;
|
||||
this.chosenKey = query.key.replace('/library/metadata/', '');
|
||||
this.chosenMediaIndex = query.mediaIndex || 0;
|
||||
this.chosenServer = this.getPlex.servers[query.chosenServer];
|
||||
this.offset = query.playertime;
|
||||
}
|
||||
|
||||
// Similuate a real plex client
|
||||
this.commandListener = this.eventbus.$on('command', (data) => {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
if (data.command === '/player/timeline/poll') {
|
||||
const key = this.chosenKey;
|
||||
let ratingKey = null;
|
||||
if (key) {
|
||||
ratingKey = `/library/metadata/${key}`;
|
||||
}
|
||||
|
||||
let machineIdentifier = null;
|
||||
if (this.chosenServer) {
|
||||
machineIdentifier = this.chosenServer.clientIdentifier;
|
||||
}
|
||||
const playerdata = {
|
||||
key,
|
||||
ratingKey,
|
||||
time: this.playertime,
|
||||
type: 'video',
|
||||
machineIdentifier,
|
||||
duration: this.playerduration,
|
||||
state: this.playerstatus,
|
||||
};
|
||||
this.lastSentTimeline = playerdata;
|
||||
if (this.playertime) {
|
||||
this.eventbus.$emit('ptplayer-poll', (err, time) => {
|
||||
if (err) {
|
||||
return data.callback(this.playertime);
|
||||
}
|
||||
// let difference = Math.abs(time - this.playertime)
|
||||
// console.log('Poll time was out by', difference)
|
||||
playerdata.time = time;
|
||||
this.playertime = time;
|
||||
data.callback(playerdata);
|
||||
});
|
||||
} else {
|
||||
data.callback(playerdata);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (data.command === '/player/playback/play') {
|
||||
this.eventbus.$emit('player-press-play', (res) => data.callback(res));
|
||||
return;
|
||||
}
|
||||
if (data.command === '/player/playback/pause') {
|
||||
this.eventbus.$emit('player-press-pause', (res) => data.callback(res));
|
||||
return;
|
||||
}
|
||||
if (data.command === '/player/playback/playMedia') {
|
||||
this.chosenKey = data.params.key.replace('/library/metadata/', '');
|
||||
this.chosenMediaIndex = data.params.mediaIndex || 0;
|
||||
this.chosenServer = this.getPlex.servers[data.params.machineIdentifier];
|
||||
this.playertime = data.params.offset || this.$route.query.playertime || 0;
|
||||
this.offset = this.playertime;
|
||||
this.$nextTick(() => {
|
||||
this.changedPlaying(true);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (data.command === '/player/playback/stop') {
|
||||
this.ready = false;
|
||||
this.chosenKey = null;
|
||||
this.chosenServer = null;
|
||||
this.playerduration = null;
|
||||
this.playertime = 0;
|
||||
this.bufferedTile = null;
|
||||
this.playingMetadata = null;
|
||||
this.$router.push('/browse');
|
||||
return data.callback(true);
|
||||
}
|
||||
if (data.command === '/player/playback/seekTo') {
|
||||
this.eventbus.$emit('player-seek', {
|
||||
time: data.params.offset,
|
||||
soft: data.params.softSeek,
|
||||
callback: async (promise) => {
|
||||
await promise.catch(() => {
|
||||
data.callback(false);
|
||||
});
|
||||
data.callback(true);
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getPlex', 'getChosenClient', 'GET_MANUAL_SYNC_QUEUED', 'GET_ME']),
|
||||
...mapGetters('settings', ['GET_SLPLAYERQUALITY', 'GET_SLPLAYERFORCETRANSCODE']),
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
<videojs-player
|
||||
ref="videoPlayer"
|
||||
:options="playerOptions"
|
||||
style="background-color:transparent !important;"
|
||||
class="ptplayer"
|
||||
@play="onPlayerPlay($event)"
|
||||
@pause="onPlayerPause($event)"
|
||||
@loadeddata="onPlayerLoadeddata($event)"
|
||||
|
@ -17,11 +19,11 @@
|
|||
@statechanged="playerStateChanged($event)"
|
||||
@volumechange="volumeChange($event)"
|
||||
@ready="playerReadied($event)"
|
||||
style="background-color:transparent !important;"
|
||||
class="ptplayer"
|
||||
/>
|
||||
<div
|
||||
v-if="!src"
|
||||
class="center"
|
||||
>
|
||||
</videojs-player>
|
||||
<div class="center" v-if="!src">
|
||||
Waiting...
|
||||
</div>
|
||||
</div>
|
||||
|
@ -35,7 +37,6 @@ const request = require('request');
|
|||
|
||||
export default {
|
||||
props: ['server', 'metadata', 'initialOffset', 'src', 'initUrl', 'stopUrl', 'params', 'sources'],
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
eventbus: window.EventBus,
|
||||
|
@ -56,6 +57,7 @@ export default {
|
|||
playbackRate: 1,
|
||||
};
|
||||
},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.source = this.src;
|
||||
this.initReqSent = true;
|
||||
|
|
|
@ -1,51 +1,88 @@
|
|||
<template>
|
||||
<div>
|
||||
<div style="text-align:center">
|
||||
<h4 style="text-align:initial">Plex Client Polling Interval</h4>
|
||||
<h4 style="text-align:initial">
|
||||
Plex Client Polling Interval
|
||||
</h4>
|
||||
<div> {{ GET_CLIENTPOLLINTERVAL }}</div>
|
||||
<v-slider class="pa-0 ma-0" :value="GET_CLIENTPOLLINTERVAL" @change="SET_CLIENTPOLLINTERVAL" :min="100" :max="10000"
|
||||
<v-slider
|
||||
class="pa-0 ma-0"
|
||||
:value="GET_CLIENTPOLLINTERVAL"
|
||||
:min="100"
|
||||
:max="10000"
|
||||
hint="Sets how frequently SyncLounge will poll external plex clients for new information in milliseconds. Default is 1000ms (1 second)"
|
||||
persistent-hint
|
||||
>
|
||||
</v-slider>
|
||||
@change="SET_CLIENTPOLLINTERVAL"
|
||||
/>
|
||||
</div>
|
||||
<v-divider></v-divider>
|
||||
<div style="text-align:center" class="pt-4">
|
||||
<h4 style="text-align:initial">Sync Flexibility</h4>
|
||||
<v-divider />
|
||||
<div
|
||||
style="text-align:center"
|
||||
class="pt-4"
|
||||
>
|
||||
<h4 style="text-align:initial">
|
||||
Sync Flexibility
|
||||
</h4>
|
||||
<div> {{ GET_SYNCFLEXIBILITY }}</div>
|
||||
<v-slider class="pa-0 ma-0" :value="GET_SYNCFLEXIBILITY" @change="SET_SYNCFLEXIBILITY" :min="0" :max="10000"
|
||||
<v-slider
|
||||
class="pa-0 ma-0"
|
||||
:value="GET_SYNCFLEXIBILITY"
|
||||
:min="0"
|
||||
:max="10000"
|
||||
hint="Sets the acceptable distance away from the host in milliseconds. Default is 3000ms (3 seconds)."
|
||||
persistent-hint
|
||||
>
|
||||
</v-slider>
|
||||
@change="SET_SYNCFLEXIBILITY"
|
||||
/>
|
||||
</div>
|
||||
<v-divider></v-divider>
|
||||
<div style="text-align:center" class="pt-4">
|
||||
<h4 style="text-align:initial">Syncing Method</h4>
|
||||
<v-divider />
|
||||
<div
|
||||
style="text-align:center"
|
||||
class="pt-4"
|
||||
>
|
||||
<h4 style="text-align:initial">
|
||||
Syncing Method
|
||||
</h4>
|
||||
<v-radio-group v-model="syncmode">
|
||||
<v-radio label="Clean Seek" class="pa-0 ma-0" value="cleanseek"></v-radio>
|
||||
<v-radio label="Skip Ahead" class="pa-0 ma-0" value="skipahead"
|
||||
persistent-hint
|
||||
hint="Sets the syncing method used when we need to get back in line with the host."
|
||||
></v-radio>
|
||||
<v-radio
|
||||
label="Clean Seek"
|
||||
class="pa-0 ma-0"
|
||||
value="cleanseek"
|
||||
/>
|
||||
<v-radio
|
||||
label="Skip Ahead"
|
||||
class="pa-0 ma-0"
|
||||
value="skipahead"
|
||||
persistent-hint
|
||||
hint="Sets the syncing method used when we need to get back in line with the host."
|
||||
/>
|
||||
</v-radio-group>
|
||||
</div>
|
||||
<div style="text-align:center" class="pt-4">
|
||||
<h4 style="text-align:initial">Autoplay</h4>
|
||||
<div
|
||||
style="text-align:center"
|
||||
class="pt-4"
|
||||
>
|
||||
<h4 style="text-align:initial">
|
||||
Autoplay
|
||||
</h4>
|
||||
<v-switch
|
||||
label="Enabled"
|
||||
hint="If enabled SyncLounge will attempt to automatically play the same content as the host."
|
||||
:input-value="GET_AUTOPLAY"
|
||||
@change="SET_AUTOPLAY"
|
||||
></v-switch>
|
||||
/>
|
||||
</div>
|
||||
<div style="text-align:center" class="pt-4">
|
||||
<h4 style="text-align:initial">SLPlayer Force Transcode</h4>
|
||||
<v-switch
|
||||
label="Enabled"
|
||||
:input-value="GET_SLPLAYERFORCETRANSCODE"
|
||||
@change="SET_SLPLAYERFORCETRANSCODE"
|
||||
></v-switch>
|
||||
<div
|
||||
style="text-align:center"
|
||||
class="pt-4"
|
||||
>
|
||||
<h4 style="text-align:initial">
|
||||
SLPlayer Force Transcode
|
||||
</h4>
|
||||
<v-switch
|
||||
label="Enabled"
|
||||
:input-value="GET_SLPLAYERFORCETRANSCODE"
|
||||
@change="SET_SLPLAYERFORCETRANSCODE"
|
||||
/>
|
||||
<small>WARNING: EXPERIMENTAL SETTING! DO NOT CHANGE IF YOU DO NOT UNDERSTAND THE RAMIFICATIONS.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -55,7 +92,7 @@
|
|||
import { mapGetters, mapMutations } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'settings',
|
||||
name: 'Settings',
|
||||
computed: {
|
||||
...mapGetters('settings', [
|
||||
'GET_AUTOPLAY',
|
||||
|
|
|
@ -1,22 +1,46 @@
|
|||
<template>
|
||||
<v-row justify="center">
|
||||
<v-col lg="8" style="background: rgba(0,0,0,0.1); border-radius: 10px" class="pa-4">
|
||||
<v-col
|
||||
lg="8"
|
||||
style="background: rgba(0,0,0,0.1); border-radius: 10px"
|
||||
class="pa-4"
|
||||
>
|
||||
<v-row justify="center">
|
||||
<v-col md="8" lg="4">
|
||||
<img style="width:100%" :src="logo" />
|
||||
<v-col
|
||||
md="8"
|
||||
lg="4"
|
||||
>
|
||||
<img
|
||||
style="width:100%"
|
||||
:src="logo"
|
||||
>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-stepper
|
||||
style="background: rgba(0,0,0,0.3); color: white !important; border-radius: 20px"
|
||||
v-model="e1"
|
||||
style="background: rgba(0,0,0,0.3); color: white !important; border-radius: 20px"
|
||||
class="ma-4"
|
||||
>
|
||||
<v-stepper-header dark>
|
||||
<v-stepper-step step="1" dark :complete="true">Select a client</v-stepper-step>
|
||||
<v-divider></v-divider>
|
||||
<v-stepper-step step="2" dark :complete="false">Join a room</v-stepper-step>
|
||||
<v-divider></v-divider>
|
||||
<v-stepper-step step="3">Sync</v-stepper-step>
|
||||
<v-stepper-step
|
||||
step="1"
|
||||
dark
|
||||
:complete="true"
|
||||
>
|
||||
Select a client
|
||||
</v-stepper-step>
|
||||
<v-divider />
|
||||
<v-stepper-step
|
||||
step="2"
|
||||
dark
|
||||
:complete="false"
|
||||
>
|
||||
Join a room
|
||||
</v-stepper-step>
|
||||
<v-divider />
|
||||
<v-stepper-step step="3">
|
||||
Sync
|
||||
</v-stepper-step>
|
||||
</v-stepper-header>
|
||||
</v-stepper>
|
||||
<div v-if="!getChosenClient">
|
||||
|
@ -26,41 +50,79 @@
|
|||
</v-col>
|
||||
</v-row>
|
||||
<v-row class="ml-4">
|
||||
<v-col class="pt-0"
|
||||
>Choose a client from the list below. Once you've found the client you would like to
|
||||
use, click the connect button. SyncLounge will test to see if it can connect with the
|
||||
client and will let you know if it cannot.</v-col
|
||||
<v-col
|
||||
class="pt-0"
|
||||
>
|
||||
Choose a client from the list below. Once you've found the client you would like to
|
||||
use, click the connect button. SyncLounge will test to see if it can connect with the
|
||||
client and will let you know if it cannot.
|
||||
</v-col>
|
||||
</v-row>
|
||||
<div v-if="plex && !plex.gotDevices" class="text-center pa-4">
|
||||
<v-progress-circular indeterminate color="primary"></v-progress-circular>
|
||||
<div
|
||||
v-if="plex && !plex.gotDevices"
|
||||
class="text-center pa-4"
|
||||
>
|
||||
<v-progress-circular
|
||||
indeterminate
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
<v-row v-else justify="center" class="ml-4 mr-4">
|
||||
<v-col md="6" lg="6" v-if="!doReverse">
|
||||
<v-row
|
||||
v-else
|
||||
justify="center"
|
||||
class="ml-4 mr-4"
|
||||
>
|
||||
<v-col
|
||||
v-if="!doReverse"
|
||||
md="6"
|
||||
lg="6"
|
||||
>
|
||||
<v-subheader>
|
||||
Plex Players {{ playercount }}
|
||||
<v-icon @click="PLEX_GET_DEVICES()" class="pl-2" small>refresh</v-icon>
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
small
|
||||
@click="PLEX_GET_DEVICES()"
|
||||
>
|
||||
refresh
|
||||
</v-icon>
|
||||
</v-subheader>
|
||||
<v-list dense style="background: none">
|
||||
<v-list
|
||||
dense
|
||||
style="background: none"
|
||||
>
|
||||
<plexclient
|
||||
v-for="i in recentClients"
|
||||
:key="i.clientIdentifier"
|
||||
:selected="isClientSelected(i)"
|
||||
:object="i"
|
||||
style="cursor: pointer"
|
||||
@click.native="
|
||||
previewClient(i);
|
||||
gotResponse = true;
|
||||
"
|
||||
:selected="isClientSelected(i)"
|
||||
:object="i"
|
||||
style="cursor: pointer"
|
||||
></plexclient>
|
||||
/>
|
||||
</v-list>
|
||||
</v-col>
|
||||
<v-col md="6" lg="6">
|
||||
<div v-if="testClient" class="pa-2">
|
||||
<v-col
|
||||
md="6"
|
||||
lg="6"
|
||||
>
|
||||
<div
|
||||
v-if="testClient"
|
||||
class="pa-2"
|
||||
>
|
||||
<v-subheader>Selected Player</v-subheader>
|
||||
<v-row>
|
||||
<v-col md="3" class="text-center" style="position: relative">
|
||||
<img :src="url" style="height: 100px; width: auto; vertical-align: middle" />
|
||||
<v-col
|
||||
md="3"
|
||||
class="text-center"
|
||||
style="position: relative"
|
||||
>
|
||||
<img
|
||||
:src="url"
|
||||
style="height: 100px; width: auto; vertical-align: middle"
|
||||
>
|
||||
</v-col>
|
||||
<v-col md="9">
|
||||
<div class="selected-player-details pl-1">
|
||||
|
@ -81,7 +143,10 @@
|
|||
<label>Platform</label>
|
||||
<span style="opacity:0.8">{{ testClient.platform }}</span>
|
||||
</div>
|
||||
<div class="red--text text--lighten-1" v-if="testClientErrorMsg">
|
||||
<div
|
||||
v-if="testClientErrorMsg"
|
||||
class="red--text text--lighten-1"
|
||||
>
|
||||
{{ testClientErrorMsg }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -89,20 +154,32 @@
|
|||
</v-row>
|
||||
<v-row class="pt-2">
|
||||
<v-col>
|
||||
<div v-if="!gotResponse" class="center spinner-orange">
|
||||
<div
|
||||
v-if="!gotResponse"
|
||||
class="center spinner-orange"
|
||||
>
|
||||
<div style="width:100%;text-align:center">
|
||||
<v-progress-circular
|
||||
indeterminate
|
||||
v-bind:size="50"
|
||||
:size="50"
|
||||
class="amber--text"
|
||||
style="display:inline-block"
|
||||
></v-progress-circular>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="gotResponse">
|
||||
<v-btn block color="primary" v-on:click.native="clientClicked()">Connect</v-btn>
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
@click.native="clientClicked()"
|
||||
>
|
||||
Connect
|
||||
</v-btn>
|
||||
</div>
|
||||
<div v-if="testClient.product.indexOf('Web') > -1" class="warning--text">
|
||||
<div
|
||||
v-if="testClient.product.indexOf('Web') > -1"
|
||||
class="warning--text"
|
||||
>
|
||||
Note: Plex Web is currently not supported.
|
||||
</div>
|
||||
<div
|
||||
|
@ -135,20 +212,27 @@
|
|||
</v-row>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col md="6" lg="7" v-if="doReverse">
|
||||
<v-col
|
||||
v-if="doReverse"
|
||||
md="6"
|
||||
lg="7"
|
||||
>
|
||||
<v-subheader>Plex Players {{ playercount }}</v-subheader>
|
||||
<v-list dense style="background: none">
|
||||
<v-list
|
||||
dense
|
||||
style="background: none"
|
||||
>
|
||||
<plexclient
|
||||
v-for="i in recentClients"
|
||||
:key="i.clientIdentifier"
|
||||
:selected="isClientSelected(i)"
|
||||
:object="i"
|
||||
style="cursor: pointer"
|
||||
@click.native="
|
||||
previewClient(i);
|
||||
gotResponse = true;
|
||||
"
|
||||
:selected="isClientSelected(i)"
|
||||
:object="i"
|
||||
style="cursor: pointer"
|
||||
></plexclient>
|
||||
/>
|
||||
</v-list>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
@ -164,8 +248,11 @@ import { mapActions, mapGetters, mapState } from 'vuex';
|
|||
import plexclient from './plexclient.vue';
|
||||
|
||||
export default {
|
||||
name: 'Walkthrough',
|
||||
components: {
|
||||
plexclient,
|
||||
},
|
||||
props: ['object'],
|
||||
name: 'walkthrough',
|
||||
data() {
|
||||
return {
|
||||
testClient: null,
|
||||
|
@ -212,9 +299,6 @@ export default {
|
|||
},
|
||||
};
|
||||
},
|
||||
components: {
|
||||
plexclient,
|
||||
},
|
||||
computed: {
|
||||
...mapState(['plex']),
|
||||
...mapGetters(['getChosenClient']),
|
||||
|
|
|
@ -1,50 +1,94 @@
|
|||
<template>
|
||||
<v-layout wrap row class="text-center" justify-center align-center>
|
||||
<v-flex v-if="!loading" xs12 md5>
|
||||
<v-card style="background: rgba(0,0,0,0.3)" class="pa-1">
|
||||
<v-container fill-height>
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12 md3 class="text-center">
|
||||
<img :src="logos.light.small" style="width: 90%" />
|
||||
</v-flex>
|
||||
<v-flex md9>
|
||||
<h1 class="white--text pa-1"> Welcome to SyncLounge!</h1>
|
||||
<div class="pt-2">
|
||||
<div>
|
||||
<span style="font-weight:900">{{ owner }}</span> has invited you to join the room
|
||||
<span style="font-weight:900">{{ room }}</span>
|
||||
</div>
|
||||
<v-layout
|
||||
wrap
|
||||
row
|
||||
class="text-center"
|
||||
justify-center
|
||||
align-center
|
||||
>
|
||||
<v-flex
|
||||
v-if="!loading"
|
||||
xs12
|
||||
md5
|
||||
>
|
||||
<v-card
|
||||
style="background: rgba(0,0,0,0.3)"
|
||||
class="pa-1"
|
||||
>
|
||||
<v-container fill-height>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
md3
|
||||
class="text-center"
|
||||
>
|
||||
<img
|
||||
:src="logos.light.small"
|
||||
style="width: 90%"
|
||||
>
|
||||
</v-flex>
|
||||
<v-flex md9>
|
||||
<h1 class="white--text pa-1">
|
||||
Welcome to SyncLounge!
|
||||
</h1>
|
||||
<div class="pt-2">
|
||||
<div>
|
||||
<span style="font-weight:900">{{ owner }}</span> has invited you to join the room
|
||||
<span style="font-weight:900">{{ room }}</span>
|
||||
</div>
|
||||
<v-layout wrap row class="pa-4 pt-2" justify-center align-center>
|
||||
<v-flex xs12 md8 class="text-center">
|
||||
<v-btn class="center" style="background-color: #E5A00D" @click.native="letsGo()">Accept Invite</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
<v-layout
|
||||
wrap
|
||||
row
|
||||
class="pa-4 pt-2"
|
||||
justify-center
|
||||
align-center
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
md8
|
||||
class="text-center"
|
||||
>
|
||||
<v-btn
|
||||
class="center"
|
||||
style="background-color: #E5A00D"
|
||||
@click.native="letsGo()"
|
||||
>
|
||||
Accept Invite
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
<v-divider></v-divider>
|
||||
<p style="opacity:0.7" class="text-center pt-3">
|
||||
SyncLounge is a tool to sync Plex content with your family and friends. For more info click <a target="_blank" href="https://github.com/samcm/synclounge"> here</a>.
|
||||
</p>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
<v-flex v-else>
|
||||
<v-progress-circular indeterminate color="primary"></v-progress-circular>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
<v-divider />
|
||||
<p
|
||||
style="opacity:0.7"
|
||||
class="text-center pt-3"
|
||||
>
|
||||
SyncLounge is a tool to sync Plex content with your family and friends. For more info click <a
|
||||
target="_blank"
|
||||
href="https://github.com/samcm/synclounge"
|
||||
> here</a>.
|
||||
</p>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
<v-flex v-else>
|
||||
<v-progress-circular
|
||||
indeterminate
|
||||
color="primary"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'join',
|
||||
mounted() {
|
||||
this.password = this.$route.query.password || '';
|
||||
this.room = this.$route.query.room;
|
||||
this.server = this.$route.query.server;
|
||||
this.owner = this.$route.query.owner;
|
||||
},
|
||||
name: 'Join',
|
||||
data() {
|
||||
return {
|
||||
server: null,
|
||||
|
@ -62,6 +106,12 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.password = this.$route.query.password || '';
|
||||
this.room = this.$route.query.room;
|
||||
this.server = this.$route.query.server;
|
||||
this.owner = this.$route.query.owner;
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('settings', [
|
||||
'GET_PLEX_AUTH_TOKEN',
|
||||
|
|
|
@ -1,33 +1,84 @@
|
|||
<template>
|
||||
<v-flex xs12>
|
||||
<v-layout row wrap justify-start align-center v-if="message.user.username === 'You'">
|
||||
<v-flex xs10 class="pr-2 ml-3 mb-1">
|
||||
<!-- <v-flex><span style="opacity:0.6;font-size:60%; float:right"> {{ message.time}}</span></v-flex> -->
|
||||
<div class="pt-1 pb-1 pl-2 pr-2 messageBubble me" style="">{{ message.msg }}</div>
|
||||
<v-layout
|
||||
v-if="message.user.username === 'You'"
|
||||
row
|
||||
wrap
|
||||
justify-start
|
||||
align-center
|
||||
>
|
||||
<v-flex
|
||||
xs10
|
||||
class="pr-2 ml-3 mb-1"
|
||||
>
|
||||
<!-- <v-flex><span style="opacity:0.6;font-size:60%; float:right"> {{ message.time}}</span></v-flex> -->
|
||||
<div
|
||||
class="pt-1 pb-1 pl-2 pr-2 messageBubble me"
|
||||
style=""
|
||||
>
|
||||
{{ message.msg }}
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs1 class="text-center pt-1">
|
||||
<v-tooltip bottom color="rgb(44, 44, 49)" multi-line>
|
||||
<v-flex
|
||||
xs1
|
||||
class="text-center pt-1"
|
||||
>
|
||||
<v-tooltip
|
||||
bottom
|
||||
color="rgb(44, 44, 49)"
|
||||
multi-line
|
||||
>
|
||||
<span slot="activator">
|
||||
<img :src="message.user.thumb || message.user.avatarUrl" class="mt-2 messageAvatar" />
|
||||
<img
|
||||
:src="message.user.thumb || message.user.avatarUrl"
|
||||
class="mt-2 messageAvatar"
|
||||
>
|
||||
</span>
|
||||
{{ message.time }}
|
||||
</v-tooltip>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout row wrap justify-start align-center v-else>
|
||||
<v-flex xs1 class="text-center pt-1 mr-2 ml-2">
|
||||
<v-tooltip bottom color="rgb(44, 44, 49)" multi-line>
|
||||
<v-layout
|
||||
v-else
|
||||
row
|
||||
wrap
|
||||
justify-start
|
||||
align-center
|
||||
>
|
||||
<v-flex
|
||||
xs1
|
||||
class="text-center pt-1 mr-2 ml-2"
|
||||
>
|
||||
<v-tooltip
|
||||
bottom
|
||||
color="rgb(44, 44, 49)"
|
||||
multi-line
|
||||
>
|
||||
<span slot="activator">
|
||||
<img :src="message.user.thumb || message.user.avatarUrl" class="mt-2 messageAvatar" />
|
||||
<img
|
||||
:src="message.user.thumb || message.user.avatarUrl"
|
||||
class="mt-2 messageAvatar"
|
||||
>
|
||||
</span>
|
||||
{{ message.time }}
|
||||
</v-tooltip>
|
||||
</v-flex>
|
||||
<v-flex xs10 class="pr-2 mr-2 mb-2">
|
||||
<!-- <v-flex><span style="opacity:0.6;font-size:60%; float:right"> {{ message.time}}</span></v-flex> -->
|
||||
<b class="pl-1" style="opacity:1;font-size:60%; float:left"> {{ message.user.username }}</b>
|
||||
<v-flex
|
||||
xs10
|
||||
class="pr-2 mr-2 mb-2"
|
||||
>
|
||||
<!-- <v-flex><span style="opacity:0.6;font-size:60%; float:right"> {{ message.time}}</span></v-flex> -->
|
||||
<b
|
||||
class="pl-1"
|
||||
style="opacity:1;font-size:60%; float:left"
|
||||
> {{ message.user.username }}</b>
|
||||
|
||||
<div class="pt-1 pb-1 pl-2 pr-2 messageBubble" style="">{{ message.msg }}</div>
|
||||
<div
|
||||
class="pt-1 pb-1 pl-2 pr-2 messageBubble"
|
||||
style=""
|
||||
>
|
||||
{{ message.msg }}
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
|
|
|
@ -1,23 +1,43 @@
|
|||
<template>
|
||||
<v-layout row wrap style="height: 100%;">
|
||||
<v-flex xs12 style="height: calc(100% - 96px)">
|
||||
<v-divider class="hidden-md-and-down"></v-divider>
|
||||
<v-subheader class="md-4">Chat</v-subheader>
|
||||
<v-layout row wrap id="chatbox" v-if="messages.length > 0" style="max-height: calc(100% - 32px); overflow-y: scroll">
|
||||
<message :message="msg" :id="getMsgId(msg)" v-for="(msg, index) in messages" :key="index"></message>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
style="height: 100%;"
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
style="height: calc(100% - 96px)"
|
||||
>
|
||||
<v-divider class="hidden-md-and-down" />
|
||||
<v-subheader class="md-4">
|
||||
Chat
|
||||
</v-subheader>
|
||||
<v-layout
|
||||
v-if="messages.length > 0"
|
||||
id="chatbox"
|
||||
row
|
||||
wrap
|
||||
style="max-height: calc(100% - 32px); overflow-y: scroll"
|
||||
>
|
||||
<message
|
||||
v-for="(msg, index) in messages"
|
||||
:id="getMsgId(msg)"
|
||||
:key="index"
|
||||
:message="msg"
|
||||
/>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
<v-flex xs12>
|
||||
<v-text-field
|
||||
v-model="messageToBeSent"
|
||||
append-outer-icon="send"
|
||||
@click:append-outer="sendMessage()"
|
||||
:label="chatboxLabel"
|
||||
hide-details
|
||||
single-line
|
||||
class="ml-2 mr-2 pr-1"
|
||||
v-on:keyup.enter.native="sendMessage()"
|
||||
v-model="messageToBeSent"
|
||||
></v-text-field>
|
||||
@click:append-outer="sendMessage()"
|
||||
@keyup.enter.native="sendMessage()"
|
||||
/>
|
||||
<!-- <v-btn block color="primary" @click="sendMessage()" :disabled="messageToBeSent.length === 0">Send<v-icon right>send</v-icon></v-btn> -->
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
@ -38,6 +58,14 @@ export default {
|
|||
messageToBeSent: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
messages() {
|
||||
return this.$store.getters.getMessages;
|
||||
},
|
||||
chatboxLabel() {
|
||||
return 'Message';
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
messages() {
|
||||
const options = {
|
||||
|
@ -50,14 +78,6 @@ export default {
|
|||
this.$scrollTo('#lastMessage', 5, options);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
messages() {
|
||||
return this.$store.getters.getMessages;
|
||||
},
|
||||
chatboxLabel() {
|
||||
return 'Message';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getMsgId(msg) {
|
||||
if (this.messages && msg === this.messages[this.messages.length - 1]) {
|
||||
|
|
|
@ -1,65 +1,116 @@
|
|||
<template>
|
||||
<v-row class="pt-2 pa-4" justify="center">
|
||||
<v-row
|
||||
class="pt-2 pa-4"
|
||||
justify="center"
|
||||
>
|
||||
<v-col md="8">
|
||||
<v-card style="background: rgba(0,0,0,0.3)" class="pa-4">
|
||||
<v-layout row wrap justify-center align-center v-if="ready">
|
||||
<v-flex xs12 sm8 lg4>
|
||||
<v-card
|
||||
style="background: rgba(0,0,0,0.3)"
|
||||
class="pa-4"
|
||||
>
|
||||
<v-layout
|
||||
v-if="ready"
|
||||
row
|
||||
wrap
|
||||
justify-center
|
||||
align-center
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
sm8
|
||||
lg4
|
||||
>
|
||||
<h1 class="text-center pa-2">
|
||||
Hello
|
||||
<span style="font-weight: 700">{{ plex.user.username }}</span
|
||||
>!
|
||||
<span style="font-weight: 700">{{ plex.user.username }}</span>!
|
||||
</h1>
|
||||
<p>
|
||||
Would you like to change your display name when using SyncLounge? By default your
|
||||
Plex.tv username will be used. You can always change this setting later.
|
||||
</p>
|
||||
<v-checkbox
|
||||
v-model="HIDEUSERNAME"
|
||||
class="pt-2"
|
||||
label="Change my display name"
|
||||
v-model="HIDEUSERNAME"
|
||||
></v-checkbox>
|
||||
/>
|
||||
<v-text-field
|
||||
v-if="HIDEUSERNAME"
|
||||
:value="GET_ALTUSERNAME"
|
||||
@change="SET_ALTUSERNAME"
|
||||
label="Alternative display name"
|
||||
></v-text-field>
|
||||
@change="SET_ALTUSERNAME"
|
||||
/>
|
||||
<div class="text-xs-right">
|
||||
<v-btn @click="letsGo" color="primary">Get started</v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="letsGo"
|
||||
>
|
||||
Get started
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div v-else>
|
||||
<h1 v-if="!GET_PLEX_AUTH_TOKEN" class="center-text pa-4">
|
||||
<h1
|
||||
v-if="!GET_PLEX_AUTH_TOKEN"
|
||||
class="center-text pa-4"
|
||||
>
|
||||
To use SyncLounge you need to sign in with your Plex account.
|
||||
</h1>
|
||||
<div v-if="!preAuth || checkingAuth">
|
||||
<v-layout wrap row style="position:relative">
|
||||
<v-flex xs12 md4 offset-md4>
|
||||
<v-layout
|
||||
wrap
|
||||
row
|
||||
style="position:relative"
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
md4
|
||||
offset-md4
|
||||
>
|
||||
<div style="width:100%;text-align:center">
|
||||
<v-progress-circular
|
||||
indeterminate
|
||||
v-bind:size="50"
|
||||
:size="50"
|
||||
class="amber--text"
|
||||
style="display:inline-block"
|
||||
></v-progress-circular>
|
||||
/>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
<div v-if="preAuth && !checkingAuth && !authError" class="text-center">
|
||||
<v-btn class="primary" @click="openPopup()">Sign in with Plex</v-btn>
|
||||
<div
|
||||
v-if="preAuth && !checkingAuth && !authError"
|
||||
class="text-center"
|
||||
>
|
||||
<v-btn
|
||||
class="primary"
|
||||
@click="openPopup()"
|
||||
>
|
||||
Sign in with Plex
|
||||
</v-btn>
|
||||
</div>
|
||||
<div v-if="authError" class="text-center error">
|
||||
<div
|
||||
v-if="authError"
|
||||
class="text-center error"
|
||||
>
|
||||
<p>You are not authorized to access this server</p>
|
||||
</div>
|
||||
<v-row justify="center" class="pt-4 pa-2">
|
||||
<v-col md="8" class="center-text">
|
||||
<v-row
|
||||
justify="center"
|
||||
class="pt-4 pa-2"
|
||||
>
|
||||
<v-col
|
||||
md="8"
|
||||
class="center-text"
|
||||
>
|
||||
<p style="opacity:0.7">
|
||||
Your Plex account is used to fetch the details of your Plex devices. None of your
|
||||
private details are sent to our servers. If you would like to install and run
|
||||
SyncLounge yourself have a look
|
||||
<a target="_blank" href="https://github.com/samcm/SyncLounge">here</a>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://github.com/samcm/SyncLounge"
|
||||
>here</a>
|
||||
for details.
|
||||
</p>
|
||||
</v-col>
|
||||
|
@ -75,7 +126,7 @@ import axios from 'axios';
|
|||
import { mapActions, mapGetters, mapMutations } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'signin',
|
||||
name: 'Signin',
|
||||
data() {
|
||||
return {
|
||||
pin: null,
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
<template>
|
||||
<v-layout wrap row>
|
||||
<v-flex xs12 md8 offset-md2>
|
||||
<h1 class="white--text center-text pa-4">Successfully signed out</h1>
|
||||
<v-layout
|
||||
wrap
|
||||
row
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
md8
|
||||
offset-md2
|
||||
>
|
||||
<h1 class="white--text center-text pa-4">
|
||||
Successfully signed out
|
||||
</h1>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</template>
|
||||
|
@ -10,7 +19,7 @@
|
|||
import { mapMutations } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'signout',
|
||||
name: 'Signout',
|
||||
mounted() {
|
||||
this.SET_PLEX_AUTH_TOKEN(null);
|
||||
this.$store.state.plex = null;
|
||||
|
|
|
@ -2,39 +2,85 @@
|
|||
<v-card>
|
||||
<v-card-title class="title">
|
||||
Donate
|
||||
<v-spacer></v-spacer>
|
||||
<img :src="logos.light.small" style="height: 50px"/>
|
||||
<v-spacer />
|
||||
<img
|
||||
:src="logos.light.small"
|
||||
style="height: 50px"
|
||||
>
|
||||
</v-card-title>
|
||||
<v-divider></v-divider>
|
||||
<v-divider />
|
||||
<v-card-text>
|
||||
<p class="pa-2"> All donations to SyncLounge go directly towards running the SyncLounge public servers and the continued development of the application. </p>
|
||||
<p class="pa-2">
|
||||
All donations to SyncLounge go directly towards running the SyncLounge public servers and the continued development of the application.
|
||||
</p>
|
||||
<v-subheader> How to donate </v-subheader>
|
||||
<v-layout row justify-center align-center class="pa-0 ma-1">
|
||||
<v-flex xs4 class="text-center">
|
||||
<v-btn block color="primary" class="white--text" target="_blank" href="https://paypal.me/PlexTogether">
|
||||
Paypal
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout
|
||||
row
|
||||
justify-center
|
||||
align-center
|
||||
class="pa-0 ma-1"
|
||||
>
|
||||
<v-flex
|
||||
xs4
|
||||
class="text-center"
|
||||
>
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
class="white--text"
|
||||
target="_blank"
|
||||
href="https://paypal.me/PlexTogether"
|
||||
>
|
||||
Paypal
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div class="text-center pa-2">
|
||||
<v-layout row justify-center align-center v-for="(address, coin) in addresses" :key="coin" class="pa-0 ma-1">
|
||||
<v-flex xs2 style="font-weight: 600">
|
||||
<v-layout
|
||||
v-for="(address, coin) in addresses"
|
||||
:key="coin"
|
||||
row
|
||||
justify-center
|
||||
align-center
|
||||
class="pa-0 ma-1"
|
||||
>
|
||||
<v-flex
|
||||
xs2
|
||||
style="font-weight: 600"
|
||||
>
|
||||
{{ coin }}
|
||||
</v-flex>
|
||||
<v-flex xs8>
|
||||
{{ address }}
|
||||
</v-flex>
|
||||
<v-flex xs2 class="text-center">
|
||||
<v-icon v-clipboard="address" v-on:click.native="sendNotification()" class="mr-2 primary--text click-cursor">content_copy</v-icon>
|
||||
<v-flex
|
||||
xs2
|
||||
class="text-center"
|
||||
>
|
||||
<v-icon
|
||||
v-clipboard="address"
|
||||
class="mr-2 primary--text click-cursor"
|
||||
@click.native="sendNotification()"
|
||||
>
|
||||
content_copy
|
||||
</v-icon>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
<v-divider></v-divider>
|
||||
<p class="pa-2 soft-text mb-0 pb-0" >If you make a donation, stop by the Discord and message samcm#2715 to get your Donator role. Thankyou!</p>
|
||||
<v-divider />
|
||||
<p class="pa-2 soft-text mb-0 pb-0">
|
||||
If you make a donation, stop by the Discord and message samcm#2715 to get your Donator role. Thankyou!
|
||||
</p>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" flat @click.stop="onClose()">Close</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
flat
|
||||
@click.stop="onClose()"
|
||||
>
|
||||
Close
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
|
|
|
@ -3,24 +3,34 @@
|
|||
app
|
||||
temporary
|
||||
:value="isLeftSidebarOpen"
|
||||
@input="SET_LEFT_SIDEBAR_OPEN"
|
||||
disable-route-watcher
|
||||
@input="SET_LEFT_SIDEBAR_OPEN"
|
||||
>
|
||||
<v-list-item v-if="plex && plex.user">
|
||||
<v-list-item-avatar>
|
||||
<img class="pa-1" :src="plex.user.thumb" />
|
||||
<img
|
||||
class="pa-1"
|
||||
:src="plex.user.thumb"
|
||||
>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title style="font-weight: bold">{{ plex.user.username }}</v-list-item-title>
|
||||
<v-list-item-title style="font-weight: bold">
|
||||
{{ plex.user.username }}
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-divider></v-divider>
|
||||
<v-divider />
|
||||
|
||||
<v-list dense nav>
|
||||
<v-list
|
||||
dense
|
||||
nav
|
||||
>
|
||||
<v-subheader>Preferences</v-subheader>
|
||||
<v-list-item @click.stop="ptsettingstoggle = !ptsettingstoggle">
|
||||
<v-list-item-icon>
|
||||
<v-icon color="white">settings</v-icon>
|
||||
<v-icon color="white">
|
||||
settings
|
||||
</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>SyncLounge Settings</v-list-item-title>
|
||||
|
@ -32,17 +42,26 @@
|
|||
@click.stop="plexsettingstoggle = !plexsettingstoggle"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon color="white">settings</v-icon>
|
||||
<v-icon color="white">
|
||||
settings
|
||||
</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Plex Settings</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-subheader v-if="plex && plex.gotDevices">Account</v-subheader>
|
||||
<v-list-item :router="true" to="/signout">
|
||||
<v-subheader v-if="plex && plex.gotDevices">
|
||||
Account
|
||||
</v-subheader>
|
||||
<v-list-item
|
||||
:router="true"
|
||||
to="/signout"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon color="white">cancel</v-icon>
|
||||
<v-icon color="white">
|
||||
cancel
|
||||
</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Sign out</v-list-item-title>
|
||||
|
@ -50,27 +69,42 @@
|
|||
</v-list-item>
|
||||
|
||||
<v-subheader>About</v-subheader>
|
||||
<v-list-item href="https://synclounge.tv/" target="_blank">
|
||||
<v-list-item
|
||||
href="https://synclounge.tv/"
|
||||
target="_blank"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon color="white">info</v-icon>
|
||||
<v-icon color="white">
|
||||
info
|
||||
</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>SyncLounge v{{appVersion}}</v-list-item-title>
|
||||
<v-list-item-title>SyncLounge v{{ appVersion }}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item href="https://discord.gg/fKQB3yt" target="_blank">
|
||||
<v-list-item
|
||||
href="https://discord.gg/fKQB3yt"
|
||||
target="_blank"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon color="white">chat</v-icon>
|
||||
<v-icon color="white">
|
||||
chat
|
||||
</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Discord</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item href="https://github.com/samcm/synclounge" target="_blank">
|
||||
<v-list-item
|
||||
href="https://github.com/samcm/synclounge"
|
||||
target="_blank"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon color="white">code</v-icon>
|
||||
<v-icon color="white">
|
||||
code
|
||||
</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>GitHub</v-list-item-title>
|
||||
|
@ -79,44 +113,70 @@
|
|||
|
||||
<v-list-item @click.stop="donateDialog = true">
|
||||
<v-list-item-icon>
|
||||
<v-icon color="white">favorite</v-icon>
|
||||
<v-icon color="white">
|
||||
favorite
|
||||
</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Donate</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
</v-list>
|
||||
|
||||
<template v-slot:append>
|
||||
<v-divider></v-divider>
|
||||
<div class="text-center pa-2" style="opacity: 0.7; font-size: 12px">
|
||||
<v-divider />
|
||||
<div
|
||||
class="text-center pa-2"
|
||||
style="opacity: 0.7; font-size: 12px"
|
||||
>
|
||||
<div>Build #{{ hash }}</div>
|
||||
<div>Last updated {{ updatedAt }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<v-dialog v-model="ptsettingstoggle" width="350">
|
||||
<v-card style="background-color: #151924" class="pa-3">
|
||||
<v-dialog
|
||||
v-model="ptsettingstoggle"
|
||||
width="350"
|
||||
>
|
||||
<v-card
|
||||
style="background-color: #151924"
|
||||
class="pa-3"
|
||||
>
|
||||
<div class="text-center">
|
||||
<h2>SyncLounge Settings</h2>
|
||||
</div>
|
||||
<v-divider class="mt-2 mb-2"></v-divider>
|
||||
<ptsettings class="darken-4 pa-1"></ptsettings>
|
||||
<v-divider class="mt-2 mb-2" />
|
||||
<ptsettings class="darken-4 pa-1" />
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="plexsettingstoggle" width="350">
|
||||
<v-card style="background-color: #151924" class="pa-3">
|
||||
<v-dialog
|
||||
v-model="plexsettingstoggle"
|
||||
width="350"
|
||||
>
|
||||
<v-card
|
||||
style="background-color: #151924"
|
||||
class="pa-3"
|
||||
>
|
||||
<div class="text-center">
|
||||
<h2>Plex Settings</h2>
|
||||
</div>
|
||||
<v-divider class="mt-2 mb-2"></v-divider>
|
||||
<plexsettings class="darken-4 pa-1" v-if="validPlex && plex.gotDevices"></plexsettings>
|
||||
<v-divider class="mt-2 mb-2" />
|
||||
<plexsettings
|
||||
v-if="validPlex && plex.gotDevices"
|
||||
class="darken-4 pa-1"
|
||||
/>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="donateDialog" max-width="650px">
|
||||
<donate :donateDialog="donateDialog" :onClose="() => this.donateDialog = false"></donate>
|
||||
<v-dialog
|
||||
v-model="donateDialog"
|
||||
max-width="650px"
|
||||
>
|
||||
<donate
|
||||
:donate-dialog="donateDialog"
|
||||
:on-close="() => this.donateDialog = false"
|
||||
/>
|
||||
</v-dialog>
|
||||
</v-navigation-drawer>
|
||||
</template>
|
||||
|
|
12
src/main.js
12
src/main.js
|
@ -59,12 +59,6 @@ window.EventBus.$on('command', (data) => {
|
|||
});
|
||||
|
||||
Vue.mixin({
|
||||
methods: {
|
||||
sinceNow(x) {
|
||||
const time = moment(x);
|
||||
return time.fromNow();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
appVersion() {
|
||||
return this.$store.getters.appVersion;
|
||||
|
@ -115,6 +109,12 @@ Vue.mixin({
|
|||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
sinceNow(x) {
|
||||
const time = moment(x);
|
||||
return time.fromNow();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
|
|
|
@ -1,12 +1,34 @@
|
|||
<template>
|
||||
<router-link :to="href">
|
||||
<v-card color="blue darken-4" hover style="height: 100%; width: 230px">
|
||||
<v-layout row wrap justify-center align-center>
|
||||
<v-flex md2 class="hidden-xs-only text-center">
|
||||
<img :src="thumb" style="height: 52px; vertical-align: middle" />
|
||||
<v-card
|
||||
color="blue darken-4"
|
||||
hover
|
||||
style="height: 100%; width: 230px"
|
||||
>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-center
|
||||
align-center
|
||||
>
|
||||
<v-flex
|
||||
md2
|
||||
class="hidden-xs-only text-center"
|
||||
>
|
||||
<img
|
||||
:src="thumb"
|
||||
style="height: 52px; vertical-align: middle"
|
||||
>
|
||||
</v-flex>
|
||||
<v-flex md10 xs12 class="pl-3 pa-1 text-xs-left" style="overflow: hidden; white-space: nowrap; line-height: 24px">
|
||||
<div style="font-size: 18px">Now Playing</div>
|
||||
<v-flex
|
||||
md10
|
||||
xs12
|
||||
class="pl-3 pa-1 text-xs-left"
|
||||
style="overflow: hidden; white-space: nowrap; line-height: 24px"
|
||||
>
|
||||
<div style="font-size: 18px">
|
||||
Now Playing
|
||||
</div>
|
||||
<div><small><b>{{ getTitle }}</b> - {{ getUnder }}</small></div>
|
||||
<!-- <div class="hidden-xs-only soft-text" style="font-size: 12px">Click for more info</div> -->
|
||||
</v-flex>
|
||||
|
@ -24,15 +46,6 @@ export default {
|
|||
return {
|
||||
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
|
||||
},
|
||||
watch: {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
computed: {
|
||||
item() {
|
||||
|
@ -114,5 +127,14 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
||||
},
|
||||
async mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
253
src/sidebar.vue
253
src/sidebar.vue
|
@ -1,66 +1,107 @@
|
|||
<template>
|
||||
<v-navigation-drawer
|
||||
:value="isRightSidebarOpen"
|
||||
@input="SET_RIGHT_SIDEBAR_OPEN"
|
||||
style="padding: 0; z-index: 6"
|
||||
app
|
||||
right
|
||||
@input="SET_RIGHT_SIDEBAR_OPEN"
|
||||
>
|
||||
<v-container class="pa-0 pb-0" fill-height>
|
||||
<v-layout v-if="getRoom" row wrap style="background: rgba(30, 31, 50,0.6)">
|
||||
<v-flex xs12 style="height: 50vh">
|
||||
<v-container
|
||||
class="pa-0 pb-0"
|
||||
fill-height
|
||||
>
|
||||
<v-layout
|
||||
v-if="getRoom"
|
||||
row
|
||||
wrap
|
||||
style="background: rgba(30, 31, 50,0.6)"
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
style="height: 50vh"
|
||||
>
|
||||
<v-flex xs12>
|
||||
<v-card
|
||||
style="background: linear-gradient(180deg,#1f1c2c,#182848); border-radius: 7px"
|
||||
class="pa-2 ma-3"
|
||||
>
|
||||
<v-layout row wrap justify-space-between align-center>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-space-between
|
||||
align-center
|
||||
>
|
||||
<v-flex xs6>
|
||||
<h3 class="mb-0 pb-0 pa-0">{{ getRoom }}</h3>
|
||||
<h3 class="mb-0 pb-0 pa-0">
|
||||
{{ getRoom }}
|
||||
</h3>
|
||||
</v-flex>
|
||||
<v-flex xs2>
|
||||
<v-menu>
|
||||
<v-btn icon class="ma-0 pa-0" dark>
|
||||
<v-btn
|
||||
icon
|
||||
class="ma-0 pa-0"
|
||||
dark
|
||||
>
|
||||
<v-icon>more_vert</v-icon>
|
||||
</v-btn>
|
||||
<v-list>
|
||||
<v-list-item @click="handleDisconnect()">
|
||||
<v-list-item-title class="user-menu-list">Leave Room</v-list-item-title>
|
||||
<v-list-item-title class="user-menu-list">
|
||||
Leave Room
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-flex>
|
||||
<v-flex xs12>
|
||||
<div v-if="getUsers.length != 1" class="participant-count">
|
||||
<div
|
||||
v-if="getUsers.length != 1"
|
||||
class="participant-count"
|
||||
>
|
||||
{{ getUsers.length }} people
|
||||
</div>
|
||||
<div v-else class="participant-count">It's just you, invite some friends</div>
|
||||
<div
|
||||
v-else
|
||||
class="participant-count"
|
||||
>
|
||||
It's just you, invite some friends
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs12>
|
||||
<v-layout row wrap>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex xs6>
|
||||
<v-switch
|
||||
v-if="isHost(me)"
|
||||
class="pa-0 mt-2 party-pausing-label"
|
||||
label="Party Pausing"
|
||||
v-if="isHost(me)"
|
||||
:input-value="getPartyPausing"
|
||||
@change="updatePartyPausing"
|
||||
></v-switch>
|
||||
<v-tooltip bottom color="rgb(44, 44, 49)" v-else>
|
||||
/>
|
||||
<v-tooltip
|
||||
v-else
|
||||
bottom
|
||||
color="rgb(44, 44, 49)"
|
||||
>
|
||||
<v-btn
|
||||
v-if="playerState(getHostUser) !== 'stop'"
|
||||
color="primary"
|
||||
:disabled="!canPause"
|
||||
style="min-width: 0; float: right;"
|
||||
@click="sendPartyPauseLocal(playerState(getHostUser) === 'play_arrow')"
|
||||
v-if="playerState(getHostUser) !== 'stop'"
|
||||
>
|
||||
<v-icon v-if="playerState(getHostUser) === 'play_arrow'">pause</v-icon>
|
||||
<v-icon v-else>play_arrow</v-icon>
|
||||
<v-icon v-if="playerState(getHostUser) === 'play_arrow'">
|
||||
pause
|
||||
</v-icon>
|
||||
<v-icon v-else>
|
||||
play_arrow
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
<span
|
||||
>Party Pausing is currently {{ canPause ? 'enabled' : 'disabled' }} by the
|
||||
host</span
|
||||
>
|
||||
<span>Party Pausing is currently {{ canPause ? 'enabled' : 'disabled' }} by the
|
||||
host</span>
|
||||
</v-tooltip>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
@ -68,15 +109,24 @@
|
|||
</v-layout>
|
||||
</v-card>
|
||||
<v-card
|
||||
v-if="me.role !== 'host' && this.$route.path.indexOf('/player') === -1"
|
||||
style="background: #E5A00D; border-radius: 7px"
|
||||
class="pa-2 ma-3"
|
||||
v-if="me.role !== 'host' && this.$route.path.indexOf('/player') === -1"
|
||||
>
|
||||
<v-layout row wrap justify-space-between align-center>
|
||||
<v-flex xs12 class="text-center">
|
||||
<span class="mb-0 pb-0 pa-0" style="color: rgb(44, 44, 49); "
|
||||
>Waiting for {{ getHostUser.username }} to start</span
|
||||
>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-space-between
|
||||
align-center
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
class="text-center"
|
||||
>
|
||||
<span
|
||||
class="mb-0 pb-0 pa-0"
|
||||
style="color: rgb(44, 44, 49); "
|
||||
>Waiting for {{ getHostUser.username }} to start</span>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-card>
|
||||
|
@ -90,21 +140,37 @@
|
|||
style="background: linear-gradient(180deg,#1f1c2c,#182848)!important; border-radius: 7px"
|
||||
class="pa-1 ml-3 mr-3"
|
||||
>
|
||||
<v-list-item style="height:4em" class="pl-1 pr-1 mb-0" tag="div">
|
||||
<v-list-item
|
||||
style="height:4em"
|
||||
class="pl-1 pr-1 mb-0"
|
||||
tag="div"
|
||||
>
|
||||
<v-list-item-avatar>
|
||||
<img v-bind:src="getHostUser.avatarUrl" :style="getImgStyle(getHostUser)" />
|
||||
<img
|
||||
:src="getHostUser.avatarUrl"
|
||||
:style="getImgStyle(getHostUser)"
|
||||
>
|
||||
<v-icon
|
||||
v-if="getHostUser.playerState !== 'playing'"
|
||||
style="font-size: 26px; opacity: 0.8; position: absolute;background-color: rgba(0,0,0,0.5)"
|
||||
>{{ playerState(getHostUser) }}</v-icon
|
||||
>
|
||||
{{ playerState(getHostUser) }}
|
||||
</v-icon>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-tooltip bottom color="rgb(44, 44, 49)" multi-line class="userlist">
|
||||
<v-tooltip
|
||||
bottom
|
||||
color="rgb(44, 44, 49)"
|
||||
multi-line
|
||||
class="userlist"
|
||||
>
|
||||
<span>
|
||||
<v-list-item-title>
|
||||
{{ getHostUser.username }}
|
||||
<span style="opacity: 0.6" v-if="getHostUser.uuid === me.uuid">(you)</span>
|
||||
<span
|
||||
v-if="getHostUser.uuid === me.uuid"
|
||||
style="opacity: 0.6"
|
||||
>(you)</span>
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle style="opacity:0.6;color:white;font-size:70%">{{
|
||||
getTitle(getHostUser)
|
||||
|
@ -112,48 +178,83 @@
|
|||
</span>
|
||||
Watching on {{ getHostUser.playerProduct || 'Unknown Plex Client' }}
|
||||
<span v-if="getPlex.servers[getHostUser.machineIdentifier]">
|
||||
<br />
|
||||
<br>
|
||||
via {{ getPlex.servers[getHostUser.machineIdentifier].name }}
|
||||
</span>
|
||||
</v-tooltip>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-tooltip bottom color="rgb(44, 44, 49)" multi-line class="userlist">
|
||||
<v-icon style="color: #E5A00D">star</v-icon>Host
|
||||
<v-tooltip
|
||||
bottom
|
||||
color="rgb(44, 44, 49)"
|
||||
multi-line
|
||||
class="userlist"
|
||||
>
|
||||
<v-icon style="color: #E5A00D">
|
||||
star
|
||||
</v-icon>Host
|
||||
</v-tooltip>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
<div class="pl-1 pr-1 pt-1 mt-0 pb-0 mb-0">
|
||||
<span style="float: left; font-size:70%" class="ptuser-time pl-1">{{
|
||||
<span
|
||||
style="float: left; font-size:70%"
|
||||
class="ptuser-time pl-1"
|
||||
>{{
|
||||
getCurrent(getHostUser)
|
||||
}}</span>
|
||||
<span style="float: right; font-size:70%" class="ptuser-maxTime pr-1">{{
|
||||
<span
|
||||
style="float: right; font-size:70%"
|
||||
class="ptuser-maxTime pr-1"
|
||||
>{{
|
||||
getMax(getHostUser)
|
||||
}}</span>
|
||||
<v-progress-linear
|
||||
class="pt-content-progress"
|
||||
:height="2"
|
||||
:value="percent(getHostUser)"
|
||||
></v-progress-linear>
|
||||
/>
|
||||
</div>
|
||||
</v-card>
|
||||
<div v-for="user in getUsers" v-bind:key="user.username">
|
||||
<div class="pa-1 ml-3 mr-3" v-if="!isHost(user)">
|
||||
<v-list-item style="height:4em" class="pb-0 mb-0" tag="div">
|
||||
<v-list-item-avatar v-on:dblclick="transferHost(user.username)">
|
||||
<img v-bind:src="user.avatarUrl" :style="getImgStyle(user)" />
|
||||
<div
|
||||
v-for="user in getUsers"
|
||||
:key="user.username"
|
||||
>
|
||||
<div
|
||||
v-if="!isHost(user)"
|
||||
class="pa-1 ml-3 mr-3"
|
||||
>
|
||||
<v-list-item
|
||||
style="height:4em"
|
||||
class="pb-0 mb-0"
|
||||
tag="div"
|
||||
>
|
||||
<v-list-item-avatar @dblclick="transferHost(user.username)">
|
||||
<img
|
||||
:src="user.avatarUrl"
|
||||
:style="getImgStyle(user)"
|
||||
>
|
||||
<v-icon
|
||||
v-if="user.playerState !== 'playing'"
|
||||
style="font-size: 26px; opacity: 0.8; position: absolute;background-color: rgba(0,0,0,0.7)"
|
||||
>{{ playerState(user) }}</v-icon
|
||||
>
|
||||
{{ playerState(user) }}
|
||||
</v-icon>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-tooltip bottom color="rgb(44, 44, 49)" multi-line class="userlist">
|
||||
<v-tooltip
|
||||
bottom
|
||||
color="rgb(44, 44, 49)"
|
||||
multi-line
|
||||
class="userlist"
|
||||
>
|
||||
<span>
|
||||
<v-list-item-title>
|
||||
{{ user.username }}
|
||||
<span style="opacity: 0.6" v-if="user.uuid === me.uuid">(you)</span>
|
||||
<span
|
||||
v-if="user.uuid === me.uuid"
|
||||
style="opacity: 0.6"
|
||||
>(you)</span>
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle style="opacity:0.6;color:white;font-size:70%">{{
|
||||
getTitle(user)
|
||||
|
@ -161,22 +262,41 @@
|
|||
</span>
|
||||
Watching on {{ user.playerProduct || 'Unknown Plex Client' }}
|
||||
<span v-if="getPlex.servers[user.machineIdentifier]">
|
||||
<br />
|
||||
<br>
|
||||
via {{ getPlex.servers[user.machineIdentifier].name }}
|
||||
</span>
|
||||
</v-tooltip>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-tooltip bottom color="rgb(44, 44, 49)" multi-line class="userlist">
|
||||
<v-icon v-if="isHost(user)" style="color: #E5A00D">star</v-icon>Host
|
||||
<v-tooltip
|
||||
bottom
|
||||
color="rgb(44, 44, 49)"
|
||||
multi-line
|
||||
class="userlist"
|
||||
>
|
||||
<v-icon
|
||||
v-if="isHost(user)"
|
||||
style="color: #E5A00D"
|
||||
>
|
||||
star
|
||||
</v-icon>Host
|
||||
</v-tooltip>
|
||||
<v-menu v-if="user.uuid !== me.uuid && isHost(me)" :offset-y="true">
|
||||
<v-btn icon class="ma-0 pa-0" dark>
|
||||
<v-menu
|
||||
v-if="user.uuid !== me.uuid && isHost(me)"
|
||||
:offset-y="true"
|
||||
>
|
||||
<v-btn
|
||||
icon
|
||||
class="ma-0 pa-0"
|
||||
dark
|
||||
>
|
||||
<v-icon>more_vert</v-icon>
|
||||
</v-btn>
|
||||
<v-list>
|
||||
<v-list-item @click="transferHost(user.username)">
|
||||
<v-list-item-title class="user-menu-list">Make Host</v-list-item-title>
|
||||
<v-list-item-title class="user-menu-list">
|
||||
Make Host
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
<!-- <v-list-item @click.stop="openInviteDialog(user)">
|
||||
<v-list-item-title class="user-menu-list">Invite to a Plex Server</v-list-item-title>
|
||||
|
@ -186,24 +306,33 @@
|
|||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
<div class="pl-0 pr-0 pt-1 mt-0 pb-0 mb-0">
|
||||
<span style="float: left; font-size:70%" class="ptuser-time pl-1">{{
|
||||
<span
|
||||
style="float: left; font-size:70%"
|
||||
class="ptuser-time pl-1"
|
||||
>{{
|
||||
getCurrent(user)
|
||||
}}</span>
|
||||
<span style="float: right; font-size:70%" class="ptuser-maxTime pr-1">{{
|
||||
<span
|
||||
style="float: right; font-size:70%"
|
||||
class="ptuser-maxTime pr-1"
|
||||
>{{
|
||||
getMax(user)
|
||||
}}</span>
|
||||
<v-progress-linear
|
||||
class="pt-content-progress"
|
||||
:height="2"
|
||||
:value="percent(user)"
|
||||
></v-progress-linear>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-list>
|
||||
</v-flex>
|
||||
<v-flex xs12 style="position: relative; height: 50vh; max-height: 50vh">
|
||||
<messages v-if="$vuetify.breakpoint.lgAndUp"></messages>
|
||||
<v-flex
|
||||
xs12
|
||||
style="position: relative; height: 50vh; max-height: 50vh"
|
||||
>
|
||||
<messages v-if="$vuetify.breakpoint.lgAndUp" />
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
|
@ -227,11 +356,6 @@ export default {
|
|||
partyPauseCooldownRunning: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
setInterval(() => {
|
||||
this.now = new Date().getTime();
|
||||
}, 250);
|
||||
},
|
||||
watch: {
|
||||
getUsers: {
|
||||
deep: true,
|
||||
|
@ -240,6 +364,11 @@ export default {
|
|||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
setInterval(() => {
|
||||
this.now = new Date().getTime();
|
||||
}, 250);
|
||||
},
|
||||
computed: {
|
||||
...mapState(['me', 'isRightSidebarOpen']),
|
||||
...mapGetters(['getPlex', 'getPartyPausing', 'getUsers', 'getRoom', 'getHostUser']),
|
||||
|
|
170
src/upnext.vue
170
src/upnext.vue
|
@ -1,34 +1,92 @@
|
|||
<template>
|
||||
<v-bottom-sheet v-model="sheet" hide-overlay>
|
||||
<v-card v-if="ready && content && !content.loading" style="max-width: 100%; margin-left: auto; margin-right: auto" class="white--text pa-0" :img="background">
|
||||
<v-container fluid align-center justify-start v-show="ready" class="pa-0" style="background: rgba(0,0,0,0.7);">
|
||||
<v-bottom-sheet
|
||||
v-model="sheet"
|
||||
hide-overlay
|
||||
>
|
||||
<v-card
|
||||
v-if="ready && content && !content.loading"
|
||||
style="max-width: 100%; margin-left: auto; margin-right: auto"
|
||||
class="white--text pa-0"
|
||||
:img="background"
|
||||
>
|
||||
<v-container
|
||||
v-show="ready"
|
||||
fluid
|
||||
align-center
|
||||
justify-start
|
||||
class="pa-0"
|
||||
style="background: rgba(0,0,0,0.7);"
|
||||
>
|
||||
<v-card-title class="pa-0">
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
</v-card-title>
|
||||
<v-layout row wrap justify-start align-start class="pa-0">
|
||||
<v-container fluid class="pa-1">
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-start
|
||||
align-start
|
||||
class="pa-0"
|
||||
>
|
||||
<v-container
|
||||
fluid
|
||||
class="pa-1"
|
||||
>
|
||||
<v-layout row>
|
||||
<v-flex xs3 sm2>
|
||||
<v-flex
|
||||
xs3
|
||||
sm2
|
||||
>
|
||||
<v-img
|
||||
:src="thumb"
|
||||
:src="thumb"
|
||||
height="125px"
|
||||
contain
|
||||
></v-img>
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<div>
|
||||
<h2 style="width: 100%">Coming up next<v-icon style="float: right" @click="sheet = false" class="clickable ma-2">close</v-icon></h2>
|
||||
<div class="headline">{{ getTitle }}</div>
|
||||
<h2 style="width: 100%">
|
||||
Coming up next<v-icon
|
||||
style="float: right"
|
||||
class="clickable ma-2"
|
||||
@click="sheet = false"
|
||||
>
|
||||
close
|
||||
</v-icon>
|
||||
</h2>
|
||||
<div class="headline">
|
||||
{{ getTitle }}
|
||||
</div>
|
||||
<div>{{ getUnder }}</div>
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12 md6 class="text-xs-left">
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex
|
||||
xs12
|
||||
md6
|
||||
class="text-xs-left"
|
||||
>
|
||||
<h5>From {{ plexserver.name }}</h5>
|
||||
</v-flex>
|
||||
<v-flex xs12 md6 class="text-xs-right">
|
||||
<v-flex
|
||||
xs12
|
||||
md6
|
||||
class="text-xs-right"
|
||||
>
|
||||
<div class="text-xs-right">
|
||||
<span>{{ (Math.round(timer / 1000) * 100) / 100 }}s</span>
|
||||
<v-btn @click="pressPlay" color="primary">Play Now</v-btn>
|
||||
<v-btn flat @click="sheet = false">Cancel</v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="pressPlay"
|
||||
>
|
||||
Play Now
|
||||
</v-btn>
|
||||
<v-btn
|
||||
flat
|
||||
@click="sheet = false"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
@ -37,7 +95,11 @@
|
|||
</v-layout>
|
||||
</v-container>
|
||||
</v-layout>
|
||||
<div :style="{ width: percent + '%'}" class="primary" style="height: 3px"></div>
|
||||
<div
|
||||
:style="{ width: percent + '%'}"
|
||||
class="primary"
|
||||
style="height: 3px"
|
||||
/>
|
||||
<!-- <v-progress-linear :value="percent" class="pa-0 ma-0" height="3"></v-progress-linear> -->
|
||||
</v-container>
|
||||
</v-card>
|
||||
|
@ -59,43 +121,6 @@ export default {
|
|||
ready: false,
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
window.EventBus.$on('upnext', (data) => {
|
||||
console.log('Upnext event', data);
|
||||
this.content = data;
|
||||
this.ready = true;
|
||||
this.startTimer();
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
|
||||
},
|
||||
methods: {
|
||||
pressPlay() {
|
||||
this.chosenClient.playMedia({
|
||||
ratingKey: this.item.ratingKey,
|
||||
mediaIndex: null,
|
||||
server: this.plexserver,
|
||||
offset: 0,
|
||||
});
|
||||
},
|
||||
startTimer() {
|
||||
this.timer = this.maxTimer;
|
||||
const data = this.item;
|
||||
this.sheet = true;
|
||||
const ticker = setInterval(() => {
|
||||
console.log('tick');
|
||||
this.timer -= 30;
|
||||
if (this.timer < 1) {
|
||||
if (this.sheet) {
|
||||
this.pressPlay(data.item);
|
||||
}
|
||||
clearInterval(ticker);
|
||||
this.sheet = false;
|
||||
}
|
||||
}, 30);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
percent() {
|
||||
return (this.timer / this.maxTimer) * 100;
|
||||
|
@ -175,5 +200,42 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
||||
},
|
||||
async mounted() {
|
||||
window.EventBus.$on('upnext', (data) => {
|
||||
console.log('Upnext event', data);
|
||||
this.content = data;
|
||||
this.ready = true;
|
||||
this.startTimer();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
pressPlay() {
|
||||
this.chosenClient.playMedia({
|
||||
ratingKey: this.item.ratingKey,
|
||||
mediaIndex: null,
|
||||
server: this.plexserver,
|
||||
offset: 0,
|
||||
});
|
||||
},
|
||||
startTimer() {
|
||||
this.timer = this.maxTimer;
|
||||
const data = this.item;
|
||||
this.sheet = true;
|
||||
const ticker = setInterval(() => {
|
||||
console.log('tick');
|
||||
this.timer -= 30;
|
||||
if (this.timer < 1) {
|
||||
if (this.sheet) {
|
||||
this.pressPlay(data.item);
|
||||
}
|
||||
clearInterval(ticker);
|
||||
this.sheet = false;
|
||||
}
|
||||
}, 30);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
lintOnSave: process.env.NODE_ENV !== 'production',
|
||||
productionSourceMap: false,
|
||||
transpileDependencies: ['vuetify'],
|
||||
configureWebpack: {
|
||||
devtool: 'source-map',
|
||||
devtool: process.env.NODE_ENV === 'production' ? false : 'cheap-eval-source-map',
|
||||
resolve: {
|
||||
alias: {
|
||||
// Alias @ to /src folder for ES/TS imports
|
||||
'@': path.join(__dirname, '/src'),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue