Skip to content

Commit ad0a93e

Browse files
committed
Merge branch 'development' into feature/subscription-cache
* development: (102 commits) Translated using Weblate (Estonian) Translated using Weblate (Dutch) Translated using Weblate (Chinese (Traditional)) Use randomArrayItem helper in more places to reduce duplicate code (FreeTubeApp#5576) Translated using Weblate (Croatian) Translated using Weblate (Hungarian) Bump lefthook from 1.7.12 to 1.7.14 (FreeTubeApp#5585) Bump stylelint from 16.8.1 to 16.8.2 in the stylelint group (FreeTubeApp#5583) Bump electron from 31.3.1 to 31.4.0 (FreeTubeApp#5584) Translated using Weblate (German) Translated using Weblate (Polish) Translated using Weblate (Japanese) Translated using Weblate (English (United Kingdom)) Translated using Weblate (Japanese) Update the Invidious instances list (FreeTubeApp#5575) Translated using Weblate (Icelandic) Translated using Weblate (Serbian) Translated using Weblate (Czech) Translated using Weblate (French) Translated using Weblate (Chinese (Simplified)) ...
2 parents dec3b96 + d12883a commit ad0a93e

File tree

136 files changed

+2910
-2262
lines changed

Some content is hidden

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

136 files changed

+2910
-2262
lines changed

.babelrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111
]
1212
],
1313
"plugins": [
14-
"@babel/proposal-class-properties"
14+
"@babel/plugin-transform-class-properties"
1515
]
1616
}

.github/workflows/flatpak.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,22 @@ jobs:
7777
date +"%Y-%m-%d" >> $GITHUB_ENV
7878
echo 'EOF' >> $GITHUB_ENV
7979
- name: Update x64 File Location in yml File
80-
uses: mikefarah/yq@v4.44.2
80+
uses: mikefarah/yq@v4.44.3
8181
with:
8282
# The Command which should be run
8383
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-portable-x64.zip"' io.freetubeapp.FreeTube.yml
8484
- name: Update x64 Hash in yml File
85-
uses: mikefarah/yq@v4.44.2
85+
uses: mikefarah/yq@v4.44.3
8686
with:
8787
# The Command which should be run
8888
cmd: yq -i '.modules[0].sources[0].sha256 = "${{ env.HASH_X64 }}"' io.freetubeapp.FreeTube.yml
8989
- name: Update ARM File Location in yml File
90-
uses: mikefarah/yq@v4.44.2
90+
uses: mikefarah/yq@v4.44.3
9191
with:
9292
# The Command which should be run
9393
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-portable-arm64.zip"' io.freetubeapp.FreeTube.yml
9494
- name: Update ARM Hash in yml File
95-
uses: mikefarah/yq@v4.44.2
95+
uses: mikefarah/yq@v4.44.3
9696
with:
9797
# The Command which should be run
9898
cmd: yq -i '.modules[0].sources[1].sha256 = "${{ env.HASH_ARM64 }}"' io.freetubeapp.FreeTube.yml

_scripts/getRegions.mjs

+26-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const initialResponse = await scrapeLanguage('en')
2828
// Scrape language menu in en-US
2929

