Skip to content

Commit

Permalink
Merge branch 'development' into iv-rss-detect-error-channels-properly
Browse files Browse the repository at this point in the history
  • Loading branch information
ChunkyProgrammer committed Nov 18, 2024
2 parents 3642b08 + f9736fb commit 77454f0
Show file tree
Hide file tree
Showing 87 changed files with 2,289 additions and 2,518 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ jobs:

- name: Install libarchive-tools
if: startsWith(matrix.os, 'ubuntu')
run: sudo apt -y install libarchive-tools; echo "Version Number ${{ toJson(job) }} ${{ toJson(needs) }}"
run: sudo apt update; sudo apt -y install libarchive-tools; echo "Version Number ${{ toJson(job) }} ${{ toJson(needs) }}"

- name: Build x64 with Node.js ${{ matrix.node-version}}
if: contains(matrix.runtime, 'x64')
Expand Down
11 changes: 11 additions & 0 deletions _scripts/eslint-rules/plugin.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import preferUseI18nPolyfillRule from './prefer-use-i18n-polyfill-rule.mjs'

export default {
meta: {
name: 'eslint-plugin-freetube',
version: '1.0'
},
rules: {
'prefer-use-i18n-polyfill': preferUseI18nPolyfillRule
}
}
62 changes: 62 additions & 0 deletions _scripts/eslint-rules/prefer-use-i18n-polyfill-rule.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { dirname, relative, resolve } from 'path'

const polyfillPath = resolve(import.meta.dirname, '../../src/renderer/composables/use-i18n-polyfill')

function getRelativePolyfillPath(filePath) {
const relativePath = relative(dirname(filePath), polyfillPath).replaceAll('\\', '/')

if (relativePath[0] !== '.') {
return `./${relativePath}`
}

return relativePath
}

/** @type {import('eslint').Rule.RuleModule} */
export default {
meta: {
type: 'problem',
fixable: 'code'
},
create(context) {
return {
'ImportDeclaration[source.value="vue-i18n"]'(node) {
const specifierIndex = node.specifiers.findIndex(specifier => specifier.type === 'ImportSpecifier' && specifier.imported.name === 'useI18n')

if (specifierIndex !== -1) {
context.report({
node: node.specifiers.length === 1 ? node : node.specifiers[specifierIndex],
message: "Please use FreeTube's useI18n polyfill, as vue-i18n's useI18n composable does not work when the vue-i18n is in legacy mode, which is needed for components using the Options API.",
fix: context.physicalFilename === '<text>'
? undefined
: (fixer) => {
const relativePath = getRelativePolyfillPath(context.physicalFilename)

// If the import only imports `useI18n`, we can just update the source/from text
// Else we need to create a new import for `useI18n` and remove useI18n from the original one
if (node.specifiers.length === 1) {
return fixer.replaceText(node.source, `'${relativePath}'`)
} else {
const specifier = node.specifiers[specifierIndex]

let specifierText = 'useI18n'

if (specifier.imported.name !== specifier.local.name) {
specifierText += ` as ${specifier.local.name}`
}

return [
fixer.removeRange([
specifierIndex === 0 ? specifier.start : node.specifiers[specifierIndex - 1].end,
specifierIndex === node.specifiers.length - 1 ? specifier.end : node.specifiers[specifierIndex + 1].start
]),
fixer.insertTextAfter(node, `\nimport { ${specifierText} } from '${relativePath}'`)
]
}
}
})
}
}
}
}
}
6 changes: 5 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import eslintPluginYml from 'eslint-plugin-yml'
import yamlEslintParser from 'yaml-eslint-parser'
import neostandard from 'neostandard'
import jsdoc from 'eslint-plugin-jsdoc'
import freetube from './_scripts/eslint-rules/plugin.mjs'

import activeLocales from './static/locales/activeLocales.json' with { type: 'json' }

