Skip to content

Commit 1b9c1fd

Browse files
committed
Merge branch 'development' into feature/subscription-cache
* development: (49 commits) Translated using Weblate (Serbian) Translated using Weblate (Turkish) Translated using Weblate (English (United Kingdom)) Translated using Weblate (Italian) Translated using Weblate (Chinese (Simplified Han script)) Translated using Weblate (Italian) Translated using Weblate (Italian) Translated using Weblate (Italian) Translated using Weblate (Italian) Translated using Weblate (French) Translated using Weblate (German) Bump swiper from 11.1.10 to 11.1.12 (FreeTubeApp#5635) Translated using Weblate (Spanish) Bump the stylelint group with 2 updates (FreeTubeApp#5633) Migrate video player from video.js to shaka-player (FreeTubeApp#4978) Bump lefthook from 1.7.14 to 1.7.15 (FreeTubeApp#5634) Bump electron-context-menu from 4.0.2 to 4.0.4 (FreeTubeApp#5636) Bump youtubei.js from 10.3.0 to 10.4.0 (FreeTubeApp#5637) Cleanup the Hide Profile Pictures in Comments code (FreeTubeApp#5625) Switch to non-deprecated Electron navigation history APIs (FreeTubeApp#5626) ... # Conflicts: # src/renderer/store/modules/index.js
2 parents ad0a93e + f60ca8b commit 1b9c1fd

File tree

128 files changed

+6366
-7977
lines changed

Some content is hidden

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

128 files changed

+6366
-7977
lines changed

.stylelintrc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"selector-pseudo-class-no-unknown": [
2727
true,
2828
{
29-
"ignorePseudoClasses": ["deep"]
29+
"ignorePseudoClasses": ["deep", "global"]
3030
}
3131
],
3232
"a11y/no-outline-none": true,

_scripts/_domParser.js

-5
This file was deleted.

_scripts/dev-runner.js

+24-10
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ const web = process.argv.indexOf('--web') !== -1
1919
let mainConfig
2020
let rendererConfig
2121
let webConfig
22+
let SHAKA_LOCALES_TO_BE_BUNDLED
2223

2324
if (!web) {
2425
mainConfig = require('./webpack.main.config')
2526
rendererConfig = require('./webpack.renderer.config')
27+
28+
SHAKA_LOCALES_TO_BE_BUNDLED = rendererConfig.SHAKA_LOCALES_TO_BE_BUNDLED
29+
delete rendererConfig.SHAKA_LOCALES_TO_BE_BUNDLED
2630
} else {
2731
webConfig = require('./webpack.web.config')
2832
}
@@ -128,17 +132,27 @@ function startRenderer(callback) {
128132
})
129133