3030
/** @type {string[]} */
31-
const youTubeLanguages = initialResponse.data.actions[0].openPopupAction.popup.multiPageMenuRenderer.sections[1].multiPageMenuSectionRenderer.items[1].compactLinkRenderer.serviceEndpoint.signalServiceEndpoint.actions[0].getMultiPageMenuAction.menu.multiPageMenuRenderer.sections[0].multiPageMenuSectionRenderer.items
31+
const youTubeLanguages = initialResponse.data.actions[0].openPopupAction.popup.multiPageMenuRenderer.sections[0].multiPageMenuSectionRenderer.items[2].compactLinkRenderer.serviceEndpoint.signalServiceEndpoint.actions[0].getMultiPageMenuAction.menu.multiPageMenuRenderer.sections[0].multiPageMenuSectionRenderer.items
3232
.map(({ compactLinkRenderer }) => {
3333
return compactLinkRenderer.serviceEndpoint.signalServiceEndpoint.actions[0].selectLanguageCommand.hl
3434
})
@@ -79,11 +79,35 @@ for (const language of youTubeLanguages) {
7979
youTube: 'no',
8080
freeTube: 'nn'
8181
})
82+
} else if (language === 'iw') {
83+
// according to https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
84+
// "iw" is the old/original code for Hebrew, these days it's "he"
85+
foundLanguageNames.push('he')
86+
languagesToScrape.push({
87+
youTube: 'iw',
88+
freeTube: 'he'
89+
})
90+
} else if (language === 'es-419') {
91+
foundLanguageNames.push('es_AR', 'es-MX')
92+
languagesToScrape.push({
93+
youTube: 'es-419',
94+
freeTube: 'es_AR'
95+
})
96+
languagesToScrape.push({
97+
youTube: 'es-419',
98+
freeTube: 'es-MX'
99+
})
82100
} else if (language !== 'en') {
83101
unusedYouTubeLanguageNames.push(language)
84102
}
85103
}
86104

105+
foundLanguageNames.push('pt-BR')
106+
languagesToScrape.push({
107+
youTube: 'pt',
108+
freeTube: 'pt-BR'
109+
})
110+
87111
console.log("Active FreeTube languages that aren't available on YouTube:")
88112
console.log(activeLanguages.filter(lang => !foundLanguageNames.includes(lang)).sort())
89113

@@ -116,7 +140,7 @@ async function scrapeLanguage(youTubeLanguageCode) {
116140
}
117141

