Commit cc780fa7 authored by Preston's avatar Preston
Browse files

Merge branch 'development'

parents 2e238460 4135f500
......@@ -107,7 +107,8 @@ const config = {
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
child_process: 'empty',
dns: 'empty'
},
plugins: [
// new WriteFilePlugin(),
......
This diff is collapsed.
......@@ -17,6 +17,8 @@
"bulma-pro": "^0.2.0",
"dateformat": "^4.4.1",
"electron-context-menu": "^2.4.0",
"http-proxy-agent": "^4.0.1",
"https-proxy-agent": "^5.0.0",
"jquery": "^3.5.1",
"js-yaml": "^4.0.0",
"lodash.debounce": "^4.0.8",
......@@ -27,6 +29,7 @@
"nedb": "^1.8.0",
"opml-to-json": "1.0.1",
"rss-parser": "^3.10.0",
"socks-proxy-agent": "^5.0.0",
"video.js": "7.10.2",
"videojs-abloop": "^1.2.0",
"videojs-contrib-quality-levels": "^2.0.9",
......@@ -36,7 +39,7 @@
"videojs-vtt-thumbnails-freetube": "0.0.15",
"vue": "^2.6.12",
"vue-electron": "^1.0.6",
"vue-i18n": "^8.22.3",
"vue-i18n": "^8.22.4",
"vue-observe-visibility": "^1.0.0",
"vue-router": "^3.4.9",
"vuex": "^3.6.0",
......@@ -44,13 +47,13 @@
"youtube-chat": "^1.1.0",
"youtube-suggest": "^1.1.0",
"yt-channel-info": "^1.2.0",
"yt-comment-scraper": "^1.3.11",
"yt-dash-manifest-generator": "^1.1.0",
"yt-trending-scraper": "1.0.4",
"yt-comment-scraper": "^2.0.0",
"yt-dash-manifest-generator": "1.1.0",
"yt-trending-scraper": "1.1.0",
"yt-xml2vtt": "^1.2.0",
"ytdl-core": "^4.4.3",
"ytdl-core": "^4.4.4",
"ytpl": "^2.0.4",
"ytsr": "^3.2.1"
"ytsr": "^3.2.2"
},
"description": "A private YouTube client",
"devDependencies": {
......@@ -59,21 +62,21 @@
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
"@babel/preset-env": "^7.12.11",
"@babel/preset-typescript": "^7.12.7",
"@typescript-eslint/eslint-plugin": "^4.13.0",
"@typescript-eslint/parser": "^4.13.0",
"@typescript-eslint/eslint-plugin": "^4.14.0",
"@typescript-eslint/parser": "^4.14.0",
"acorn": "^8.0.4",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.2",
"copy-webpack-plugin": "6.4.0",
"css-loader": "^5.0.1",
"devtron": "^1.4.0",
"electron": "^11.1.1",
"electron": "11.1.1",
"electron-builder": "^22.9.1",
"electron-builder-squirrel-windows": "^22.10.4",
"electron-debug": "^3.2.0",
"electron-rebuild": "^2.3.4",
"eslint": "^7.17.0",
"eslint-config-prettier": "^7.1.0",
"eslint": "^7.18.0",
"eslint-config-prettier": "^7.2.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
......@@ -81,7 +84,7 @@
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^5.0.0",
"eslint-plugin-vue": "^7.4.1",
"fast-glob": "^3.2.4",
"fast-glob": "^3.2.5",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^4.5.1",
"jest": "^26.6.3",
......@@ -90,14 +93,14 @@
"node-loader": "^1.0.2",
"npm-run-all": "^4.1.5",
"prettier": "^2.2.1",
"sass": "^1.32.4",
"sass": "^1.32.5",
"sass-loader": "^10.1.1",
"style-loader": "^2.0.0",
"tree-kill": "1.2.2",
"typescript": "^4.1.3",
"url-loader": "^4.1.1",
"vue-devtools": "^5.1.4",
"vue-eslint-parser": "^7.3.0",
"vue-eslint-parser": "^7.4.1",
"vue-loader": "^15.9.6",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.12",
......@@ -143,5 +146,5 @@
"test": "run-s rebuild:node pack:workers jest",
"test:watch": "run-s rebuild:node pack:workers jest:watch"
},
"version": "0.11.1"
"version": "0.11.2"
}
......@@ -8,7 +8,7 @@ import FtPrompt from '../ft-prompt/ft-prompt.vue'
import { remote } from 'electron'
import fs from 'fs'
import opmlToJson from 'opml-to-json'
import { opmlToJSON } from 'opml-to-json'
import ytch from 'yt-channel-info'
const app = remote.app
......@@ -357,17 +357,7 @@ export default Vue.extend({
return
}
opmlToJson(data, async (err, json) => {
if (err) {
console.log(err)
console.log('error reading')
const message = this.$t('Settings.Data Settings.Invalid subscriptions file')
this.showToast({
message: `${message}: ${err}`
})
return
}
opmlToJSON(data).then((json) => {
let feedData = json.children[0].children
if (typeof feedData === 'undefined') {
......@@ -442,6 +432,13 @@ export default Vue.extend({
this.updateShowProgressBar(false)
}
})
}).catch((err) => {
console.log(err)
console.log('error reading')
const message = this.$t('Settings.Data Settings.Invalid subscriptions file')
this.showToast({
message: `${message}: ${err}`
})
})
})
})
......
......@@ -76,6 +76,8 @@ export default Vue.extend({
maxFramerate: 0,
activeSourceList: [],
mouseTimeout: null,
touchTimeout: null,
lastTouchTime: null,
dataSetup: {
fluid: true,
nativeTextTracks: false,
......@@ -116,7 +118,6 @@ export default Vue.extend({
2.25,
2.5,
2.75,
2.75,
3
]
}
......@@ -284,7 +285,7 @@ export default Vue.extend({
return
}
if (videoWidth < videoHeight) {
if ((videoWidth - videoHeight) <= 240) {
this.player.fluid(false)
this.player.aspectRatio('16:9')
}
......@@ -719,6 +720,25 @@ export default Vue.extend({
}
},
handleTouchStart: function (event) {
const v = this
this.touchPauseTimeout = setTimeout(() => {
v.togglePlayPause()
}, 1000)
const touchTime = new Date()
if (this.lastTouchTime !== null && (touchTime.getTime() - this.lastTouchTime.getTime()) < 250) {
this.toggleFullscreen()
}
this.lastTouchTime = touchTime
},
handleTouchEnd: function (event) {
clearTimeout(this.touchPauseTimeout)
},
keyboardShortcutHandler: function (event) {
const activeInputs = $('.ft-input')
......
......@@ -7,6 +7,8 @@
controls
preload="auto"
:data-setup="JSON.stringify(dataSetup)"
@touchstart="handleTouchStart"
@touchend="handleTouchEnd"
>
<source
v-for="(source, index) in activeSourceList"
......
......@@ -138,7 +138,7 @@ export default Vue.extend({
}
},
mounted: function () {
const requestUrl = 'https://instances.invidio.us/instances.json'
const requestUrl = 'https://api.invidious.io/instances.json'
$.getJSON(requestUrl, (response) => {
console.log(response)
const instances = response.filter((instance) => {
......
......@@ -97,6 +97,13 @@
@input="handleInvidiousInstanceInput"
/>
</ft-flex-box>
<ft-flex-box>
<a
href="https://api.invidious.io"
>
{{ $t('Settings.General Settings.View all Invidious instance information') }}
</a>
</ft-flex-box>
</ft-card>
</template>
......
......@@ -5,10 +5,7 @@ import FtLoader from '../../components/ft-loader/ft-loader.vue'
import FtSelect from '../../components/ft-select/ft-select.vue'
import FtTimestampCatcher from '../../components/ft-timestamp-catcher/ft-timestamp-catcher.vue'
import autolinker from 'autolinker'
import { fork } from 'child_process'
import path from 'path'
// eslint-disable-next-line
import commentControllerRelativePath from 'file-loader!../../../process/comment-module-controller.js'
import ytcm from 'yt-comment-scraper'
export default Vue.extend({
name: 'WatchVideoComments',
......@@ -93,8 +90,9 @@ export default Vue.extend({
this.sortNewest = !this.sortNewest
switch (this.backendPreference) {
case 'local':
console.log('In handle')
this.sortingChanged = true
this.isLoading = true
this.commentData = []
this.nextPageToken = undefined
this.getCommentDataLocal()
break
case 'invidious':
......@@ -122,7 +120,6 @@ export default Vue.extend({
this.showToast({
message: this.$t('Comments.There are no more comments for this video')
})
this.getCommentData()
} else {
this.getCommentData()
}
......@@ -144,90 +141,72 @@ export default Vue.extend({
},
getCommentDataLocal: function () {
// we need the path from the working directory to fork correctly
if (this.commentProcess === null) {
let modulePath
if (this.isDev) {
modulePath = '../../../process/comment-module-controller.js'
} else {
modulePath = commentControllerRelativePath
}
const payload = {
videoId: this.id,
setCookie: false,
sortByNewest: this.sortNewest,
continuation: this.nextPageToken ? this.nextPageToken : undefined
}
this.commentProcess = fork(path.join(__dirname, modulePath), ['args'], {
stdio: ['pipe', 'pipe', 'pipe', 'ipc']
})
ytcm.getComments(payload).then((response) => {
console.log(response)
const commentData = response.comments.map((comment) => {
comment.showReplies = false
comment.dataType = 'local'
this.toLocalePublicationString({
publishText: (comment.time + ' ago'),
templateString: this.$t('Video.Publicationtemplate'),
timeStrings: this.$t('Video.Published'),
liveStreamString: this.$t('Video.Watching'),
upcomingString: this.$t('Video.Published.Upcoming'),
isLive: false,
isUpcoming: false,
isRSS: false
}).then((data) => {
comment.time = data
}).catch((error) => {
console.error(error)
})
if (this.hideCommentLikes) {
comment.likes = null
}
comment.text = autolinker.link(comment.text)
this.commentProcess.on('message', (msg) => {
if (msg.error === null) {
const commentJSON = JSON.parse(msg.comments)
if (commentJSON === null) {
this.showToast({
message: this.$t('Comments.No more comments available'),
time: 7000,
action: () => {
}
})
this.isLoading = false
} else {
// console.log(msg.comments)
const commentData = commentJSON.map((comment) => {
comment.showReplies = false
comment.dataType = 'local'
this.toLocalePublicationString({
publishText: (comment.time + ' ago'),
templateString: this.$t('Video.Publicationtemplate'),
timeStrings: this.$t('Video.Published'),
liveStreamString: this.$t('Video.Watching'),
upcomingString: this.$t('Video.Published.Upcoming'),
isLive: false,
isUpcoming: false,
isRSS: false
}).then((data) => {
comment.time = data
}).catch((error) => {
console.error(error)
})
if (this.hideCommentLikes) {
comment.likes = null
}
comment.text = autolinker.link(comment.text)
comment.replies.forEach((reply) => {
reply.text = autolinker.link(reply.text)
})
return comment
})
if (this.sortingChanged) {
this.commentData = []
this.sortingChanged = false
}
this.commentData = this.commentData.concat(commentData)
this.isLoading = false
this.showComments = true
this.nextPageToken = ''
}
} else {
console.log(msg.error)
const errorMessage = this.$t('Local API Error (Click to copy)')
this.showToast({
message: `${errorMessage}: ${msg.error}`,
time: 10000,
action: () => {
navigator.clipboard.writeText(msg.error)
}
if (comment.numReplies > 0) {
comment.replies.forEach((reply) => {
reply.text = autolinker.link(reply.text)
})
if (this.backendFallback && this.backendPreference === 'local') {
this.showToast({
message: this.$t('Falling back to Invidious API')
})
this.getCommentDataInvidious()
} else {
this.isLoading = false
}
}
})
}
this.commentProcess.send({ id: this.id, sortNewest: this.sortNewest })
return comment
})
if (this.sortingChanged) {
this.commentData = []
this.sortingChanged = false
}
this.commentData = this.commentData.concat(commentData)
this.isLoading = false
this.showComments = true
this.nextPageToken = response.continuation
}).catch((err) => {
console.log(err)
const errorMessage = this.$t('Local API Error (Click to copy)')
this.showToast({
message: `${errorMessage}: ${err}`,
time: 10000,
action: () => {
navigator.clipboard.writeText(err)
}
})
if (this.backendFallback && this.backendPreference === 'local') {
this.showToast({
message: this.$t('Falling back to Invidious API')
})
this.getCommentDataInvidious()
} else {
this.isLoading = false
}
})
},
getCommentDataInvidious: function () {
......@@ -269,7 +248,6 @@ export default Vue.extend({
return comment
})
console.log(commentData)
this.commentData = this.commentData.concat(commentData)
this.nextPageToken = response.continuation
this.isLoading = false
......@@ -329,7 +307,6 @@ export default Vue.extend({
return comment
})
console.log(commentData)
this.commentData[index].replies = commentData
this.commentData[index].showReplies = true
this.isLoading = false
......
<template>
<ft-card>
<ft-loader
v-if="isLoading"
/>
<h4
v-if="commentData.length === 0 && !isLoading"
class="getCommentsTitle"
......@@ -148,6 +145,9 @@
>
{{ $t("Comments.Load More Comments") }}
</h4>
<ft-loader
v-if="isLoading"
/>
</ft-card>
</template>
......
......@@ -3,6 +3,9 @@ import ytsr from 'ytsr'
import ytpl from 'ytpl'
import IsEqual from 'lodash.isequal'
import { SocksProxyAgent } from 'socks-proxy-agent'
import { HttpsProxyAgent } from 'https-proxy-agent'
import { HttpProxyAgent } from 'http-proxy-agent'
const state = {
main: 0,
......@@ -38,6 +41,47 @@ const actions = {
duration: ''
}
let agent = {}
const settings = rootState.settings
const useProxy = settings.useProxy
if (useProxy) {
const proxyProtocol = settings.proxyProtocol
const proxyHostname = settings.proxyHostname
const proxyPort = settings.proxyPort
switch (proxyProtocol) {
case 'http':
agent = new HttpProxyAgent({
host: proxyHostname,
port: proxyPort
})
break
case 'https':
agent = new HttpsProxyAgent({
host: proxyHostname,
port: proxyPort
})
break
case 'socks4':
agent = new SocksProxyAgent({
host: proxyHostname,
port: proxyPort,
type: 4
})
break
case 'socks5':
agent = new SocksProxyAgent({
host: proxyHostname,
port: proxyPort,
type: 5
})
break
}
payload.options.requestOptions = { agent }
}
commit('toggleIsYtSearchRunning')
if (!IsEqual(defaultFilters, rootState.utils.searchSettings)) {
......@@ -79,7 +123,51 @@ const actions = {
},
async ytSearchGetFilters ({ rootState }, payload) {
let filter = await ytsr.getFilters(payload.query)
let options = null
let agent = null
const settings = rootState.settings
const useProxy = settings.useProxy
if (useProxy) {
const proxyProtocol = settings.proxyProtocol
const proxyHostname = settings.proxyHostname
const proxyPort = settings.proxyPort
switch (proxyProtocol) {
case 'http':
agent = new HttpProxyAgent({
host: proxyHostname,
port: proxyPort
})
break
case 'https':
agent = new HttpsProxyAgent({
host: proxyHostname,
port: proxyPort
})
break
case 'socks4':
agent = new SocksProxyAgent({
host: proxyHostname,
port: proxyPort,
type: 4
})
break
case 'socks5':
agent = new SocksProxyAgent({
host: proxyHostname,
port: proxyPort,
type: 5
})
break
}
}
options = {
requestOptions: { agent }
}
let filter = await ytsr.getFilters(payload.query, options)
let filterUrl = null
let searchSettings = payload.searchSettings
......@@ -104,7 +192,7 @@ const actions = {
break
}
filterUrl = filter.get('Sort by').get(filterValue).url
filter = await ytsr.getFilters(filterUrl)
filter = await ytsr.getFilters(filterUrl, options)
}
console.log(`Current ref: ${filterUrl}`)
......@@ -118,7 +206,7 @@ const actions = {
}
filterUrl = filter.get('Duration').get(filterValue).url
filter = await ytsr.getFilters(filterUrl)
filter = await ytsr.getFilters(filterUrl, options)
}