Skip to content

Commit f07ab54

Browse files
committed
Merge branch 'development' into custom-builds/current
* development: (49 commits) Bump electron from 35.2.1 to 36.2.0 (FreeTubeApp#7403) Translated using Weblate (Hebrew) Translated using Weblate (Hebrew) Translated using Weblate (Hebrew) Translated using Weblate (Hebrew) Translated using Weblate (Hebrew) Translated using Weblate (Slovak) Switch from OPEN_EXTERNAL_LINK IPC call to window.open() (FreeTubeApp#7380) Translated using Weblate (Korean) Translated using Weblate (Slovak) Translated using Weblate (Assamese) Translated using Weblate (Romanian) Translated using Weblate (Croatian) Translated using Weblate (Slovak) Translated using Weblate (Assamese) Fix typo in WRITE_TO_DEFAULT_FOLDER IPC call (FreeTubeApp#7378) Pause player when opening recommended video in external player (FreeTubeApp#7387) Migrate the PlaylistInfo component to the composition API (FreeTubeApp#7383) Migrate the PrivacySettings component to the composition API (FreeTubeApp#7397) Migrate the FtProfileSelector component to the composition API (FreeTubeApp#7388) ...
2 parents 1603958 + ab9e655 commit f07ab54

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+2457
-2138
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# Title
2-
31
<!-- Thanks for sending a pull request! Make sure to follow the contributing guidelines. -->
42
<!-- Important note, we may remove your pull request if you do not use this provided PR template correctly. -->
53
<!-- Do not create PR's with AI! (PRs created mainly with AI will be closed. They waste our team's time. We ban repeat offenders.) -->
@@ -22,10 +20,9 @@
2220
## Screenshots <!-- If appropriate -->
2321
<!-- Please add before and after screenshots if there is a visible change. -->
2422

25-
## Testing <!-- for code that is not small enough to be easily understandable -->
26-
<!-- Has this pull request been tested? -->
27-
<!-- Please describe shortly how you tested it. -->
28-
<!-- Are there any ramifications remaining? -->
23+
## Testing
24+
<!-- How can reviewers verify that the PR produces correct results? -->
25+
<!-- Please provide instructions so that others can ensure that your pull request would produce correct results. For examples see, https://github.com/FreeTubeApp/FreeTube/pull/5743, https://github.com/FreeTubeApp/FreeTube/pull/7349, https://github.com/FreeTubeApp/FreeTube/pull/5125, https://github.com/FreeTubeApp/FreeTube/pull/7338 -->
2926

3027
## Desktop
3128
<!-- Please complete the following information-->

.github/workflows/flatpak.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,22 +76,22 @@ jobs:
7676
date +"%Y-%m-%d" >> $GITHUB_ENV
7777
echo 'EOF' >> $GITHUB_ENV
7878
- name: Update x64 File Location in yml File
79-
uses: mikefarah/[email protected].2
79+
uses: mikefarah/[email protected].4
8080
with:
8181
# The Command which should be run
8282
cmd: yq -i '.modules[0].sources[0].url = "https://github.com/FreeTubeApp/FreeTube/releases/download/v${{ steps.sub.outputs.result }}-beta/freetube-${{ steps.sub.outputs.result }}-linux-x64-portable.zip"' io.freetubeapp.FreeTube.yml
8383
- name: Update x64 Hash in yml File
84-
uses: mikefarah/[email protected].2
84+
uses: mikefarah/[email protected].4
8585
with:
8686
# The Command which should be run
8787
cmd: yq -i '.modules[0].sources[0].sha256 = "${{ env.HASH_X64 }}"' io.freetubeapp.FreeTube.yml
8888
- name: Update ARM File Location in yml File
89-
uses: mikefarah/[email protected].2
89+
uses: mikefarah/[email protected].4
9090
with:
9191
# The Command which should be run
9292
cmd: yq -i '.modules[0].sources[1].url = "https://github.com/FreeTubeApp/FreeTube/releases/download/v${{ steps.sub.outputs.result }}-beta/freetube-${{ steps.sub.outputs.result }}-linux-arm64-portable.zip"' io.freetubeapp.FreeTube.yml
9393
- name: Update ARM Hash in yml File
94-
uses: mikefarah/[email protected].2
94+
uses: mikefarah/[email protected].4
9595
with:
9696
# The Command which should be run
9797
cmd: yq -i '.modules[0].sources[1].sha256 = "${{ env.HASH_ARM64 }}"' io.freetubeapp.FreeTube.yml