118142
function processGeolocations(freeTubeLanguage, youTubeLanguage, response) {
119-
const geolocations = response.data.actions[0].openPopupAction.popup.multiPageMenuRenderer.sections[1].multiPageMenuSectionRenderer.items[3].compactLinkRenderer.serviceEndpoint.signalServiceEndpoint.actions[0].getMultiPageMenuAction.menu.multiPageMenuRenderer.sections[0].multiPageMenuSectionRenderer.items
143+
const geolocations = response.data.actions[0].openPopupAction.popup.multiPageMenuRenderer.sections[0].multiPageMenuSectionRenderer.items[4].compactLinkRenderer.serviceEndpoint.signalServiceEndpoint.actions[0].getMultiPageMenuAction.menu.multiPageMenuRenderer.sections[0].multiPageMenuSectionRenderer.items
120144
.map(({ compactLinkRenderer }) => {
121145
return {
122146
name: new Misc.Text(compactLinkRenderer.title).toString().trim(),

package.json

+22-22
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "freetube",
33
"productName": "FreeTube",
44
"description": "A private YouTube client",
5-
"version": "0.21.1",
5+
"version": "0.21.3",
66
"license": "AGPL-3.0-or-later",
77
"main": "./dist/main.js",
88
"private": true,
@@ -53,21 +53,21 @@
5353
"ci": "yarn install --silent --frozen-lockfile"
5454
},
5555
"dependencies": {
56-
"@fortawesome/fontawesome-svg-core": "^6.5.2",
57-
"@fortawesome/free-brands-svg-icons": "^6.5.2",
58-
"@fortawesome/free-regular-svg-icons": "^6.5.2",
59-
"@fortawesome/free-solid-svg-icons": "^6.5.2",
56+
"@fortawesome/fontawesome-svg-core": "^6.6.0",
57+
"@fortawesome/free-brands-svg-icons": "^6.6.0",
58+
"@fortawesome/free-regular-svg-icons": "^6.6.0",
59+
"@fortawesome/free-solid-svg-icons": "^6.6.0",
6060
"@fortawesome/vue-fontawesome": "^2.0.10",
6161
"@seald-io/nedb": "^4.0.4",
6262
"@silvermine/videojs-quality-selector": "^1.3.1",
6363
"autolinker": "^4.0.0",
6464
"electron-context-menu": "^4.0.1",
6565
"lodash.debounce": "^4.0.8",
66-
"marked": "^13.0.2",
66+
"marked": "^14.0.0",
6767
"path-browserify": "^1.0.1",
6868
"portal-vue": "^2.1.7",
6969
"process": "^0.11.10",
70-
"swiper": "^11.1.4",
70+
"swiper": "^11.1.9",
7171
"video.js": "7.21.5",
7272
"videojs-contrib-quality-levels": "^3.0.0",
7373
"videojs-http-source-selector": "^1.1.6",
@@ -79,46 +79,46 @@
7979
"vue-observe-visibility": "^1.0.0",
8080
"vue-router": "^3.6.5",
8181
"vuex": "^3.6.2",
82-
"youtubei.js": "^10.1.0"
82+
"youtubei.js": "^10.3.0"
8383
},
8484
"devDependencies": {
85-
"@babel/core": "^7.24.9",
86-
"@babel/eslint-parser": "^7.24.8",
87-
"@babel/plugin-proposal-class-properties": "^7.18.6",
88-
"@babel/preset-env": "^7.24.8",
85+
"@babel/core": "^7.25.2",
86+
"@babel/eslint-parser": "^7.25.1",
87+
"@babel/plugin-transform-class-properties": "^7.24.7",
88+
"@babel/preset-env": "^7.25.3",
8989
"@double-great/stylelint-a11y": "^3.0.2",
9090
"@intlify/eslint-plugin-vue-i18n": "^3.0.0",
9191
"babel-loader": "^9.1.3",
9292
"copy-webpack-plugin": "^12.0.2",
9393
"css-loader": "^7.1.2",
9494
"css-minimizer-webpack-plugin": "^7.0.0",
95-
"electron": "^31.2.0",
95+
"electron": "^31.4.0",
9696
"electron-builder": "^24.13.3",
9797
"eslint": "^8.57.0",
9898
"eslint-config-prettier": "^9.1.0",
9999
"eslint-config-standard": "^17.1.0",
100100
"eslint-plugin-import": "^2.29.1",
101101
"eslint-plugin-jsonc": "^2.16.0",
102-
"eslint-plugin-n": "^17.9.0",
103-
"eslint-plugin-prettier": "^5.1.3",
104-
"eslint-plugin-promise": "^6.4.0",
105-
"eslint-plugin-unicorn": "^54.0.0",
102+
"eslint-plugin-n": "^17.10.2",
103+
"eslint-plugin-prettier": "^5.2.1",
104+
"eslint-plugin-promise": "^7.1.0",
105+
"eslint-plugin-unicorn": "^55.0.0",
106106
"eslint-plugin-vue": "^9.27.0",
107-
"eslint-plugin-vuejs-accessibility": "^2.3.1",
107+
"eslint-plugin-vuejs-accessibility": "^2.4.1",
108108
"eslint-plugin-yml": "^1.14.0",
109109
"html-webpack-plugin": "^5.6.0",
110110
"js-yaml": "^4.1.0",
111111
"json-minimizer-webpack-plugin": "^5.0.0",
112-
"lefthook": "^1.7.2",
112+
"lefthook": "^1.7.14",
113113
"mini-css-extract-plugin": "^2.9.0",
114114
"npm-run-all2": "^6.2.2",
115-
"postcss": "^8.4.39",
115+
"postcss": "^8.4.41",
116116
"postcss-scss": "^4.0.9",
117117
"prettier": "^2.8.8",
118118
"rimraf": "^6.0.1",
119119
"sass": "^1.77.8",
120-
"sass-loader": "^14.2.1",
121-
"stylelint": "^16.7.0",
120+
"sass-loader": "^16.0.0",
121+
"stylelint": "^16.8.2",
122122
"stylelint-config-sass-guidelines": "^12.0.0",
123123
"stylelint-config-standard": "^36.0.1",
124124
"stylelint-high-performance-animation": "^1.10.0",

src/main/index.js

+38-12
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ function runApp() {
9494
const path = urlParts[1]
9595

9696
if (path) {
97-
visible = ['/channel', '/watch'].some(p => path.startsWith(p)) ||
97+
visible = ['/channel', '/watch', '/hashtag'].some(p => path.startsWith(p)) ||
9898
// Only show copy link entry for non user playlists
9999
(path.startsWith('/playlist') && !/playlistType=user/.test(path))
100100
}
@@ -131,6 +131,8 @@ function runApp() {
131131
return `${origin}/playlist?list=${id}`
132132
case 'channel':
133133
return `${origin}/channel/${id}`
134+
case 'hashtag':
135+
return `${origin}/hashtag/${id}`
134136
case 'watch': {
135137
let url
136138

@@ -199,9 +201,11 @@ function runApp() {
199201
let startupUrl
200202

201203
if (process.platform === 'linux') {
202-
// Enable hardware acceleration via VA-API
204+
// Enable hardware acceleration via VA-API with OpenGL if no other feature flags are found
203205
// https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/gpu/vaapi.md
204-
app.commandLine.appendSwitch('enable-features', 'VaapiVideoDecodeLinuxGL')
206+
if (!app.commandLine.hasSwitch('enable-features')) {
207+
app.commandLine.appendSwitch('enable-features', 'VaapiVideoDecodeLinuxGL')
208+
}
205209
}
206210

207211
const userDataPath = app.getPath('userData')
@@ -408,9 +412,24 @@ function runApp() {
408412
requestHeaders.Origin = 'https://www.youtube.com'
409413

410414
if (url.startsWith('https://www.youtube.com/youtubei/')) {
411-
requestHeaders['Sec-Fetch-Site'] = 'same-origin'
412-
requestHeaders['Sec-Fetch-Mode'] = 'same-origin'
413-
requestHeaders['X-Youtube-Bootstrap-Logged-In'] = 'false'
415+
// Make iOS requests work and look more realistic
416+
if (requestHeaders['x-youtube-client-name'] === '5') {
417+
delete requestHeaders.Referer
418+
delete requestHeaders.Origin
419+
delete requestHeaders['Sec-Fetch-Site']
420+
delete requestHeaders['Sec-Fetch-Mode']
421+
delete requestHeaders['Sec-Fetch-Dest']
422+
delete requestHeaders['sec-ch-ua']
423+
delete requestHeaders['sec-ch-ua-mobile']
424+
delete requestHeaders['sec-ch-ua-platform']
425+
426+
requestHeaders['User-Agent'] = requestHeaders['x-user-agent']
427+
delete requestHeaders['x-user-agent']
428+
} else {
429+
requestHeaders['Sec-Fetch-Site'] = 'same-origin'
430+
requestHeaders['Sec-Fetch-Mode'] = 'same-origin'
431+
requestHeaders['X-Youtube-Bootstrap-Logged-In'] = 'false'
432+
}
414433
} else {
415434
// YouTube doesn't send the Content-Type header for the media requests, so we shouldn't either
416435
delete requestHeaders['Content-Type']
@@ -977,12 +996,6 @@ function runApp() {
977996
try {
978997
const contents = await asyncFs.readFile(filePath)
979998

980-
// Probably a corrupted/broken cache entry, pretend it's absent
981-
// A valid entry should be a few KB large
982-
if (contents.byteLength < 500) {
983-
return undefined
984-
}
985-
986999
return contents.buffer
9871000
} catch (e) {
9881001
console.error(e)
@@ -1585,6 +1598,19 @@ function runApp() {
15851598
}
15861599
}
15871600
},
1601+
{
1602+
label: 'GPU Internals (chrome://gpu)',
1603+
click() {
1604+
const gpuWindow = new BrowserWindow({
1605+
show: true,
1606+
autoHideMenuBar: true,
1607+
webPreferences: {
1608+
devTools: false
1609+
}
1610+
})
1611+
gpuWindow.loadURL('chrome://gpu')
1612+
}
1613+
},
15881614
{ type: 'separator' },
15891615
{ role: 'resetzoom' },
15901616
{ role: 'resetzoom', accelerator: 'CmdOrCtrl+num0', visible: false },

0 commit comments

Comments
 (0)