Skip to content

Commit

Permalink
Merge branch 'development' into dev/petaded/add_option_to_hide_channels
Browse files Browse the repository at this point in the history
  • Loading branch information
petaded committed Nov 24, 2022
2 parents 09553c5 + d32739e commit b01798d
Show file tree
Hide file tree
Showing 50 changed files with 2,056 additions and 1,146 deletions.
17 changes: 8 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
"lodash.debounce": "^4.0.8",
"marked": "^4.1.1",
"nedb-promises": "^6.2.1",
"opml-to-json": "^1.0.1",
"process": "^0.11.10",
"socks-proxy-agent": "^7.0.0",
"video.js": "7.18.1",
Expand All @@ -83,15 +82,15 @@
"ytsr": "^3.8.0"
},
"devDependencies": {
"@babel/core": "^7.18.13",
"@babel/core": "^7.20.2",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/preset-env": "^7.18.10",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.5",
"babel-loader": "^9.1.0",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.1",
"css-loader": "^6.7.2",
"css-minimizer-webpack-plugin": "^4.2.2",
"electron": "^21.2.2",
"electron": "^21.2.3",
"electron-builder": "^23.6.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
Expand All @@ -101,22 +100,22 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-standard": "^5.0.0",
"eslint-plugin-vue": "^9.6.0",
"eslint-plugin-vue": "^9.7.0",
"html-webpack-plugin": "^5.3.2",
"js-yaml": "^4.1.0",
"json-minimizer-webpack-plugin": "^4.0.0",
"lefthook": "^1.1.4",
"mini-css-extract-plugin": "^2.6.1",
"mini-css-extract-plugin": "^2.7.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.7.1",
"rimraf": "^3.0.2",
"sass": "^1.56.0",
"sass-loader": "^13.0.2",
"sass-loader": "^13.2.0",
"tree-kill": "1.2.2",
"vue-devtools": "^5.1.4",
"vue-eslint-parser": "^9.1.0",
"vue-loader": "^15.10.0",
"webpack": "^5.74.0",
"webpack": "^5.75.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1"
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ function runApp() {
},
{
label: 'Open in a New Window',
visible: parameters.linkURL.includes((new URL(browserWindow.webContents.getURL())).origin),
// Only show the option for in-app URLs and not external ones
visible: parameters.linkURL.split('#')[0] === browserWindow.webContents.getURL().split('#')[0],
click: () => {
createWindow({ replaceMainWindow: false, windowStartupUrl: parameters.linkURL, showWindowNow: true })
}
Expand Down
129 changes: 73 additions & 56 deletions src/renderer/components/data-settings/data-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
import FtPrompt from '../ft-prompt/ft-prompt.vue'
import { MAIN_PROFILE_ID } from '../../../constants'

import { opmlToJSON } from 'opml-to-json'
import ytch from 'yt-channel-info'
import { calculateColorLuminance, getRandomColor } from '../../helpers/colors'
import {
Expand Down Expand Up @@ -330,79 +329,97 @@ export default Vue.extend({
},

importOpmlYouTubeSubscriptions: async function (data) {
let json
let xmlDom
const domParser = new DOMParser()
try {
json = await opmlToJSON(data)
xmlDom = domParser.parseFromString(data, 'application/xml')

// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#error_handling
const errorNode = xmlDom.querySelector('parsererror')
if (errorNode) {
throw errorNode.textContent
}
} catch (err) {
console.error('error reading OPML subscriptions file, falling back to HTML parser...')
console.error(err)
console.error('error reading')
const message = this.$t('Settings.Data Settings.Invalid subscriptions file')
showToast(`${message}: ${err}`)
}
// try parsing with the html parser instead which is more lenient
try {
const htmlDom = domParser.parseFromString(data, 'text/html')

if (json !== undefined) {
let feedData = json.children[0].children
if (typeof feedData === 'undefined') {
if (json.title.includes('gPodder')) {
feedData = json.children
} else {
const message = this.$t('Settings.Data Settings.Invalid subscriptions file')
showToast(message)
return
}
xmlDom = htmlDom
} catch {
const message = this.$t('Settings.Data Settings.Invalid subscriptions file')
showToast(`${message}: ${err}`)
return
}
}

const subscriptions = []
const feedData = xmlDom.querySelectorAll('body outline[xmlUrl]')
if (feedData.length === 0) {
const message = this.$t('Settings.Data Settings.Invalid subscriptions file')
showToast(message)
return
}

showToast(this.$t('Settings.Data Settings.This might take a while, please wait'))
const subscriptions = []

this.updateShowProgressBar(true)
this.setProgressBarPercentage(0)
showToast(this.$t('Settings.Data Settings.This might take a while, please wait'))

let count = 0
this.updateShowProgressBar(true)
this.setProgressBarPercentage(0)

feedData.forEach(async (channel, index) => {
const channelId = channel.xmlurl.replace('https://www.youtube.com/feeds/videos.xml?channel_id=', '')
const subExists = this.primaryProfile.subscriptions.findIndex((sub) => {
return sub.id === channelId
})
if (subExists === -1) {
let channelInfo
if (this.backendPreference === 'invidious') {
channelInfo = await this.getChannelInfoInvidious(channelId)
} else {
channelInfo = await this.getChannelInfoLocal(channelId)
}
let count = 0

if (typeof channelInfo.author !== 'undefined') {
const subscription = {
id: channelId,
name: channelInfo.author,
thumbnail: channelInfo.authorThumbnails[1].url
}
subscriptions.push(subscription)
}
feedData.forEach(async (channel) => {
const xmlUrl = channel.getAttribute('xmlUrl')
let channelId
if (xmlUrl.includes('https://www.youtube.com/feeds/videos.xml?channel_id=')) {
channelId = new URL(xmlUrl).searchParams.get('channel_id')
} else if (xmlUrl.includes('/feed/channel/')) {
// handle invidious exports https://yewtu.be/feed/channel/{CHANNELID}
channelId = new URL(xmlUrl).pathname.split('/').filter(part => part).at(-1)
} else {
console.error(`Unknown xmlUrl format: ${xmlUrl}`)
}
const subExists = this.primaryProfile.subscriptions.findIndex((sub) => {
return sub.id === channelId
})
if (subExists === -1) {
let channelInfo
if (this.backendPreference === 'invidious') {
channelInfo = await this.getChannelInfoInvidious(channelId)
} else {
channelInfo = await this.getChannelInfoLocal(channelId)
}

count++
if (typeof channelInfo.author !== 'undefined') {
const subscription = {
id: channelId,
name: channelInfo.author,
thumbnail: channelInfo.authorThumbnails[1].url
}
subscriptions.push(subscription)
}
}

const progressPercentage = (count / feedData.length) * 100
this.setProgressBarPercentage(progressPercentage)
count++

if (count === feedData.length) {
this.primaryProfile.subscriptions = this.primaryProfile.subscriptions.concat(subscriptions)
this.updateProfile(this.primaryProfile)
const progressPercentage = (count / feedData.length) * 100
this.setProgressBarPercentage(progressPercentage)

if (subscriptions.length < count) {
showToast(this.$t('Settings.Data Settings.One or more subscriptions were unable to be imported'))
} else {
showToast(this.$t('Settings.Data Settings.All subscriptions have been successfully imported'))
}
if (count === feedData.length) {
this.primaryProfile.subscriptions = this.primaryProfile.subscriptions.concat(subscriptions)
this.updateProfile(this.primaryProfile)

this.updateShowProgressBar(false)
if (subscriptions.length < count) {
showToast(this.$t('Settings.Data Settings.One or more subscriptions were unable to be imported'))
} else {
showToast(this.$t('Settings.Data Settings.All subscriptions have been successfully imported'))
}
})
}

this.updateShowProgressBar(false)
}
})
},

importNewPipeSubscriptions: async function (newPipeData) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ export default Vue.extend({
hideLiveStreams: function() {
return this.$store.getters.getHideLiveStreams
},
hideUpcomingPremieres: function () {
return this.$store.getters.getHideUpcomingPremieres
},
hideSharingActions: function () {
return this.$store.getters.getHideSharingActions
},
Expand Down Expand Up @@ -94,6 +97,7 @@ export default Vue.extend({
'updateHideVideoDescription',
'updateHideComments',
'updateHideLiveStreams',
'updateHideUpcomingPremieres',
'updateHideSharingActions',
'updateHideChapters',
'updateChannelsHidden'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@
:default-value="hideLiveStreams"
@change="updateHideLiveStreams"
/>
<ft-toggle-switch
:label="$t('Settings.Distraction Free Settings.Hide Upcoming Premieres')"
:compact="true"
:default-value="hideUpcomingPremieres"
@change="updateHideUpcomingPremieres"
/>
<ft-toggle-switch
:label="$t('Settings.Distraction Free Settings.Hide Comments')"
:compact="true"
Expand Down
19 changes: 2 additions & 17 deletions src/renderer/components/ft-input/ft-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ export default Vue.extend({
this.id = this._uid
this.inputData = this.value
this.updateVisibleDataList()

setTimeout(this.addListener, 200)
},
methods: {
handleClick: function (e) {
Expand Down Expand Up @@ -144,11 +142,10 @@ export default Vue.extend({
this.handleActionIconChange()
this.updateVisibleDataList()

const inputElement = document.getElementById(this.id)
inputElement.value = ''
this.$refs.input.value = ''

// Focus on input element after text is clear for better UX
inputElement.focus()
this.$refs.input.focus()

this.$emit('clear')
},
Expand Down Expand Up @@ -205,18 +202,6 @@ export default Vue.extend({
}
},

addListener: function () {
const inputElement = document.getElementById(this.id)

if (inputElement !== null) {
inputElement.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
this.handleClick(event)
}
})
}
},

handleOptionClick: function (index) {
this.searchState.showOptions = false
this.inputData = this.visibleDataList[index]
Expand Down
1 change: 1 addition & 0 deletions src/renderer/components/ft-input/ft-input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
@focus="handleFocus"
@blur="handleInputBlur"
@keydown="handleKeyDown"
@keydown.enter="handleClick"
>
<font-awesome-icon
v-if="showActionButton"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ export default Vue.extend({
},
channelsHidden: function() {
return JSON.parse(this.$store.getters.getChannelsHidden)
},
hideUpcomingPremieres: function () {
return this.$store.getters.getHideUpcomingPremieres
}
},
methods: {
Expand All @@ -52,26 +55,38 @@ export default Vue.extend({
* @return {bool} false to hide the video, true to show it
*/
showResult: function (data) {
if (data.type !== undefined) {
if (data.type === 'video') {
if ((data.liveNow || data.lengthSeconds == null) && this.hideLiveStreams) {
// hide livestreams
return false
}
if (this.channelsHidden.includes(data.authorId) || this.channelsHidden.includes(data.author)) {
// hide videos by author
return false
}
} else if (data.type === 'channel') {
if (this.channelsHidden.includes(data.channelID) || this.channelsHidden.includes(data.name)) {
// hide channels by author
return false
}
} else if (data.type === 'playlist') {
if (this.channelsHidden.includes(data.authorId) || this.channelsHidden.includes(data.author)) {
// hide playlists by author
return false
}
if (!data.type) {
return false
}
if (data.type === 'video') {
if (this.hideLiveStreams && (data.liveNow || data.lengthSeconds == null)) {
// hide livestreams
return false
}

if (this.hideUpcomingPremieres &&
// Observed for premieres in Local API Channels.
(data.durationText === 'PREMIERE' ||
// viewCount is our only method of detecting premieres in RSS
// data without sending an additional request.
// If we ever get a better flag, use it here instead.
(data.isRSS && data.viewCount === '0'))) {
// hide upcoming
return false
}
if (this.channelsHidden.includes(data.authorId) || this.channelsHidden.includes(data.author)) {
// hide videos by author
return false
}
} else if (data.type === 'channel') {
if (this.channelsHidden.includes(data.channelID) || this.channelsHidden.includes(data.name)) {
// hide channels by author
return false
}
} else if (data.type === 'playlist') {
if (this.channelsHidden.includes(data.authorId) || this.channelsHidden.includes(data.author)) {
// hide playlists by author
return false
}
}
return true
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/components/ft-list-video/ft-list-video.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ export default Vue.extend({
return this.$store.getters.getHideLiveStreams
},

hideUpcomingPremieres: function () {
return this.$store.getters.getHideUpcomingPremieres
},

hideVideoViews: function () {
return this.$store.getters.getHideVideoViews
},
Expand Down
Loading

0 comments on commit b01798d

Please sign in to comment.