_scripts/getShakaLocales.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
const { readFileSync, readdirSync } = require('fs')
2+
const { join } = require('path')
23

34
function getPreloadedLocales() {
4-
const localesFile = readFileSync(`${__dirname}/../node_modules/shaka-player/dist/locales.js`, 'utf-8')
5+
const localesFile = readFileSync(join(__dirname, '../node_modules/shaka-player/dist/locales.js'), 'utf-8')
56

67
const localesLine = localesFile.match(/^\/\/ LOCALES: ([\w ,-]+)$/m)
78

@@ -13,7 +14,7 @@ function getPreloadedLocales() {
1314
}
1415

1516
function getAllLocales() {
16-
const filenames = readdirSync(`${__dirname}/../node_modules/shaka-player/ui/locales`)
17+
const filenames = readdirSync(join(__dirname, '../node_modules/shaka-player/ui/locales'))
1718

1819
return new Set(filenames
1920
.filter(filename => filename !== 'source.json' && filename.endsWith('.json'))
@@ -85,7 +86,7 @@ function getShakaLocales() {
8586
const shakaLocales = getAllLocales()
8687

8788
/** @type {string[]} */
88-
const freeTubeLocales = JSON.parse(readFileSync(`${__dirname}/../static/locales/activeLocales.json`, 'utf-8'))
89+
const freeTubeLocales = JSON.parse(readFileSync(join(__dirname, '../static/locales/activeLocales.json'), 'utf-8'))
8990

9091
const mappings = getMappings(shakaLocales, freeTubeLocales)
9192

_scripts/webpack.main.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ const config = {
2525
use: path.join(__dirname, 'mime-db-shrinking-loader.js')
2626
}
2727
],
28+
generator: {
29+
json: {
30+
JSONParse: false
31+
}
32+
}
2833
},
2934
// webpack defaults to only optimising the production builds, so having this here is fine
3035
optimization: {

_scripts/webpack.renderer.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ const config = {
108108
}
109109
},
110110
],
111+
generator: {
112+
json: {
113+
JSONParse: false
114+
}
115+
}
111116
},
112117
// webpack defaults to only optimising the production builds, so having this here is fine
113118
optimization: {

_scripts/webpack.web.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ const config = {
102102
}
103103
},
104104
],
105+
generator: {
106+
json: {
107+
JSONParse: false
108+
}
109+
}
105110
},
106111
// webpack defaults to only optimising the production builds, so having this here is fine
107112
optimization: {

eslint.config.mjs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,6 @@ export default [
8989
}],
9090

9191
'vuejs-accessibility/no-static-element-interactions': 'off',
92-
'n/no-callback-literal': 'warn',
93-
'n/no-path-concat': 'warn',
9492
'unicorn/better-regex': 'error',
9593
'unicorn/prefer-single-call': 'error',
9694
'unicorn/prefer-keyboard-event-key': 'error',
@@ -138,6 +136,15 @@ export default [
138136
},
139137
},
140138

