Initial vuecli conversion. Still much broken.
16
.babelrc
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"presets": [
|
||||
[ "env", { "modules": false } ],
|
||||
"stage-2",
|
||||
"es2015",
|
||||
"es2016"
|
||||
],
|
||||
"plugins": ["transform-runtime"],
|
||||
"comments": false,
|
||||
"env": {
|
||||
"test": {
|
||||
"presets": [ "env", "stage-2" ],
|
||||
"plugins": [ "istanbul" ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
|
@ -0,0 +1,7 @@
|
|||
[*.{js,jsx,ts,tsx,vue}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
max_line_length = 100
|
53
.eslintrc.js
|
@ -1,50 +1,15 @@
|
|||
// https://eslint.org/docs/user-guide/configuring
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
node: true
|
||||
},
|
||||
extends: ["plugin:vue/essential", "eslint:recommended"],
|
||||
parserOptions: {
|
||||
parser: "babel-eslint"
|
||||
},
|
||||
extends: [
|
||||
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
|
||||
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
|
||||
'plugin:vue/essential',
|
||||
'airbnb-base',
|
||||
|
||||
],
|
||||
// required to lint *.vue files
|
||||
plugins: [
|
||||
'vue'
|
||||
],
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
// allow async-await
|
||||
'generator-star-spacing': 'off',
|
||||
// allow debugger during development
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'vue/html-closing-bracket-newline': ['error', {
|
||||
singleline: 'never',
|
||||
multiline: 'always',
|
||||
}],
|
||||
'vue/html-closing-bracket-spacing': ['error', {
|
||||
startTag: 'never',
|
||||
endTag: 'never',
|
||||
selfClosingTag: 'always',
|
||||
}],
|
||||
'import/extensions': ['error', 'always', {
|
||||
js: 'never',
|
||||
json: 'never',
|
||||
vue: 'never',
|
||||
}],
|
||||
'no-param-reassign': ['error', {
|
||||
props: true,
|
||||
ignorePropertyModificationsFor: [
|
||||
'state',
|
||||
],
|
||||
}],
|
||||
'no-plusplus': 'off',
|
||||
"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 }]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -10,3 +10,7 @@ ptinvites.json
|
|||
db.sqlite
|
||||
.tmp
|
||||
.vscode
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
"plugins": {
|
||||
// to edit target browsers: use "browserlist" field in package.json
|
||||
"autoprefixer": {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset',
|
||||
],
|
||||
};
|
|
@ -1,35 +0,0 @@
|
|||
require('./check-versions')()
|
||||
|
||||
process.env.NODE_ENV = 'production'
|
||||
|
||||
var ora = require('ora')
|
||||
var rm = require('rimraf')
|
||||
var path = require('path')
|
||||
var chalk = require('chalk')
|
||||
var webpack = require('webpack')
|
||||
var config = require('../config')
|
||||
var webpackConfig = require('./webpack.prod.conf')
|
||||
|
||||
var spinner = ora('building for production...')
|
||||
spinner.start()
|
||||
|
||||
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
||||
if (err) throw err
|
||||
webpack(webpackConfig, function (err, stats) {
|
||||
spinner.stop()
|
||||
if (err) throw err
|
||||
process.stdout.write(stats.toString({
|
||||
colors: true,
|
||||
modules: false,
|
||||
children: false,
|
||||
chunks: false,
|
||||
chunkModules: false
|
||||
}) + '\n\n')
|
||||
|
||||
console.log(chalk.cyan(' Build complete.\n'))
|
||||
console.log(chalk.yellow(
|
||||
' Tip: built files are meant to be served over an HTTP server.\n' +
|
||||
' Opening index.html over file:// won\'t work.\n'
|
||||
))
|
||||
})
|
||||
})
|
|
@ -1,48 +0,0 @@
|
|||
var chalk = require('chalk')
|
||||
var semver = require('semver')
|
||||
var packageConfig = require('../package.json')
|
||||
var shell = require('shelljs')
|
||||
function exec (cmd) {
|
||||
return require('child_process').execSync(cmd).toString().trim()
|
||||
}
|
||||
|
||||
var versionRequirements = [
|
||||
{
|
||||
name: 'node',
|
||||
currentVersion: semver.clean(process.version),
|
||||
versionRequirement: packageConfig.engines.node
|
||||
},
|
||||
]
|
||||
|
||||
if (shell.which('npm')) {
|
||||
versionRequirements.push({
|
||||
name: 'npm',
|
||||
currentVersion: exec('npm --version'),
|
||||
versionRequirement: packageConfig.engines.npm
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
var warnings = []
|
||||
for (var i = 0; i < versionRequirements.length; i++) {
|
||||
var mod = versionRequirements[i]
|
||||
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
|
||||
warnings.push(mod.name + ': ' +
|
||||
chalk.red(mod.currentVersion) + ' should be ' +
|
||||
chalk.green(mod.versionRequirement)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (warnings.length) {
|
||||
console.log('')
|
||||
console.log(chalk.yellow('To use this template, you must update following to modules:'))
|
||||
console.log()
|
||||
for (var i = 0; i < warnings.length; i++) {
|
||||
var warning = warnings[i]
|
||||
console.log(' ' + warning)
|
||||
}
|
||||
console.log()
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
/* eslint-disable */
|
||||
require('eventsource-polyfill')
|
||||
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
|
||||
|
||||
hotClient.subscribe(function (event) {
|
||||
if (event.action === 'reload') {
|
||||
window.location.reload()
|
||||
}
|
||||
})
|
|
@ -1,89 +0,0 @@
|
|||
require('./check-versions')()
|
||||
|
||||
var config = require('../config')
|
||||
if (!process.env.NODE_ENV) {
|
||||
process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
|
||||
}
|
||||
|
||||
var opn = require('opn')
|
||||
var path = require('path')
|
||||
var express = require('express')
|
||||
var webpack = require('webpack')
|
||||
var proxyMiddleware = require('http-proxy-middleware')
|
||||
var webpackConfig = require('./webpack.dev.conf')
|
||||
|
||||
// default port where dev server listens for incoming traffic
|
||||
var port = process.env.PORT || config.dev.port
|
||||
// automatically open browser, if not set will be false
|
||||
var autoOpenBrowser = !!config.dev.autoOpenBrowser
|
||||
// Define HTTP proxies to your custom API backend
|
||||
// https://github.com/chimurai/http-proxy-middleware
|
||||
var proxyTable = config.dev.proxyTable
|
||||
|
||||
var app = express()
|
||||
var compiler = webpack(webpackConfig)
|
||||
|
||||
var devMiddleware = require('webpack-dev-middleware')(compiler, {
|
||||
publicPath: webpackConfig.output.publicPath,
|
||||
quiet: true
|
||||
})
|
||||
|
||||
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
|
||||
log: () => {}
|
||||
})
|
||||
// force page reload when html-webpack-plugin template changes
|
||||
compiler.plugin('compilation', function (compilation) {
|
||||
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
|
||||
hotMiddleware.publish({ action: 'reload' })
|
||||
cb()
|
||||
})
|
||||
})
|
||||
|
||||
// proxy api requests
|
||||
Object.keys(proxyTable).forEach(function (context) {
|
||||
var options = proxyTable[context]
|
||||
if (typeof options === 'string') {
|
||||
options = { target: options }
|
||||
}
|
||||
app.use(proxyMiddleware(options.filter || context, options))
|
||||
})
|
||||
|
||||
// handle fallback for HTML5 history API
|
||||
app.use(require('connect-history-api-fallback')())
|
||||
|
||||
// serve webpack bundle output
|
||||
app.use(devMiddleware)
|
||||
|
||||
// enable hot-reload and state-preserving
|
||||
// compilation error display
|
||||
app.use(hotMiddleware)
|
||||
|
||||
// serve pure static assets
|
||||
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
|
||||
app.use(staticPath, express.static('./static'))
|
||||
|
||||
var uri = 'http://localhost:' + port
|
||||
|
||||
var _resolve
|
||||
var readyPromise = new Promise(resolve => {
|
||||
_resolve = resolve
|
||||
})
|
||||
|
||||
console.log('> Starting dev server...')
|
||||
devMiddleware.waitUntilValid(() => {
|
||||
console.log('> Listening at ' + uri + '\n')
|
||||
// when env is testing, don't need open it
|
||||
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
|
||||
opn(uri)
|
||||
}
|
||||
_resolve()
|
||||
})
|
||||
|
||||
var server = app.listen(port)
|
||||
|
||||
module.exports = {
|
||||
ready: readyPromise,
|
||||
close: () => {
|
||||
server.close()
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
var path = require('path')
|
||||
var config = require('../config')
|
||||
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
|
||||
exports.assetsPath = function (_path) {
|
||||
var assetsSubDirectory = process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsSubDirectory
|
||||
: config.dev.assetsSubDirectory
|
||||
return path.posix.join(assetsSubDirectory, _path)
|
||||
}
|
||||
|
||||
exports.cssLoaders = function (options) {
|
||||
options = options || {}
|
||||
|
||||
var cssLoader = {
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
minimize: process.env.NODE_ENV === 'production',
|
||||
sourceMap: options.sourceMap
|
||||
}
|
||||
}
|
||||
|
||||
// generate loader string to be used with extract text plugin
|
||||
function generateLoaders (loader, loaderOptions) {
|
||||
var loaders = [cssLoader]
|
||||
if (loader) {
|
||||
loaders.push({
|
||||
loader: loader + '-loader',
|
||||
options: Object.assign({}, loaderOptions, {
|
||||
sourceMap: options.sourceMap
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Extract CSS when that option is specified
|
||||
// (which is the case during production build)
|
||||
if (options.extract) {
|
||||
return ExtractTextPlugin.extract({
|
||||
use: loaders,
|
||||
fallback: 'vue-style-loader'
|
||||
})
|
||||
} else {
|
||||
return ['vue-style-loader'].concat(loaders)
|
||||
}
|
||||
}
|
||||
|
||||
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
|
||||
return {
|
||||
css: generateLoaders(),
|
||||
postcss: generateLoaders(),
|
||||
less: generateLoaders('less'),
|
||||
sass: generateLoaders('sass', { indentedSyntax: true }),
|
||||
scss: generateLoaders('sass'),
|
||||
stylus: generateLoaders('stylus'),
|
||||
styl: generateLoaders('stylus')
|
||||
}
|
||||
}
|
||||
|
||||
// Generate loaders for standalone style files (outside of .vue)
|
||||
exports.styleLoaders = function (options) {
|
||||
var output = []
|
||||
var loaders = exports.cssLoaders(options)
|
||||
for (var extension in loaders) {
|
||||
var loader = loaders[extension]
|
||||
output.push({
|
||||
test: new RegExp('\\.' + extension + '$'),
|
||||
use: loader
|
||||
})
|
||||
}
|
||||
return output
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
var utils = require('./utils')
|
||||
var config = require('../config')
|
||||
var isProduction = process.env.NODE_ENV === 'production'
|
||||
|
||||
module.exports = {
|
||||
loaders: utils.cssLoaders({
|
||||
sourceMap: isProduction
|
||||
? config.build.productionSourceMap
|
||||
: config.dev.cssSourceMap,
|
||||
extract: isProduction
|
||||
})
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
var path = require('path')
|
||||
var utils = require('./utils')
|
||||
var config = require('../config')
|
||||
var vueLoaderConfig = require('./vue-loader.conf')
|
||||
|
||||
function resolve (dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
app: './src/main.js'
|
||||
},
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: '[name].js',
|
||||
publicPath: process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsPublicPath
|
||||
: config.dev.assetsPublicPath
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.vue', '.json'],
|
||||
alias: {
|
||||
'vue$': 'vue/dist/vue.esm.js',
|
||||
'@': resolve('src')
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
options: vueLoaderConfig
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
include: [resolve('src'), resolve('test')]
|
||||
},
|
||||
{
|
||||
test: /\.styl$/,
|
||||
loader: ['style-loader', 'css-loader', 'stylus-loader']
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('img/[name].[hash:7].[ext]')
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
node: {
|
||||
console: true,
|
||||
fs: 'empty',
|
||||
net: 'empty',
|
||||
tls: 'empty'
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
var utils = require('./utils')
|
||||
var webpack = require('webpack')
|
||||
var config = require('../config')
|
||||
var merge = require('webpack-merge')
|
||||
var baseWebpackConfig = require('./webpack.base.conf')
|
||||
var HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
|
||||
// add hot-reload related code to entry chunks
|
||||
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
|
||||
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
|
||||
})
|
||||
|
||||
module.exports = merge(baseWebpackConfig, {
|
||||
module: {
|
||||
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
|
||||
},
|
||||
// cheap-module-eval-source-map is faster for development
|
||||
devtool: '#cheap-module-eval-source-map',
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': config.dev.env
|
||||
}),
|
||||
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
// https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: 'index.html',
|
||||
inject: true
|
||||
}),
|
||||
new FriendlyErrorsPlugin()
|
||||
]
|
||||
})
|
|
@ -1,125 +0,0 @@
|
|||
var path = require('path')
|
||||
var utils = require('./utils')
|
||||
var webpack = require('webpack')
|
||||
var config = require('../config')
|
||||
var merge = require('webpack-merge')
|
||||
var baseWebpackConfig = require('./webpack.base.conf')
|
||||
var CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
var HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
||||
|
||||
var env = config.build.env
|
||||
|
||||
var webpackConfig = merge(baseWebpackConfig, {
|
||||
module: {
|
||||
rules: utils.styleLoaders({
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
extract: true
|
||||
})
|
||||
},
|
||||
devtool: config.build.productionSourceMap ? '#source-map' : false,
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: utils.assetsPath('js/[name].[chunkhash].js'),
|
||||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
|
||||
},
|
||||
plugins: [
|
||||
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': env
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'typeof global': JSON.stringify('undefined')
|
||||
}),
|
||||
new UglifyJsPlugin({
|
||||
}),
|
||||
// new webpack.optimize.UglifyJsPlugin({
|
||||
// compress: true,
|
||||
// sourceMap: false
|
||||
// }),
|
||||
// extract css into its own file
|
||||
new ExtractTextPlugin({
|
||||
filename: utils.assetsPath('css/[name].[contenthash].css')
|
||||
}),
|
||||
// Compress extracted CSS. We are using this plugin so that possible
|
||||
// duplicated CSS from different components can be deduped.
|
||||
new OptimizeCSSPlugin({
|
||||
cssProcessorOptions: {
|
||||
safe: true
|
||||
}
|
||||
}),
|
||||
// generate dist index.html with correct asset hash for caching.
|
||||
// you can customize output by editing /index.html
|
||||
// see https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({
|
||||
filename: config.build.index,
|
||||
template: 'index.html',
|
||||
inject: true,
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true
|
||||
// more options:
|
||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||
},
|
||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||
chunksSortMode: 'dependency'
|
||||
}),
|
||||
// split vendor js into its own file
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'vendor',
|
||||
minChunks: function (module, count) {
|
||||
// any required modules inside node_modules are extracted to vendor
|
||||
return (
|
||||
module.resource &&
|
||||
/\.js$/.test(module.resource) &&
|
||||
module.resource.indexOf(
|
||||
path.join(__dirname, '../node_modules')
|
||||
) === 0
|
||||
)
|
||||
}
|
||||
}),
|
||||
// extract webpack runtime and module manifest to its own file in order to
|
||||
// prevent vendor hash from being updated whenever app bundle is updated
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'manifest',
|
||||
chunks: ['vendor']
|
||||
}),
|
||||
// copy custom static assets
|
||||
new CopyWebpackPlugin([
|
||||
{
|
||||
from: path.resolve(__dirname, '../static'),
|
||||
to: config.build.assetsSubDirectory,
|
||||
ignore: ['.*']
|
||||
}
|
||||
])
|
||||
]
|
||||
})
|
||||
|
||||
if (config.build.productionGzip) {
|
||||
var CompressionWebpackPlugin = require('compression-webpack-plugin')
|
||||
|
||||
webpackConfig.plugins.push(
|
||||
new CompressionWebpackPlugin({
|
||||
asset: '[path].gz[query]',
|
||||
algorithm: 'gzip',
|
||||
test: new RegExp(
|
||||
'\\.(' +
|
||||
config.build.productionGzipExtensions.join('|') +
|
||||
')$'
|
||||
),
|
||||
threshold: 10240,
|
||||
minRatio: 0.8
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (config.build.bundleAnalyzerReport) {
|
||||
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
||||
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
|
||||
}
|
||||
|
||||
module.exports = webpackConfig
|
|
@ -1,9 +0,0 @@
|
|||
var merge = require('webpack-merge')
|
||||
var prodEnv = require('./prod.env')
|
||||
var git = require('git-rev-sync')
|
||||
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"',
|
||||
gitHash: '"' + git.short() + '"',
|
||||
gitDate: '"' + git.date() + '"'
|
||||
})
|
|
@ -1,41 +0,0 @@
|
|||
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||
var path = require('path')
|
||||
|
||||
let SettingsHelper = require('../SettingsHelper.js')
|
||||
let settings = new SettingsHelper()
|
||||
|
||||
module.exports = {
|
||||
build: {
|
||||
env: require('./prod.env'),
|
||||
index: path.resolve(__dirname, '../dist/index.html'),
|
||||
assetsRoot: path.resolve(__dirname, '../dist'),
|
||||
assetsSubDirectory: '',
|
||||
assetsPublicPath: settings.webroot || '/',
|
||||
productionSourceMap: true,
|
||||
// Gzip off by default as many popular static hosts such as
|
||||
// Surge or Netlify already gzip all static assets for you.
|
||||
// Before setting to `true`, make sure to:
|
||||
// npm install --save-dev compression-webpack-plugin
|
||||
productionGzip: false,
|
||||
productionGzipExtensions: ['js', 'css'],
|
||||
// Run the build command with an extra argument to
|
||||
// View the bundle analyzer report after build finishes:
|
||||
// `npm run build --report`
|
||||
// Set to `true` or `false` to always turn it on or off
|
||||
bundleAnalyzerReport: process.env.npm_config_report
|
||||
},
|
||||
dev: {
|
||||
env: require('./dev.env'),
|
||||
port: 8080,
|
||||
autoOpenBrowser: true,
|
||||
assetsSubDirectory: '',
|
||||
assetsPublicPath: settings.webroot || '/',
|
||||
proxyTable: {},
|
||||
// CSS Sourcemaps off by default because relative paths are "buggy"
|
||||
// with this option, according to the CSS-Loader README
|
||||
// (https://github.com/webpack/css-loader#sourcemaps)
|
||||
// In our experience, they generally work as expected,
|
||||
// just be aware of this issue when enabling this option.
|
||||
cssSourceMap: false
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
const git = require('git-rev-sync');
|
||||
|
||||
const settings = new (require('../SettingsHelper'))();
|
||||
|
||||
console.log('Production settings', settings);
|
||||
if (process.env.API_OVERRIDE) {
|
||||
console.log('Building with API_OVERRIDE', process.env.API_OVERRIDE);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
NODE_ENV: '"production"',
|
||||
gitHash: `"${git.short()}"`,
|
||||
gitDate: `"${git.date()}"`,
|
||||
|
||||
webroot: `"${settings.webroot}"`,
|
||||
API_OVERRIDE: `"${process.env.API_OVERRIDE}"` || undefined,
|
||||
};
|
21
index.html
|
@ -1,21 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<link rel="shortcut icon" href="favicon.png" type="image/x-icon">
|
||||
<link rel="icon" href="favicon.png" type="image/x-icon">
|
||||
<title>SyncLounge</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet"
|
||||
type="text/css">
|
||||
<link href='https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' rel="stylesheet"
|
||||
type="text/css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
|
||||
</html>
|
142
package.json
|
@ -1,106 +1,58 @@
|
|||
{
|
||||
"name": "SyncLounge",
|
||||
"version": "2.0.0",
|
||||
"description": "Synced playback of Plex content",
|
||||
"author": "samcm",
|
||||
"private": false,
|
||||
"author": "samcm",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/samcm/synclounge.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/samcm/synclounge/issues"
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "https://synclounge.tv/",
|
||||
"scripts": {
|
||||
"dev": "node build/dev-server.js",
|
||||
"start": "npm run build; node webapp.js",
|
||||
"server": "node server.js",
|
||||
"build": "node build/build.js"
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"args-parser": "^1.1.0",
|
||||
"axios": "^0.18.1",
|
||||
"babel-eslint": "^8.2.2",
|
||||
"body-parser": "^1.19.0",
|
||||
"cors": "^2.8.3",
|
||||
"express": "^4.16.3",
|
||||
"fscreen": "^1.0.2",
|
||||
"git-rev-sync": "^1.12.0",
|
||||
"jsonfile": "^4.0.0",
|
||||
"moment": "^2.18.1",
|
||||
"sails-disk": "^1.1.0",
|
||||
"socket.io": "^2.0.3",
|
||||
"string-similarity": "^1.2.0",
|
||||
"videojs-contrib-hls": "^5.15.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-cookies": "^1.7.0",
|
||||
"vue-router": "^2.3.1",
|
||||
"vuetify": "^1.5.14",
|
||||
"vuex": "^2.3.1",
|
||||
"waterline": "^0.13.6",
|
||||
"waterline-mysql": "^0.6.0"
|
||||
"core-js": "^3.6.5",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuetify": "^2.2.11",
|
||||
"vuex": "^3.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^6.7.2",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^6.2.10",
|
||||
"babel-plugin-transform-runtime": "^6.22.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-es2016": "^6.24.1",
|
||||
"babel-preset-stage-2": "^6.22.0",
|
||||
"babel-register": "^6.22.0",
|
||||
"chalk": "^1.1.3",
|
||||
"clipboard": "^1.7.1",
|
||||
"connect-history-api-fallback": "^1.3.0",
|
||||
"copy-webpack-plugin": "^4.0.1",
|
||||
"css-loader": "^0.28.0",
|
||||
"eslint": "^4.19.0",
|
||||
"eslint-config-airbnb-base": "^12.1.0",
|
||||
"eslint-config-standard": "^11.0.0",
|
||||
"eslint-plugin-import": "^2.9.0",
|
||||
"eslint-plugin-node": "^6.0.1",
|
||||
"eslint-plugin-promise": "^3.7.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"eslint-plugin-vue": "^4.3.0",
|
||||
"eventsource-polyfill": "^0.9.6",
|
||||
"extract-text-webpack-plugin": "^2.0.0",
|
||||
"file-loader": "^0.11.1",
|
||||
"friendly-errors-webpack-plugin": "^1.1.3",
|
||||
"html-webpack-plugin": "^2.28.0",
|
||||
"http-proxy-middleware": "^0.19.1",
|
||||
"humanize-duration": "^3.10.0",
|
||||
"opn": "^4.0.2",
|
||||
"optimize-css-assets-webpack-plugin": "^1.3.0",
|
||||
"ora": "^1.2.0",
|
||||
"prettier-eslint": "^8.7.0",
|
||||
"prettier-eslint-cli": "^4.7.0",
|
||||
"request": "^2.88.0",
|
||||
"rimraf": "^2.6.0",
|
||||
"@vue/cli-plugin-babel": "~4.4.0",
|
||||
"@vue/cli-plugin-eslint": "~4.4.0",
|
||||
"@vue/cli-plugin-router": "~4.4.0",
|
||||
"@vue/cli-plugin-vuex": "~4.4.0",
|
||||
"@vue/cli-service": "~4.4.0",
|
||||
"@vue/eslint-config-airbnb": "^5.0.2",
|
||||
"args-parser": "^1.1.0",
|
||||
"axios": "^0.19.2",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"fscreen": "^1.0.2",
|
||||
"humanize-duration": "^3.23.0",
|
||||
"moment": "^2.26.0",
|
||||
"safe-json-parse": "^4.0.0",
|
||||
"semver": "^5.3.0",
|
||||
"shelljs": "^0.7.6",
|
||||
"socket.io-client": "^2.0.2",
|
||||
"stylus": "^0.54.5",
|
||||
"stylus-loader": "^3.0.1",
|
||||
"uglifyjs-webpack-plugin": "^1.2.7",
|
||||
"url-loader": "^0.5.8",
|
||||
"vanilla-tilt": "^1.4.0",
|
||||
"vue-clipboards": "^1.0.2",
|
||||
"vue-loader": "^11.3.4",
|
||||
"vue-observe-visibility": "^0.1.3",
|
||||
"vue-resource": "^1.3.4",
|
||||
"vue-scrollto": "^2.6.10",
|
||||
"vue-style-loader": "^2.0.5",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"vue-video-player": "^3.1.1",
|
||||
"webpack": "^2.3.3",
|
||||
"webpack-bundle-analyzer": "^2.2.1",
|
||||
"webpack-dev-middleware": "^1.10.0",
|
||||
"webpack-hot-middleware": "^2.18.0",
|
||||
"webpack-merge": "^4.1.0",
|
||||
"xml2js": "^0.4.17"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 8"
|
||||
]
|
||||
"sass": "^1.26.5",
|
||||
"sass-loader": "^8.0.2",
|
||||
"socket.io-client": "^2.3.0",
|
||||
"string-similarity": "^4.0.1",
|
||||
"vue-cli-plugin-vuetify": "~2.0.5",
|
||||
"vue-clipboard2": "^0.3.1",
|
||||
"vue-cookies": "^1.7.0",
|
||||
"vue-observe-visibility": "^0.4.6",
|
||||
"vue-scrollto": "^2.18.1",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"vue-video-player": "^5.0.2",
|
||||
"vuetify-loader": "^1.3.0",
|
||||
"xml2js": "^0.4.23"
|
||||
}
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
|
||||
Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
|
||||
</html>
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 671 B After Width: | Height: | Size: 671 B |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 671 B After Width: | Height: | Size: 671 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 857 B After Width: | Height: | Size: 857 B |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
301
src/App.vue
|
@ -1,8 +1,6 @@
|
|||
<template>
|
||||
<v-app dark style="height:100%">
|
||||
<v-navigation-drawer app temporary style="padding: 0" v-model="drawer" disable-route-watcher>
|
||||
<leftsidebar></leftsidebar>
|
||||
</v-navigation-drawer>
|
||||
<leftsidebar :drawer="drawer"></leftsidebar>
|
||||
<v-navigation-drawer
|
||||
v-if="showRightDrawerButton"
|
||||
style="padding: 0; z-index: 6"
|
||||
|
@ -15,15 +13,8 @@
|
|||
<drawerright></drawerright>
|
||||
</v-navigation-drawer>
|
||||
|
||||
<v-toolbar
|
||||
app
|
||||
fixed
|
||||
scroll-off-screen
|
||||
:scroll-threshold="1"
|
||||
:manual-scroll="appIsFullscreen"
|
||||
style="z-index: 5"
|
||||
>
|
||||
<v-toolbar-side-icon @click="drawer = !drawer"></v-toolbar-side-icon>
|
||||
<v-app-bar fixed scroll-off-screen :scroll-threshold="1" style="z-index: 5">
|
||||
<v-app-bar-nav-icon @click="drawer = !drawer"></v-app-bar-nav-icon>
|
||||
<a href="https://synclounge.tv" target="_blank">
|
||||
<img
|
||||
class="ma-1 hidden-xs-only"
|
||||
|
@ -54,20 +45,20 @@
|
|||
small
|
||||
tag="a"
|
||||
class="hidden-sm-and-down"
|
||||
flat
|
||||
text
|
||||
v-for="item in links"
|
||||
:key="item.title"
|
||||
:href="item.href"
|
||||
:target="item.target"
|
||||
>{{ item.title }}</v-btn>
|
||||
<v-btn small tag="a" class="hidden-sm-and-down" flat @click="donateDialog = true">Donate ♥</v-btn>
|
||||
<v-btn small tag="a" class="hidden-sm-and-down" text @click="donateDialog = true">Donate ♥</v-btn>
|
||||
<v-icon
|
||||
v-if="showRightDrawerButton"
|
||||
@click="toggleDrawerRight"
|
||||
class="clickable"
|
||||
>{{ drawerRight ? 'last_page' : 'first_page' }}</v-icon>
|
||||
</v-toolbar-items>
|
||||
</v-toolbar>
|
||||
</v-app-bar>
|
||||
<v-content v-bind:style="mainStyle" app>
|
||||
<v-container
|
||||
class="ma-0 pa-0"
|
||||
|
@ -77,16 +68,11 @@
|
|||
fluid
|
||||
>
|
||||
<v-flex xs12 v-if="configError">
|
||||
<v-alert
|
||||
:dismissible="true"
|
||||
:value="configError"
|
||||
type="error"
|
||||
class="mt-0"
|
||||
>{{ configError }}</v-alert>
|
||||
<v-alert :dismissible="true" type="error" class="mt-0">{{ configError }}</v-alert>
|
||||
</v-flex>
|
||||
<v-flex xs12 v-if="(loading || (plex && !plex.gotDevices)) && route.protected">
|
||||
<v-container fill-height>
|
||||
<v-layout justify-center align-center wrap row class="pt-4 text-xs-center">
|
||||
<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" class="amber--text"></v-progress-circular>
|
||||
</v-flex>
|
||||
|
@ -123,19 +109,18 @@
|
|||
|
||||
<script>
|
||||
// Custom css
|
||||
import './assets/css/style.css';
|
||||
import "./assets/css/style.css";
|
||||
|
||||
import fscreen from 'fscreen';
|
||||
import fscreen from "fscreen";
|
||||
|
||||
import drawerright from './sidebar';
|
||||
import leftsidebar from './leftsidebar';
|
||||
import upnext from './upnext';
|
||||
import nowplayingchip from './nowplayingchip';
|
||||
import donate from './donate';
|
||||
import { mapActions, mapState } from "vuex";
|
||||
import drawerright from "./sidebar.vue";
|
||||
import leftsidebar from "./leftsidebar.vue";
|
||||
import upnext from "./upnext.vue";
|
||||
import nowplayingchip from "./nowplayingchip.vue";
|
||||
import donate from "./donate.vue";
|
||||
|
||||
import { mapActions, mapState } from 'vuex';
|
||||
|
||||
const SettingsHelper = require('../SettingsHelper');
|
||||
const SettingsHelper = require("../SettingsHelper");
|
||||
|
||||
const settings = new SettingsHelper();
|
||||
|
||||
|
@ -145,7 +130,7 @@ export default {
|
|||
upnext,
|
||||
nowplayingchip,
|
||||
leftsidebar,
|
||||
donate,
|
||||
donate
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -165,38 +150,38 @@ export default {
|
|||
|
||||
items: [
|
||||
{
|
||||
title: 'Preferences',
|
||||
title: "Preferences"
|
||||
},
|
||||
{
|
||||
title: 'Signout',
|
||||
},
|
||||
title: "Signout"
|
||||
}
|
||||
],
|
||||
links: [
|
||||
{
|
||||
title: 'Github',
|
||||
href: 'https://github.com/samcm/SyncLounge',
|
||||
target: '_blank',
|
||||
title: "Github",
|
||||
href: "https://github.com/samcm/SyncLounge",
|
||||
target: "_blank"
|
||||
},
|
||||
{
|
||||
title: 'Discord',
|
||||
target: '_blank',
|
||||
href: 'https://discord.gg/fKQB3yt',
|
||||
},
|
||||
title: "Discord",
|
||||
target: "_blank",
|
||||
href: "https://discord.gg/fKQB3yt"
|
||||
}
|
||||
],
|
||||
appIsFullscreen: false,
|
||||
appIsFullscreen: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
...mapActions('config', ['fetchConfig']),
|
||||
...mapActions("config", ["fetchConfig"]),
|
||||
sendNotification() {
|
||||
window.EventBus.$emit('notification', 'Copied to clipboard');
|
||||
window.EventBus.$emit("notification", "Copied to clipboard");
|
||||
},
|
||||
toggleDrawerRight() {
|
||||
this.drawerRight = !this.drawerRight;
|
||||
},
|
||||
goFullscreen() {
|
||||
fscreen.requestFullscreen(document.body);
|
||||
},
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
try {
|
||||
|
@ -210,102 +195,106 @@ export default {
|
|||
//
|
||||
// Set AutoJoin information in order of importance: query -> config -> settings
|
||||
if (this.$route.query.autojoin) {
|
||||
this.$store.commit('SET_AUTOJOIN', true);
|
||||
this.$store.commit('SET_AUTOJOINROOM', this.$route.query.room);
|
||||
this.$store.commit('SET_AUTOJOINURL', this.$route.query.server);
|
||||
this.$store.commit('SET_VALUE', [
|
||||
'autoJoinOwner',
|
||||
this.$route.query.owner,
|
||||
this.$store.commit("SET_AUTOJOIN", true);
|
||||
this.$store.commit("SET_AUTOJOINROOM", this.$route.query.room);
|
||||
this.$store.commit("SET_AUTOJOINURL", this.$route.query.server);
|
||||
this.$store.commit("SET_VALUE", [
|
||||
"autoJoinOwner",
|
||||
this.$route.query.owner
|
||||
]);
|
||||
if (this.$route.query.password) {
|
||||
this.$store.commit('SET_AUTOJOINPASSWORD', this.$route.query.password);
|
||||
this.$store.commit("SET_AUTOJOINPASSWORD", this.$route.query.password);
|
||||
}
|
||||
} else if (this.config) {
|
||||
if (
|
||||
this.config.autoJoin &&
|
||||
(this.config.autoJoin === true || this.config.autoJoin === 'true')
|
||||
(this.config.autoJoin === true || this.config.autoJoin === "true")
|
||||
) {
|
||||
this.$store.commit('SET_AUTOJOIN', true);
|
||||
this.$store.commit('SET_AUTOJOINROOM', this.config.autoJoinRoom);
|
||||
this.$store.commit('SET_AUTOJOINURL', this.config.autoJoinServer);
|
||||
this.$store.commit("SET_AUTOJOIN", true);
|
||||
this.$store.commit("SET_AUTOJOINROOM", this.config.autoJoinRoom);
|
||||
this.$store.commit("SET_AUTOJOINURL", this.config.autoJoinServer);
|
||||
this.$store.commit(
|
||||
'SET_AUTOJOINPASSWORD',
|
||||
this.config.autoJoinPassword,
|
||||
"SET_AUTOJOINPASSWORD",
|
||||
this.config.autoJoinPassword
|
||||
);
|
||||
}
|
||||
} else if (settings) {
|
||||
if (
|
||||
settings.autoJoin &&
|
||||
(settings.autoJoin === true || settings.autoJoin === 'true')
|
||||
(settings.autoJoin === true || settings.autoJoin === "true")
|
||||
) {
|
||||
this.$store.commit('SET_AUTOJOIN', true);
|
||||
this.$store.commit('SET_AUTOJOINROOM', settings.autoJoinRoom);
|
||||
this.$store.commit('SET_AUTOJOINURL', settings.autoJoinServer);
|
||||
this.$store.commit('SET_AUTOJOINPASSWORD', settings.autoJoinPassword);
|
||||
this.$store.commit("SET_AUTOJOIN", true);
|
||||
this.$store.commit("SET_AUTOJOINROOM", settings.autoJoinRoom);
|
||||
this.$store.commit("SET_AUTOJOINURL", settings.autoJoinServer);
|
||||
this.$store.commit("SET_AUTOJOINPASSWORD", settings.autoJoinPassword);
|
||||
}
|
||||
}
|
||||
|
||||
// Get other settings in order of importance: config -> settings
|
||||
// Authentication Mechanism setting
|
||||
if (this.config && this.config.authentication) {
|
||||
this.$store.commit('SET_AUTHENTICATION', this.config.authentication);
|
||||
this.$store.commit("SET_AUTHENTICATION", this.config.authentication);
|
||||
} else if (settings && settings.authentication) {
|
||||
this.$store.commit('SET_AUTHENTICATION', settings.authentication);
|
||||
this.$store.commit("SET_AUTHENTICATION", settings.authentication);
|
||||
} else {
|
||||
this.$store.commit('SET_AUTHENTICATION', {
|
||||
type: 'none',
|
||||
this.$store.commit("SET_AUTHENTICATION", {
|
||||
type: "none"
|
||||
});
|
||||
}
|
||||
|
||||
// Custom Servers list settings
|
||||
let servers = [
|
||||
{
|
||||
name: 'SyncLounge AU1',
|
||||
location: 'Sydney, Australia',
|
||||
url: 'https://v3au1.synclounge.tv/slserver',
|
||||
image: 'flags/au.png',
|
||||
name: "SyncLounge AU1",
|
||||
location: "Sydney, Australia",
|
||||
url: "https://v3au1.synclounge.tv/slserver",
|
||||
image: "flags/au.png"
|
||||
},
|
||||
{
|
||||
name: 'SyncLounge EU1',
|
||||
location: 'Amsterdam, Netherlands',
|
||||
url: 'https://v2eu1.synclounge.tv/server',
|
||||
image: 'flags/eu.png',
|
||||
name: "SyncLounge EU1",
|
||||
location: "Amsterdam, Netherlands",
|
||||
url: "https://v2eu1.synclounge.tv/server",
|
||||
image: "flags/eu.png"
|
||||
},
|
||||
{
|
||||
name: 'SyncLounge US1',
|
||||
location: 'Miami, United States',
|
||||
url: 'https://v2us1.synclounge.tv/server',
|
||||
image: 'flags/us.png',
|
||||
name: "SyncLounge US1",
|
||||
location: "Miami, United States",
|
||||
url: "https://v2us1.synclounge.tv/server",
|
||||
image: "flags/us.png"
|
||||
},
|
||||
{
|
||||
name: 'SyncLounge US2',
|
||||
location: 'Miami, United States',
|
||||
url: 'https://v3us1.synclounge.tv/slserver',
|
||||
image: 'flags/us.png',
|
||||
name: "SyncLounge US2",
|
||||
location: "Miami, United States",
|
||||
url: "https://v3us1.synclounge.tv/slserver",
|
||||
image: "flags/us.png"
|
||||
},
|
||||
{
|
||||
name: 'SyncLounge US3',
|
||||
location: 'Miami, United States',
|
||||
url: 'https://v3us2.synclounge.tv/slserver',
|
||||
image: 'flags/us.png',
|
||||
},
|
||||
name: "SyncLounge US3",
|
||||
location: "Miami, United States",
|
||||
url: "https://v3us2.synclounge.tv/slserver",
|
||||
image: "flags/us.png"
|
||||
}
|
||||
];
|
||||
const customServer = {
|
||||
name: 'Custom Server',
|
||||
location: 'Anywhere!',
|
||||
url: 'custom',
|
||||
image: 'synclounge-white.png',
|
||||
name: "Custom Server",
|
||||
location: "Anywhere!",
|
||||
url: "custom",
|
||||
image: "synclounge-white.png"
|
||||
};
|
||||
|
||||
if (this.config && this.config.servers) {
|
||||
servers = this.config.servers;
|
||||
if (this.config.customServer) {
|
||||
console.error("'customServer' setting provided with 'servers' setting. Ignoring 'customServer' setting.");
|
||||
console.error(
|
||||
"'customServer' setting provided with 'servers' setting. Ignoring 'customServer' setting."
|
||||
);
|
||||
}
|
||||
} else if (settings && settings.servers) {
|
||||
servers = settings.servers;
|
||||
if (settings.customServer) {
|
||||
console.error("'customServer' setting provided with 'servers' setting. Ignoring 'customServer' setting.");
|
||||
console.error(
|
||||
"'customServer' setting provided with 'servers' setting. Ignoring 'customServer' setting."
|
||||
);
|
||||
}
|
||||
} else if (this.config && this.config.customServer) {
|
||||
servers.push(this.config.customServer);
|
||||
|
@ -315,72 +304,74 @@ export default {
|
|||
servers.push(customServer);
|
||||
}
|
||||
|
||||
this.$store.commit('setSetting', ['SERVERS', servers]);
|
||||
this.$store.commit("setSetting", ["SERVERS", servers]);
|
||||
|
||||
// Auto-join if a single server is provided and autoJoinServer is not
|
||||
if (servers.length == 1 && !this.$store.autoJoinServer) {
|
||||
if (servers.length === 1 && !this.$store.autoJoinServer) {
|
||||
const server = servers[0];
|
||||
this.$store.commit('SET_AUTOJOIN', true);
|
||||
this.$store.commit('SET_AUTOJOINURL', server.url);
|
||||
this.$store.commit("SET_AUTOJOIN", true);
|
||||
this.$store.commit("SET_AUTOJOINURL", server.url);
|
||||
if (!this.$store.autoJoinRoom && server.defaultRoom) {
|
||||
this.$store.commit('SET_AUTOJOINROOM', server.defaultRoom);
|
||||
this.$store.commit("SET_AUTOJOINROOM", server.defaultRoom);
|
||||
}
|
||||
if (!this.$store.autoJoinPassword && server.defaultPassword) {
|
||||
this.$store.commit('SET_AUTOJOINPASSWORD', server.defaultPassword);
|
||||
this.$store.commit("SET_AUTOJOINPASSWORD", server.defaultPassword);
|
||||
}
|
||||
}
|
||||
//
|
||||
// End Settings
|
||||
//
|
||||
|
||||
window.EventBus.$on('notification', (msg) => {
|
||||
window.EventBus.$on("notification", msg => {
|
||||
this.snackbarMsg = msg;
|
||||
this.snackbar = true;
|
||||
});
|
||||
window.EventBus.$on('NEW_TIMELINE', (timeline) => {
|
||||
this.$store.dispatch('NEW_TIMELINE', timeline);
|
||||
window.EventBus.$on("NEW_TIMELINE", timeline => {
|
||||
this.$store.dispatch("NEW_TIMELINE", timeline);
|
||||
});
|
||||
window.EventBus.$on('PLAYBACK_CHANGE', (data) => {
|
||||
if (this.chosenClient.clientIdentifier !== 'PTPLAYER9PLUS10' && data[1]) {
|
||||
this.$router.push(`/nowplaying/${data[2].machineIdentifier}/${data[1]}`);
|
||||
window.EventBus.$on("PLAYBACK_CHANGE", data => {
|
||||
if (this.chosenClient.clientIdentifier !== "PTPLAYER9PLUS10" && data[1]) {
|
||||
this.$router.push(
|
||||
`/nowplaying/${data[2].machineIdentifier}/${data[1]}`
|
||||
);
|
||||
}
|
||||
if (
|
||||
this.chosenClient.clientIdentifier !== 'PTPLAYER9PLUS10' &&
|
||||
this.chosenClient.clientIdentifier !== "PTPLAYER9PLUS10" &&
|
||||
!data[1] &&
|
||||
this.$route.fullPath.indexOf('/nowplaying') > -1
|
||||
this.$route.fullPath.indexOf("/nowplaying") > -1
|
||||
) {
|
||||
this.$router.push('/browse/');
|
||||
this.$router.push("/browse/");
|
||||
}
|
||||
this.$store.dispatch('PLAYBACK_CHANGE', data);
|
||||
this.$store.dispatch("PLAYBACK_CHANGE", data);
|
||||
});
|
||||
if (!window.localStorage.getItem('plexuser')) {
|
||||
this.$router.push('/signin');
|
||||
if (!window.localStorage.getItem("plexuser")) {
|
||||
this.$router.push("/signin");
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
if (this.$route.path === '/') {
|
||||
this.$router.push('/clientselect');
|
||||
if (this.$route.path === "/") {
|
||||
this.$router.push("/clientselect");
|
||||
}
|
||||
const plexstorage = JSON.parse(window.localStorage.getItem('plexuser'));
|
||||
const plexstorage = JSON.parse(window.localStorage.getItem("plexuser"));
|
||||
try {
|
||||
await this.$store.dispatch('PLEX_LOGIN_TOKEN', plexstorage.authToken);
|
||||
await this.$store.dispatch("PLEX_LOGIN_TOKEN", plexstorage.authToken);
|
||||
} catch (e) {
|
||||
this.$router.push('/signin');
|
||||
//this.$router.push('/signin');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.$store.state.autoJoin) {
|
||||
this.$store.dispatch('autoJoin', {
|
||||
this.$store.dispatch("autoJoin", {
|
||||
server: this.$store.state.autoJoinUrl,
|
||||
password: this.$store.state.autoJoinPassword,
|
||||
room: this.$store.state.autoJoinRoom,
|
||||
room: this.$store.state.autoJoinRoom
|
||||
});
|
||||
}
|
||||
|
||||
fscreen.addEventListener('fullscreenchange', () => {
|
||||
fscreen.addEventListener("fullscreenchange", () => {
|
||||
const isFullscreen = fscreen.fullscreenElement !== null;
|
||||
this.appIsFullscreen = isFullscreen;
|
||||
document.body.classList.toggle('is-fullscreen', isFullscreen);
|
||||
document.body.classList.toggle("is-fullscreen", isFullscreen);
|
||||
});
|
||||
|
||||
this.loading = false;
|
||||
|
@ -390,11 +381,11 @@ export default {
|
|||
if (this.showRightDrawerButton) {
|
||||
this.drawerRight = true;
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('config', {
|
||||
config: state => state.configuration,
|
||||
...mapState("config", {
|
||||
config: state => state.configuration
|
||||
}),
|
||||
plex() {
|
||||
return this.$store.getters.getPlex;
|
||||
|
@ -410,39 +401,39 @@ export default {
|
|||
},
|
||||
crumbs() {
|
||||
if (
|
||||
this.$route.path.indexOf('browse') === -1 &&
|
||||
this.$route.path.indexOf('nowplaying') === -1
|
||||
this.$route.path.indexOf("browse") === -1 &&
|
||||
this.$route.path.indexOf("nowplaying") === -1
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
const getTitle = (id) => {
|
||||
const getTitle = id => {
|
||||
try {
|
||||
return this.itemCache[this.$route.params.machineIdentifier][id].title;
|
||||
} catch (e) {
|
||||
return 'Loading..';
|
||||
return "Loading..";
|
||||
}
|
||||
};
|
||||
const getLibrary = (id) => {
|
||||
const getLibrary = id => {
|
||||
try {
|
||||
return this.libraryCache[this.$route.params.machineIdentifier][id];
|
||||
} catch (e) {
|
||||
return 'Library';
|
||||
return "Library";
|
||||
}
|
||||
};
|
||||
const data = [
|
||||
{
|
||||
text: 'Home',
|
||||
to: '/browse',
|
||||
},
|
||||
text: "Home",
|
||||
to: "/browse"
|
||||
}
|
||||
];
|
||||
const map = {
|
||||
machineIdentifier: () => ({
|
||||
text: this.plex.servers[this.$route.params.machineIdentifier].name,
|
||||
to: `/browse/${this.$route.params.machineIdentifier}`,
|
||||
to: `/browse/${this.$route.params.machineIdentifier}`
|
||||
}),
|
||||
sectionId: () => ({
|
||||
text: getLibrary(this.$route.params.sectionId),
|
||||
to: `/browse/${this.$route.params.machineIdentifier}/${this.$route.params.sectionId}`,
|
||||
to: `/browse/${this.$route.params.machineIdentifier}/${this.$route.params.sectionId}`
|
||||
}),
|
||||
parentKey: () => {
|
||||
let to;
|
||||
|
@ -453,19 +444,19 @@ export default {
|
|||
}
|
||||
return {
|
||||
text: getTitle(this.$route.params.parentKey),
|
||||
to,
|
||||
to
|
||||
};
|
||||
},
|
||||
grandparentKey: () => ({
|
||||
text: getTitle(this.$route.params.grandparentKey),
|
||||
to: `/browse/${this.$route.params.machineIdentifier}/${this.$route.params.sectionId}/tv/${this.$route.params.grandparentKey}/`,
|
||||
to: `/browse/${this.$route.params.machineIdentifier}/${this.$route.params.sectionId}/tv/${this.$route.params.grandparentKey}/`
|
||||
}),
|
||||
ratingKey: () => ({
|
||||
text: getTitle(this.$route.params.ratingKey),
|
||||
to: `/browse/${this.$route.params.machineIdentifier}/${this.$route.params.sectionId}/${this.$route.params.ratingKey}`,
|
||||
}),
|
||||
to: `/browse/${this.$route.params.machineIdentifier}/${this.$route.params.sectionId}/${this.$route.params.ratingKey}`
|
||||
})
|
||||
};
|
||||
Object.keys(this.$route.params).forEach((param) => {
|
||||
Object.keys(this.$route.params).forEach(param => {
|
||||
const link = map[param]();
|
||||
if (link) {
|
||||
data.push(link);
|
||||
|
@ -477,7 +468,7 @@ export default {
|
|||
return (
|
||||
this.chosenClient &&
|
||||
this.chosenClient.clientPlayingMetadata &&
|
||||
this.$route.name === 'browse'
|
||||
this.$route.name === "browse"
|
||||
);
|
||||
},
|
||||
showRightDrawerButton() {
|
||||
|
@ -496,7 +487,7 @@ export default {
|
|||
return this.logos.light.small;
|
||||
},
|
||||
isPlayer() {
|
||||
if (this.$route.path === '/') {
|
||||
if (this.$route.path === "/") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -532,10 +523,10 @@ export default {
|
|||
mainStyle() {
|
||||
if (this.$store.getters.getBackground !== null) {
|
||||
return {
|
||||
'background-image': `url(${this.$store.getters.getBackground})`,
|
||||
'background-repeat': 'no-repeat',
|
||||
'background-size': 'cover',
|
||||
'background-position': 'center',
|
||||
"background-image": `url(${this.$store.getters.getBackground})`,
|
||||
"background-repeat": "no-repeat",
|
||||
"background-size": "cover",
|
||||
"background-position": "center"
|
||||
};
|
||||
}
|
||||
return {};
|
||||
|
@ -544,21 +535,21 @@ export default {
|
|||
const arr = [];
|
||||
if (this.$store.getters.getBackground !== null) {
|
||||
arr.push({
|
||||
background: 'rgba(0,0,0,0.7)',
|
||||
background: "rgba(0,0,0,0.7)"
|
||||
});
|
||||
}
|
||||
return arr;
|
||||
},
|
||||
paddingStyle() {
|
||||
const arr = [];
|
||||
if (this.$route.path.indexOf('/player') === -1) {
|
||||
if (this.$route.path.indexOf("/player") === -1) {
|
||||
arr.push({
|
||||
padding: '16px',
|
||||
padding: "16px"
|
||||
});
|
||||
}
|
||||
return arr;
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -568,7 +559,3 @@ export default {
|
|||
text-decoration: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="stylus">
|
||||
@import './stylus/main';
|
||||
</style>
|
||||
|
|
|
@ -88,6 +88,10 @@ html {
|
|||
background: #353e58
|
||||
}
|
||||
|
||||
.v-navigation-drawer .theme--dark.v-list--nav.v-list {
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
main {
|
||||
/*background: #272c38;*/
|
||||
background: #2b5876;
|
||||
|
|
After Width: | Height: | Size: 6.7 KiB |
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg>
|
After Width: | Height: | Size: 539 B |
|
@ -36,18 +36,18 @@
|
|||
<v-subheader>Recent Rooms</v-subheader>
|
||||
<v-list class="pa-0">
|
||||
<template v-for="(item, index) in recentsSorted">
|
||||
<v-list-tile :key="index" v-if="index < 5" avatar @click="recentConnect(item)">
|
||||
<v-list-tile-avatar>
|
||||
<v-list-item :key="index" v-if="index < 5" avatar @click="recentConnect(item)">
|
||||
<v-list-item-avatar>
|
||||
<img :src="logos.light.small" style="width: 32px; height: auto" />
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ item.name || item.server || 'Custom' }}</v-list-tile-title>
|
||||
<v-list-tile-sub-title>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{ item.name || item.server || 'Custom' }}</v-list-item-title>
|
||||
<v-list-item-subtitle>
|
||||
<b>{{ item.room }}</b>
|
||||
<span style="opacity: 0.5; float: right">{{ sinceNow(item.time) }}</span>
|
||||
</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
<v-list-tile-action>
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-tooltip top color="light-blue darken-4">
|
||||
<v-icon
|
||||
color="white"
|
||||
|
@ -56,8 +56,8 @@
|
|||
@click.stop="removeHistoryItem(item)"
|
||||
>close</v-icon>Remove
|
||||
</v-tooltip>
|
||||
</v-list-tile-action>
|
||||
</v-list-tile>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-list>
|
||||
</v-flex>
|
||||
|
@ -79,17 +79,17 @@
|
|||
>
|
||||
<v-card height="300px" style="border-radius: 20px">
|
||||
<v-layout row wrap justify-start align-center style="height: 100%">
|
||||
<v-flex xs12 class="text-xs-center pa-2" style="height: 80px">
|
||||
<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-xs-center">
|
||||
<v-flex xs12 class="text-center">
|
||||
<h2>{{ server.name }}</h2>
|
||||
<h4>{{ server.location }}</h4>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="text-xs-center" v-if="server.url !== 'custom'">
|
||||
<v-flex xs12 class="text-center" v-if="server.url !== 'custom'">
|
||||
<div v-if="results[server.url]">
|
||||
<div v-if="results[server.url].alive">
|
||||
Ping:
|
||||
|
@ -98,10 +98,10 @@
|
|||
:class="connectionQualityClass(results[server.url].latency)"
|
||||
>{{ results[server.url].latency }}ms</span>
|
||||
</div>
|
||||
<div v-else class="text-xs-center red--text">error</div>
|
||||
<div v-else class="text-center red--text">error</div>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="text-xs-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">
|
||||
|
@ -113,12 +113,12 @@
|
|||
>{{ results[server.url].result || 'Unknown' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="text-xs-center red--text">error</div>
|
||||
<div v-else class="text-center red--text">error</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs12 class="text-xs-center pt-1 mt-4">
|
||||
<v-flex xs12 class="text-center pt-1 mt-4">
|
||||
<v-btn
|
||||
color="primary"
|
||||
:disabled="connectionPending"
|
||||
|
@ -160,14 +160,14 @@
|
|||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout class="pt-3 text-xs-center" row wrap v-if="serverError">
|
||||
<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>
|
||||
{{ serverError }}
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
<v-flex xs12 v-if="context.getters.getConnected" class="text-xs-center">
|
||||
<v-flex xs12 v-if="context.getters.getConnected" class="text-center">
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12 md6 offset-md3>
|
||||
<v-text-field
|
||||
|
@ -193,7 +193,7 @@
|
|||
<v-flex xs12 md6 offset-md3>
|
||||
<v-btn block color="primary" v-on:click.native="joinRoom()">Join</v-btn>
|
||||
</v-flex>
|
||||
<v-layout class="pt-3 text-xs-center" row wrap v-if="roomError">
|
||||
<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>
|
||||
{{ roomError }}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
contain
|
||||
></v-img>
|
||||
</v-flex>
|
||||
<v-flex xs8 md12 class="text-xs-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)" class="primary white--text">
|
||||
<v-icon> play_arrow </v-icon>
|
||||
|
@ -47,12 +47,12 @@
|
|||
<v-icon>more_vert</v-icon>
|
||||
</v-btn>
|
||||
<v-list>
|
||||
<v-list-tile @click="markWatched(contents)">
|
||||
<v-list-tile-title>Mark as played</v-list-tile-title>
|
||||
</v-list-tile>
|
||||
<v-list-tile :href="'https://app.plex.tv/desktop#!/server/' + contents.machineIdentifier + '/details?key=' + contents.key" target="_blank">
|
||||
<v-list-tile-title>Open in Plex Web</v-list-tile-title>
|
||||
</v-list-tile>
|
||||
<v-list-item @click="markWatched(contents)">
|
||||
<v-list-item-title>Mark as played</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item :href="'https://app.plex.tv/desktop#!/server/' + contents.machineIdentifier + '/details?key=' + contents.key" target="_blank">
|
||||
<v-list-item-title>Open in Plex Web</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</span>
|
||||
|
@ -71,7 +71,7 @@
|
|||
<v-chip v-if="contents.studio" color="grey darken-2" small label> {{ contents.studio }}</v-chip>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="text-xs-center hidden-md-and-up ">
|
||||
<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)" class="primary white--text">
|
||||
<v-icon> play_arrow </v-icon>
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
<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-xs-center" style="max-width:100%; cursor: pointer; border-radius: 0px !important">
|
||||
<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-xs-center pa-1">
|
||||
<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>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<template>
|
||||
<v-list-tile avatar :style="styleObj" class="pa-1">
|
||||
<v-list-tile-avatar>
|
||||
<v-list-item avatar :style="styleObj" class="pa-1">
|
||||
<v-list-item-avatar>
|
||||
<img class="clientLogo" :class="platformClass" :src="url">
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>{{ object.name }}<v-chip v-for="label in object.labels" :key="label[0]" :color="label[1]" small label>{{ label[0] }}</v-chip></v-list-tile-title>
|
||||
<v-list-tile-sub-title>{{ object.product }} - last seen {{ lastSeenAgo }}</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{ object.name }}<v-chip v-for="label in object.labels" :key="label[0]" :color="label[1]" small label>{{ 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>
|
||||
</v-list-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
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-flex>
|
||||
</v-layout>
|
||||
<div v-if="plex && !plex.gotDevices" class="text-xs-center pa-4">
|
||||
<div v-if="plex && !plex.gotDevices" class="text-center pa-4">
|
||||
<v-progress-circular indeterminate color="primary"></v-progress-circular>
|
||||
</div>
|
||||
<v-layout v-else row wrap justify-center class="ml-4 mr-4">
|
||||
|
@ -42,7 +42,7 @@
|
|||
Selected Player
|
||||
</v-subheader>
|
||||
<v-layout row wrap>
|
||||
<v-flex md3 class="text-xs-center" style="position: relative">
|
||||
<v-flex md3 class="text-center" style="position: relative">
|
||||
<img :src="url" style="height: 100px; width: auto; vertical-align: middle" />
|
||||
</v-flex>
|
||||
<v-flex xs12 md9>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<v-layout wrap row class="text-xs-center" justify-center align-center>
|
||||
<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-xs-center">
|
||||
<v-flex xs12 md3 class="text-center">
|
||||
<img :src="logos.light.small" style="width: 90%" />
|
||||
</v-flex>
|
||||
<v-flex md9>
|
||||
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<v-layout wrap row class="pa-4 pt-2" justify-center align-center>
|
||||
<v-flex xs12 md8 class="text-xs-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>
|
||||
|
@ -24,7 +24,7 @@
|
|||
</v-layout>
|
||||
</v-container>
|
||||
<v-divider></v-divider>
|
||||
<p style="opacity:0.7" class="text-xs-center pt-3">
|
||||
<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>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<!-- <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-xs-center pt-1">
|
||||
<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" />
|
||||
|
@ -15,7 +15,7 @@
|
|||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout row wrap justify-start align-center v-else>
|
||||
<v-flex xs1 class="text-xs-center pt-1 mr-2 ml-2">
|
||||
<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" />
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<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>
|
||||
<h1 class="text-xs-center pa-2">
|
||||
<h1 class="text-center pa-2">
|
||||
Hello
|
||||
<span style="font-weight: 700">{{ plex.user.username }}</span>!
|
||||
</h1>
|
||||
|
@ -39,13 +39,13 @@
|
|||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
<div v-if="preAuth && !checkingAuth && !authError" class="text-xs-center">
|
||||
<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-xs-center error">
|
||||
<div v-if="authError" class="text-center error">
|
||||
<p>You are not authorized to access this server</p>
|
||||
</div>
|
||||
<v-layout wrap row class="pt-4 pa-2">
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
<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-xs-center">
|
||||
<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-xs-center pa-2">
|
||||
<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">
|
||||
{{ coin }}
|
||||
|
@ -24,7 +24,7 @@
|
|||
<v-flex xs8>
|
||||
{{ address }}
|
||||
</v-flex>
|
||||
<v-flex xs2 class="text-xs-center">
|
||||
<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>
|
||||
</v-layout>
|
||||
|
|
|
@ -1,101 +1,99 @@
|
|||
<template>
|
||||
<v-container fill-height class="pa-0" style="height: 100%">
|
||||
<v-layout row wrap justify-space-between>
|
||||
<v-flex xs12>
|
||||
<v-list class="pa-1 left-sidebar-list" dense style="background: none;">
|
||||
<template>
|
||||
<v-list-tile v-if="plex && plex.user">
|
||||
<v-list-tile-avatar>
|
||||
<img class="pa-1" :src="plex.user.thumb" />
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title style="font-weight: bold">{{ plex.user.username }}</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-divider></v-divider>
|
||||
<v-subheader>Preferences</v-subheader>
|
||||
<v-list-tile @click.stop="ptsettingstoggle = !ptsettingstoggle" class="text-xs-center">
|
||||
<v-list-tile-action>
|
||||
<v-icon color="white">settings</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>SyncLounge Settings</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile
|
||||
v-if="plex && plex.gotDevices"
|
||||
@click.stop="plexsettingstoggle = !plexsettingstoggle"
|
||||
>
|
||||
<v-list-tile-action>
|
||||
<v-icon color="white">settings</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>Plex Settings</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-subheader v-if="plex && plex.gotDevices">Account</v-subheader>
|
||||
<v-list-tile :router="true" to="/signout">
|
||||
<v-list-tile-action>
|
||||
<v-icon color="white">cancel</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>Sign out</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-subheader>About</v-subheader>
|
||||
<v-list-tile href="https://synclounge.tv/" target="_blank">
|
||||
<v-list-tile-action>
|
||||
<v-icon color="white">info</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>SyncLounge v{{appVersion}}</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile href="https://discord.gg/fKQB3yt" target="_blank">
|
||||
<v-list-tile-action>
|
||||
<v-icon color="white">chat</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>Discord</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile href="https://github.com/samcm/synclounge" target="_blank">
|
||||
<v-list-tile-action>
|
||||
<v-icon color="white">code</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>GitHub</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile @click.stop="donateDialog = true">
|
||||
<v-list-tile-action>
|
||||
<v-icon color="white">favorite</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>Donate</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</template>
|
||||
</v-list>
|
||||
</v-flex>
|
||||
<v-navigation-drawer app temporary v-model="drawer" disable-route-watcher>
|
||||
<v-list-item v-if="plex && plex.user">
|
||||
<v-list-item-avatar>
|
||||
<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-content>
|
||||
</v-list-item>
|
||||
<v-divider></v-divider>
|
||||
|
||||
<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-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>SyncLounge Settings</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item
|
||||
v-if="plex && plex.gotDevices"
|
||||
@click.stop="plexsettingstoggle = !plexsettingstoggle"
|
||||
>
|
||||
<v-list-item-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-list-item-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>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-subheader>About</v-subheader>
|
||||
<v-list-item href="https://synclounge.tv/" target="_blank">
|
||||
<v-list-item-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-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item href="https://discord.gg/fKQB3yt" target="_blank">
|
||||
<v-list-item-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-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>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item @click.stop="donateDialog = true">
|
||||
<v-list-item-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-flex xs12>
|
||||
<v-layout row wrap justify-end align-end style="height: 100%">
|
||||
<v-flex xs12>
|
||||
<v-divider></v-divider>
|
||||
<div class="text-xs-center pa-2" style="opacity: 0.7; font-size: 12px">
|
||||
<div>Build #{{ hash }}</div>
|
||||
<div>Last updated {{ updatedAt }}</div>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-list>
|
||||
|
||||
<template v-slot:append>
|
||||
<v-divider></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">
|
||||
<div class="text-xs-center">
|
||||
<div class="text-center">
|
||||
<h2>SyncLounge Settings</h2>
|
||||
</div>
|
||||
<v-divider class="mt-2 mb-2"></v-divider>
|
||||
|
@ -104,7 +102,7 @@
|
|||
</v-dialog>
|
||||
<v-dialog v-model="plexsettingstoggle" width="350">
|
||||
<v-card style="background-color: #151924" class="pa-3">
|
||||
<div class="text-xs-center">
|
||||
<div class="text-center">
|
||||
<h2>Plex Settings</h2>
|
||||
</div>
|
||||
<v-divider class="mt-2 mb-2"></v-divider>
|
||||
|
@ -114,7 +112,7 @@
|
|||
<v-dialog v-model="donateDialog" max-width="650px">
|
||||
<donate :donateDialog="donateDialog" :onClose="() => this.donateDialog = false"></donate>
|
||||
</v-dialog>
|
||||
</v-container>
|
||||
</v-navigation-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -130,6 +128,9 @@ export default {
|
|||
plexsettings,
|
||||
donate
|
||||
},
|
||||
props: {
|
||||
drawer: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ptsettingstoggle: false,
|
||||
|
|
82
src/main.js
|
@ -1,49 +1,32 @@
|
|||
import Vue from 'vue';
|
||||
import VueScrollTo from 'vue-scrollto';
|
||||
import Vuetify from 'vuetify';
|
||||
import { ObserveVisibility } from 'vue-observe-visibility/dist/vue-observe-visibility';
|
||||
import VueObserveVisibility from 'vue-observe-visibility';
|
||||
import VueVideoPlayer from 'vue-video-player';
|
||||
import VueResource from 'vue-resource';
|
||||
import VueClipboards from 'vue-clipboards';
|
||||
import VueCookies from 'vue-cookies'
|
||||
import VueClipboard from 'vue-clipboard2';
|
||||
import VueCookies from 'vue-cookies';
|
||||
import moment from 'moment';
|
||||
|
||||
import App from './App';
|
||||
import vuetify from './plugins/vuetify';
|
||||
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
|
||||
require('videojs-contrib-hls/dist/videojs-contrib-hls.js');
|
||||
require('vanilla-tilt');
|
||||
// require('videojs-contrib-hls/dist/videojs-contrib-hls.js');
|
||||
// require('vanilla-tilt');
|
||||
|
||||
const moment = require('moment');
|
||||
|
||||
Vue.use(VueScrollTo);
|
||||
Vue.use(VueClipboards);
|
||||
Vue.use(VueResource);
|
||||
Vue.directive('observe-visibility', ObserveVisibility);
|
||||
Vue.use(VueClipboard);
|
||||
Vue.use(VueObserveVisibility);
|
||||
Vue.use(VueVideoPlayer);
|
||||
|
||||
Vue.use(Vuetify, {
|
||||
theme: {
|
||||
primary: '#E5A00D',
|
||||
secondary: '#b0bec5',
|
||||
accent: '#E5A00D',
|
||||
error: '#b71c1c',
|
||||
},
|
||||
});
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
Vue.use(VueCookies);
|
||||
// set default config
|
||||
Vue.$cookies.config('7d');
|
||||
|
||||
function nolog() {}
|
||||
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
// console.log = nolog
|
||||
// console.warn = nolog
|
||||
// console.error = nolog
|
||||
}
|
||||
|
||||
// Our Event bus
|
||||
window.EventBus = new Vue();
|
||||
window.EventBus.$on('command', (data) => {
|
||||
|
@ -80,7 +63,7 @@ Vue.mixin({
|
|||
sinceNow(x) {
|
||||
const time = moment(x);
|
||||
return time.fromNow();
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
appVersion() {
|
||||
|
@ -117,39 +100,41 @@ Vue.mixin({
|
|||
return this.$route;
|
||||
},
|
||||
fontSizes() {
|
||||
const w = Math.round(Math.max(document.documentElement.clientWidth, window.innerWidth || 0));
|
||||
const w = Math.round(
|
||||
Math.max(document.documentElement.clientWidth, window.innerWidth || 0)
|
||||
);
|
||||
const maxPx = 94;
|
||||
const maxRes = 3000;
|
||||
return {
|
||||
largest: {
|
||||
'font-size': `${(w / maxRes) * maxPx}px`,
|
||||
'font-size': `${(w / maxRes) * maxPx}px`
|
||||
},
|
||||
medium: {
|
||||
'font-size': `${(w / maxRes) * maxPx * 0.6}px`,
|
||||
},
|
||||
'font-size': `${(w / maxRes) * maxPx * 0.6}px`
|
||||
}
|
||||
};
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
// console.log('Route change', to, this, store)
|
||||
if (to.matched.some(record => record.meta.protected)) {
|
||||
if (to.matched.some((record) => record.meta.protected)) {
|
||||
// this route requires us to be in a room with a client selected
|
||||
// if not, redirect to the needed stage
|
||||
if (!store.getters.getChosenClient) {
|
||||
return next({
|
||||
path: '/clientselect',
|
||||
path: '/clientselect'
|
||||
});
|
||||
}
|
||||
if (!store.getters.getRoom) {
|
||||
return next({
|
||||
path: '/joinroom',
|
||||
path: '/joinroom'
|
||||
});
|
||||
}
|
||||
if (!store.getters.getServer) {
|
||||
return next({
|
||||
path: '/joinroom',
|
||||
path: '/joinroom'
|
||||
});
|
||||
}
|
||||
next();
|
||||
|
@ -161,20 +146,15 @@ router.beforeEach((to, from, next) => {
|
|||
}
|
||||
});
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
store,
|
||||
template: '<App/>',
|
||||
components: {
|
||||
App,
|
||||
},
|
||||
vuetify,
|
||||
render: (h) => h(App),
|
||||
}).$mount('#app');
|
||||
|
||||
global.waitFor = async (ms) => new Promise((resolve) => {
|
||||
setTimeout(() => resolve, ms);
|
||||
});
|
||||
|
||||
global.waitFor = async ms =>
|
||||
new Promise((resolve) => {
|
||||
setTimeout(() => resolve, ms);
|
||||
});
|
||||
|
||||
global.to = promise => promise.then(data => [null, data]).catch(err => [err]);
|
||||
global.to = (promise) => promise.then((data) => [null, data]).catch((err) => [err]);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<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-xs-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">
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import Vue from 'vue';
|
||||
import Vuetify from 'vuetify/lib';
|
||||
|
||||
Vue.use(Vuetify);
|
||||
|
||||
export default new Vuetify({
|
||||
icons: {
|
||||
iconfont: 'md',
|
||||
},
|
||||
theme: {
|
||||
dark: true,
|
||||
themes: {
|
||||
dark: {
|
||||
primary: '#E5A00D',
|
||||
secondary: '#b0bec5',
|
||||
accent: '#E5A00D',
|
||||
error: '#b71c1c',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import Vue from 'vue';
|
||||
import Router from 'vue-router';
|
||||
// ===================== Pages Components ======================
|
||||
import signin from '../components/signin';
|
||||
import signout from '../components/signout';
|
||||
import join from '../components/join';
|
||||
import signin from '../components/signin.vue';
|
||||
import signout from '../components/signout.vue';
|
||||
import join from '../components/join.vue';
|
||||
|
||||
const SettingsHelper = require('../../SettingsHelper.js');
|
||||
|
||||
|
@ -15,128 +15,131 @@ Vue.use(Router);
|
|||
export default new Router({
|
||||
mode: 'hash',
|
||||
base: settings.webroot || '/',
|
||||
routes: [{
|
||||
path: '/',
|
||||
meta: {
|
||||
protected: true,
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
meta: {
|
||||
protected: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/signin',
|
||||
meta: {
|
||||
noload: true,
|
||||
{
|
||||
path: '/signin',
|
||||
meta: {
|
||||
noload: true,
|
||||
},
|
||||
component: signin,
|
||||
},
|
||||
component: signin,
|
||||
},
|
||||
{
|
||||
path: '/signout',
|
||||
meta: {
|
||||
noload: true,
|
||||
{
|
||||
path: '/signout',
|
||||
meta: {
|
||||
noload: true,
|
||||
},
|
||||
component: signout,
|
||||
},
|
||||
component: signout,
|
||||
},
|
||||
{
|
||||
path: '/join',
|
||||
meta: {
|
||||
noload: true,
|
||||
protected: false,
|
||||
{
|
||||
path: '/join',
|
||||
meta: {
|
||||
noload: true,
|
||||
protected: false,
|
||||
},
|
||||
component: join,
|
||||
},
|
||||
component: join,
|
||||
},
|
||||
{
|
||||
path: '/clientselect',
|
||||
meta: {
|
||||
noload: false,
|
||||
{
|
||||
path: '/clientselect',
|
||||
meta: {
|
||||
noload: false,
|
||||
},
|
||||
component: () => import('../components/application/walkthrough.vue'),
|
||||
},
|
||||
component: require('../components/application/walkthrough.vue'),
|
||||
},
|
||||
{
|
||||
path: '/joinroom',
|
||||
meta: {
|
||||
noload: false,
|
||||
{
|
||||
path: '/joinroom',
|
||||
meta: {
|
||||
noload: false,
|
||||
},
|
||||
component: () => import('../components/application/joinroom.vue'),
|
||||
},
|
||||
component: require('../components/application/joinroom.vue'),
|
||||
},
|
||||
|
||||
{
|
||||
path: '/player',
|
||||
meta: {
|
||||
protected: true,
|
||||
{
|
||||
path: '/player',
|
||||
meta: {
|
||||
protected: true,
|
||||
},
|
||||
component: () => import('../components/application/ptplayer.vue'),
|
||||
},
|
||||
component: require('../components/application/ptplayer.vue'),
|
||||
},
|
||||
{
|
||||
path: '/nowplaying/:machineIdentifier/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
{
|
||||
path: '/nowplaying/:machineIdentifier/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
},
|
||||
name: 'nowplaying',
|
||||
component: () => import('../components/application/plexbrowser/plexcontent.vue'),
|
||||
},
|
||||
name: 'nowplaying',
|
||||
component: require('../components/application/plexbrowser/plexcontent.vue'),
|
||||
},
|
||||
|
||||
{
|
||||
path: '/browse',
|
||||
meta: {
|
||||
protected: true,
|
||||
{
|
||||
path: '/browse',
|
||||
meta: {
|
||||
protected: true,
|
||||
},
|
||||
name: 'browse',
|
||||
component: () => import('../components/application/plexbrowser.vue'),
|
||||
},
|
||||
name: 'browse',
|
||||
component: require('../components/application/plexbrowser.vue'),
|
||||
},
|
||||
{
|
||||
path: '/browse/:machineIdentifier',
|
||||
meta: {
|
||||
protected: true,
|
||||
{
|
||||
path: '/browse/:machineIdentifier',
|
||||
meta: {
|
||||
protected: true,
|
||||
},
|
||||
name: 'server',
|
||||
component: () => import('../components/application/plexbrowser/plexserver.vue'),
|
||||
},
|
||||
name: 'server',
|
||||
component: require('../components/application/plexbrowser/plexserver.vue'),
|
||||
},
|
||||
{
|
||||
path: '/browse/:machineIdentifier/:sectionId',
|
||||
meta: {
|
||||
protected: true,
|
||||
{
|
||||
path: '/browse/:machineIdentifier/:sectionId',
|
||||
meta: {
|
||||
protected: true,
|
||||
},
|
||||
name: 'library',
|
||||
component: () => import('../components/application/plexbrowser/plexlibrary.vue'),
|
||||
},
|
||||
name: 'library',
|
||||
component: require('../components/application/plexbrowser/plexlibrary.vue'),
|
||||
},
|
||||
{
|
||||
path: '/browse/:machineIdentifier/:sectionId/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
{
|
||||
path: '/browse/:machineIdentifier/:sectionId/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
},
|
||||
name: 'content',
|
||||
component: () => import('../components/application/plexbrowser/plexcontent.vue'),
|
||||
},
|
||||
name: 'content',
|
||||
component: require('../components/application/plexbrowser/plexcontent.vue'),
|
||||
},
|
||||
{
|
||||
path: '/browse/:machineIdentifier/:sectionId/tv/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
{
|
||||
path: '/browse/:machineIdentifier/:sectionId/tv/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
},
|
||||
name: 'series',
|
||||
component: () => import('../components/application/plexbrowser/plexseries.vue'),
|
||||
},
|
||||
name: 'series',
|
||||
component: require('../components/application/plexbrowser/plexseries.vue'),
|
||||
},
|
||||
{
|
||||
path: '/browse/:machineIdentifier/:sectionId/tv/:parentKey/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
{
|
||||
path: '/browse/:machineIdentifier/:sectionId/tv/:parentKey/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
},
|
||||
name: 'season',
|
||||
component: () => import('../components/application/plexbrowser/plexseason.vue'),
|
||||
},
|
||||
name: 'season',
|
||||
component: require('../components/application/plexbrowser/plexseason.vue'),
|
||||
},
|
||||
{
|
||||
path: '/browse/:machineIdentifier/:sectionId/tv/:grandparentKey/:parentKey/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
{
|
||||
path:
|
||||
'/browse/:machineIdentifier/:sectionId/tv/:grandparentKey/:parentKey/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
},
|
||||
name: 'content',
|
||||
component: () => import('../components/application/plexbrowser/plexcontent.vue'),
|
||||
},
|
||||
name: 'content',
|
||||
component: require('../components/application/plexbrowser/plexcontent.vue'),
|
||||
},
|
||||
{
|
||||
path: '/browse/:machineIdentifier/tv/:grandparentKey/:parentKey/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
{
|
||||
path:
|
||||
'/browse/:machineIdentifier/tv/:grandparentKey/:parentKey/:ratingKey',
|
||||
meta: {
|
||||
protected: true,
|
||||
},
|
||||
name: 'content',
|
||||
component: () => import('../components/application/plexbrowser/plexcontent.vue'),
|
||||
},
|
||||
name: 'content',
|
||||
component: require('../components/application/plexbrowser/plexcontent.vue'),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
<v-icon>more_vert</v-icon>
|
||||
</v-btn>
|
||||
<v-list>
|
||||
<v-list-tile @click="handleDisconnect()">
|
||||
<v-list-tile-title class="user-menu-list">Leave Room</v-list-tile-title>
|
||||
</v-list-tile>
|
||||
<v-list-item @click="handleDisconnect()">
|
||||
<v-list-item-title class="user-menu-list">Leave Room</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-flex>
|
||||
|
@ -62,7 +62,7 @@
|
|||
</v-card>
|
||||
<v-card 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-xs-center">
|
||||
<v-flex xs12 class="text-center">
|
||||
<span class="mb-0 pb-0 pa-0" style="color: rgb(44, 44, 49); "> Waiting for {{ hostUser().username }} to start</span>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
@ -70,33 +70,33 @@
|
|||
</v-flex>
|
||||
<v-list dense two-line style="overflow: auto; max-height: calc(50vh - 154px); background: none">
|
||||
<v-card style="background: linear-gradient(180deg,#1f1c2c,#182848)!important; border-radius: 7px" class="pa-1 ml-3 mr-3">
|
||||
<v-list-tile avatar style="height:4em" class="pl-1 pr-1 mb-0" tag="div">
|
||||
<v-list-tile-avatar>
|
||||
<v-list-item avatar style="height:4em" class="pl-1 pr-1 mb-0" tag="div">
|
||||
<v-list-item-avatar>
|
||||
<img v-bind:src="hostUser().avatarUrl" :style="getImgStyle(hostUser())">
|
||||
<v-icon v-if="hostUser().playerState !== 'playing'" style="font-size: 26px; opacity: 0.8; position: absolute;background-color: rgba(0,0,0,0.5)">
|
||||
{{ playerState(hostUser()) }}
|
||||
</v-icon>
|
||||
</img>
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-content>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-tooltip bottom color="rgb(44, 44, 49)" multi-line class="userlist">
|
||||
<span slot="activator">
|
||||
<v-list-tile-title> {{ hostUser().username }} <span style="opacity: 0.6" v-if="hostUser().uuid === me.uuid"> (you) </span></v-list-tile-title>
|
||||
<v-list-tile-sub-title style="opacity:0.6;color:white;font-size:70%">{{ getTitle(hostUser()) }}</v-list-tile-sub-title>
|
||||
<v-list-item-title> {{ hostUser().username }} <span style="opacity: 0.6" v-if="hostUser().uuid === me.uuid"> (you) </span></v-list-item-title>
|
||||
<v-list-item-subtitle style="opacity:0.6;color:white;font-size:70%">{{ getTitle(hostUser()) }}</v-list-item-subtitle>
|
||||
</span>
|
||||
Watching on {{ hostUser().playerProduct || 'Unknown Plex Client' }}
|
||||
<span v-if="plex.servers[hostUser().machineIdentifier]">
|
||||
<br />via {{ plex.servers[hostUser().machineIdentifier].name }}
|
||||
</span>
|
||||
</v-tooltip>
|
||||
</v-list-tile-content>
|
||||
<v-list-tile-action>
|
||||
</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" slot="activator">star</v-icon>
|
||||
Host
|
||||
</v-tooltip>
|
||||
</v-list-tile-action>
|
||||
</v-list-tile>
|
||||
</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">{{ getCurrent(hostUser()) }}</span>
|
||||
<span style="float: right; font-size:70%" class="ptuser-maxTime pr-1">{{ getMax(hostUser()) }}</span>
|
||||
|
@ -105,27 +105,27 @@
|
|||
</v-card>
|
||||
<div v-for="user in ptUsers" v-bind:key="user.username">
|
||||
<div class="pa-1 ml-3 mr-3" v-if="!isHost(user)">
|
||||
<v-list-tile avatar style="height:4em" class="pb-0 mb-0" tag="div">
|
||||
<v-list-tile-avatar v-on:dblclick="transferHost(user.username)">
|
||||
<v-list-item avatar 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)">
|
||||
<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>
|
||||
</img>
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-content>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-tooltip bottom color="rgb(44, 44, 49)" multi-line class="userlist">
|
||||
<span slot="activator">
|
||||
<v-list-tile-title> {{ user.username }} <span style="opacity: 0.6" v-if="user.uuid === me.uuid"> (you) </span></v-list-tile-title>
|
||||
<v-list-tile-sub-title style="opacity:0.6;color:white;font-size:70%">{{ getTitle(user) }}</v-list-tile-sub-title>
|
||||
<v-list-item-title> {{ user.username }} <span style="opacity: 0.6" v-if="user.uuid === me.uuid"> (you) </span></v-list-item-title>
|
||||
<v-list-item-subtitle style="opacity:0.6;color:white;font-size:70%">{{ getTitle(user) }}</v-list-item-subtitle>
|
||||
</span>
|
||||
Watching on {{ user.playerProduct || 'Unknown Plex Client' }}
|
||||
<span v-if="plex.servers[user.machineIdentifier]">
|
||||
<br />via {{ plex.servers[user.machineIdentifier].name }}
|
||||
</span>
|
||||
</v-tooltip>
|
||||
</v-list-tile-content>
|
||||
<v-list-tile-action>
|
||||
</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" slot="activator">star</v-icon>
|
||||
Host
|
||||
|
@ -135,16 +135,16 @@
|
|||
<v-icon>more_vert</v-icon>
|
||||
</v-btn>
|
||||
<v-list>
|
||||
<v-list-tile @click="transferHost(user.username)">
|
||||
<v-list-tile-title class="user-menu-list">Make Host</v-list-tile-title>
|
||||
</v-list-tile>
|
||||
<!-- <v-list-tile @click.stop="openInviteDialog(user)">
|
||||
<v-list-tile-title class="user-menu-list">Invite to a Plex Server</v-list-tile-title>
|
||||
</v-list-tile> -->
|
||||
<v-list-item @click="transferHost(user.username)">
|
||||
<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>
|
||||
</v-list-item> -->
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-list-tile-action>
|
||||
</v-list-tile>
|
||||
</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">{{ getCurrent(user) }}</span>
|
||||
<span style="float: right; font-size:70%" class="ptuser-maxTime pr-1">{{ getMax(user) }}</span>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
},
|
||||
mutations: {
|
||||
},
|
||||
actions: {
|
||||
},
|
||||
modules: {
|
||||
},
|
||||
});
|
|
@ -1,15 +0,0 @@
|
|||
@import '../../node_modules/vuetify/src/stylus/settings/_colors'
|
||||
|
||||
$theme := {
|
||||
primary: #E5A00D
|
||||
accent: #353e58
|
||||
lighter: #353e58
|
||||
secondary: #353e58
|
||||
info: $blue.lighten-1
|
||||
warning: $amber.darken-2
|
||||
error: $red.accent-4
|
||||
success: $green.lighten-2
|
||||
}
|
||||
|
||||
/** Stylus Styles */
|
||||
@import '../../node_modules/vuetify/src/stylus/main'
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
transpileDependencies: [
|
||||
'vuetify',
|
||||
],
|
||||
};
|