130134
const server = new WebpackDevServer({
131-
static: {
132-
directory: path.resolve(__dirname, '..', 'static'),
133-
watch: {
134-
ignored: [
135-
/(dashFiles|storyboards)\/*/,
136-
'/**/.DS_Store',
137-
'**/static/locales/*'
138-
]
135+
static: [
136+
{
137+
directory: path.resolve(__dirname, '..', 'static'),
138+
watch: {
139+
ignored: [
140+
/(dashFiles|storyboards)\/*/,
141+
'/**/.DS_Store',
142+
'**/static/locales/*'
143+
]
144+
},
145+
publicPath: '/static'
139146
},
140-
publicPath: '/static'
141-
},
147+
{
148+
directory: path.resolve(__dirname, '..', 'node_modules', 'shaka-player', 'ui', 'locales'),
149+
publicPath: '/static/shaka-player-locales',
150+
watch: {
151+
// Ignore everything that isn't one of the locales that we would bundle in production mode
152+
ignored: `**/!(${SHAKA_LOCALES_TO_BE_BUNDLED.join('|')}).json`
153+
}
154+
}
155+
],
142156
port
143157
}, compiler)
144158

_scripts/getShakaLocales.js

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
const { readFileSync, readdirSync } = require('fs')
2+
3+
function getPreloadedLocales() {
4+
const localesFile = readFileSync(`${__dirname}/../node_modules/shaka-player/dist/locales.js`, 'utf-8')
5+
6+
const localesLine = localesFile.match(/^\/\/ LOCALES: ([\w, -]+)$/m)
7+
8+
if (!localesLine) {
9+
throw new Error("Failed to parse shaka-player's preloaded locales")
10+
}
11+
12+
return localesLine[1].split(',').map(locale => locale.trim())
13+
}
14+
15+
function getAllLocales() {
16+
const filenames = readdirSync(`${__dirname}/../node_modules/shaka-player/ui/locales`)
17+
18+
return new Set(filenames
19+
.filter(filename => filename !== 'source.json' && filename.endsWith('.json'))
20+
.map(filename => filename.replace('.json', '')))
21+
}
22+
23+
/**
24+
* Maps the shaka locales to FreeTube's active ones
25+
* This allows us to know which locale files are actually needed
26+
* and which shaka locale needs to be activated for a given FreeTube one.
27+
* @param {Set<string>} shakaLocales
28+
* @param {string[]} freeTubeLocales
29+
*/
30+
function getMappings(shakaLocales, freeTubeLocales) {
31+
/**
32+
* @type {[string, string][]}
33+
* Using this structure as it gets passed to `new Map()` in the player component
34+
* The first element is the FreeTube locale, the second one is the shaka-player one
35+
**/
36+
const mappings = []
37+
38+
for (const locale of freeTubeLocales) {
39+
if (shakaLocales.has(locale)) {
40+
mappings.push([
41+
locale,
42+
locale
43+
])
44+
} else if (shakaLocales.has(locale.replace('_', '-'))) {
45+
mappings.push([
46+
locale,
47+
locale.replace('_', '-')
48+
])
49+
} else if (shakaLocales.has(locale.split(/[-_]/)[0])) {
50+
mappings.push([
51+
locale,
52+
locale.split(/[-_]/)[0]
53+
])
54+
}
55+
}
56+
57+
// special cases
58+
59+
mappings.push(
60+
// according to https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
61+
// "no" is the macro language for "nb" and "nn"
62+
[
63+
'nb_NO',
64+
'no'
65+
],
66+
[
67+
'nn',
68+
'no'
69+
],
70+
71+
// according to https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
72+
// "iw" is the old/original code for Hebrew, these days it's "he"
73+
[
74+
'he',
75+
'iw'
76+
],
77+
78+
// not sure why we have pt, pt-PT and pt-BR in the FreeTube locales
79+
// as pt and pt-PT are the same thing, but we should handle it here anyway
80+
[
81+
'pt',
82+
'pt-PT'
83+
]
84+
)
85+
86+
return mappings
87+
}
88+
89+
function getShakaLocales() {
90+
const shakaLocales = getAllLocales()
91+
92+
/** @type {string[]} */
93+
const freeTubeLocales = JSON.parse(readFileSync(`${__dirname}/../static/locales/activeLocales.json`, 'utf-8'))
94+
95+
const mappings = getMappings(shakaLocales, freeTubeLocales)
96+
97+
const preloaded = getPreloadedLocales()
98+
99+
const shakaMappings = mappings.map(mapping => mapping[1])
100+
101+
// use a set to deduplicate the list
102+
// we don't need to bundle any locale files that are already embedded in shaka-player/preloaded
103+
104+
/** @type {string[]} */
105+
const toBeBundled = [...new Set(shakaMappings.filter(locale => !preloaded.includes(locale)))]
106+
107+
return {
108+
SHAKA_LOCALE_MAPPINGS: mappings,
109+
SHAKA_LOCALES_PREBUNDLED: preloaded,
110+
SHAKA_LOCALES_TO_BE_BUNDLED: toBeBundled
111+
}
112+
}
113+
114+
module.exports = getShakaLocales()

_scripts/patchShaka.mjs

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// This script fixes shaka not exporting its type definitions and referencing remote google fonts in its CSS
2+
// by adding an export line to the type definitions and downloading the fonts and updating the CSS to point to the local files
3+
// this script only makes changes if they are needed, so running it multiple times doesn't cause any problems
4+
5+
import { appendFileSync, closeSync, ftruncateSync, openSync, readFileSync, writeFileSync, writeSync } from 'fs'
6+
import { resolve } from 'path'
7+
8+
const SHAKA_DIST_DIR = resolve(import.meta.dirname, '../node_modules/shaka-player/dist')
9+
10+
function fixTypes() {
11+
let fixedTypes = false
12+
13+
let fileHandleNormal
14+
try {
15+
fileHandleNormal = openSync(`${SHAKA_DIST_DIR}/shaka-player.ui.d.ts`, 'a+')
16+
17+
const contents = readFileSync(fileHandleNormal, 'utf-8')
18+
19+
// This script is run after every `yarn install`, even if shaka-player wasn't updated
20+
// So we want to check first, if we actually need to make any changes
21+
// or if the ones from the previous run are still intact
22+
if (!contents.includes('export default shaka')) {
23+
appendFileSync(fileHandleNormal, 'export default shaka;\n')
24+
25+
fixedTypes = true
26+
}
27+
} finally {
28+
if (typeof fileHandleNormal !== 'undefined') {
29+
closeSync(fileHandleNormal)
30+
}
31+
}
32+
33+
let fileHandleDebug
34+
try {
35+
fileHandleDebug = openSync(`${SHAKA_DIST_DIR}/shaka-player.ui.debug.d.ts`, 'a+')
36+
37+
const contents = readFileSync(fileHandleDebug, 'utf-8')
38+
39+
// This script is run after every `yarn install`, even if shaka-player wasn't updated
40+
// So we want to check first, if we actually need to make any changes
41+
// or if the ones from the previous run are still intact
42+
if (!contents.includes('export default shaka')) {
43+
appendFileSync(fileHandleDebug, 'export default shaka;\n')
44+
45+
fixedTypes = true
46+
}
47+
} finally {
48+
if (typeof fileHandleDebug !== 'undefined') {
49+
closeSync(fileHandleDebug)
50+
}
51+
}
52+
53+
if (fixedTypes) {
54+
console.log('Fixed shaka-player types')
55+
}
56+
}
57+
58+
async function removeRobotoFont() {
59+
let cssFileHandle
60+
try {
61+
cssFileHandle = openSync(`${SHAKA_DIST_DIR}/controls.css`, 'r+')
62+
63+
let cssContents = readFileSync(cssFileHandle, 'utf-8')
64+
65+
const beforeReplacement = cssContents.length
66+
cssContents = cssContents.replace(/@font-face\{font-family:Roboto;[^}]+\}/, '')
67+
68+
if (cssContents.length !== beforeReplacement) {
69+
ftruncateSync(cssFileHandle)
70+
writeSync(cssFileHandle, cssContents, 0, 'utf-8')
71+
72+
console.log('Removed shaka-player Roboto font, so it uses ours')
73+
}
74+
} finally {
75+
if (typeof cssFileHandle !== 'undefined') {
76+
closeSync(cssFileHandle)
77+
}
78+
}
79+
}
80+
81+
async function replaceAndDownloadMaterialIconsFont() {
82+
let cssFileHandle
83+
try {
84+
cssFileHandle = openSync(`${SHAKA_DIST_DIR}/controls.css`, 'r+')
85+
86+
let cssContents = readFileSync(cssFileHandle, 'utf-8')
87+
88+
const fontFaceRegex = /@font-face{font-family:'Material Icons Round'[^}]+format\('opentype'\)}/
89+
90+
if (fontFaceRegex.test(cssContents)) {
91+
const cssResponse = await fetch('https://fonts.googleapis.com/icon?family=Material+Icons+Round', {
92+
headers: {
93+
// Without the user-agent it returns the otf file instead of the woff2 one
94+
'user-agent': 'Firefox/125.0'
95+
}
96+
})
97+
98+
const text = await cssResponse.text()
99+
100+
let newFontCSS = text.match(/(@font-face\s*{[^}]+})/)[1].replaceAll('\n', '')
101+
102+
103+
const urlMatch = newFontCSS.match(/https:\/\/fonts\.gstatic\.com\/s\/materialiconsround\/(?<version>[^\/]+)\/[^.]+\.(?<extension>[\w]+)/)
104+
105+
const url = urlMatch[0]
106+
const { version, extension } = urlMatch.groups
107+
108+
const fontResponse = await fetch(url)
109+
const fontContent = new Uint8Array(await fontResponse.arrayBuffer())
110+
111+
const filename = `shaka-materialiconsround-${version}.${extension}`
112+
writeFileSync(`${SHAKA_DIST_DIR}/${filename}`, fontContent)
113+
114+
newFontCSS = newFontCSS.replace(url, `./${filename}`)
115+
116+
cssContents = cssContents.replace(fontFaceRegex, newFontCSS)
117+
118+
ftruncateSync(cssFileHandle)
119+
writeSync(cssFileHandle, cssContents, 0, 'utf-8')
120+
121+
console.log('Changed shaka-player Material Icons Rounded font to use the smaller woff2 format instead of otf')
122+
console.log('Downloaded shaka-player Material Icons Rounded font')
123+
}
124+
} catch (e) {
125+
console.error(e)
126+
} finally {
127+
if (typeof cssFileHandle !== 'undefined') {
128+
closeSync(cssFileHandle)
129+
}
130+
}
131+
}
132+
133+
fixTypes()
134+
await removeRobotoFont()
135+
await replaceAndDownloadMaterialIconsFont()