139+
{
140+
files: ['src/main/index.js'],
141+
languageOptions: {
142+
globals: {
143+
__FREETUBE_ALLOWED_PATHS__: 'readable'
144+
}
145+
}
146+
},
147+
141148
...eslintPluginJsonc.configs['flat/base'],
142149
{
143150
files: ['**/*.json'],
@@ -223,7 +230,6 @@ export default [
223230
'@stylistic/space-before-function-paren': 'off',
224231
'@stylistic/comma-dangle': ['error', 'only-multiline'],
225232
'no-console': 'off',
226-
'n/no-path-concat': 'off',
227233
'unicorn/better-regex': 'error',
228234
'unicorn/prefer-optional-catch-binding': 'error',
229235
'unicorn/prefer-date-now': 'error',
@@ -246,7 +252,6 @@ export default [
246252
'no-console': 'off',
247253
'@stylistic/space-before-function-paren': 'off',
248254
'@stylistic/comma-dangle': ['error', 'only-multiline'],
249-
'n/no-path-concat': 'off',
250255
'unicorn/better-regex': 'error',
251256
'unicorn/prefer-optional-catch-binding': 'error',
252257
'unicorn/prefer-date-now': 'error',

package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
"marked": "^15.0.11",
6666
"portal-vue": "^2.1.7",
6767
"process": "^0.11.10",
68-
"shaka-player": "^4.14.10",
68+
"shaka-player": "^4.14.11",
6969
"swiper": "^11.2.6",
7070
"vue": "^2.7.16",
7171
"vue-i18n": "^8.28.2",
@@ -77,24 +77,24 @@
7777
"devDependencies": {
7878
"@babel/core": "^7.27.1",
7979
"@babel/plugin-transform-class-properties": "^7.27.1",
80-
"@babel/preset-env": "^7.27.1",
80+
"@babel/preset-env": "^7.27.2",
8181
"@double-great/stylelint-a11y": "^3.0.4",
8282
"@eslint/js": "^9.26.0",
8383
"@intlify/eslint-plugin-vue-i18n": "^3.2.0",
8484
"babel-loader": "^10.0.0",
8585
"copy-webpack-plugin": "^13.0.0",
8686
"css-loader": "^7.1.2",
8787
"css-minimizer-webpack-plugin": "^7.0.2",
88-
"electron": "^35.2.1",
88+
"electron": "^36.2.0",
8989
"electron-builder": "^26.0.15",
9090
"eslint": "^9.26.0",
91-
"eslint-plugin-jsdoc": "^50.6.11",
91+
"eslint-plugin-jsdoc": "^50.6.14",
9292
"eslint-plugin-jsonc": "^2.20.0",
93-
"eslint-plugin-unicorn": "^59.0.0",
93+
"eslint-plugin-unicorn": "^59.0.1",
9494
"eslint-plugin-vue": "^10.1.0",
9595
"eslint-plugin-vuejs-accessibility": "^2.4.1",
9696
"eslint-plugin-yml": "^1.18.0",
97-
"globals": "^16.0.0",
97+
"globals": "^16.1.0",
9898
"html-webpack-plugin": "^5.6.3",
9999
"js-yaml": "^4.1.0",
100100
"json-minimizer-webpack-plugin": "^5.0.1",
@@ -104,7 +104,7 @@
104104
"npm-run-all2": "^8.0.1",
105105
"postcss": "^8.5.3",
106106
"postcss-scss": "^4.0.9",
107-
"sass": "^1.87.0",
107+
"sass": "^1.88.0",
108108
"sass-loader": "^16.0.5",
109109
"stylelint": "^16.19.1",
110110
"stylelint-config-sass-guidelines": "^12.1.0",
@@ -115,7 +115,7 @@
115115
"vue-devtools": "^5.1.4",
116116
"vue-eslint-parser": "^10.1.3",
117117
"vue-loader": "^15.10.0",
118-
"webpack": "^5.99.7",
118+
"webpack": "^5.99.8",
119119
"webpack-cli": "^6.0.1",
120120
"webpack-dev-server": "^5.2.1",
121121
"yaml-eslint-parser": "^1.3.0"

src/constants.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
const IpcChannels = {
33
ENABLE_PROXY: 'enable-proxy',
44
DISABLE_PROXY: 'disable-proxy',
5-
OPEN_EXTERNAL_LINK: 'open-external-link',
65
GET_SYSTEM_LOCALE: 'get-system-locale',
76
GET_NAVIGATION_HISTORY: 'get-navigation-history',
87
STOP_POWER_SAVE_BLOCKER: 'stop-power-save-blocker',

src/main/index.js

Lines changed: 45 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,12 @@ Options:
5858

5959
function runApp() {
6060
/** @type {Set<string>} */
61-
let ALLOWED_RENDERER_FILES
62-
63-
if (process.env.NODE_ENV === 'production') {
61+
const ALLOWED_RENDERER_FILES = process.env.NODE_ENV === 'production'
6462
// __FREETUBE_ALLOWED_PATHS__ is replaced by the injectAllowedPaths.mjs script
65-
// eslint-disable-next-line no-undef
66-
ALLOWED_RENDERER_FILES = new Set(__FREETUBE_ALLOWED_PATHS__)
63+
? new Set(__FREETUBE_ALLOWED_PATHS__)
64+
: new Set()
6765

66+
if (process.env.NODE_ENV === 'production') {
6867
protocol.registerSchemesAsPrivileged([{
6968
scheme: 'app',
7069
privileges: {
@@ -781,15 +780,21 @@ function runApp() {
781780
}
782781

783782
/**
784-
* @param {string} urlString
783+
* @param {string | URL} url
785784
*/
786-
function isFreeTubeUrl(urlString) {
787-
const { protocol, host, pathname } = new URL(urlString)
785+
function isFreeTubeUrl(url) {
786+
let url_
787+
788+
if (url instanceof URL) {
789+
url_ = url
790+
} else {
791+
url_ = URL.parse(url)
792+
}
788793

789794
if (process.env.NODE_ENV === 'development') {
790-
return protocol === 'http:' && host === 'localhost:9080' && (pathname === '/' || pathname === '/index.html')
795+
return url_ !== null && url_.protocol === 'http:' && url_.host === 'localhost:9080' && (url_.pathname === '/' || url_.pathname === '/index.html')
791796
} else {
792-
return protocol === 'app:' && host === 'bundle' && pathname === '/index.html'
797+
return url_ !== null && url_.protocol === 'app:' && url_.host === 'bundle' && url_.pathname === '/index.html'
793798
}
794799
}
795800

@@ -867,8 +872,7 @@ function runApp() {
867872
darkTheme: nativeTheme.shouldUseDarkColors,
868873
icon: process.env.NODE_ENV === 'development'
869874
? path.join(__dirname, '../../_icons/iconColor.png')
870-
/* eslint-disable-next-line n/no-path-concat */
871-
: `${__dirname}/_icons/iconColor.png`,
875+
: path.join(__dirname, '../_icons/iconColor.png'),
872876
autoHideMenuBar: true,
873877
// useContentSize: true,
874878
webPreferences: {
@@ -896,14 +900,33 @@ function runApp() {
896900

897901
// https://github.com/electron/electron/blob/14-x-y/docs/api/window-open.md#native-window-example
898902
newWindow.webContents.setWindowOpenHandler((details) => {
899-
createWindow({
900-
replaceMainWindow: false,
901-
showWindowNow: true,
902-
windowStartupUrl: details.url
903-
})
904-
return {
905-
action: 'deny'
903+
const url = URL.parse(details.url)
904+
905+
// Only handle valid URLs that came from a FreeTube page
906+
if (url !== null && isFreeTubeUrl(details.referrer.url)) {
907+
if (isFreeTubeUrl(url)) {
908+
createWindow({
909+
replaceMainWindow: false,
910+
showWindowNow: true,
911+
windowStartupUrl: details.url
912+
})
913+
} else if (
914+
url.protocol === 'http:' || url.protocol === 'https:' ||
915+
916+
// Email address on the about page and Autolinker detects and links email addresses
917+
url.protocol === 'mailto:' ||
918+
919+
// Autolinker detects and links phone numbers
920+
url.protocol === 'tel:' ||
921+
922+
// Donation links on the about page
923+
(url.protocol === 'bitcoin:' && url.pathname === ABOUT_BITCOIN_ADDRESS)
924+
) {
925+
shell.openExternal(details.url)
926+
}
906927
}
928+
929+
return { action: 'deny' }
907930
})
908931

909932
// endregion Ensure child windows use same options since electron 14
@@ -1140,37 +1163,6 @@ function runApp() {
11401163

11411164
// #endregion navigation history
11421165

1143-
ipcMain.handle(IpcChannels.OPEN_EXTERNAL_LINK, (_, url) => {
1144-
if (typeof url === 'string') {
1145-
let parsedURL
1146-
1147-
try {
1148-
parsedURL = new URL(url)
1149-
} catch {
1150-
// If it's not a valid URL don't open it
1151-
return false
1152-
}
1153-
1154-
if (
1155-
parsedURL.protocol === 'http:' || parsedURL.protocol === 'https:' ||
1156-
1157-
// Email address on the about page and Autolinker detects and links email addresses
1158-
parsedURL.protocol === 'mailto:' ||
1159-
1160-
// Autolinker detects and links phone numbers
1161-
parsedURL.protocol === 'tel:' ||
1162-
1163-
// Donation links on the about page
1164-
(parsedURL.protocol === 'bitcoin:' && parsedURL.pathname === ABOUT_BITCOIN_ADDRESS)
1165-
) {
1166-
shell.openExternal(url)
1167-
return true
1168-
}
1169-
}
1170-
1171-
return false
1172-
})
1173-
11741166
ipcMain.handle(IpcChannels.GET_SYSTEM_LOCALE, () => {
11751167
// we should switch to getPreferredSystemLanguages at some point and iterate through until we find a supported locale
11761168
return app.getSystemLocale()
@@ -1253,11 +1245,11 @@ function runApp() {
12531245

12541246
const settingId = kind === DefaultFolderKind.DOWNLOADS ? 'downloadFolderPath' : 'screenshotFolderPath'
12551247

1256-
const folderPath = await baseHandlers.settings._findOne(settingId)
1248+
const folderPath = (await baseHandlers.settings._findOne(settingId))?.value
12571249

12581250
let directory
1259-
if (typeof currentPath === 'string' && folderPath.value.length > 0) {
1260-
directory = folderPath.value
1251+
if (typeof folderPath === 'string' && folderPath.length > 0) {
1252+
directory = folderPath
12611253
} else {
12621254
directory = path.join(app.getPath(kind === DefaultFolderKind.DOWNLOADS ? 'downloads' : 'pictures'), 'FreeTube')
12631255
}
@@ -1329,11 +1321,6 @@ function runApp() {
13291321
return
13301322
}
13311323

1332-
if (path == null && query == null && searchQueryText == null) {
1333-
createWindow({ replaceMainWindow: false, showWindowNow: true })
1334-
return
1335-
}
1336-
13371324
if (
13381325
typeof path !== 'string' ||
13391326
(query != null && typeof query !== 'object') ||

src/main/poTokenGenerator.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,7 @@ async function getScript(videoId, visitorData, context) {
117117
if (!cachedScript) {
118118
const pathToScript = process.env.NODE_ENV === 'development'
119119
? join(__dirname, '../../dist/botGuardScript.js')
120-
/* eslint-disable-next-line n/no-path-concat */
121-
: `${__dirname}/botGuardScript.js`
120+
: join(__dirname, 'botGuardScript.js')
122121

123122
const content = await readFile(pathToScript, 'utf-8')
124123

src/renderer/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import SideNav from './components/SideNav/SideNav.vue'
66
import FtNotificationBanner from './components/FtNotificationBanner/FtNotificationBanner.vue'
77
import FtPrompt from './components/FtPrompt/FtPrompt.vue'
88
import FtButton from './components/FtButton/FtButton.vue'
9-
import FtToast from './components/ft-toast/ft-toast.vue'
9+
import FtToast from './components/FtToast/FtToast.vue'
1010
import FtProgressBar from './components/FtProgressBar/FtProgressBar.vue'
1111
import FtPlaylistAddVideoPrompt from './components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.vue'
1212
import FtCreatePlaylistPrompt from './components/ft-create-playlist-prompt/ft-create-playlist-prompt.vue'

0 commit comments

Comments
 (0)