Expand Down Expand Up @@ -42,6 +43,7 @@ export default [
plugins: {
unicorn: eslintPluginUnicorn,
jsdoc,
freetube,
},

languageOptions: {
Expand Down Expand Up @@ -126,6 +128,8 @@ export default [
'jsdoc/check-types': 'error',
'jsdoc/no-bad-blocks': 'error',
'jsdoc/no-multi-asterisks': 'error',

'freetube/prefer-use-i18n-polyfill': 'error',
},
},

Expand Down Expand Up @@ -220,7 +224,7 @@ export default [
}
},
{
files: ['_scripts/*.mjs'],
files: ['_scripts/**/*.mjs'],
languageOptions: {
globals: {
...globals.node,
Expand Down
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
"lint-all": "run-p lint lint-json",
"lint": "run-p eslint-lint lint-style",
"lint-fix": "run-p eslint-lint-fix lint-style-fix",
"eslint-lint": "eslint --config eslint.config.mjs \"./src/**/*.js\" \"./src/**/*.vue\" \"./static/**/*.js\" \"./_scripts/*.js\" \"./_scripts/*.mjs\"",
"eslint-lint-fix": "eslint --config eslint.config.mjs --fix \"./src/**/*.js\" \"./src/**/*.vue\" \"./static/**/*.js\" \"./_scripts/*.js\" \"./_scripts/*.mjs\"",
"eslint-lint": "eslint --config eslint.config.mjs \"./src/**/*.js\" \"./src/**/*.vue\" \"./static/**/*.js\" \"./_scripts/*.js\" \"_scripts/**/*.mjs\"",
"eslint-lint-fix": "eslint --config eslint.config.mjs --fix \"./src/**/*.js\" \"./src/**/*.vue\" \"./static/**/*.js\" \"./_scripts/*.js\" \"_scripts/**/*.mjs\"",
"lint-json": "eslint --config eslint.config.mjs \"./static/**/*.json\"",
"lint-style": "stylelint \"**/*.{css,scss}\"",
"lint-style-fix": "stylelint --fix \"**/*.{css,scss}\"",
Expand All @@ -63,7 +63,7 @@
"autolinker": "^4.0.0",
"electron-context-menu": "^4.0.4",
"lodash.debounce": "^4.0.8",
"marked": "^14.1.3",
"marked": "^15.0.0",
"path-browserify": "^1.0.1",
"portal-vue": "^2.1.7",
"process": "^0.11.10",
Expand All @@ -87,25 +87,25 @@
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^7.1.2",
"css-minimizer-webpack-plugin": "^7.0.0",
"electron": "^32.2.2",
"electron": "^32.2.3",
"electron-builder": "^25.1.8",
"eslint": "^9.11.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsdoc": "^50.4.3",
"eslint-plugin-jsonc": "^2.16.0",
"eslint-plugin-jsonc": "^2.18.1",
"eslint-plugin-unicorn": "^56.0.0",
"eslint-plugin-vue": "^9.30.0",
"eslint-plugin-vuejs-accessibility": "^2.4.1",
"eslint-plugin-yml": "^1.15.0",
"globals": "^15.11.0",
"globals": "^15.12.0",
"html-webpack-plugin": "^5.6.3",
"js-yaml": "^4.1.0",
"json-minimizer-webpack-plugin": "^5.0.0",
"lefthook": "^1.8.2",
"mini-css-extract-plugin": "^2.9.2",
"neostandard": "^0.11.7",
"npm-run-all2": "^7.0.1",
"postcss": "^8.4.47",
"postcss": "^8.4.48",
"postcss-scss": "^4.0.9",
"rimraf": "^6.0.1",
"sass": "^1.80.6",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<template>
<FtSettingsSection
:title="$t('Settings.Experimental Settings.Experimental Settings')"
>
<p class="experimental-warning">
{{ $t('Settings.Experimental Settings.Warning') }}
</p>
<FtFlexBox>
<FtToggleSwitch
tooltip-position="top"
:label="$t('Settings.Experimental Settings.Replace HTTP Cache')"
compact
:default-value="replaceHttpCache"
:disabled="replaceHttpCacheLoading"
:tooltip="$t('Tooltips.Experimental Settings.Replace HTTP Cache')"
@change="handleRestartPrompt"
/>
</FtFlexBox>
<FtPrompt
v-if="showRestartPrompt"
:label="$t('Settings[\'The app needs to restart for changes to take effect. Restart and apply change?\']')"
:option-names="[$t('Yes, Restart'), $t('Cancel')]"
:option-values="['restart', 'cancel']"
@click="handleReplaceHttpCache"
/>
</FtSettingsSection>
</template>

<script setup>
import { onMounted, ref } from 'vue'
import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import FtPrompt from '../ft-prompt/ft-prompt.vue'
import { IpcChannels } from '../../../constants'
const replaceHttpCacheLoading = ref(true)
const replaceHttpCache = ref(false)
const showRestartPrompt = ref(false)
onMounted(async () => {
if (process.env.IS_ELECTRON) {
const { ipcRenderer } = require('electron')
replaceHttpCache.value = await ipcRenderer.invoke(IpcChannels.GET_REPLACE_HTTP_CACHE)
}
replaceHttpCacheLoading.value = false
})
/**
* @param {boolean} value
*/
function handleRestartPrompt(value) {
replaceHttpCache.value = value
showRestartPrompt.value = true
}
/**
* @param {'restart' | 'cancel' | null} value
*/
function handleReplaceHttpCache(value) {
showRestartPrompt.value = false
if (value === null || value === 'cancel') {
replaceHttpCache.value = !replaceHttpCache.value
return
}
if (process.env.IS_ELECTRON) {
const { ipcRenderer } = require('electron')
ipcRenderer.send(IpcChannels.TOGGLE_REPLACE_HTTP_CACHE)
}
}
</script>

<style scoped src="./ExperimentalSettings.css" />
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<template>
<svg
class="ft-logo-full"
viewBox="0 0 640 200"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
Expand Down Expand Up @@ -63,4 +62,4 @@
</svg>
</template>

<style scoped src="./ft-logo-full.css" />
<style scoped src="./FtLogoFull.css" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<template>
<FtSettingsSection
:title="$t('Settings.Parental Control Settings.Parental Control Settings')"
>
<div class="switchColumnGrid">
<div class="switchColumn">
<FtToggleSwitch
:label="$t('Settings.Parental Control Settings.Hide Unsubscribe Button')"
compact
:default-value="hideUnsubscribeButton"
@change="updateHideUnsubscribeButton"
/>
<FtToggleSwitch
:label="$t('Settings.Parental Control Settings.Show Family Friendly Only')"
compact
:default-value="showFamilyFriendlyOnly"
@change="updateShowFamilyFriendlyOnly"
/>
</div>
<div class="switchColumn">
<FtToggleSwitch
:label="$t('Settings.Parental Control Settings.Hide Search Bar')"
compact
:default-value="hideSearchBar"
@change="updateHideSearchBar"
/>
</div>
</div>
</FtSettingsSection>
</template>

<script setup>
import { computed } from 'vue'
import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import store from '../../store/index'
const hideSearchBar = computed(() => {
return store.getters.getHideSearchBar
})
const hideUnsubscribeButton = computed(() => {
return store.getters.getHideUnsubscribeButton
})
const showFamilyFriendlyOnly = computed(() => {
return store.getters.getShowFamilyFriendlyOnly
})
/**
* @param {boolean} value
*/
function updateHideSearchBar(value) {
store.dispatch('updateHideSearchBar', value)
}
/**
* @param {boolean} value
*/
function updateHideUnsubscribeButton(value) {
store.dispatch('updateHideUnsubscribeButton', value)
}
/**
* @param {boolean} value
*/
function updateShowFamilyFriendlyOnly(value) {
store.dispatch('updateShowFamilyFriendlyOnly', value)
}
</script>
15 changes: 12 additions & 3 deletions src/renderer/components/data-settings/data-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -837,12 +837,12 @@ export default defineComponent({
]

const optionalKeys = [
'_id',
'description',
'createdAt',
]

const ignoredKeys = [
'_id',
'title',
'type',
'protected',
Expand Down Expand Up @@ -910,6 +910,10 @@ export default defineComponent({
}

const existingPlaylist = this.allPlaylists.find((playlist) => {
if (playlistObject._id != null && playlist._id === playlistObject._id) {
return true
}

return playlist.playlistName === playlistObject.playlistName
})

Expand Down Expand Up @@ -957,8 +961,13 @@ export default defineComponent({
this.addVideo(payload)
}
})
// Update playlist's `lastUpdatedAt`
this.updatePlaylist({ _id: existingPlaylist._id })
// Update playlist's `lastUpdatedAt` & other attributes
this.updatePlaylist({
_id: existingPlaylist._id,
// Only these attributes would be updated (besides videos)
playlistName: playlistObject.playlistName,
description: playlistObject.description,
})
})

showToast(this.$t('Settings.Data Settings.All playlists has been successfully imported'))
Expand Down
Loading

0 comments on commit 77454f0

Please sign in to comment.