_scripts/webpack.renderer.config.js

+31-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
77
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
88
const ProcessLocalesPlugin = require('./ProcessLocalesPlugin')
99
const CopyWebpackPlugin = require('copy-webpack-plugin')
10+
const {
11+
SHAKA_LOCALE_MAPPINGS,
12+
SHAKA_LOCALES_PREBUNDLED,
13+
SHAKA_LOCALES_TO_BE_BUNDLED
14+
} = require('./getShakaLocales')
1015

1116
const isDevMode = process.env.NODE_ENV === 'development'
1217

@@ -122,7 +127,9 @@ const config = {
122127
'process.env.SUPPORTS_LOCAL_API': true,
123128
'process.env.LOCALE_NAMES': JSON.stringify(processLocalesPlugin.localeNames),
124129
'process.env.GEOLOCATION_NAMES': JSON.stringify(readdirSync(path.join(__dirname, '..', 'static', 'geolocations')).map(filename => filename.replace('.json', ''))),
125-
'process.env.SWIPER_VERSION': `'${swiperVersion}'`
130+
'process.env.SWIPER_VERSION': `'${swiperVersion}'`,
131+
'process.env.SHAKA_LOCALE_MAPPINGS': JSON.stringify(SHAKA_LOCALE_MAPPINGS),
132+
'process.env.SHAKA_LOCALES_PREBUNDLED': JSON.stringify(SHAKA_LOCALES_PREBUNDLED)
126133
}),
127134
new HtmlWebpackPlugin({
128135
excludeChunks: ['processTaskWorker'],
@@ -143,7 +150,21 @@ const config = {
143150
transformAll: (assets) => {
144151
return Buffer.concat(assets.map(asset => asset.data))
145152
}
146-
}
153+
},
154+
// Don't need to copy them in dev mode,
155+
// as we configure WebpackDevServer to serve them
156+
...(isDevMode ? [] : [
157+
{
158+
from: path.join(__dirname, '../node_modules/shaka-player/ui/locales', `{${SHAKA_LOCALES_TO_BE_BUNDLED.join(',')}}.json`).replaceAll('\\', '/'),
159+
to: path.join(__dirname, '../dist/static/shaka-player-locales'),
160+
context: path.join(__dirname, '../node_modules/shaka-player/ui/locales'),
161+
transform: {
162+
transformer: (input) => {
163+
return JSON.stringify(JSON.parse(input.toString('utf-8')))
164+
}
165+
}
166+
}
167+
])
147168
]
148169
})
149170
],
@@ -156,14 +177,18 @@ const config = {
156177

157178
'youtubei.js$': 'youtubei.js/web',
158179

159-
// video.js's mpd-parser uses @xmldom/xmldom so that it can support both node and web browsers
160-
// as FreeTube only runs in electron and web browsers we can use the native DOMParser class, instead of the "polyfill"
161-
// https://caniuse.com/mdn-api_domparser
162-
'@xmldom/xmldom$': path.resolve(__dirname, '_domParser.js')
180+
// change to "shaka-player.ui.debug.js" to get debug logs (update jsconfig to get updated types)
181+
'shaka-player$': 'shaka-player/dist/shaka-player.ui.js',
163182
},
164183
extensions: ['.js', '.vue']
165184
},
166185
target: 'electron-renderer',
167186
}
168187

188+
if (isDevMode) {
189+
// hack to pass it through to the dev-runner.js script
190+
// gets removed there before the config object is passed to webpack
191+
config.SHAKA_LOCALES_TO_BE_BUNDLED = SHAKA_LOCALES_TO_BE_BUNDLED
192+
}
193+
169194
module.exports = config

0 commit comments

Comments
 (0)