Merge branch 'master' into ft-toast
This commit is contained in:
commit
f31bf4f881
|
@ -6,8 +6,6 @@ name: Build
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -25,6 +23,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
|
- run: npm run lint
|
||||||
- run: npm run build --if-present
|
- run: npm run build --if-present
|
||||||
- name: Upload .deb Artifact
|
- name: Upload .deb Artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# This is a basic workflow to help you get started with Actions
|
||||||
|
|
||||||
|
name: Linter
|
||||||
|
|
||||||
|
# Controls when the action will run. Triggers the workflow on push or pull request
|
||||||
|
# events but only for the master branch
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
|
jobs:
|
||||||
|
# This workflow contains a single job called "build"
|
||||||
|
lint:
|
||||||
|
# The type of runner that the job will run on
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Use Node.js 12.X
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 12.X
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run lint
|
File diff suppressed because it is too large
Load Diff
43
package.json
43
package.json
|
@ -8,9 +8,9 @@
|
||||||
"url": "https://github.com/FreeTubeApp/FreeTube/issues"
|
"url": "https://github.com/FreeTubeApp/FreeTube/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.28",
|
"@fortawesome/fontawesome-svg-core": "^1.2.29",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.13.0",
|
"@fortawesome/free-solid-svg-icons": "^5.13.1",
|
||||||
"@fortawesome/vue-fontawesome": "^0.1.9",
|
"@fortawesome/vue-fontawesome": "^0.1.10",
|
||||||
"@silvermine/videojs-quality-selector": "^1.2.4",
|
"@silvermine/videojs-quality-selector": "^1.2.4",
|
||||||
"autolinker": "^3.14.1",
|
"autolinker": "^3.14.1",
|
||||||
"bulma-pro": "^0.2.0",
|
"bulma-pro": "^0.2.0",
|
||||||
|
@ -31,56 +31,58 @@
|
||||||
"videojs-vtt-thumbnails": "0.0.13",
|
"videojs-vtt-thumbnails": "0.0.13",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-electron": "^1.0.6",
|
"vue-electron": "^1.0.6",
|
||||||
"vue-router": "^3.3.2",
|
"vue-router": "^3.3.4",
|
||||||
"vuex": "^3.4.0",
|
"vuex": "^3.4.0",
|
||||||
"xml2json": "^0.12.0",
|
"xml2json": "^0.12.0",
|
||||||
"youtube-chat": "^1.1.0",
|
"youtube-chat": "^1.1.0",
|
||||||
"youtube-comments-fetch": "^1.0.1",
|
"youtube-comments-fetch": "^1.0.1",
|
||||||
"youtube-comments-task": "^1.3.15",
|
"youtube-comments-task": "^1.3.15",
|
||||||
"youtube-suggest": "^1.1.0",
|
"youtube-suggest": "^1.1.0",
|
||||||
"yt-xml2vtt": "^1.0.1",
|
"yt-channel-info": "git+https://github.com/FreeTubeApp/yt-channel-info.git",
|
||||||
|
"yt-xml2vtt": "^1.1.1",
|
||||||
"ytdl-core": "^3.1.1",
|
"ytdl-core": "^3.1.1",
|
||||||
"ytpl": "^0.1.21",
|
"ytpl": "^0.1.21",
|
||||||
"ytsr": "^0.1.15"
|
"ytsr": "^0.1.15"
|
||||||
},
|
},
|
||||||
"description": "A private YouTube client",
|
"description": "A private YouTube client",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.10.2",
|
"@babel/core": "^7.10.3",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.10.1",
|
"@babel/plugin-proposal-class-properties": "^7.10.1",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.10.1",
|
"@babel/plugin-proposal-object-rest-spread": "^7.10.3",
|
||||||
"@babel/preset-env": "^7.10.2",
|
"@babel/preset-env": "^7.10.3",
|
||||||
"@babel/preset-typescript": "^7.10.1",
|
"@babel/preset-typescript": "^7.10.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^3.1.0",
|
"@typescript-eslint/eslint-plugin": "^3.3.0",
|
||||||
"@typescript-eslint/parser": "^3.1.0",
|
"@typescript-eslint/parser": "^3.3.0",
|
||||||
"acorn": "^7.2.0",
|
"acorn": "^7.3.1",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"copy-webpack-plugin": "^6.0.2",
|
"copy-webpack-plugin": "^6.0.2",
|
||||||
"css-loader": "^3.5.3",
|
"css-loader": "^3.6.0",
|
||||||
"devtron": "^1.4.0",
|
"devtron": "^1.4.0",
|
||||||
"electron": "^8.3.0",
|
"electron": "^9.0.4",
|
||||||
"electron-builder": "^22.7.0",
|
"electron-builder": "^22.7.0",
|
||||||
"electron-builder-squirrel-windows": "^22.7.0",
|
"electron-builder-squirrel-windows": "^22.7.0",
|
||||||
"electron-debug": "^3.1.0",
|
"electron-debug": "^3.1.0",
|
||||||
"electron-rebuild": "^1.11.0",
|
"electron-rebuild": "^1.11.0",
|
||||||
"eslint": "^7.1.0",
|
"eslint": "^7.3.0",
|
||||||
"eslint-config-prettier": "^6.11.0",
|
"eslint-config-prettier": "^6.11.0",
|
||||||
"eslint-config-standard": "^14.1.1",
|
"eslint-config-standard": "^14.1.1",
|
||||||
"eslint-plugin-import": "^2.20.2",
|
"eslint-plugin-import": "^2.21.2",
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-prettier": "^3.1.3",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
"eslint-plugin-standard": "^4.0.1",
|
"eslint-plugin-standard": "^4.0.1",
|
||||||
"eslint-plugin-vue": "^6.2.2",
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
"fast-glob": "^3.2.2",
|
"fast-glob": "^3.2.4",
|
||||||
"file-loader": "^6.0.0",
|
"file-loader": "^6.0.0",
|
||||||
"html-webpack-plugin": "^4.3.0",
|
"html-webpack-plugin": "^4.3.0",
|
||||||
"jest": "^26.0.1",
|
"jest": "^26.0.1",
|
||||||
"mini-css-extract-plugin": "^0.9.0",
|
"mini-css-extract-plugin": "^0.9.0",
|
||||||
|
"node-abi": "^2.18.0",
|
||||||
"node-loader": "^0.6.0",
|
"node-loader": "^0.6.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^2.0.5",
|
"prettier": "^2.0.5",
|
||||||
"sass": "^1.26.7",
|
"sass": "^1.26.8",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
"style-loader": "^1.2.1",
|
"style-loader": "^1.2.1",
|
||||||
"tree-kill": "1.2.2",
|
"tree-kill": "1.2.2",
|
||||||
|
@ -92,7 +94,7 @@
|
||||||
"vue-style-loader": "^4.1.2",
|
"vue-style-loader": "^4.1.2",
|
||||||
"vue-template-compiler": "^2.6.11",
|
"vue-template-compiler": "^2.6.11",
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.43.0",
|
||||||
"webpack-cli": "^3.3.11",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-dev-server": "^3.11.0"
|
"webpack-dev-server": "^3.11.0"
|
||||||
},
|
},
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
|
@ -116,7 +118,8 @@
|
||||||
"jest": "jest",
|
"jest": "jest",
|
||||||
"jest:coverage": "jest --collect-coverage",
|
"jest:coverage": "jest --collect-coverage",
|
||||||
"jest:watch": "jest --watch",
|
"jest:watch": "jest --watch",
|
||||||
"lint": "eslint --fix --ext .js,.ts,.vue ./",
|
"lint-fix": "eslint --fix --ext .js,.ts,.vue ./",
|
||||||
|
"lint": "eslint --ext .js,.ts,.vue ./",
|
||||||
"pack": "run-p pack:main pack:renderer pack:web pack:workers",
|
"pack": "run-p pack:main pack:renderer pack:web pack:workers",
|
||||||
"pack:main": "webpack --mode=production --env.NODE_ENV=production --hide-modules --config _scripts/webpack.main.config.js",
|
"pack:main": "webpack --mode=production --env.NODE_ENV=production --hide-modules --config _scripts/webpack.main.config.js",
|
||||||
"pack:renderer": "webpack --mode=production --env.NODE_ENV=production --hide-modules --config _scripts/webpack.renderer.config.js",
|
"pack:renderer": "webpack --mode=production --env.NODE_ENV=production --hide-modules --config _scripts/webpack.renderer.config.js",
|
||||||
|
|
|
@ -14,30 +14,36 @@ app.setName(productName)
|
||||||
// disable electron warning
|
// disable electron warning
|
||||||
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'
|
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'
|
||||||
|
|
||||||
const gotTheLock = app.requestSingleInstanceLock()
|
// const gotTheLock = app.requestSingleInstanceLock()
|
||||||
const isDev = process.env.NODE_ENV === 'development'
|
const isDev = process.env.NODE_ENV === 'development'
|
||||||
const isDebug = process.argv.includes('--debug')
|
const isDebug = process.argv.includes('--debug')
|
||||||
let mainWindow
|
let mainWindow
|
||||||
|
|
||||||
|
// CORS somehow gets re-enabled in Electron v9.0.4
|
||||||
|
// This line disables it.
|
||||||
|
// This line can possible be removed if the issue is fixed upstream
|
||||||
|
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors')
|
||||||
|
|
||||||
|
// TODO: Uncomment if needed
|
||||||
// only allow single instance of application
|
// only allow single instance of application
|
||||||
if (!isDev) {
|
// if (!isDev) {
|
||||||
if (gotTheLock) {
|
// if (gotTheLock) {
|
||||||
app.on('second-instance', () => {
|
// app.on('second-instance', () => {
|
||||||
// Someone tried to run a second instance, we should focus our window.
|
// // Someone tried to run a second instance, we should focus our window.
|
||||||
if (mainWindow && mainWindow.isMinimized()) {
|
// if (mainWindow && mainWindow.isMinimized()) {
|
||||||
mainWindow.restore()
|
// mainWindow.restore()
|
||||||
}
|
// }
|
||||||
mainWindow.focus()
|
// mainWindow.focus()
|
||||||
})
|
// })
|
||||||
} else {
|
// } else {
|
||||||
app.quit()
|
// app.quit()
|
||||||
process.exit(0)
|
// process.exit(0)
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
require('electron-debug')({
|
// require('electron-debug')({
|
||||||
showDevTools: !(process.env.RENDERER_REMOTE_DEBUGGING === 'true')
|
// showDevTools: !(process.env.RENDERER_REMOTE_DEBUGGING === 'true')
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
async function installDevTools () {
|
async function installDevTools () {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="129.158" height="129.158" viewBox="0 0 34.173 34.173"><g transform="translate(26.909 -78.793)" paint-order="fill markers stroke"><circle cx="-9.822" cy="95.88" r="16.557" fill="none" stroke="#ddd" stroke-width="1.058" stroke-linecap="round" stroke-linejoin="round"/><path style="line-height:normal;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;text-transform:none;text-orientation:mixed;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1" d="M-10.713 89.306l-.743 2.64 6.893 13.75h2.034zm-.743 2.64l-3.976 13.423.508.15 4.49-15.177zm-4.933 13.228v.53h2.813v-.53z" color="#000" font-weight="400" font-family="sans-serif" overflow="visible" fill="#ddd"/><circle cx="-10.763" cy="87.186" r="1.105" fill="#00b6f0"/></g></svg>
|
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="129.158" height="129.158" viewBox="0 0 34.173 34.173"><g transform="translate(26.909 -78.793)" paint-order="fill markers stroke"><circle cx="-9.822" cy="95.88" r="16.557" fill="none" stroke="#212121" stroke-width="1.058" stroke-linecap="round" stroke-linejoin="round"/><path style="line-height:normal;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;text-transform:none;text-orientation:mixed;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1" d="M-10.713 89.306l-.743 2.64 6.893 13.75h2.034zm-.743 2.64l-3.976 13.423.508.15 4.49-15.177zm-4.933 13.228v.53h2.813v-.53z" color="#000" font-weight="400" font-family="sans-serif" overflow="visible" fill="#212121"/><circle cx="-10.763" cy="87.186" r="1.105" fill="#00b6f0"/></g></svg>
|
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
|
@ -17,7 +17,7 @@
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
box-shadow: 0 0 2px -2px rgba(29, 39, 231, .1), 0 0 3px 0 rgba(29, 39, 231, .1), 0 0 5px 0 rgba(29, 39, 231, .1), 0 2px 2px -4px rgba(29, 39, 231, .1), 0 4px 8px 0 rgba(29, 39, 231, .1), 0 2px 15px 0 rgba(29, 39, 231, .1);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ripple {
|
.ripple {
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default Vue.extend({
|
||||||
props: {
|
props: {
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
default: ''
|
||||||
},
|
},
|
||||||
textColor: {
|
textColor: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
}"
|
}"
|
||||||
@click="$emit('click')"
|
@click="$emit('click')"
|
||||||
>
|
>
|
||||||
{{ label }}
|
<slot>
|
||||||
|
{{ label }}
|
||||||
|
</slot>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,116 +0,0 @@
|
||||||
.ftIconButton {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row wrap;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconButton {
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 20px;
|
|
||||||
border-radius: 50%;
|
|
||||||
cursor: pointer;
|
|
||||||
-moz-transition: background 0.2s ease-out;
|
|
||||||
-o-transition: background 0.2s ease-out;
|
|
||||||
transition: background 0.2s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadow {
|
|
||||||
box-shadow: 0 1px 2px rgba(0,0,0,.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconButton:hover {
|
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
.base {
|
|
||||||
background-color: var(--card-bg-color);
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.base:hover {
|
|
||||||
background-color: var(--side-nav-hover-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.base:active {
|
|
||||||
background-color: var(--side-nav-active-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
color: var(--text-with-main-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary:hover {
|
|
||||||
background-color: var(--primary-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary:active {
|
|
||||||
background-color: var(--primary-color-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary {
|
|
||||||
background-color: var(--accent-color);
|
|
||||||
color: var(--text-with-accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary:hover {
|
|
||||||
background-color: var(--accent-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary:active {
|
|
||||||
background-color: var(--accent-color-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconDropdown {
|
|
||||||
position: absolute;
|
|
||||||
text-align: center;
|
|
||||||
list-style-type: none;
|
|
||||||
z-index: 100;
|
|
||||||
margin-top: 45px;
|
|
||||||
font-size: 12px;
|
|
||||||
box-shadow: 0 1px 2px rgba(0,0,0,.5);
|
|
||||||
background-color: var(--card-bg-color);
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconDropdown p {
|
|
||||||
padding: 10px;
|
|
||||||
margin: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
cursor: pointer;
|
|
||||||
-moz-transition: background 0.2s ease-out;
|
|
||||||
-o-transition: background 0.2s ease-out;
|
|
||||||
transition: background 0.2s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconDropdown p:hover {
|
|
||||||
background-color: var(--side-nav-hover-color);
|
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconDropdown p:active {
|
|
||||||
background-color: var(--side-nav-active-color);
|
|
||||||
-moz-transition: background 0.1s ease-in;
|
|
||||||
-o-transition: background 0.1s ease-in;
|
|
||||||
transition: background 0.1s ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconDropdown p a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left {
|
|
||||||
right: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
|
||||||
left: 50%;
|
|
||||||
}
|
|
|
@ -19,10 +19,18 @@ export default Vue.extend({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
dropdownPosition: {
|
forceDropdown: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
dropdownPositionX: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'center'
|
default: 'center'
|
||||||
},
|
},
|
||||||
|
dropdownPositionY: {
|
||||||
|
type: String,
|
||||||
|
default: 'bottom'
|
||||||
|
},
|
||||||
dropdownNames: {
|
dropdownNames: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => { return [] }
|
default: () => { return [] }
|
||||||
|
@ -43,7 +51,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
handleIconClick: function () {
|
handleIconClick: function () {
|
||||||
if (this.dropdownNames.length > 0 && this.dropdownValues.length > 0) {
|
if (this.forceDropdown || (this.dropdownNames.length > 0 && this.dropdownValues.length > 0)) {
|
||||||
this.toggleDropdown()
|
this.toggleDropdown()
|
||||||
} else {
|
} else {
|
||||||
this.$emit('click')
|
this.$emit('click')
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
.ftIconButton
|
||||||
|
display: flex
|
||||||
|
flex-flow: row wrap
|
||||||
|
justify-content: space-evenly
|
||||||
|
position: relative
|
||||||
|
|
||||||
|
.iconButton
|
||||||
|
width: 1em
|
||||||
|
height: 1em
|
||||||
|
padding: 10px
|
||||||
|
font-size: 20px
|
||||||
|
border-radius: 50%
|
||||||
|
cursor: pointer
|
||||||
|
transition: background 0.15s ease-out
|
||||||
|
|
||||||
|
&.shadow
|
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,.5)
|
||||||
|
|
||||||
|
&.base
|
||||||
|
background-color: var(--card-bg-color)
|
||||||
|
color: var(--primary-text-color)
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background-color: var(--side-nav-hover-color)
|
||||||
|
|
||||||
|
&:active
|
||||||
|
background-color: var(--side-nav-active-color)
|
||||||
|
|
||||||
|
&.primary
|
||||||
|
background-color: var(--primary-color)
|
||||||
|
color: var(--text-with-main-color)
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background-color: var(--primary-color-hover)
|
||||||
|
|
||||||
|
&:active
|
||||||
|
background-color: var(--primary-color-active)
|
||||||
|
|
||||||
|
&.secondary
|
||||||
|
background-color: var(--accent-color)
|
||||||
|
color: var(--text-with-accent-color)
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background-color: var(--accent-color-hover)
|
||||||
|
|
||||||
|
&:active
|
||||||
|
background-color: var(--accent-color-active)
|
||||||
|
|
||||||
|
.iconDropdown
|
||||||
|
position: absolute
|
||||||
|
text-align: center
|
||||||
|
list-style-type: none
|
||||||
|
z-index: 3
|
||||||
|
margin-top: 45px
|
||||||
|
font-size: 12px
|
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,.5)
|
||||||
|
background-color: var(--side-nav-color)
|
||||||
|
color: var(--secondary-text-color)
|
||||||
|
user-select: none
|
||||||
|
|
||||||
|
&.left
|
||||||
|
right: calc(50% - 20px)
|
||||||
|
|
||||||
|
&.right
|
||||||
|
left: calc(50% - 20px)
|
||||||
|
|
||||||
|
.list
|
||||||
|
margin: 0
|
||||||
|
padding: 0
|
||||||
|
list-style-type: none
|
||||||
|
|
||||||
|
.listItem
|
||||||
|
padding: 10px
|
||||||
|
margin: 0
|
||||||
|
white-space: nowrap
|
||||||
|
cursor: pointer
|
||||||
|
transition: background 0.2s ease-out
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background-color: var(--side-nav-hover-color)
|
||||||
|
transition: background 0.2s ease-in
|
||||||
|
|
||||||
|
&:active
|
||||||
|
background-color: var(--side-nav-active-color)
|
||||||
|
transition: background 0.1s ease-in
|
|
@ -13,24 +13,34 @@
|
||||||
@click="handleIconClick"
|
@click="handleIconClick"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="dropdownNames.length > 0 && showDropdown"
|
v-if="showDropdown"
|
||||||
class="iconDropdown"
|
class="iconDropdown"
|
||||||
:class="{
|
:class="{
|
||||||
left: dropdownPosition === 'left',
|
left: dropdownPositionX === 'left',
|
||||||
right: dropdownPosition === 'right',
|
right: dropdownPositionX === 'right',
|
||||||
center: dropdownPosition === 'center'
|
center: dropdownPositionX === 'center',
|
||||||
|
bottom: dropdownPositionY === 'bottom',
|
||||||
|
top: dropdownPositionY === 'top'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<p
|
<slot>
|
||||||
v-for="(label, index) in dropdownNames"
|
<ul
|
||||||
:key="index"
|
v-if="dropdownNames.length > 0"
|
||||||
@click="handleDropdownClick(index)"
|
class="list"
|
||||||
>
|
>
|
||||||
{{ label }}
|
<li
|
||||||
</p>
|
v-for="(label, index) in dropdownNames"
|
||||||
|
:key="index"
|
||||||
|
class="listItem"
|
||||||
|
@click="handleDropdownClick(index)"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./ft-icon-button.js" />
|
<script src="./ft-icon-button.js" />
|
||||||
<style scoped src="./ft-icon-button.css" />
|
<style scoped lang="sass" src="./ft-icon-button.sass" />
|
||||||
|
|
|
@ -49,6 +49,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.id = this._uid
|
this.id = this._uid
|
||||||
|
this.inputData = this.value
|
||||||
|
|
||||||
setTimeout(this.addListener, 200)
|
setTimeout(this.addListener, 200)
|
||||||
},
|
},
|
||||||
|
@ -57,9 +58,8 @@ export default Vue.extend({
|
||||||
this.$emit('click', this.inputData)
|
this.$emit('click', this.inputData)
|
||||||
},
|
},
|
||||||
|
|
||||||
handleInput: function (input) {
|
handleInput: function () {
|
||||||
this.inputData = input
|
this.$emit('input', this.inputData)
|
||||||
this.$emit('input', input)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addListener: function () {
|
addListener: function () {
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
:id="id"
|
:id="id"
|
||||||
|
v-model="inputData"
|
||||||
:list="idDataList"
|
:list="idDataList"
|
||||||
:value="value"
|
|
||||||
class="ft-input"
|
class="ft-input"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
|
|
|
@ -190,3 +190,58 @@
|
||||||
height: 35px;
|
height: 35px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.videoRecommendation.list {
|
||||||
|
height: 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoRecommendation.list .videoThumbnail {
|
||||||
|
width: 180px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoRecommendation.list .videoThumbnail img {
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoRecommendation.list .videoTitle {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 185px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoRecommendation.list .channelName {
|
||||||
|
margin-left: 185px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoRecommendation.list .viewCount {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlistItem .list {
|
||||||
|
height: 60px;
|
||||||
|
width: calc(100% - 30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlistItem .list .videoThumbnail {
|
||||||
|
width: 100px;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlistItem .list .videoThumbnail img {
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlistItem .list .videoTitle {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 105px;
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlistItem .list .channelName {
|
||||||
|
margin-left: 105px;
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlistItem .list .viewCount {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
if (typeof (this.data.descriptionHtml) !== 'undefined' ||
|
if (typeof (this.data.descriptionHtml) !== 'undefined' ||
|
||||||
typeof (this.data.index) !== 'undefined' ||
|
typeof (this.data.index) !== 'undefined' ||
|
||||||
|
typeof (this.data.authorId) !== 'undefined' ||
|
||||||
typeof (this.data.publishedText) !== 'undefined' ||
|
typeof (this.data.publishedText) !== 'undefined' ||
|
||||||
typeof (this.data.authorThumbnails) === 'object'
|
typeof (this.data.authorThumbnails) === 'object'
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
title="More Options"
|
title="More Options"
|
||||||
theme="base"
|
theme="base"
|
||||||
:use-shadow="false"
|
:use-shadow="false"
|
||||||
dropdown-position="left"
|
dropdown-position-x="left"
|
||||||
:dropdown-names="optionsNames"
|
:dropdown-names="optionsNames"
|
||||||
:dropdown-values="optionsValues"
|
:dropdown-values="optionsValues"
|
||||||
@click="handleOptionsClick"
|
@click="handleOptionsClick"
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
import FtIconButton from '../ft-icon-button/ft-icon-button.vue'
|
||||||
|
import FtButton from '../ft-button/ft-button.vue'
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
name: 'FtShareButton',
|
||||||
|
components: {
|
||||||
|
'ft-icon-button': FtIconButton,
|
||||||
|
'ft-button': FtButton
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
invidiousInstance: function () {
|
||||||
|
return this.$store.getters.getInvidiousInstance
|
||||||
|
},
|
||||||
|
|
||||||
|
usingElectron: function () {
|
||||||
|
return this.$store.getters.getUsingElectron
|
||||||
|
},
|
||||||
|
|
||||||
|
invidiousURL() {
|
||||||
|
return `${this.invidiousInstance}/watch?v=${this.id}`
|
||||||
|
},
|
||||||
|
|
||||||
|
invidiousEmbedURL() {
|
||||||
|
return `${this.invidiousInstance}/embed/${this.id}`
|
||||||
|
},
|
||||||
|
|
||||||
|
youtubeURL() {
|
||||||
|
return `https://www.youtube.com/watch?v=${this.id}`
|
||||||
|
},
|
||||||
|
|
||||||
|
youtubeEmbedURL() {
|
||||||
|
return `https://www.youtube-nocookie.com/embed/${this.id}`
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
copy(text) {
|
||||||
|
navigator.clipboard.writeText(text)
|
||||||
|
},
|
||||||
|
|
||||||
|
open(url) {
|
||||||
|
if (this.usingElectron) {
|
||||||
|
const shell = require('electron').shell
|
||||||
|
shell.openExternal(url)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
openInvidious() {
|
||||||
|
this.open(this.invidiousURL)
|
||||||
|
this.$refs.iconButton.toggleDropdown()
|
||||||
|
},
|
||||||
|
|
||||||
|
copyInvidious() {
|
||||||
|
this.copy(this.invidiousURL)
|
||||||
|
this.$refs.iconButton.toggleDropdown()
|
||||||
|
},
|
||||||
|
|
||||||
|
openYoutube() {
|
||||||
|
this.open(this.youtubeURL)
|
||||||
|
this.$refs.iconButton.toggleDropdown()
|
||||||
|
},
|
||||||
|
|
||||||
|
copyYoutube() {
|
||||||
|
this.copy(this.youtubeURL)
|
||||||
|
this.$refs.iconButton.toggleDropdown()
|
||||||
|
},
|
||||||
|
|
||||||
|
openYoutubeEmbed() {
|
||||||
|
this.open(this.youtubeEmbedURL)
|
||||||
|
this.$refs.iconButton.toggleDropdown()
|
||||||
|
},
|
||||||
|
|
||||||
|
copyYoutubeEmbed() {
|
||||||
|
this.copy(this.youtubeEmbedURL)
|
||||||
|
this.$refs.iconButton.toggleDropdown()
|
||||||
|
},
|
||||||
|
|
||||||
|
openInvidiousEmbed() {
|
||||||
|
this.open(this.invidiousEmbedURL)
|
||||||
|
this.$refs.iconButton.toggleDropdown()
|
||||||
|
},
|
||||||
|
|
||||||
|
copyInvidiousEmbed() {
|
||||||
|
this.copy(this.invidiousEmbedURL)
|
||||||
|
this.$refs.iconButton.toggleDropdown()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,55 @@
|
||||||
|
.shareLinks
|
||||||
|
display: grid
|
||||||
|
grid-template-rows: auto auto
|
||||||
|
grid-auto-flow: column
|
||||||
|
padding: 12px
|
||||||
|
width: max-content
|
||||||
|
|
||||||
|
.header
|
||||||
|
font-size: 18px
|
||||||
|
font-weight: bold
|
||||||
|
margin: 4px 0px 8px
|
||||||
|
color: var(--primary-text-color)
|
||||||
|
|
||||||
|
.buttons
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
|
||||||
|
.action
|
||||||
|
padding: 6px
|
||||||
|
|
||||||
|
.divider
|
||||||
|
grid-row: span 3
|
||||||
|
margin: 0px 12px
|
||||||
|
width: 1px
|
||||||
|
background: var(--tertiary-text-color)
|
||||||
|
|
||||||
|
.youtubeLogo
|
||||||
|
height: 18px
|
||||||
|
width: auto
|
||||||
|
|
||||||
|
@at-root
|
||||||
|
.dark &
|
||||||
|
filter: brightness(0.868)
|
||||||
|
|
||||||
|
.light &
|
||||||
|
filter: invert(0.87)
|
||||||
|
|
||||||
|
.invidious
|
||||||
|
display: flex
|
||||||
|
justify-content: center
|
||||||
|
letter-spacing: -0.4px
|
||||||
|
|
||||||
|
.invidiousLogo
|
||||||
|
display: inline-block
|
||||||
|
width: 20px
|
||||||
|
height: 20px
|
||||||
|
background-size: cover
|
||||||
|
margin-right: 2px
|
||||||
|
|
||||||
|
@at-root
|
||||||
|
.dark &
|
||||||
|
background-image: url(~../../assets/img/invidious-logo-dark.svg)
|
||||||
|
|
||||||
|
.light &
|
||||||
|
background-image: url(~../../assets/img/invidious-logo-light.svg)
|
|
@ -0,0 +1,97 @@
|
||||||
|
<template>
|
||||||
|
<ft-icon-button
|
||||||
|
ref="iconButton"
|
||||||
|
title="Share Video"
|
||||||
|
theme="secondary"
|
||||||
|
icon="share-alt"
|
||||||
|
dropdown-position-x="left"
|
||||||
|
:force-dropdown="true"
|
||||||
|
>
|
||||||
|
<div class="shareLinks">
|
||||||
|
<div class="header">
|
||||||
|
<img
|
||||||
|
class="youtubeLogo"
|
||||||
|
src="~../../assets/img/yt_logo_mono_dark.png"
|
||||||
|
alt="YouTube"
|
||||||
|
width="794"
|
||||||
|
height="178"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<ft-button
|
||||||
|
class="action"
|
||||||
|
@click="copyYoutube()"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="copy" />
|
||||||
|
Copy link
|
||||||
|
</ft-button>
|
||||||
|
<ft-button
|
||||||
|
class="action"
|
||||||
|
@click="openYoutube()"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="globe" />
|
||||||
|
Open link
|
||||||
|
</ft-button>
|
||||||
|
<ft-button
|
||||||
|
class="action"
|
||||||
|
background-color="var(--accent-color-active)"
|
||||||
|
@click="copyYoutubeEmbed()"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="copy" />
|
||||||
|
Copy embed
|
||||||
|
</ft-button>
|
||||||
|
<ft-button
|
||||||
|
class="action"
|
||||||
|
background-color="var(--accent-color-active)"
|
||||||
|
@click="openYoutubeEmbed()"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="globe" />
|
||||||
|
Open embed
|
||||||
|
</ft-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="divider" />
|
||||||
|
|
||||||
|
<div class="header invidious">
|
||||||
|
<span class="invidiousLogo" />Invidious
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<ft-button
|
||||||
|
class="action"
|
||||||
|
@click="copyInvidious()"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="copy" />
|
||||||
|
Copy link
|
||||||
|
</ft-button>
|
||||||
|
<ft-button
|
||||||
|
class="action"
|
||||||
|
@click="openInvidious()"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="globe" />
|
||||||
|
Open link
|
||||||
|
</ft-button>
|
||||||
|
<ft-button
|
||||||
|
class="action"
|
||||||
|
background-color="var(--accent-color-active)"
|
||||||
|
@click="copyInvidiousEmbed()"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="copy" />
|
||||||
|
Copy embed
|
||||||
|
</ft-button>
|
||||||
|
<ft-button
|
||||||
|
class="action"
|
||||||
|
background-color="var(--accent-color-active)"
|
||||||
|
@click="openInvidiousEmbed()"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="globe" />
|
||||||
|
Open embed
|
||||||
|
</ft-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ft-icon-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./ft-share-button.js" />
|
||||||
|
<style scoped lang="sass" src="./ft-share-button.sass" />
|
|
@ -4,19 +4,19 @@
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
:id="id"
|
:id="id"
|
||||||
|
v-model.number="currentValue"
|
||||||
type="range"
|
type="range"
|
||||||
:min="minValue"
|
:min="minValue"
|
||||||
:max="maxValue"
|
:max="maxValue"
|
||||||
:step="step"
|
:step="step"
|
||||||
v-model.number="currentValue"
|
|
||||||
@change="$emit('change', $event.target.value)"
|
@change="$emit('change', $event.target.value)"
|
||||||
>
|
>
|
||||||
|
<span>
|
||||||
|
{{ label }} -
|
||||||
<span>
|
<span>
|
||||||
{{ label }} -
|
{{ displayLabel }}
|
||||||
<span>
|
|
||||||
{{ displayLabel }}
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
|
||||||
:id="id"
|
:id="id"
|
||||||
|
v-model="currentValue"
|
||||||
|
type="checkbox"
|
||||||
name="set-name"
|
name="set-name"
|
||||||
class="switch-input"
|
class="switch-input"
|
||||||
:checked='currentValue'
|
:checked="currentValue"
|
||||||
v-model="currentValue"
|
|
||||||
@change="$emit('change', currentValue)"
|
@change="$emit('change', currentValue)"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
.relative {
|
.relative {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 85%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ftVideoPlayer {
|
.ftVideoPlayer {
|
||||||
width: 85%;
|
|
||||||
max-height: 50vh;
|
max-height: 50vh;
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,7 +221,11 @@ export default Vue.extend({
|
||||||
qualitySelector(videojs, { showQualitySelectionLabelInControlBar: true })
|
qualitySelector(videojs, { showQualitySelectionLabelInControlBar: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
this.player = videojs(videoPlayer)
|
this.player = videojs(videoPlayer, {
|
||||||
|
userActions: {
|
||||||
|
hotkeys: this.keyboardShortcutHandler
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
this.player.volume(this.volume)
|
this.player.volume(this.volume)
|
||||||
this.player.playbackRate(this.defaultPlayback)
|
this.player.playbackRate(this.defaultPlayback)
|
||||||
|
@ -245,7 +249,7 @@ export default Vue.extend({
|
||||||
}, 200)
|
}, 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).on('keydown', this.keyboardShortcutHandler)
|
// $(document).on('keydown', this.keyboardShortcutHandler)
|
||||||
|
|
||||||
this.player.on('mousemove', this.hideMouseTimeout)
|
this.player.on('mousemove', this.hideMouseTimeout)
|
||||||
this.player.on('mouseleave', this.removeMouseTimeout)
|
this.player.on('mouseleave', this.removeMouseTimeout)
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
:type="source.type || source.mimeType"
|
:type="source.type || source.mimeType"
|
||||||
:label="source.qualityLabel"
|
:label="source.qualityLabel"
|
||||||
:selected="source.qualityLabel === selectedDefaultQuality"
|
:selected="source.qualityLabel === selectedDefaultQuality"
|
||||||
/>
|
>
|
||||||
<track
|
<track
|
||||||
v-for="(caption, index) in captionList"
|
v-for="(caption, index) in captionList"
|
||||||
:key="index + '_caption'"
|
:key="index + '_caption'"
|
||||||
|
|
|
@ -552,6 +552,9 @@ export default Vue.extend({
|
||||||
invidiousInstance: function () {
|
invidiousInstance: function () {
|
||||||
return this.$store.getters.getInvidiousInstance
|
return this.$store.getters.getInvidiousInstance
|
||||||
},
|
},
|
||||||
|
enableSearchSuggestions: function () {
|
||||||
|
return this.$store.getters.getEnableSearchSuggestions
|
||||||
|
},
|
||||||
backendFallback: function () {
|
backendFallback: function () {
|
||||||
return this.$store.getters.getBackendFallback
|
return this.$store.getters.getBackendFallback
|
||||||
},
|
},
|
||||||
|
@ -616,6 +619,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
...mapActions([
|
...mapActions([
|
||||||
|
'updateEnableSearchSuggestions',
|
||||||
'updateBackendFallback',
|
'updateBackendFallback',
|
||||||
'updateCheckForUpdates',
|
'updateCheckForUpdates',
|
||||||
'updateBarColor',
|
'updateBarColor',
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<ft-card
|
<ft-card
|
||||||
class="card">
|
class="card"
|
||||||
|
>
|
||||||
<h3
|
<h3
|
||||||
class="videoTitle"
|
class="videoTitle"
|
||||||
>
|
>
|
||||||
|
@ -12,6 +13,11 @@
|
||||||
:default-value="backendFallback"
|
:default-value="backendFallback"
|
||||||
@change="updateBackendFallback"
|
@change="updateBackendFallback"
|
||||||
/>
|
/>
|
||||||
|
<ft-toggle-switch
|
||||||
|
label="Enable Search Suggestions"
|
||||||
|
:default-value="enableSearchSuggestions"
|
||||||
|
@change="updateEnableSearchSuggestions"
|
||||||
|
/>
|
||||||
<ft-toggle-switch
|
<ft-toggle-switch
|
||||||
v-if="false"
|
v-if="false"
|
||||||
label="Check for Updates"
|
label="Check for Updates"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<ft-card
|
<ft-card
|
||||||
class="relative card">
|
class="relative card"
|
||||||
|
>
|
||||||
<h3
|
<h3
|
||||||
class="videoTitle"
|
class="videoTitle"
|
||||||
>
|
>
|
||||||
|
|
|
@ -44,7 +44,7 @@ export default Vue.extend({
|
||||||
invidiousInstance: function () {
|
invidiousInstance: function () {
|
||||||
return this.$store.getters.getInvidiousInstance
|
return this.$store.getters.getInvidiousInstance
|
||||||
},
|
},
|
||||||
|
|
||||||
listType: function () {
|
listType: function () {
|
||||||
return this.$store.getters.getListType
|
return this.$store.getters.getListType
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,19 +2,30 @@
|
||||||
display: block;
|
display: block;
|
||||||
height: calc(100vh - 60px);
|
height: calc(100vh - 60px);
|
||||||
width: 200px;
|
width: 200px;
|
||||||
overflow-y: auto;
|
overflow-x: hidden;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
margin-top: 60px;
|
margin-top: 60px;
|
||||||
-webkit-box-shadow: 1px -1px 1px -1px var(--primary-shadow-color);
|
box-shadow: 1px -1px 1px -1px var(--primary-shadow-color);
|
||||||
background-color: var(--side-nav-color);
|
background-color: var(--side-nav-color);
|
||||||
transition-property: width;
|
transition-property: width;
|
||||||
transition-duration: 150ms;
|
transition-duration: 150ms;
|
||||||
transition-timing-function: ease-in-out;
|
transition-timing-function: ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
height: 100%;
|
||||||
|
width: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.closed .inner {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
.topNavOption {
|
.topNavOption {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
@ -97,6 +108,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 680px) {
|
@media only screen and (max-width: 680px) {
|
||||||
|
.inner {
|
||||||
|
display: contents; /* sunglasses emoji */
|
||||||
|
}
|
||||||
|
|
||||||
hr, .mobileHidden, .refreshIcon {
|
hr, .mobileHidden, .refreshIcon {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +132,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
top: auto;
|
top: auto;
|
||||||
overflow-y: inherit;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navOption, .closed .navOption {
|
.navOption, .closed .navOption {
|
||||||
|
|
|
@ -4,99 +4,101 @@
|
||||||
class="sideNav"
|
class="sideNav"
|
||||||
:class="{closed: !isOpen}"
|
:class="{closed: !isOpen}"
|
||||||
>
|
>
|
||||||
<div
|
<div class="inner">
|
||||||
class="navOption topNavOption mobileShow"
|
<div
|
||||||
@click="navigate('subscriptions')"
|
class="navOption topNavOption mobileShow"
|
||||||
>
|
@click="navigate('subscriptions')"
|
||||||
<font-awesome-icon
|
>
|
||||||
icon="rss"
|
<font-awesome-icon
|
||||||
class="navIcon"
|
icon="rss"
|
||||||
/>
|
class="navIcon"
|
||||||
<p class="navLabel">
|
/>
|
||||||
Subscriptions
|
<p class="navLabel">
|
||||||
</p>
|
Subscriptions
|
||||||
<font-awesome-icon
|
</p>
|
||||||
class="refreshIcon"
|
<font-awesome-icon
|
||||||
icon="sync"
|
class="refreshIcon"
|
||||||
|
icon="sync"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="navOption mobileHidden"
|
||||||
|
@click="navigate('trending')"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
icon="fire"
|
||||||
|
class="navIcon"
|
||||||
|
/>
|
||||||
|
<p class="navLabel">
|
||||||
|
Trending
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="navOption mobileHidden"
|
||||||
|
@click="navigate('popular')"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
icon="users"
|
||||||
|
class="navIcon"
|
||||||
|
/>
|
||||||
|
<p class="navLabel">
|
||||||
|
Most Popular
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="navOption mobileShow"
|
||||||
|
@click="navigate('userplaylists')"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
icon="bookmark"
|
||||||
|
class="navIcon"
|
||||||
|
/>
|
||||||
|
<p class="navLabel">
|
||||||
|
Playlists
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<side-nav-more-options
|
||||||
|
@navigate="navigate"
|
||||||
/>
|
/>
|
||||||
|
<div
|
||||||
|
class="navOption mobileShow"
|
||||||
|
@click="navigate('history')"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
icon="history"
|
||||||
|
class="navIcon"
|
||||||
|
/>
|
||||||
|
<p class="navLabel">
|
||||||
|
History
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div
|
||||||
|
class="navOption mobileShow"
|
||||||
|
@click="navigate('settings')"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
icon="sliders-h"
|
||||||
|
class="navIcon"
|
||||||
|
/>
|
||||||
|
<p class="navLabel">
|
||||||
|
Settings
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="navOption mobileHidden"
|
||||||
|
@click="navigate('about')"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
icon="info-circle"
|
||||||
|
class="navIcon"
|
||||||
|
/>
|
||||||
|
<p class="navLabel">
|
||||||
|
About
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
class="navOption mobileHidden"
|
|
||||||
@click="navigate('trending')"
|
|
||||||
>
|
|
||||||
<font-awesome-icon
|
|
||||||
icon="fire"
|
|
||||||
class="navIcon"
|
|
||||||
/>
|
|
||||||
<p class="navLabel">
|
|
||||||
Trending
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="navOption mobileHidden"
|
|
||||||
@click="navigate('popular')"
|
|
||||||
>
|
|
||||||
<font-awesome-icon
|
|
||||||
icon="users"
|
|
||||||
class="navIcon"
|
|
||||||
/>
|
|
||||||
<p class="navLabel">
|
|
||||||
Most Popular
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="navOption mobileShow"
|
|
||||||
@click="navigate('userplaylists')"
|
|
||||||
>
|
|
||||||
<font-awesome-icon
|
|
||||||
icon="bookmark"
|
|
||||||
class="navIcon"
|
|
||||||
/>
|
|
||||||
<p class="navLabel">
|
|
||||||
Playlists
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<side-nav-more-options
|
|
||||||
@navigate="navigate"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="navOption mobileShow"
|
|
||||||
@click="navigate('history')"
|
|
||||||
>
|
|
||||||
<font-awesome-icon
|
|
||||||
icon="history"
|
|
||||||
class="navIcon"
|
|
||||||
/>
|
|
||||||
<p class="navLabel">
|
|
||||||
History
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div
|
|
||||||
class="navOption mobileShow"
|
|
||||||
@click="navigate('settings')"
|
|
||||||
>
|
|
||||||
<font-awesome-icon
|
|
||||||
icon="sliders-h"
|
|
||||||
class="navIcon"
|
|
||||||
/>
|
|
||||||
<p class="navLabel">
|
|
||||||
Settings
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="navOption mobileHidden"
|
|
||||||
@click="navigate('about')"
|
|
||||||
>
|
|
||||||
<font-awesome-icon
|
|
||||||
icon="info-circle"
|
|
||||||
class="navIcon"
|
|
||||||
/>
|
|
||||||
<p class="navLabel">
|
|
||||||
About
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
</ft-flex-box>
|
</ft-flex-box>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<ft-card
|
<ft-card
|
||||||
class="relative card">
|
class="relative card"
|
||||||
|
>
|
||||||
<h3
|
<h3
|
||||||
class="videoTitle"
|
class="videoTitle"
|
||||||
>
|
>
|
||||||
|
|
|
@ -21,11 +21,13 @@ export default Vue.extend({
|
||||||
currentSecColor: '',
|
currentSecColor: '',
|
||||||
baseThemeNames: [
|
baseThemeNames: [
|
||||||
'Light',
|
'Light',
|
||||||
'Dark'
|
'Dark',
|
||||||
|
'Black'
|
||||||
],
|
],
|
||||||
baseThemeValues: [
|
baseThemeValues: [
|
||||||
'light',
|
'light',
|
||||||
'dark'
|
'dark',
|
||||||
|
'black'
|
||||||
],
|
],
|
||||||
colorNames: [
|
colorNames: [
|
||||||
'Red',
|
'Red',
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<ft-card
|
<ft-card
|
||||||
class="relative card">
|
class="relative card"
|
||||||
|
>
|
||||||
<h3>
|
<h3>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
|
@ -17,11 +17,14 @@ export default Vue.extend({
|
||||||
component: this,
|
component: this,
|
||||||
windowWidth: 0,
|
windowWidth: 0,
|
||||||
showFilters: false,
|
showFilters: false,
|
||||||
searchValue: '',
|
|
||||||
searchSuggestionsDataList: []
|
searchSuggestionsDataList: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
enableSearchSuggestions: function () {
|
||||||
|
return this.$store.getters.getEnableSearchSuggestions
|
||||||
|
},
|
||||||
|
|
||||||
searchSettings: function () {
|
searchSettings: function () {
|
||||||
return this.$store.getters.getSearchSettings
|
return this.$store.getters.getSearchSettings
|
||||||
},
|
},
|
||||||
|
@ -103,7 +106,9 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
getSearchSuggestionsDebounce: function (query) {
|
getSearchSuggestionsDebounce: function (query) {
|
||||||
this.debounceSearchResults(query)
|
if (this.enableSearchSuggestions) {
|
||||||
|
this.debounceSearchResults(query)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getSearchSuggestions: function (query) {
|
getSearchSuggestions: function (query) {
|
||||||
|
@ -120,20 +125,17 @@ export default Vue.extend({
|
||||||
getSearchSuggestionsLocal: function (query) {
|
getSearchSuggestionsLocal: function (query) {
|
||||||
if (query === '') {
|
if (query === '') {
|
||||||
this.searchSuggestionsDataList = []
|
this.searchSuggestionsDataList = []
|
||||||
this.searchValue = ''
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ytSuggest(query).then((results) => {
|
ytSuggest(query).then((results) => {
|
||||||
this.searchSuggestionsDataList = results
|
this.searchSuggestionsDataList = results
|
||||||
this.searchValue = query
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
getSearchSuggestionsInvidious: function (query) {
|
getSearchSuggestionsInvidious: function (query) {
|
||||||
if (query === '') {
|
if (query === '') {
|
||||||
this.searchSuggestionsDataList = []
|
this.searchSuggestionsDataList = []
|
||||||
this.searchValue = ''
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +149,6 @@ export default Vue.extend({
|
||||||
|
|
||||||
this.$store.dispatch('invidiousAPICall', searchPayload).then((results) => {
|
this.$store.dispatch('invidiousAPICall', searchPayload).then((results) => {
|
||||||
this.searchSuggestionsDataList = results.suggestions
|
this.searchSuggestionsDataList = results.suggestions
|
||||||
this.searchValue = query
|
|
||||||
}).error((err) => {
|
}).error((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
if (this.backendFallback) {
|
if (this.backendFallback) {
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
class="searchInput"
|
class="searchInput"
|
||||||
:is-search="true"
|
:is-search="true"
|
||||||
:data-list="searchSuggestionsDataList"
|
:data-list="searchSuggestionsDataList"
|
||||||
:value="searchValue"
|
|
||||||
@input="getSearchSuggestionsDebounce"
|
@input="getSearchSuggestionsDebounce"
|
||||||
@click="goToSearch"
|
@click="goToSearch"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -60,7 +60,9 @@
|
||||||
class="commentMoreReplies"
|
class="commentMoreReplies"
|
||||||
@click="getCommentReplies(index)"
|
@click="getCommentReplies(index)"
|
||||||
>
|
>
|
||||||
View {{ comment.numReplies }} replies
|
<span v-if="!comment.showReplies">View</span>
|
||||||
|
<span v-else>Hide</span>
|
||||||
|
{{ comment.numReplies }} replies
|
||||||
</p>
|
</p>
|
||||||
<div
|
<div
|
||||||
v-if="comment.showReplies"
|
v-if="comment.showReplies"
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
|
.videoDescription {
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
.description {
|
.description {
|
||||||
font-family: 'Roboto', sans-serif;
|
font-family: 'Roboto', sans-serif;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,15 +23,10 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
dateString: '',
|
|
||||||
shownDescription: ''
|
shownDescription: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
const date = new Date(this.published)
|
|
||||||
const dateSplit = date.toDateString().split(' ')
|
|
||||||
this.dateString = `${dateSplit[0]} ${dateSplit[1]} ${dateSplit[2]}, ${dateSplit[3]}`
|
|
||||||
|
|
||||||
if (this.descriptionHtml !== '') {
|
if (this.descriptionHtml !== '') {
|
||||||
this.shownDescription = this.parseDescriptionHtml(this.descriptionHtml)
|
this.shownDescription = this.parseDescriptionHtml(this.descriptionHtml)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<ft-card class="videoDescription">
|
<ft-card class="videoDescription">
|
||||||
<h4>Published on {{ dateString }}</h4>
|
|
||||||
<p
|
<p
|
||||||
class="description"
|
class="description"
|
||||||
v-html="shownDescription"
|
v-html="shownDescription"
|
||||||
|
|
|
@ -1,117 +0,0 @@
|
||||||
.relative {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.watchVideoInfo {
|
|
||||||
min-height: 130px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.videoTitle {
|
|
||||||
font-size: 22px;
|
|
||||||
max-width: 45%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.channelInformation {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 10px;
|
|
||||||
width: 350px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.channelThumbnail {
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 200px 200px 200px 200px;
|
|
||||||
-webkit-border-radius: 200px 200px 200px 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.channelName {
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
left: 55px;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 15px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subscribeButton {
|
|
||||||
height: 20px;
|
|
||||||
position: absolute;
|
|
||||||
top: 20px;
|
|
||||||
left: 50px;
|
|
||||||
line-height: 1px;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewCount {
|
|
||||||
position: absolute;
|
|
||||||
right: 15px;
|
|
||||||
bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.likeBarContainer {
|
|
||||||
position: absolute;
|
|
||||||
right: 15px;
|
|
||||||
bottom: 35px;
|
|
||||||
width: 300px;
|
|
||||||
height: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.likeBar {
|
|
||||||
background-color: var(--accent-color);
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
left: 0px;
|
|
||||||
z-index: 1;
|
|
||||||
border-radius: 200px 200px 200px 200px;
|
|
||||||
-webkit-border-radius: 200px 200px 200px 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dislikeBar {
|
|
||||||
background-color: #9E9E9E;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
left: 0px;
|
|
||||||
border-radius: 200px 200px 200px 200px;
|
|
||||||
-webkit-border-radius: 200px 200px 200px 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.likeCountContainer {
|
|
||||||
position: absolute;
|
|
||||||
right: 15px;
|
|
||||||
bottom: 0px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--tertiary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.videoOptions {
|
|
||||||
position: absolute;
|
|
||||||
right: 15px;
|
|
||||||
top: 20px;
|
|
||||||
width: 175px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 1500px) {
|
|
||||||
.videoOptions {
|
|
||||||
width: 175px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.watchVideoInfo {
|
|
||||||
min-height: 150px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 1350px) {
|
|
||||||
.theatreModeButton {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.watchVideoInfo {
|
|
||||||
min-height: 130px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.videoOptions {
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ import FtButton from '../ft-button/ft-button.vue'
|
||||||
import FtListDropdown from '../ft-list-dropdown/ft-list-dropdown.vue'
|
import FtListDropdown from '../ft-list-dropdown/ft-list-dropdown.vue'
|
||||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
||||||
import FtIconButton from '../ft-icon-button/ft-icon-button.vue'
|
import FtIconButton from '../ft-icon-button/ft-icon-button.vue'
|
||||||
import FtToastEvents from '../ft-toast/ft-toast-events'
|
import FtShareButton from '../ft-share-button/ft-share-button.vue'
|
||||||
// import { shell } from 'electron'
|
// import { shell } from 'electron'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
|
@ -14,7 +14,8 @@ export default Vue.extend({
|
||||||
'ft-button': FtButton,
|
'ft-button': FtButton,
|
||||||
'ft-list-dropdown': FtListDropdown,
|
'ft-list-dropdown': FtListDropdown,
|
||||||
'ft-flex-box': FtFlexBox,
|
'ft-flex-box': FtFlexBox,
|
||||||
'ft-icon-button': FtIconButton
|
'ft-icon-button': FtIconButton,
|
||||||
|
'ft-share-button': FtShareButton
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
id: {
|
id: {
|
||||||
|
@ -37,6 +38,10 @@ export default Vue.extend({
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
published: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
viewCount: {
|
viewCount: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
|
@ -66,19 +71,6 @@ export default Vue.extend({
|
||||||
'dash',
|
'dash',
|
||||||
'legacy',
|
'legacy',
|
||||||
'audio'
|
'audio'
|
||||||
],
|
|
||||||
shareLabel: 'SHARE VIDEO',
|
|
||||||
shareNames: [
|
|
||||||
'COPY INVIDIOUS LINK',
|
|
||||||
'OPEN INVIDIOUS LINK',
|
|
||||||
'COPY YOUTUBE LINK',
|
|
||||||
'OPEN YOUTUBE LINK'
|
|
||||||
],
|
|
||||||
shareValues: [
|
|
||||||
'copyInvidious',
|
|
||||||
'openInvidious',
|
|
||||||
'copyYoutube',
|
|
||||||
'openYoutube'
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -91,18 +83,6 @@ export default Vue.extend({
|
||||||
return this.$store.getters.getUsingElectron
|
return this.$store.getters.getUsingElectron
|
||||||
},
|
},
|
||||||
|
|
||||||
invidiousUrl: function () {
|
|
||||||
return `${this.invidiousInstance}/watch?v=${this.id}`
|
|
||||||
},
|
|
||||||
|
|
||||||
youtubeUrl: function () {
|
|
||||||
return `https://www.youtube.com/watch?v=${this.id}`
|
|
||||||
},
|
|
||||||
|
|
||||||
youtubeEmbedUrl: function () {
|
|
||||||
return `https://www.youtube-nocookie.com/embed/${this.id}`
|
|
||||||
},
|
|
||||||
|
|
||||||
totalLikeCount: function () {
|
totalLikeCount: function () {
|
||||||
return this.likeCount + this.dislikeCount
|
return this.likeCount + this.dislikeCount
|
||||||
},
|
},
|
||||||
|
@ -117,6 +97,12 @@ export default Vue.extend({
|
||||||
|
|
||||||
subscribedText: function () {
|
subscribedText: function () {
|
||||||
return `SUBSCRIBE ${this.subscriptionCountText}`
|
return `SUBSCRIBE ${this.subscriptionCountText}`
|
||||||
|
},
|
||||||
|
|
||||||
|
dateString() {
|
||||||
|
const date = new Date(this.published)
|
||||||
|
const dateSplit = date.toDateString().split(' ')
|
||||||
|
return `${dateSplit[1]} ${dateSplit[2]}, ${dateSplit[3]}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -140,43 +126,6 @@ export default Vue.extend({
|
||||||
this.$parent.enableAudioFormat()
|
this.$parent.enableAudioFormat()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
handleShare: function (method) {
|
|
||||||
console.log('Handling share')
|
|
||||||
|
|
||||||
switch (method) {
|
|
||||||
case 'copyYoutube':
|
|
||||||
FtToastEvents.$emit('toast.open', "YouTube URL copied to clipboard")
|
|
||||||
navigator.clipboard.writeText(this.youtubeUrl)
|
|
||||||
break
|
|
||||||
case 'openYoutube':
|
|
||||||
if (this.usingElectron) {
|
|
||||||
const shell = require('electron').shell
|
|
||||||
shell.openExternal(this.youtubeUrl)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'copyYoutubeEmbed':
|
|
||||||
FtToastEvents.$emit('toast.open', "YouTube Embed URL copied to clipboard")
|
|
||||||
navigator.clipboard.writeText(this.youtubeEmbedUrl)
|
|
||||||
break
|
|
||||||
case 'openYoutubeEmbed':
|
|
||||||
if (this.usingElectron) {
|
|
||||||
const shell = require('electron').shell
|
|
||||||
shell.openExternal(this.youtubeEmbedUrl)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'copyInvidious':
|
|
||||||
FtToastEvents.$emit('toast.open', "Invidious URL copied to clipboard")
|
|
||||||
navigator.clipboard.writeText(this.invidiousUrl)
|
|
||||||
break
|
|
||||||
case 'openInvidious':
|
|
||||||
if (this.usingElectron) {
|
|
||||||
const shell = require('electron').shell
|
|
||||||
shell.openExternal(this.invidiousUrl)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
.watchVideoInfo
|
||||||
|
display: grid
|
||||||
|
grid-template-columns: 2fr 1fr
|
||||||
|
padding: 16px
|
||||||
|
|
||||||
|
@media screen and (max-width: 680px)
|
||||||
|
grid-template-columns: auto
|
||||||
|
|
||||||
|
.videoTitle
|
||||||
|
font-size: 22px
|
||||||
|
margin: 0 0 24px
|
||||||
|
|
||||||
|
.channelInformation
|
||||||
|
.profileRow
|
||||||
|
display: flex
|
||||||
|
|
||||||
|
.channelThumbnail
|
||||||
|
border-radius: 50%
|
||||||
|
margin-right: 10px
|
||||||
|
cursor: pointer
|
||||||
|
width: 56px
|
||||||
|
|
||||||
|
.channelName
|
||||||
|
margin-left: 6px
|
||||||
|
cursor: pointer
|
||||||
|
position: relative
|
||||||
|
top: -2px
|
||||||
|
|
||||||
|
.subscribeButton
|
||||||
|
margin-top: 6px
|
||||||
|
margin-left: 6px
|
||||||
|
padding: 6px
|
||||||
|
font-size: 14px
|
||||||
|
|
||||||
|
.viewCount, .datePublished
|
||||||
|
color: var(--secondary-text-color)
|
||||||
|
text-align: right
|
||||||
|
font-size: 15px
|
||||||
|
|
||||||
|
@media screen and (max-width: 680px)
|
||||||
|
text-align: left
|
||||||
|
|
||||||
|
.viewCount
|
||||||
|
margin: 18px 0px 0px
|
||||||
|
|
||||||
|
.datePublished
|
||||||
|
margin: 4px 0px 0px
|
||||||
|
|
||||||
|
@media screen and (max-width: 680px)
|
||||||
|
margin-top: 16px
|
||||||
|
|
||||||
|
.likeSection
|
||||||
|
margin-top: 4px
|
||||||
|
font-size: 12px
|
||||||
|
color: var(--tertiary-text-color)
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
margin-left: auto
|
||||||
|
text-align: right
|
||||||
|
max-width: 210px
|
||||||
|
|
||||||
|
@media screen and (max-width: 680px)
|
||||||
|
margin-left: 0
|
||||||
|
text-align: left
|
||||||
|
|
||||||
|
.likeBar
|
||||||
|
height: 8px
|
||||||
|
border-radius: 4px
|
||||||
|
margin-bottom: 4px
|
||||||
|
|
||||||
|
.likeCount
|
||||||
|
margin-right: 6px
|
||||||
|
|
||||||
|
.videoOptions
|
||||||
|
margin-top: 16px
|
||||||
|
display: flex
|
||||||
|
justify-content: flex-end
|
||||||
|
|
||||||
|
.option:not(:first-child)
|
||||||
|
margin-left: 4px
|
||||||
|
|
||||||
|
@media screen and (max-width: 680px)
|
||||||
|
justify-content: flex-start
|
||||||
|
|
||||||
|
::v-deep .iconDropdown
|
||||||
|
left: calc(50% - 20px)
|
||||||
|
right: auto
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1350px)
|
||||||
|
.theatreModeButton
|
||||||
|
display: none
|
|
@ -1,79 +1,87 @@
|
||||||
<template>
|
<template>
|
||||||
<ft-card class="relative watchVideoInfo">
|
<ft-card class="watchVideoInfo">
|
||||||
<p
|
<div>
|
||||||
class="videoTitle"
|
<p
|
||||||
>
|
class="videoTitle"
|
||||||
{{ title }}
|
|
||||||
</p>
|
|
||||||
<div
|
|
||||||
class="channelInformation"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
:src="channelThumbnail"
|
|
||||||
class="channelThumbnail"
|
|
||||||
@click="goToChannel"
|
|
||||||
>
|
>
|
||||||
<span
|
{{ title }}
|
||||||
class="channelName"
|
</p>
|
||||||
@click="goToChannel"
|
|
||||||
>
|
|
||||||
{{ channelName }}
|
|
||||||
</span>
|
|
||||||
<ft-button
|
|
||||||
:label="subscribedText"
|
|
||||||
class="subscribeButton"
|
|
||||||
background-color="var(--primary-color)"
|
|
||||||
@click="handleSubscription"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<ft-flex-box class="videoOptions">
|
|
||||||
<ft-icon-button
|
|
||||||
title="Toggle Theatre Mode"
|
|
||||||
class="theatreModeButton"
|
|
||||||
icon="expand-alt"
|
|
||||||
theme="secondary"
|
|
||||||
@click="$emit('theatreMode')"
|
|
||||||
/>
|
|
||||||
<ft-icon-button
|
|
||||||
title="Change Video Formats"
|
|
||||||
theme="secondary"
|
|
||||||
icon="file-video"
|
|
||||||
:dropdown-names="formatTypeNames"
|
|
||||||
:dropdown-values="formatTypeValues"
|
|
||||||
@click="handleFormatChange"
|
|
||||||
/>
|
|
||||||
<ft-icon-button
|
|
||||||
title="Share Video"
|
|
||||||
theme="secondary"
|
|
||||||
icon="share-alt"
|
|
||||||
:dropdown-names="shareNames"
|
|
||||||
:dropdown-values="shareValues"
|
|
||||||
@click="handleShare"
|
|
||||||
/>
|
|
||||||
</ft-flex-box>
|
|
||||||
<p class="viewCount">
|
|
||||||
{{ parsedViewCount }}
|
|
||||||
</p>
|
|
||||||
<div class="likeBarContainer">
|
|
||||||
<div
|
<div
|
||||||
class="likeBar"
|
class="channelInformation"
|
||||||
:style="{ width: likePercentageRatio + '%' }"
|
>
|
||||||
/>
|
<div
|
||||||
<div class="dislikeBar" />
|
class="profileRow"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
:src="channelThumbnail"
|
||||||
|
class="channelThumbnail"
|
||||||
|
@click="goToChannel"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="channelName"
|
||||||
|
@click="goToChannel"
|
||||||
|
>
|
||||||
|
{{ channelName }}
|
||||||
|
</div>
|
||||||
|
<ft-button
|
||||||
|
:label="subscribedText"
|
||||||
|
class="subscribeButton"
|
||||||
|
background-color="var(--primary-color)"
|
||||||
|
@click="handleSubscription"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="datePublished">
|
||||||
|
Published {{ dateString }}
|
||||||
|
</div>
|
||||||
|
<div class="viewCount">
|
||||||
|
{{ parsedViewCount }}
|
||||||
|
</div>
|
||||||
|
<div class="likeBarContainer">
|
||||||
|
<div
|
||||||
|
class="likeSection"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="likeBar"
|
||||||
|
:style="{ background: `linear-gradient(to right, var(--accent-color) ${likePercentageRatio}%, #9E9E9E ${likePercentageRatio}%` }"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<span class="likeCount"><font-awesome-icon icon="thumbs-up" /> {{ likeCount }}</span>
|
||||||
|
<span class="dislikeCount"><font-awesome-icon icon="thumbs-down" /> {{ dislikeCount }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="videoOptions">
|
||||||
|
<ft-icon-button
|
||||||
|
title="Toggle Theatre Mode"
|
||||||
|
class="theatreModeButton option"
|
||||||
|
icon="expand-alt"
|
||||||
|
theme="secondary"
|
||||||
|
@click="$emit('theatreMode')"
|
||||||
|
/>
|
||||||
|
<ft-icon-button
|
||||||
|
title="Change Video Formats"
|
||||||
|
class="option"
|
||||||
|
theme="secondary"
|
||||||
|
icon="file-video"
|
||||||
|
:dropdown-names="formatTypeNames"
|
||||||
|
:dropdown-values="formatTypeValues"
|
||||||
|
@click="handleFormatChange"
|
||||||
|
/>
|
||||||
|
<ft-share-button
|
||||||
|
:id="id"
|
||||||
|
class="option"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="likeCountContainer">
|
|
||||||
<font-awesome-icon
|
|
||||||
icon="thumbs-up"
|
|
||||||
/>
|
|
||||||
{{ likeCount }}
|
|
||||||
|
|
||||||
<font-awesome-icon
|
|
||||||
icon="thumbs-down"
|
|
||||||
/>
|
|
||||||
{{ dislikeCount }}
|
|
||||||
</p>
|
|
||||||
</ft-card>
|
</ft-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./watch-video-info.js" />
|
<script src="./watch-video-info.js" />
|
||||||
<style scoped src="./watch-video-info.css" />
|
<style scoped src="./watch-video-info.sass" lang="sass" />
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else-if="comments.length === 0"
|
v-else-if="comments.length === 0"
|
||||||
class="messageContainer liveChatMessage"
|
class="messageContainer liveChatMessage"
|
||||||
>
|
>
|
||||||
<p
|
<p
|
||||||
class="message"
|
class="message"
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
<img
|
<img
|
||||||
:src="comment.author.thumbnail.url"
|
:src="comment.author.thumbnail.url"
|
||||||
class="channelThumbnail"
|
class="channelThumbnail"
|
||||||
/>
|
>
|
||||||
<p
|
<p
|
||||||
class="superChatContent"
|
class="superChatContent"
|
||||||
:style="{ color: 'var(--text-with-main-color)' }"
|
:style="{ color: 'var(--text-with-main-color)' }"
|
||||||
|
@ -67,8 +67,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="openedSuperChat"
|
|
||||||
v-if="showSuperChat"
|
v-if="showSuperChat"
|
||||||
|
class="openedSuperChat"
|
||||||
:class="superChat.superchat.colorClass"
|
:class="superChat.superchat.colorClass"
|
||||||
@click="showSuperChat = false"
|
@click="showSuperChat = false"
|
||||||
>
|
>
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
<img
|
<img
|
||||||
:src="superChat.author.thumbnail.url"
|
:src="superChat.author.thumbnail.url"
|
||||||
class="channelThumbnail"
|
class="channelThumbnail"
|
||||||
/>
|
>
|
||||||
<p
|
<p
|
||||||
class="channelName"
|
class="channelName"
|
||||||
>
|
>
|
||||||
|
@ -95,11 +95,10 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
class="chatMessage"
|
|
||||||
v-if="superChat.message.length > 0"
|
v-if="superChat.message.length > 0"
|
||||||
|
class="chatMessage"
|
||||||
v-html="superChat.messageHtml"
|
v-html="superChat.messageHtml"
|
||||||
>
|
/>
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
@ -107,9 +106,11 @@
|
||||||
:style="{ height: chatHeight }"
|
:style="{ height: chatHeight }"
|
||||||
@mousewheel="e => onScroll(e)"
|
@mousewheel="e => onScroll(e)"
|
||||||
>
|
>
|
||||||
<div v-for="(comment, index) in comments"
|
<div
|
||||||
:key="index"
|
v-for="(comment, index) in comments"
|
||||||
class="comment">
|
:key="index"
|
||||||
|
class="comment"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-if="typeof (comment.superchat) !== 'undefined'"
|
v-if="typeof (comment.superchat) !== 'undefined'"
|
||||||
class="superChatMessage"
|
class="superChatMessage"
|
||||||
|
@ -121,7 +122,7 @@
|
||||||
<img
|
<img
|
||||||
:src="comment.author.thumbnail.url"
|
:src="comment.author.thumbnail.url"
|
||||||
class="channelThumbnail"
|
class="channelThumbnail"
|
||||||
/>
|
>
|
||||||
<p
|
<p
|
||||||
class="channelName"
|
class="channelName"
|
||||||
>
|
>
|
||||||
|
@ -134,50 +135,48 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
class="chatMessage"
|
|
||||||
v-if="comment.message.length > 0"
|
v-if="comment.message.length > 0"
|
||||||
|
class="chatMessage"
|
||||||
v-html="comment.messageHtml"
|
v-html="comment.messageHtml"
|
||||||
>
|
/>
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
:src="comment.author.thumbnail.url"
|
:src="comment.author.thumbnail.url"
|
||||||
class="channelThumbnail"
|
class="channelThumbnail"
|
||||||
/>
|
|
||||||
<p
|
|
||||||
class="chatContent"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="channelName"
|
|
||||||
:class="{
|
|
||||||
member: typeof (comment.author.badge) !== 'undefined' || comment.membership,
|
|
||||||
moderator: comment.isOwner,
|
|
||||||
owner: comment.author.name === channelName
|
|
||||||
}"
|
|
||||||
>
|
>
|
||||||
{{ comment.author.name }}
|
<p
|
||||||
</span>
|
class="chatContent"
|
||||||
<span
|
|
||||||
v-if="typeof (comment.author.badge) !== 'undefined'"
|
|
||||||
class="badge"
|
|
||||||
>
|
>
|
||||||
<img
|
<span
|
||||||
:src="comment.author.badge.thumbnail.url"
|
class="channelName"
|
||||||
:alt="comment.author.badge.thumbnail.alt"
|
:class="{
|
||||||
:title="comment.author.badge.thumbnail.alt"
|
member: typeof (comment.author.badge) !== 'undefined' || comment.membership,
|
||||||
class="badgeImage"
|
moderator: comment.isOwner,
|
||||||
|
owner: comment.author.name === channelName
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ comment.author.name }}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-if="typeof (comment.author.badge) !== 'undefined'"
|
||||||
|
class="badge"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="comment.author.badge.thumbnail.url"
|
||||||
|
:alt="comment.author.badge.thumbnail.alt"
|
||||||
|
:title="comment.author.badge.thumbnail.alt"
|
||||||
|
class="badgeImage"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-if="comment.message.length > 0"
|
||||||
|
class="chatMessage"
|
||||||
|
v-html="comment.messageHtml"
|
||||||
/>
|
/>
|
||||||
</span>
|
</p>
|
||||||
<span
|
|
||||||
class="chatMessage"
|
|
||||||
v-if="comment.message.length > 0"
|
|
||||||
v-html="comment.messageHtml"
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -75,32 +75,3 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
bottom: 7px;
|
bottom: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/deep/ .list {
|
|
||||||
height: 60px;
|
|
||||||
width: calc(100% - 30px);
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .list .videoThumbnail {
|
|
||||||
width: 100px;
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .list .videoThumbnail img {
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .list .videoTitle {
|
|
||||||
font-size: 12px;
|
|
||||||
margin-left: 105px;
|
|
||||||
margin-right: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .list .channelName {
|
|
||||||
margin-left: 105px;
|
|
||||||
margin-right: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .list .viewCount {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,29 +5,3 @@
|
||||||
.videoRecommendation {
|
.videoRecommendation {
|
||||||
margin-bottom: -15px;
|
margin-bottom: -15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/deep/ .list {
|
|
||||||
height: 110px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .list .videoThumbnail {
|
|
||||||
width: 180px;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .list .videoThumbnail img {
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .list .videoTitle {
|
|
||||||
font-size: 12px;
|
|
||||||
margin-left: 185px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .list .channelName {
|
|
||||||
margin-left: 185px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .list .viewCount {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ const state = {
|
||||||
thumbnailPreference: '',
|
thumbnailPreference: '',
|
||||||
invidiousInstance: 'https://invidio.us',
|
invidiousInstance: 'https://invidio.us',
|
||||||
barColor: false,
|
barColor: false,
|
||||||
|
enableSearchSuggestions: true,
|
||||||
rememberHistory: true,
|
rememberHistory: true,
|
||||||
autoplayVideos: true,
|
autoplayVideos: true,
|
||||||
autoplayPlaylists: true,
|
autoplayPlaylists: true,
|
||||||
|
@ -72,6 +73,10 @@ const getters = {
|
||||||
return state.barColor
|
return state.barColor
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getEnableSearchSuggestions: () => {
|
||||||
|
return state.enableSearchSuggestions
|
||||||
|
},
|
||||||
|
|
||||||
getBackendPreference: () => {
|
getBackendPreference: () => {
|
||||||
return state.backendPreference
|
return state.backendPreference
|
||||||
},
|
},
|
||||||
|
@ -169,6 +174,9 @@ const actions = {
|
||||||
case 'checkForUpdates':
|
case 'checkForUpdates':
|
||||||
commit('setCheckForUpdates', result.value)
|
commit('setCheckForUpdates', result.value)
|
||||||
break
|
break
|
||||||
|
case 'enableSearchSuggestions':
|
||||||
|
commit('setEnableSearchSuggestions', result.value)
|
||||||
|
break
|
||||||
case 'backendPreference':
|
case 'backendPreference':
|
||||||
commit('setBackendPreference', result.value)
|
commit('setBackendPreference', result.value)
|
||||||
break
|
break
|
||||||
|
@ -255,6 +263,14 @@ const actions = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateEnableSearchSuggestions ({ commit }, enableSearchSuggestions) {
|
||||||
|
settingsDb.update({ _id: 'enableSearchSuggestions' }, { _id: 'enableSearchSuggestions', value: enableSearchSuggestions }, { upsert: true }, (err, numReplaced) => {
|
||||||
|
if (!err) {
|
||||||
|
commit('setEnableSearchSuggestions', enableSearchSuggestions)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
updateBackendPreference ({ commit }, backendPreference) {
|
updateBackendPreference ({ commit }, backendPreference) {
|
||||||
settingsDb.update({ _id: 'backendPreference' }, { _id: 'backendPreference', value: backendPreference }, { upsert: true }, (err, numReplaced) => {
|
settingsDb.update({ _id: 'backendPreference' }, { _id: 'backendPreference', value: backendPreference }, { upsert: true }, (err, numReplaced) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
|
@ -440,6 +456,9 @@ const mutations = {
|
||||||
setBarColor (state, barColor) {
|
setBarColor (state, barColor) {
|
||||||
state.barColor = barColor
|
state.barColor = barColor
|
||||||
},
|
},
|
||||||
|
setEnableSearchSuggestions (state, enableSearchSuggestions) {
|
||||||
|
state.enableSearchSuggestions = enableSearchSuggestions
|
||||||
|
},
|
||||||
setRememberHistory (state, rememberHistory) {
|
setRememberHistory (state, rememberHistory) {
|
||||||
state.rememberHistory = rememberHistory
|
state.rememberHistory = rememberHistory
|
||||||
},
|
},
|
||||||
|
|
|
@ -53,18 +53,37 @@ const actions = {
|
||||||
return state.colorClasses[randomInt]
|
return state.colorClasses[randomInt]
|
||||||
},
|
},
|
||||||
|
|
||||||
getVideoIdFromUrl ({ state }, url) {
|
getVideoIdFromUrl (_, url) {
|
||||||
console.log('checking for id')
|
/** @type {URL} */
|
||||||
console.log(url)
|
let urlObject
|
||||||
const rx = /^.*(?:(?:(you|hook)tu\.?be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/
|
try {
|
||||||
|
urlObject = new URL(url)
|
||||||
const match = url.match(rx)
|
} catch (e) {
|
||||||
|
|
||||||
if (match) {
|
|
||||||
return match[2]
|
|
||||||
} else {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const extractors = [
|
||||||
|
// anything with /watch?v=
|
||||||
|
function() {
|
||||||
|
if (urlObject.pathname === '/watch' && urlObject.searchParams.has('v')) {
|
||||||
|
return urlObject.searchParams.get('v')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// youtu.be
|
||||||
|
function() {
|
||||||
|
if (urlObject.host === 'youtu.be' && urlObject.pathname.match(/^\/[A-Za-z0-9_-]+$/)) {
|
||||||
|
return urlObject.pathname.slice(1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// cloudtube
|
||||||
|
function() {
|
||||||
|
if (urlObject.host.match(/^cadence\.(gq|moe)$/) && urlObject.pathname.match(/^\/cloudtube\/video\/[A-Za-z0-9_-]+$/)) {
|
||||||
|
return urlObject.pathname.slice('/cloudtube/video/'.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return extractors.reduce((a, c) => a || c(), null) || false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,15 @@
|
||||||
--primary-shadow-color: rgba(232, 232, 232, 1);
|
--primary-shadow-color: rgba(232, 232, 232, 1);
|
||||||
--title-color: #3f7ac6;
|
--title-color: #3f7ac6;
|
||||||
--bg-color: #f1f1f1;
|
--bg-color: #f1f1f1;
|
||||||
|
--link-color: var(--accent-color);
|
||||||
|
--link-visited-color: var(--accent-color-visited);
|
||||||
--card-bg-color: #FFFFFF;
|
--card-bg-color: #FFFFFF;
|
||||||
--secondary-card-bg-color: #eeeeee;
|
--secondary-card-bg-color: #eeeeee;
|
||||||
--side-nav-color: #FFFFFF;
|
--side-nav-color: #FFFFFF;
|
||||||
--side-nav-hover-color: #e0e0e0;
|
--side-nav-hover-color: #e0e0e0;
|
||||||
--side-nav-active-color: #757575;
|
--side-nav-active-color: #757575;
|
||||||
--search-bar-color: #f5f5f5;
|
--search-bar-color: #f5f5f5;
|
||||||
|
--instance-menu-color: var(--search-bar-color);
|
||||||
--logo-icon: url("~../../_icons/iconColorSmall.png");
|
--logo-icon: url("~../../_icons/iconColorSmall.png");
|
||||||
--logo-text: url("~../../_icons/textColorSmall.png");
|
--logo-text: url("~../../_icons/textColorSmall.png");
|
||||||
}
|
}
|
||||||
|
@ -20,21 +23,44 @@
|
||||||
.dark {
|
.dark {
|
||||||
--primary-text-color: #EEEEEE;
|
--primary-text-color: #EEEEEE;
|
||||||
--secondary-text-color: #ddd;
|
--secondary-text-color: #ddd;
|
||||||
--tertiary-text-color: #888;
|
--tertiary-text-color: #999;
|
||||||
--primary-input-color: rgba(0, 0, 0, 0.50);
|
--primary-input-color: rgba(0, 0, 0, 0.50);
|
||||||
--primary-shadow-color: rgba(0, 0, 0, 0.75);
|
--primary-shadow-color: rgba(0, 0, 0, 0.75);
|
||||||
--title-color: #EEEEEE;
|
--title-color: #EEEEEE;
|
||||||
--bg-color: #212121;
|
--bg-color: #212121;
|
||||||
|
--link-color: var(--accent-color);
|
||||||
|
--link-visited-color: var(--accent-color-visited);
|
||||||
--card-bg-color: #303030;
|
--card-bg-color: #303030;
|
||||||
--secondary-card-bg-color: rgba(0, 0, 0, 0.75);
|
--secondary-card-bg-color: rgba(0, 0, 0, 0.75);
|
||||||
--side-nav-color: #262626;
|
--side-nav-color: #262626;
|
||||||
--side-nav-hover-color: #212121;
|
--side-nav-hover-color: #212121;
|
||||||
--side-nav-active-color: #303030;
|
--side-nav-active-color: #303030;
|
||||||
--search-bar-color: #262626;
|
--search-bar-color: #262626;
|
||||||
|
--instance-menu-color: var(--search-bar-color);
|
||||||
--logo-icon: url("~../../_icons/iconColorSmall.png");
|
--logo-icon: url("~../../_icons/iconColorSmall.png");
|
||||||
--logo-text: url("~../../_icons/textColorSmall.png");
|
--logo-text: url("~../../_icons/textColorSmall.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.black {
|
||||||
|
--primary-text-color: #EEEEEE;
|
||||||
|
--secondary-text-color: #ddd;
|
||||||
|
--tertiary-text-color: #EEEEEE;
|
||||||
|
--primary-input-color: rgba(0, 0, 0, 0.50);
|
||||||
|
--primary-shadow-color: rgba(0, 0, 0, 0.75);
|
||||||
|
--title-color: #EEEEEEE;
|
||||||
|
--bg-color: #000000;
|
||||||
|
--link-color: var(--accent-color);
|
||||||
|
--link-visited-color: var(--accent-color-visited);
|
||||||
|
--card-bg-color: #000000;
|
||||||
|
--secondary-card-bg-color: rgba(0, 0, 0, 0.75);
|
||||||
|
--side-nav-color: #000000;
|
||||||
|
--side-nav-hover-color: #212121;
|
||||||
|
--side-nav-active-color: #303030;
|
||||||
|
--search-bar-color: #262626;
|
||||||
|
--instance-menu-color: var(--search-bar-color);
|
||||||
|
--logo-icon: url("~../../_icons/iconColorSmall.png");
|
||||||
|
--logo-text: url("~../../_icons/textColorSmall.png");
|
||||||
|
}
|
||||||
|
|
||||||
.gray {
|
.gray {
|
||||||
--primary-text-color: #EEEEEE;
|
--primary-text-color: #EEEEEE;
|
||||||
|
@ -203,6 +229,7 @@
|
||||||
--accent-color-hover: #e53935;
|
--accent-color-hover: #e53935;
|
||||||
--accent-color-active: #c62828;
|
--accent-color-active: #c62828;
|
||||||
--accent-color-light: #ef9a9a;
|
--accent-color-light: #ef9a9a;
|
||||||
|
--accent-color-visited: #b71c1c;
|
||||||
--text-with-accent-color: #FFFFFF;
|
--text-with-accent-color: #FFFFFF;
|
||||||
--accent-color-opacity1: rgba(244,67,54,0.04);
|
--accent-color-opacity1: rgba(244,67,54,0.04);
|
||||||
--accent-color-opacity2: rgba(244,67,54,0.12);
|
--accent-color-opacity2: rgba(244,67,54,0.12);
|
||||||
|
@ -215,6 +242,7 @@
|
||||||
--accent-color-hover: #D81B60;
|
--accent-color-hover: #D81B60;
|
||||||
--accent-color-active: #AD1457;
|
--accent-color-active: #AD1457;
|
||||||
--accent-color-light: #F48FB1;
|
--accent-color-light: #F48FB1;
|
||||||
|
--accent-color-visited: #880E4F;
|
||||||
--text-with-accent-color: #FFFFFF;
|
--text-with-accent-color: #FFFFFF;
|
||||||
--accent-color-opacity1: rgba(233,30,99,0.04);
|
--accent-color-opacity1: rgba(233,30,99,0.04);
|
||||||
--accent-color-opacity2: rgba(233,30,99,0.12);
|
--accent-color-opacity2: rgba(233,30,99,0.12);
|
||||||
|
@ -227,6 +255,7 @@
|
||||||
--accent-color-hover: #8E24AA;
|
--accent-color-hover: #8E24AA;
|
||||||
--accent-color-active: #6A1B9A;
|
--accent-color-active: #6A1B9A;
|
||||||
--accent-color-light: #CE93D8;
|
--accent-color-light: #CE93D8;
|
||||||
|
--accent-color-visited: #4A148C;
|
||||||
--text-with-accent-color: #FFFFFF;
|
--text-with-accent-color: #FFFFFF;
|
||||||
--accent-color-opacity1: rgba(156,39,176,0.04);
|
--accent-color-opacity1: rgba(156,39,176,0.04);
|
||||||
--accent-color-opacity2: rgba(156,39,176,0.12);
|
--accent-color-opacity2: rgba(156,39,176,0.12);
|
||||||
|
@ -239,6 +268,7 @@
|
||||||
--accent-color-hover: #5E35B1;
|
--accent-color-hover: #5E35B1;
|
||||||
--accent-color-active: #4527A0;
|
--accent-color-active: #4527A0;
|
||||||
--accent-color-light: #B39DDB;
|
--accent-color-light: #B39DDB;
|
||||||
|
--accent-color-visited: #311B92;
|
||||||
--text-with-accent-color: #FFFFFF;
|
--text-with-accent-color: #FFFFFF;
|
||||||
--accent-color-opacity1: rgba(103,58,183,0.04);
|
--accent-color-opacity1: rgba(103,58,183,0.04);
|
||||||
--accent-color-opacity2: rgba(103,58,183,0.12);
|
--accent-color-opacity2: rgba(103,58,183,0.12);
|
||||||
|
@ -251,6 +281,7 @@
|
||||||
--accent-color-hover: #3949AB;
|
--accent-color-hover: #3949AB;
|
||||||
--accent-color-active: #283593;
|
--accent-color-active: #283593;
|
||||||
--accent-color-light: #9FA8DA;
|
--accent-color-light: #9FA8DA;
|
||||||
|
--accent-color-visited: #1A237E;
|
||||||
--text-with-accent-color: #FFFFFF;
|
--text-with-accent-color: #FFFFFF;
|
||||||
--accent-color-opacity1: rgba(63,81,181,0.04);
|
--accent-color-opacity1: rgba(63,81,181,0.04);
|
||||||
--accent-color-opacity2: rgba(63,81,181,0.12);
|
--accent-color-opacity2: rgba(63,81,181,0.12);
|
||||||
|
@ -263,6 +294,7 @@
|
||||||
--accent-color-hover: #1E88E5;
|
--accent-color-hover: #1E88E5;
|
||||||
--accent-color-active: #1565C0;
|
--accent-color-active: #1565C0;
|
||||||
--accent-color-light: #90CAF9;
|
--accent-color-light: #90CAF9;
|
||||||
|
--accent-color-visited: #0D47A1;
|
||||||
--text-with-accent-color: #FFFFFF;
|
--text-with-accent-color: #FFFFFF;
|
||||||
--accent-color-opacity1: rgba(33,150,243,0.04);
|
--accent-color-opacity1: rgba(33,150,243,0.04);
|
||||||
--accent-color-opacity2: rgba(33,150,243,0.12);
|
--accent-color-opacity2: rgba(33,150,243,0.12);
|
||||||
|
@ -275,6 +307,7 @@
|
||||||
--accent-color-hover: #039BE5;
|
--accent-color-hover: #039BE5;
|
||||||
--accent-color-active: #0277BD;
|
--accent-color-active: #0277BD;
|
||||||
--accent-color-light: #81D4FA;
|
--accent-color-light: #81D4FA;
|
||||||
|
--accent-color-visited: #01579B;
|
||||||
--text-with-accent-color: #FFFFFF;
|
--text-with-accent-color: #FFFFFF;
|
||||||
--accent-color-opacity1: rgba(3,169,244,0.04);
|
--accent-color-opacity1: rgba(3,169,244,0.04);
|
||||||
--accent-color-opacity2: rgba(3,169,244,0.12);
|
--accent-color-opacity2: rgba(3,169,244,0.12);
|
||||||
|
@ -287,6 +320,7 @@
|
||||||
--accent-color-hover: #00ACC1;
|
--accent-color-hover: #00ACC1;
|
||||||
--accent-color-active: #00838F;
|
--accent-color-active: #00838F;
|
||||||
--accent-color-light: #80DEEA;
|
--accent-color-light: #80DEEA;
|
||||||
|
--accent-color-visited: #006064;
|
||||||
--text-with-accent-color: #FFFFFF;
|
--text-with-accent-color: #FFFFFF;
|
||||||
--accent-color-opacity1: rgba(0,188,212,0.04);
|
--accent-color-opacity1: rgba(0,188,212,0.04);
|
||||||
--accent-color-opacity2: rgba(0,188,212,0.12);
|
--accent-color-opacity2: rgba(0,188,212,0.12);
|
||||||
|
@ -299,6 +333,7 @@
|
||||||
--accent-color-hover: #00897B;
|
--accent-color-hover: #00897B;
|
||||||
--accent-color-active: #00695C;
|
--accent-color-active: #00695C;
|
||||||
--accent-color-light: #80CBC4;
|
--accent-color-light: #80CBC4;
|
||||||
|
--accent-color-visited: #004D40;
|
||||||
--text-with-accent-color: #FFFFFF;
|
--text-with-accent-color: #FFFFFF;
|
||||||
--accent-color-opacity1: rgba(0,150,136,0.04);
|
--accent-color-opacity1: rgba(0,150,136,0.04);
|
||||||
--accent-color-opacity2: rgba(0,150,136,0.12);
|
--accent-color-opacity2: rgba(0,150,136,0.12);
|
||||||
|
@ -311,6 +346,7 @@
|
||||||
--accent-color-hover: #43A047;
|
--accent-color-hover: #43A047;
|
||||||
--accent-color-active: #2E7D32;
|
--accent-color-active: #2E7D32;
|
||||||
--accent-color-light: #A5D6A7;
|
--accent-color-light: #A5D6A7;
|
||||||
|
--accent-color-visited: #1B5E20;
|
||||||
--text-with-accent-color: #FFFFFF;
|
--text-with-accent-color: #FFFFFF;
|
||||||
--accent-color-opacity1: rgba(76,175,80,0.04);
|
--accent-color-opacity1: rgba(76,175,80,0.04);
|
||||||
--accent-color-opacity2: rgba(76,175,80,0.12);
|
--accent-color-opacity2: rgba(76,175,80,0.12);
|
||||||
|
@ -323,6 +359,7 @@
|
||||||
--accent-color-hover: #7CB342;
|
--accent-color-hover: #7CB342;
|
||||||
--accent-color-active: #558B2F;
|
--accent-color-active: #558B2F;
|
||||||
--accent-color-light: #C5E1A5;
|
--accent-color-light: #C5E1A5;
|
||||||
|
--accent-color-visited: #33691E;
|
||||||
--text-with-accent-color: #000000;
|
--text-with-accent-color: #000000;
|
||||||
--accent-color-opacity1: rgba(139,195,74,0.04);
|
--accent-color-opacity1: rgba(139,195,74,0.04);
|
||||||
--accent-color-opacity2: rgba(139,195,74,0.12);
|
--accent-color-opacity2: rgba(139,195,74,0.12);
|
||||||
|
@ -335,6 +372,7 @@
|
||||||
--accent-color-hover: #C0CA33;
|
--accent-color-hover: #C0CA33;
|
||||||
--accent-color-active: #9E9D24;
|
--accent-color-active: #9E9D24;
|
||||||
--accent-color-light: #E6EE9C;
|
--accent-color-light: #E6EE9C;
|
||||||
|
--accent-color-visited: #827717;
|
||||||
--text-with-accent-color: #000000;
|
--text-with-accent-color: #000000;
|
||||||
--accent-color-opacity1: rgba(205,220,57,0.04);
|
--accent-color-opacity1: rgba(205,220,57,0.04);
|
||||||
--accent-color-opacity2: rgba(205,220,57,0.12);
|
--accent-color-opacity2: rgba(205,220,57,0.12);
|
||||||
|
@ -347,6 +385,7 @@
|
||||||
--accent-color-hover: #FDD835;
|
--accent-color-hover: #FDD835;
|
||||||
--accent-color-active: #F9A825;
|
--accent-color-active: #F9A825;
|
||||||
--accent-color-light: #FFF59D;
|
--accent-color-light: #FFF59D;
|
||||||
|
--accent-color-visited: #F57F17;
|
||||||
--text-with-accent-color: #000000;
|
--text-with-accent-color: #000000;
|
||||||
--accent-color-opacity1: rgba(255,235,59,0.04);
|
--accent-color-opacity1: rgba(255,235,59,0.04);
|
||||||
--accent-color-opacity2: rgba(255,235,59,0.12);
|
--accent-color-opacity2: rgba(255,235,59,0.12);
|
||||||
|
@ -359,6 +398,7 @@
|
||||||
--accent-color-hover: #FFB300;
|
--accent-color-hover: #FFB300;
|
||||||
--accent-color-active: #FF8F00;
|
--accent-color-active: #FF8F00;
|
||||||
--accent-color-light: #FFE082;
|
--accent-color-light: #FFE082;
|
||||||
|
--accent-color-visited: #FF6F00;
|
||||||
--text-with-accent-color: #000000;
|
--text-with-accent-color: #000000;
|
||||||
--accent-color-opacity1: rgba(255,193,7,0.04);
|
--accent-color-opacity1: rgba(255,193,7,0.04);
|
||||||
--accent-color-opacity2: rgba(255,193,7,0.12);
|
--accent-color-opacity2: rgba(255,193,7,0.12);
|
||||||
|
@ -371,6 +411,7 @@
|
||||||
--accent-color-hover: #FB8C00;
|
--accent-color-hover: #FB8C00;
|
||||||
--accent-color-active: #EF6C00;
|
--accent-color-active: #EF6C00;
|
||||||
--accent-color-light: #FFCC80;
|
--accent-color-light: #FFCC80;
|
||||||
|
--accent-color-visited: #E65100;
|
||||||
--text-with-accent-color: #000000;
|
--text-with-accent-color: #000000;
|
||||||
--accent-color-opacity1: rgba(255,152,0,0.04);
|
--accent-color-opacity1: rgba(255,152,0,0.04);
|
||||||
--accent-color-opacity2: rgba(255,152,0,0.12);
|
--accent-color-opacity2: rgba(255,152,0,0.12);
|
||||||
|
@ -383,6 +424,7 @@
|
||||||
--accent-color-hover: #F4511E;
|
--accent-color-hover: #F4511E;
|
||||||
--accent-color-active: #D84315;
|
--accent-color-active: #D84315;
|
||||||
--accent-color-light: #FFAB91;
|
--accent-color-light: #FFAB91;
|
||||||
|
--accent-color-visited: #BF360C;
|
||||||
--text-with-accent-color: #000000;
|
--text-with-accent-color: #000000;
|
||||||
--accent-color-opacity1: rgba(255,87,34,0.04);
|
--accent-color-opacity1: rgba(255,87,34,0.04);
|
||||||
--accent-color-opacity2: rgba(255,87,34,0.12);
|
--accent-color-opacity2: rgba(255,87,34,0.12);
|
||||||
|
@ -400,3 +442,9 @@ body {
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
background-color: var(--bg-color);
|
background-color: var(--bg-color);
|
||||||
}
|
}
|
||||||
|
a:link {
|
||||||
|
color: var(--link-color);
|
||||||
|
}
|
||||||
|
a:visited {
|
||||||
|
color: var(--link-visited-color);
|
||||||
|
}
|
||||||
|
|
|
@ -166,10 +166,15 @@
|
||||||
font-family: VideoJS;
|
font-family: VideoJS;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
position: relative;
|
||||||
|
top: -3px;
|
||||||
}
|
}
|
||||||
.vjs-icon-cog:before {
|
.vjs-icon-cog:before {
|
||||||
content: "\f110";
|
content: "\f110";
|
||||||
}
|
}
|
||||||
|
.video-js .vjs-icon-cog {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
.vjs-icon-circle, .vjs-seek-to-live-control .vjs-icon-placeholder, .video-js .vjs-volume-level, .video-js .vjs-play-progress {
|
.vjs-icon-circle, .vjs-seek-to-live-control .vjs-icon-placeholder, .video-js .vjs-volume-level, .video-js .vjs-play-progress {
|
||||||
font-family: VideoJS;
|
font-family: VideoJS;
|
||||||
|
@ -335,7 +340,6 @@
|
||||||
|
|
||||||
.video-js {
|
.video-js {
|
||||||
display: block;
|
display: block;
|
||||||
vertical-align: top;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
|
@ -774,7 +778,7 @@ body.vjs-full-window {
|
||||||
}
|
}
|
||||||
|
|
||||||
.vjs-button > .vjs-icon-placeholder:before {
|
.vjs-button > .vjs-icon-placeholder:before {
|
||||||
font-size: 1.8em;
|
font-size: 2em;
|
||||||
line-height: 1.67;
|
line-height: 1.67;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,6 +814,7 @@ body.vjs-full-window {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 4em;
|
min-width: 4em;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-js .vjs-progress-control.disabled {
|
.video-js .vjs-progress-control.disabled {
|
||||||
|
@ -1012,7 +1017,7 @@ body.vjs-full-window {
|
||||||
transition: left 0s;
|
transition: left 0s;
|
||||||
}
|
}
|
||||||
.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal:active, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active {
|
.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal:active, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active {
|
||||||
width: 10em;
|
width: 8em;
|
||||||
transition: width 0.1s;
|
transition: width 0.1s;
|
||||||
}
|
}
|
||||||
.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-mute-toggle-only {
|
.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-mute-toggle-only {
|
||||||
|
@ -1057,6 +1062,8 @@ body.vjs-full-window {
|
||||||
.vjs-volume-bar.vjs-slider-horizontal {
|
.vjs-volume-bar.vjs-slider-horizontal {
|
||||||
width: 5em;
|
width: 5em;
|
||||||
height: 0.3em;
|
height: 0.3em;
|
||||||
|
position: relative;
|
||||||
|
top: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vjs-volume-bar.vjs-slider-vertical {
|
.vjs-volume-bar.vjs-slider-vertical {
|
||||||
|
@ -1237,6 +1244,8 @@ body.vjs-full-window {
|
||||||
|
|
||||||
.video-js .vjs-play-control {
|
.video-js .vjs-play-control {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-js .vjs-play-control .vjs-icon-placeholder {
|
.video-js .vjs-play-control .vjs-icon-placeholder {
|
||||||
|
@ -1285,15 +1294,19 @@ video::-webkit-media-text-track-display {
|
||||||
.video-js .vjs-picture-in-picture-control {
|
.video-js .vjs-picture-in-picture-control {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
flex: none;
|
flex: none;
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
}
|
}
|
||||||
.video-js .vjs-fullscreen-control {
|
.video-js .vjs-fullscreen-control {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
flex: none;
|
flex: none;
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
}
|
}
|
||||||
.vjs-playback-rate > .vjs-menu-button,
|
.vjs-playback-rate > .vjs-menu-button,
|
||||||
.vjs-playback-rate .vjs-playback-rate-value {
|
.vjs-playback-rate .vjs-playback-rate-value {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 16px;
|
top: 12px;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1760,7 +1773,10 @@ video::-webkit-media-text-track-display {
|
||||||
-webkit-flex: 0 1 auto;
|
-webkit-flex: 0 1 auto;
|
||||||
-ms-flex: 0 1 auto;
|
-ms-flex: 0 1 auto;
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
width: auto
|
width: auto;
|
||||||
|
font-size: 14px;
|
||||||
|
position: relative;
|
||||||
|
top: -6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-js .vjs-time-control.vjs-time-divider {
|
.video-js .vjs-time-control.vjs-time-divider {
|
||||||
|
@ -1815,8 +1831,8 @@ video::-webkit-media-text-track-display {
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-js .vjs-progress-control:hover {
|
.video-js .vjs-progress-control:hover {
|
||||||
height: 1em;
|
height: 1.25em;
|
||||||
top: -1em
|
top: -0.95em
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-js .vjs-control-bar {
|
.video-js .vjs-control-bar {
|
||||||
|
@ -1831,6 +1847,7 @@ video::-webkit-media-text-track-display {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
-webkit-backface-visibility: hidden;
|
-webkit-backface-visibility: hidden;
|
||||||
|
backface-visibility: hidden;
|
||||||
-webkit-transform: translateY(3em);
|
-webkit-transform: translateY(3em);
|
||||||
-moz-transform: translateY(3em);
|
-moz-transform: translateY(3em);
|
||||||
-ms-transform: translateY(3em);
|
-ms-transform: translateY(3em);
|
||||||
|
@ -1896,6 +1913,12 @@ video::-webkit-media-text-track-display {
|
||||||
width: 5.5em;
|
width: 5.5em;
|
||||||
left: 1.5em;
|
left: 1.5em;
|
||||||
padding-bottom: .5em;
|
padding-bottom: .5em;
|
||||||
|
z-index: 1;
|
||||||
|
bottom: 1.15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-js .vjs-menu-button-popup.vjs-http-source-selector .vjs-menu .vjs-menu-content {
|
||||||
|
bottom: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-js .vjs-menu-button-popup .vjs-menu .vjs-menu-item,.video-js .vjs-menu-button-popup .vjs-menu .vjs-menu-title {
|
.video-js .vjs-menu-button-popup .vjs-menu .vjs-menu-item,.video-js .vjs-menu-button-popup .vjs-menu .vjs-menu-title {
|
||||||
|
@ -1988,3 +2011,13 @@ video::-webkit-media-text-track-display {
|
||||||
.video-js .vjs-http-source-selector {
|
.video-js .vjs-http-source-selector {
|
||||||
top: 4px;
|
top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vjs-subs-caps-button.vjs-control {
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-volume-panel .vjs-mute-control {
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import FtChannelBubble from '../../components/ft-channel-bubble/ft-channel-bubbl
|
||||||
import FtLoader from '../../components/ft-loader/ft-loader.vue'
|
import FtLoader from '../../components/ft-loader/ft-loader.vue'
|
||||||
import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
|
import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
|
||||||
|
|
||||||
|
import ytch from 'yt-channel-info'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'Search',
|
name: 'Search',
|
||||||
components: {
|
components: {
|
||||||
|
@ -32,7 +34,9 @@ export default Vue.extend({
|
||||||
subCount: 0,
|
subCount: 0,
|
||||||
latestVideosPage: 2,
|
latestVideosPage: 2,
|
||||||
searchPage: 2,
|
searchPage: 2,
|
||||||
|
videoContinuationString: '',
|
||||||
playlistContinuationString: '',
|
playlistContinuationString: '',
|
||||||
|
searchContinuationString: '',
|
||||||
channelDescription: '',
|
channelDescription: '',
|
||||||
videoSortBy: 'newest',
|
videoSortBy: 'newest',
|
||||||
playlistSortBy: 'last',
|
playlistSortBy: 'last',
|
||||||
|
@ -42,6 +46,7 @@ export default Vue.extend({
|
||||||
latestPlaylists: [],
|
latestPlaylists: [],
|
||||||
searchResults: [],
|
searchResults: [],
|
||||||
shownElementList: [],
|
shownElementList: [],
|
||||||
|
apiUsed: '',
|
||||||
videoSelectNames: [
|
videoSelectNames: [
|
||||||
'Newest',
|
'Newest',
|
||||||
'Oldest',
|
'Oldest',
|
||||||
|
@ -65,6 +70,18 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
usingElectron: function () {
|
||||||
|
return this.$store.getters.getUsingElectron
|
||||||
|
},
|
||||||
|
|
||||||
|
backendPreference: function () {
|
||||||
|
return this.$store.getters.getBackendPreference
|
||||||
|
},
|
||||||
|
|
||||||
|
backendFallback: function () {
|
||||||
|
return this.$store.getters.getBackendFallback
|
||||||
|
},
|
||||||
|
|
||||||
sessionSearchHistory: function () {
|
sessionSearchHistory: function () {
|
||||||
return this.$store.getters.getSessionSearchHistory
|
return this.$store.getters.getSessionSearchHistory
|
||||||
},
|
},
|
||||||
|
@ -77,25 +94,92 @@ export default Vue.extend({
|
||||||
videoSortBy () {
|
videoSortBy () {
|
||||||
this.isElementListLoading = true
|
this.isElementListLoading = true
|
||||||
this.latestVideos = []
|
this.latestVideos = []
|
||||||
this.latestVideosPage = 1
|
switch (this.apiUsed) {
|
||||||
this.channelNextPage()
|
case 'local':
|
||||||
|
this.getChannelVideosLocal()
|
||||||
|
break
|
||||||
|
case 'invidious':
|
||||||
|
this.latestVideosPage = 1
|
||||||
|
this.channelInvidiousNextPage()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
this.getChannelVideosLocal()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
playlistSortBy () {
|
playlistSortBy () {
|
||||||
this.isElementListLoading = true
|
this.isElementListLoading = true
|
||||||
this.latestPlaylists = []
|
this.latestPlaylists = []
|
||||||
this.playlistContinuationString = ''
|
this.playlistContinuationString = ''
|
||||||
this.getPlaylists()
|
switch (this.apiUsed) {
|
||||||
|
case 'local':
|
||||||
|
this.getPlaylistsLocal()
|
||||||
|
break
|
||||||
|
case 'invidious':
|
||||||
|
this.channelInvidiousNextPage()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
this.getPlaylistsLocal()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.id = this.$route.params.id
|
this.id = this.$route.params.id
|
||||||
|
this.isLoading = true
|
||||||
|
|
||||||
this.getChannelInfo()
|
if (!this.usingElectron) {
|
||||||
this.getPlaylists()
|
this.getVideoInformationInvidious()
|
||||||
|
} else {
|
||||||
|
switch (this.backendPreference) {
|
||||||
|
case 'local':
|
||||||
|
this.apiUsed = 'local'
|
||||||
|
this.getChannelInfoLocal()
|
||||||
|
this.getChannelVideosLocal()
|
||||||
|
this.getPlaylistsLocal()
|
||||||
|
break
|
||||||
|
case 'invidious':
|
||||||
|
this.apiUsed = 'invidious'
|
||||||
|
this.getChannelInfoInvidious()
|
||||||
|
this.getPlaylistsInvidious()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getChannelInfo: function () {
|
getChannelInfoLocal: function () {
|
||||||
|
ytch.getChannelInfo(this.id).then((response) => {
|
||||||
|
this.id = response.authorId
|
||||||
|
this.channelName = response.author
|
||||||
|
this.subCount = response.subscriberCount
|
||||||
|
this.thumbnailUrl = response.authorThumbnails[2].url
|
||||||
|
this.bannerUrl = `https://${response.authorBanners[response.authorBanners.length - 1].url}`
|
||||||
|
this.channelDescription = response.description
|
||||||
|
this.relatedChannels = response.relatedChannels
|
||||||
|
this.isLoading = false
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getChannelVideosLocal: function () {
|
||||||
|
this.isElementListLoading = true
|
||||||
|
ytch.getChannelVideos(this.id, this.videoSortBy).then((response) => {
|
||||||
|
this.latestVideos = response.items
|
||||||
|
this.videoContinuationString = response.continuation
|
||||||
|
this.isElementListLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
channelLocalNextPage: function () {
|
||||||
|
console.log(this.videoContinuationString)
|
||||||
|
ytch.getChannelVideosMore(this.id, this.videoContinuationString).then((response) => {
|
||||||
|
this.latestVideos = this.latestVideos.concat(response.items)
|
||||||
|
this.videoContinuationString = response.continuation
|
||||||
|
console.log(this.videoContinuationString)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getChannelInfoInvidious: function () {
|
||||||
this.isLoading = true
|
this.isLoading = true
|
||||||
|
|
||||||
this.$store.dispatch('invidiousGetChannelInfo', this.id).then((response) => {
|
this.$store.dispatch('invidiousGetChannelInfo', this.id).then((response) => {
|
||||||
|
@ -115,7 +199,7 @@ export default Vue.extend({
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
channelNextPage: function () {
|
channelInvidiousNextPage: function () {
|
||||||
const payload = {
|
const payload = {
|
||||||
resource: 'channels/videos',
|
resource: 'channels/videos',
|
||||||
id: this.id,
|
id: this.id,
|
||||||
|
@ -132,7 +216,24 @@ export default Vue.extend({
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
getPlaylists: function () {
|
getPlaylistsLocal: function () {
|
||||||
|
ytch.getChannelPlaylistInfo(this.id, this.playlistSortBy).then((response) => {
|
||||||
|
console.log(response)
|
||||||
|
this.latestPlaylists = response.items
|
||||||
|
this.playlistContinuationString = response.continuation
|
||||||
|
this.isElementListLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getPlaylistsLocalMore: function () {
|
||||||
|
ytch.getChannelPlaylistsMore(this.id, this.playlistContinuationString).then((response) => {
|
||||||
|
console.log(response)
|
||||||
|
this.latestPlaylists = this.latestPlaylists.concat(response.items)
|
||||||
|
this.playlistContinuationString = response.continuation
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getPlaylistsInvidious: function () {
|
||||||
if (this.playlistContinuationString === null) {
|
if (this.playlistContinuationString === null) {
|
||||||
console.log('There are no more playlists available for this channel')
|
console.log('There are no more playlists available for this channel')
|
||||||
return
|
return
|
||||||
|
@ -163,13 +264,34 @@ export default Vue.extend({
|
||||||
handleFetchMore: function () {
|
handleFetchMore: function () {
|
||||||
switch (this.currentTab) {
|
switch (this.currentTab) {
|
||||||
case 'videos':
|
case 'videos':
|
||||||
this.channelNextPage()
|
switch (this.apiUsed) {
|
||||||
|
case 'local':
|
||||||
|
this.channelLocalNextPage()
|
||||||
|
break
|
||||||
|
case 'invidious':
|
||||||
|
this.channelInvidiousNextPage()
|
||||||
|
break
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 'playlists':
|
case 'playlists':
|
||||||
this.getPlaylists()
|
switch (this.apiUsed) {
|
||||||
|
case 'local':
|
||||||
|
this.getPlaylistsLocalMore()
|
||||||
|
break
|
||||||
|
case 'invidious':
|
||||||
|
this.getPlaylistsInvidious()
|
||||||
|
break
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 'search':
|
case 'search':
|
||||||
this.searchChannel()
|
switch (this.apiUsed) {
|
||||||
|
case 'local':
|
||||||
|
this.searchChannelLocal()
|
||||||
|
break
|
||||||
|
case 'invidious':
|
||||||
|
this.searchChannelInvidious()
|
||||||
|
break
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -180,14 +302,40 @@ export default Vue.extend({
|
||||||
|
|
||||||
newSearch: function (query) {
|
newSearch: function (query) {
|
||||||
this.lastSearchQuery = query
|
this.lastSearchQuery = query
|
||||||
|
this.searchContinuationString = ''
|
||||||
this.isElementListLoading = true
|
this.isElementListLoading = true
|
||||||
this.searchPage = 1
|
this.searchPage = 1
|
||||||
this.searchResults = []
|
this.searchResults = []
|
||||||
this.changeTab('search')
|
this.changeTab('search')
|
||||||
this.searchChannel()
|
switch (this.apiUsed) {
|
||||||
|
case 'local':
|
||||||
|
this.searchChannelLocal()
|
||||||
|
break
|
||||||
|
case 'invidious':
|
||||||
|
this.searchChannelInvidious()
|
||||||
|
break
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
searchChannel: function () {
|
searchChannelLocal: function () {
|
||||||
|
if (this.searchContinuationString === '') {
|
||||||
|
ytch.searchChannel(this.id, this.lastSearchQuery).then((response) => {
|
||||||
|
console.log(response)
|
||||||
|
this.searchResults = response.items
|
||||||
|
this.isElementListLoading = false
|
||||||
|
this.searchContinuationString = response.continuation
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ytch.searchChannelMore(this.id, this.searchContinuationString).then((response) => {
|
||||||
|
console.log(response)
|
||||||
|
this.searchResults = this.searchResults.concat(response.items)
|
||||||
|
this.isElementListLoading = false
|
||||||
|
this.searchContinuationString = response.continuation
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
searchChannelInvidious: function () {
|
||||||
const payload = {
|
const payload = {
|
||||||
resource: 'channels/search',
|
resource: 'channels/search',
|
||||||
id: this.id,
|
id: this.id,
|
||||||
|
|
|
@ -109,7 +109,7 @@
|
||||||
:key="index"
|
:key="index"
|
||||||
:channel-name="channel.author"
|
:channel-name="channel.author"
|
||||||
:channel-id="channel.authorId"
|
:channel-id="channel.authorId"
|
||||||
:channel-thumbnail="channel.authorThumbnails[3].url"
|
:channel-thumbnail="channel.authorThumbnails[channel.authorThumbnails.length - 1].url"
|
||||||
/>
|
/>
|
||||||
</ft-flex-box>
|
</ft-flex-box>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,123 +0,0 @@
|
||||||
.watchVideo {
|
|
||||||
width: 65%;
|
|
||||||
float: left;
|
|
||||||
margin-top: 0px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theatreWatchVideo {
|
|
||||||
float: none;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 85%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.videoPlayer {
|
|
||||||
width: calc(65% + 30px);
|
|
||||||
float: left;
|
|
||||||
margin-top: 0px;
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theatrePlayer {
|
|
||||||
width: 100%;
|
|
||||||
float: none;
|
|
||||||
margin: 0 auto;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.watchVideoSideBar {
|
|
||||||
width: 27%;
|
|
||||||
max-width: 425px;
|
|
||||||
float: right;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.watchVideoPlaylist {
|
|
||||||
right: 10px;
|
|
||||||
top: 70px;
|
|
||||||
height: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theatrePlaylist {
|
|
||||||
float: none;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 85%;
|
|
||||||
height: 500px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
max-width: none;
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
|
|
||||||
.watchVideoRecommendations {
|
|
||||||
right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.watchVideoRecommendationsNoCard {
|
|
||||||
top: 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.watchVideoRecommendationsLowerCard {
|
|
||||||
top: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theatreRecommendations {
|
|
||||||
float: none;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 85%;
|
|
||||||
max-width: none;
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 1500px) {
|
|
||||||
.watchVideo {
|
|
||||||
width: 63%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.videoPlayer {
|
|
||||||
width: calc(63% + 30px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theatreWatchVideo {
|
|
||||||
width: 85%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theatrePlayer {
|
|
||||||
width: calc(85% + 30px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 1350px) {
|
|
||||||
.watchVideo {
|
|
||||||
float: none;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 85%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.videoPlayer {
|
|
||||||
float: none;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: calc(85% + 30px);
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.watchVideoPlaylist {
|
|
||||||
float: none;
|
|
||||||
margin: 0 auto;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
width: 85%;
|
|
||||||
max-width: none;
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
|
|
||||||
.watchVideoRecommendations {
|
|
||||||
float: none;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 85%;
|
|
||||||
max-width: none;
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
=dual-column-template
|
||||||
|
grid-template: "video video sidebar" 0fr "info info sidebar" auto "info info sidebar" auto / 1fr 1fr 1fr
|
||||||
|
|
||||||
|
=theatre-mode-template
|
||||||
|
grid-template: "video video video" auto "info info sidebar" auto "info info sidebar" auto / 1fr 1fr 1fr
|
||||||
|
|
||||||
|
=single-column-template
|
||||||
|
grid-template: "video" auto "info" auto "sidebar" auto / auto
|
||||||
|
|
||||||
|
.videoLayout
|
||||||
|
display: grid
|
||||||
|
align-items: start
|
||||||
|
+dual-column-template
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1350px)
|
||||||
|
+theatre-mode-template
|
||||||
|
|
||||||
|
@media only screen and (min-width: 901px)
|
||||||
|
&.useTheatreMode
|
||||||
|
+theatre-mode-template
|
||||||
|
|
||||||
|
@media only screen and (max-width: 900px)
|
||||||
|
+single-column-template
|
||||||
|
|
||||||
|
&.isLoading
|
||||||
|
+single-column-template
|
||||||
|
|
||||||
|
.videoArea
|
||||||
|
grid-area: video
|
||||||
|
|
||||||
|
.videoAreaMargin
|
||||||
|
margin: 0px 8px 16px
|
||||||
|
|
||||||
|
.videoPlayer
|
||||||
|
grid-column: 1
|
||||||
|
max-width: calc(80vh * 1.78)
|
||||||
|
margin: 0 auto
|
||||||
|
|
||||||
|
.watchVideo
|
||||||
|
margin: 0px 8px 16px
|
||||||
|
grid-column: 1
|
||||||
|
|
||||||
|
.infoArea
|
||||||
|
grid-area: info
|
||||||
|
|
||||||
|
.sidebarArea
|
||||||
|
grid-area: sidebar
|
||||||
|
|
||||||
|
@media only screen and (min-width: 901px)
|
||||||
|
min-width: 380px
|
||||||
|
|
||||||
|
.watchVideoPlaylist, .watchVideoSidebar, .theatrePlaylist
|
||||||
|
height: 500px
|
||||||
|
margin: 0 8px 16px
|
||||||
|
|
||||||
|
.watchVideoRecommendations, .theatreRecommendations
|
||||||
|
margin: 0 8px 16px
|
|
@ -1,80 +1,95 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div
|
||||||
|
class="videoLayout"
|
||||||
|
:class="{
|
||||||
|
isLoading,
|
||||||
|
useTheatreMode
|
||||||
|
}"
|
||||||
|
>
|
||||||
<ft-loader
|
<ft-loader
|
||||||
v-if="isLoading"
|
v-if="isLoading"
|
||||||
:fullscreen="true"
|
:fullscreen="true"
|
||||||
/>
|
/>
|
||||||
<ft-video-player
|
<div class="videoArea">
|
||||||
v-if="!isLoading && !hidePlayer"
|
<div class="videoAreaMargin">
|
||||||
:dash-src="dashSrc"
|
<ft-video-player
|
||||||
:source-list="activeSourceList"
|
v-if="!isLoading && !hidePlayer"
|
||||||
:caption-list="captionSourceList"
|
ref="videoPlayer"
|
||||||
:storyboard-src="videoStoryboardSrc"
|
:dash-src="dashSrc"
|
||||||
:format="activeFormat"
|
:source-list="activeSourceList"
|
||||||
:thumbnail="thumbnail"
|
:caption-list="captionSourceList"
|
||||||
class="videoPlayer"
|
:storyboard-src="videoStoryboardSrc"
|
||||||
:class="{ theatrePlayer: useTheatreMode }"
|
:format="activeFormat"
|
||||||
ref="videoPlayer"
|
:thumbnail="thumbnail"
|
||||||
@ended="handleVideoEnded"
|
class="videoPlayer"
|
||||||
@error="handleVideoError"
|
:class="{ theatrePlayer: useTheatreMode }"
|
||||||
/>
|
@ended="handleVideoEnded"
|
||||||
<watch-video-info
|
@error="handleVideoError"
|
||||||
v-if="!isLoading"
|
/>
|
||||||
:id="videoId"
|
</div>
|
||||||
:title="videoTitle"
|
</div>
|
||||||
:channel-id="channelId"
|
<div class="infoArea">
|
||||||
:channel-name="channelName"
|
<watch-video-info
|
||||||
:channel-thumbnail="channelThumbnail"
|
v-if="!isLoading"
|
||||||
:subscription-count-text="channelSubscriptionCountText"
|
:id="videoId"
|
||||||
:like-count="videoLikeCount"
|
:title="videoTitle"
|
||||||
:dislike-count="videoDislikeCount"
|
:channel-id="channelId"
|
||||||
:view-count="videoViewCount"
|
:channel-name="channelName"
|
||||||
@theatreMode="toggleTheatreMode"
|
:channel-thumbnail="channelThumbnail"
|
||||||
class="watchVideo"
|
:published="videoPublished"
|
||||||
:class="{ theatreWatchVideo: useTheatreMode }"
|
:subscription-count-text="channelSubscriptionCountText"
|
||||||
/>
|
:like-count="videoLikeCount"
|
||||||
<watch-video-description
|
:dislike-count="videoDislikeCount"
|
||||||
v-if="!isLoading"
|
:view-count="videoViewCount"
|
||||||
:published="videoPublished"
|
class="watchVideo"
|
||||||
:description="videoDescription"
|
:class="{ theatreWatchVideo: useTheatreMode }"
|
||||||
:description-html="videoDescriptionHtml"
|
@theatreMode="toggleTheatreMode"
|
||||||
class="watchVideo"
|
/>
|
||||||
:class="{ theatreWatchVideo: useTheatreMode }"
|
<watch-video-description
|
||||||
/>
|
v-if="!isLoading"
|
||||||
<watch-video-comments
|
:published="videoPublished"
|
||||||
v-if="!isLoading && !isLive"
|
:description="videoDescription"
|
||||||
:id="videoId"
|
:description-html="videoDescriptionHtml"
|
||||||
class="watchVideo"
|
class="watchVideo"
|
||||||
:class="{ theatreWatchVideo: useTheatreMode }"
|
:class="{ theatreWatchVideo: useTheatreMode }"
|
||||||
/>
|
/>
|
||||||
<watch-video-live-chat
|
<watch-video-comments
|
||||||
v-if="!isLoading && isLive"
|
v-if="!isLoading && !isLive"
|
||||||
:video-id="videoId"
|
:id="videoId"
|
||||||
:channel-name="channelName"
|
class="watchVideo"
|
||||||
class="watchVideoSideBar watchVideoPlaylist"
|
:class="{ theatreWatchVideo: useTheatreMode }"
|
||||||
:class="{ theatrePlaylist: useTheatreMode }"
|
/>
|
||||||
/>
|
</div>
|
||||||
<watch-video-playlist
|
<div class="sidebarArea">
|
||||||
v-if="watchingPlaylist"
|
<watch-video-live-chat
|
||||||
v-show="!isLoading"
|
v-if="!isLoading && isLive"
|
||||||
:playlist-id="playlistId"
|
:video-id="videoId"
|
||||||
:video-id="videoId"
|
:channel-name="channelName"
|
||||||
ref="watchVideoPlaylist"
|
class="watchVideoSideBar watchVideoPlaylist"
|
||||||
class="watchVideoSideBar watchVideoPlaylist"
|
:class="{ theatrePlaylist: useTheatreMode }"
|
||||||
:class="{ theatrePlaylist: useTheatreMode }"
|
/>
|
||||||
/>
|
<watch-video-playlist
|
||||||
<watch-video-recommendations
|
v-if="watchingPlaylist"
|
||||||
v-if="!isLoading"
|
v-show="!isLoading"
|
||||||
:data="recommendedVideos"
|
ref="watchVideoPlaylist"
|
||||||
class="watchVideoSideBar watchVideoRecommendations"
|
:playlist-id="playlistId"
|
||||||
:class="{
|
:video-id="videoId"
|
||||||
theatreRecommendations: useTheatreMode,
|
class="watchVideoSideBar watchVideoPlaylist"
|
||||||
watchVideoRecommendationsLowerCard: watchingPlaylist || isLive,
|
:class="{ theatrePlaylist: useTheatreMode }"
|
||||||
watchVideoRecommendationsNoCard: !watchingPlaylist || !isLive
|
/>
|
||||||
}"
|
<watch-video-recommendations
|
||||||
/>
|
v-if="!isLoading"
|
||||||
|
:data="recommendedVideos"
|
||||||
|
class="watchVideoSideBar watchVideoRecommendations"
|
||||||
|
:class="{
|
||||||
|
theatreRecommendations: useTheatreMode,
|
||||||
|
watchVideoRecommendationsLowerCard: watchingPlaylist || isLive,
|
||||||
|
watchVideoRecommendationsNoCard: !watchingPlaylist || !isLive
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./Watch.js" />
|
<script src="./Watch.js" />
|
||||||
<style scoped src="./Watch.css" />
|
<style scoped src="./Watch.sass" lang="sass" />
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
{
|
||||||
|
"File": "File",
|
||||||
|
"Quit": "Quit",
|
||||||
|
"Edit": "Edit",
|
||||||
|
"Undo": "Undo",
|
||||||
|
"Redo": "Redo",
|
||||||
|
"Cut": "Cut",
|
||||||
|
"Copy": "Copy",
|
||||||
|
"Paste": "Paste",
|
||||||
|
"Delete": "Delete",
|
||||||
|
"Select all": "Select all",
|
||||||
|
"View": "View",
|
||||||
|
"Reload": "Reload",
|
||||||
|
"Force Reload": "Force Reload",
|
||||||
|
"Toggle Developer Tools": "Toggle Developer Tools",
|
||||||
|
"Actual size": "Actual size",
|
||||||
|
"Zoom in": "Zoom in",
|
||||||
|
"Zoom out": "Zoom out",
|
||||||
|
"Toggle fullscreen": "Toggle fullscreen",
|
||||||
|
"Window": "Window",
|
||||||
|
"Minimize": "Minimize",
|
||||||
|
"Close": "Close",
|
||||||
|
"FreeTube": "FreeTube",
|
||||||
|
"Subscriptions": "Subscriptions",
|
||||||
|
"Featured": "Featured",
|
||||||
|
"Most Popular": "Most Popular",
|
||||||
|
"Saved": "Saved",
|
||||||
|
"Playlists": "Playlists",
|
||||||
|
"History": "History",
|
||||||
|
"Settings": "Settings",
|
||||||
|
"About": "About",
|
||||||
|
"Search / Go to URL": "Search / Go to URL",
|
||||||
|
"Search Results": "Search Results",
|
||||||
|
"Subscriber": "Subscriber",
|
||||||
|
"Subscribers": "Subscribers",
|
||||||
|
"Video": "Video",
|
||||||
|
"Videos": "Videos",
|
||||||
|
"View Full Playlist": "View Full Playlist",
|
||||||
|
"Live Now": "Live Now",
|
||||||
|
"Fetch more results": "Fetch more results",
|
||||||
|
"Fetching results. Please wait": "Fetching results. Please wait",
|
||||||
|
"Latest Subscriptions": "Latest Subscriptions",
|
||||||
|
"Save Video": "Save Video",
|
||||||
|
"Remove Saved Video": "Remove Saved Video",
|
||||||
|
"Open in YouTube": "Open in YouTube",
|
||||||
|
"Copy YouTube Link": "Copy YouTube Link",
|
||||||
|
"Open in Invidious": "Open in Invidious",
|
||||||
|
"Copy Invidious Link": "Copy Invidious Link",
|
||||||
|
"URL has been copied to the clipboard": "URL copied to clipboard",
|
||||||
|
"Found valid URL for 480p, but returned a 404. Video type might be available in the future.": "Found valid URL for 480p, but returned a 404. Video type might be available in the future.",
|
||||||
|
"Save": "Save",
|
||||||
|
"Mini Player": "Mini Player",
|
||||||
|
"View": "View",
|
||||||
|
"Views": "Views",
|
||||||
|
"Subscribe": "Subscribe",
|
||||||
|
"Unsubscribe": "Unsubscribe",
|
||||||
|
"Published on": "Published on",
|
||||||
|
"Jan": "Jan",
|
||||||
|
"Feb": "Feb",
|
||||||
|
"Mar": "Mar",
|
||||||
|
"Apr": "Apr",
|
||||||
|
"May": "May",
|
||||||
|
"Jun": "Jun",
|
||||||
|
"Jul": "Jul",
|
||||||
|
"Aug": "Aug",
|
||||||
|
"Sep": "Sep",
|
||||||
|
"Oct": "Oct",
|
||||||
|
"Nov": "Nov",
|
||||||
|
"Dec": "Dec",
|
||||||
|
"Show Comments": "Show Comments",
|
||||||
|
"Max of 100": "Max of 100",
|
||||||
|
"Recommendations": "Recommendations",
|
||||||
|
"Latest Subscriptions": "Latest Subscriptions",
|
||||||
|
"Getting Subscriptions. Please wait...": "Getting Subscriptions. Please wait…",
|
||||||
|
"Your Subscription list is currently empty. Start adding subscriptions to see them here.": "Add subscriptions to see them here.",
|
||||||
|
"Saved Videos": "Saved Videos",
|
||||||
|
"Watch History": "Watch History",
|
||||||
|
"Use Dark Theme": "Use Dark Theme",
|
||||||
|
"Import Subscriptions": "Import Subscriptions",
|
||||||
|
"Export Subscriptions": "Export Subscriptions",
|
||||||
|
"Clear History": "Clear History",
|
||||||
|
"Are you sure you want to delete your history?": "Are you sure you want to delete your history?",
|
||||||
|
"Clear Saved Videos": "Clear Favorited Videos",
|
||||||
|
"Are you sure you want to remove all saved videos?": "Are you sure you want to remove all saved videos?",
|
||||||
|
"Clear Subscriptions": "Clear Subscriptions",
|
||||||
|
"Are you sure you want to remove all subscriptions?": "Are you sure you want to remove all subscriptions?",
|
||||||
|
"Save Settings": "Save Settings",
|
||||||
|
"Yes": "Yes",
|
||||||
|
"No": "No",
|
||||||
|
"Beta": "Beta",
|
||||||
|
"This software is FOSS and released under the GNU Public License v3+.": "This copylefted software is freely licensed GPLv3+.",
|
||||||
|
"Found a bug? Want to suggest a feature? Want to help out? Check out our GitHub page. Pull requests are welcome.": "Found a bug? Want to suggest a feature? Want to help out? Check out our GitHub page. Pull requests welcome."
|
||||||
|
}
|
|
@ -143,7 +143,7 @@ function fromCache(request) {
|
||||||
return caches.open(CACHE).then(function (cache) {
|
return caches.open(CACHE).then(function (cache) {
|
||||||
return cache.match(request).then(function (matching) {
|
return cache.match(request).then(function (matching) {
|
||||||
if (!matching || matching.status === 404) {
|
if (!matching || matching.status === 404) {
|
||||||
return Promise.reject('no-match')
|
return Promise.reject(new Error('no-match'))
|
||||||
}
|
}
|
||||||
|
|
||||||
return matching
|
return matching
|
||||||
|
|
Loading…
Reference in New Issue