Skip to content

Commit

Permalink
Merge branch 'shaka-migration' into custom-builds/shaka
Browse files Browse the repository at this point in the history
* shaka-migration: (89 commits)
  Fix position and alignment for auto-generated subtitles
  Update shaka-player to version 4.10.10
  Fix quality selection when switching from audio to DASH
  Cleanup the Invidious DASH manifest in builds without the local API
  Fix the text color and RTL handling
  Show a message while buffering if it was caused by the internet connection disappearing
  Gracefully handle the internet connection disappearing during playback
  Include the video ID in the error logs
  When an error occurs with the thumbnails just log it
  Use vp9 streams if the Invidious instance is running a new enough version
  Fix duplicate qualities with the Invidious API
  Fix multiple audio track detection for Invidious
  Update outdated comment
  Fix Invidious API error
  Actually downgrade shaka-player
  Downgrade shaka-player to fix subtitle alignment
  Add support for secondary audio tracks
  Fix some type issues
  Update shaka-player to version 4.10.9
  Fix scrolling over the big play pause button not working
  ...

# Conflicts:
#	src/renderer/store/modules/index.js
  • Loading branch information
PikachuEXE committed Aug 21, 2024
2 parents ed3ef53 + 6e2e888 commit 4921676
Show file tree
Hide file tree
Showing 100 changed files with 5,412 additions and 7,153 deletions.
2 changes: 1 addition & 1 deletion .stylelintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"selector-pseudo-class-no-unknown": [
true,
{
"ignorePseudoClasses": ["deep"]
"ignorePseudoClasses": ["deep", "global"]
}
],
"a11y/no-outline-none": true,
Expand Down
5 changes: 0 additions & 5 deletions _scripts/_domParser.js

This file was deleted.

34 changes: 24 additions & 10 deletions _scripts/dev-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ const web = process.argv.indexOf('--web') !== -1
let mainConfig
let rendererConfig
let webConfig
let SHAKA_LOCALES_TO_BE_BUNDLED

if (!web) {
mainConfig = require('./webpack.main.config')
rendererConfig = require('./webpack.renderer.config')

SHAKA_LOCALES_TO_BE_BUNDLED = rendererConfig.SHAKA_LOCALES_TO_BE_BUNDLED
delete rendererConfig.SHAKA_LOCALES_TO_BE_BUNDLED
} else {
webConfig = require('./webpack.web.config')
}
Expand Down Expand Up @@ -128,17 +132,27 @@ function startRenderer(callback) {
})

const server = new WebpackDevServer({
static: {
directory: path.resolve(__dirname, '..', 'static'),
watch: {
ignored: [
/(dashFiles|storyboards)\/*/,
'/**/.DS_Store',
'**/static/locales/*'
]
static: [
{
directory: path.resolve(__dirname, '..', 'static'),
watch: {
ignored: [
/(dashFiles|storyboards)\/*/,
'/**/.DS_Store',
'**/static/locales/*'
]
},
publicPath: '/static'
},
publicPath: '/static'
},
{
directory: path.resolve(__dirname, '..', 'node_modules', 'shaka-player', 'ui', 'locales'),
publicPath: '/static/shaka-player-locales',
watch: {
// Ignore everything that isn't one of the locales that we would bundle in production mode
ignored: `**/!(${SHAKA_LOCALES_TO_BE_BUNDLED.join('|')}).json`
}
}
],
port
}, compiler)

Expand Down
114 changes: 114 additions & 0 deletions _scripts/getShakaLocales.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
const { readFileSync, readdirSync } = require('fs')

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

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

if (!localesLine) {
throw new Error("Failed to parse shaka-player's preloaded locales")
}

return localesLine[1].split(',').map(locale => locale.trim())
}

function getAllLocales() {
const filenames = readdirSync(`${__dirname}/../node_modules/shaka-player/ui/locales`)

return new Set(filenames
.filter(filename => filename !== 'source.json' && filename.endsWith('.json'))
.map(filename => filename.replace('.json', '')))
}

/**
* Maps the shaka locales to FreeTube's active ones
* This allows us to know which locale files are actually needed
* and which shaka locale needs to be activated for a given FreeTube one.
* @param {Set<string>} shakaLocales
* @param {string[]} freeTubeLocales
*/
function getMappings(shakaLocales, freeTubeLocales) {
/**
* @type {[string, string][]}
* Using this structure as it gets passed to `new Map()` in the player component
* The first element is the FreeTube locale, the second one is the shaka-player one
**/
const mappings = []

for (const locale of freeTubeLocales) {
if (shakaLocales.has(locale)) {
mappings.push([
locale,
locale
])
} else if (shakaLocales.has(locale.replace('_', '-'))) {
mappings.push([
locale,
locale.replace('_', '-')
])
} else if (shakaLocales.has(locale.split(/[-_]/)[0])) {
mappings.push([
locale,
locale.split(/[-_]/)[0]
])
}
}

// special cases

mappings.push(
// according to https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
// "no" is the macro language for "nb" and "nn"
[
'nb_NO',
'no'
],
[
'nn',
'no'
],

// according to https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
// "iw" is the old/original code for Hebrew, these days it's "he"
[
'he',
'iw'
],

// not sure why we have pt, pt-PT and pt-BR in the FreeTube locales
// as pt and pt-PT are the same thing, but we should handle it here anyway
[
'pt',
'pt-PT'
]
)

return mappings
}

function getShakaLocales() {
const shakaLocales = getAllLocales()

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

const mappings = getMappings(shakaLocales, freeTubeLocales)

const preloaded = getPreloadedLocales()

const shakaMappings = mappings.map(mapping => mapping[1])

// use a set to deduplicate the list
// we don't need to bundle any locale files that are already embedded in shaka-player/preloaded

/** @type {string[]} */
const toBeBundled = [...new Set(shakaMappings.filter(locale => !preloaded.includes(locale)))]

return {
SHAKA_LOCALE_MAPPINGS: mappings,
SHAKA_LOCALES_PREBUNDLED: preloaded,
SHAKA_LOCALES_TO_BE_BUNDLED: toBeBundled
}
}

module.exports = getShakaLocales()
135 changes: 135 additions & 0 deletions _scripts/patchShaka.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// This script fixes shaka not exporting its type definitions and referencing remote google fonts in its CSS
// by adding an export line to the type definitions and downloading the fonts and updating the CSS to point to the local files
// this script only makes changes if they are needed, so running it multiple times doesn't cause any problems

import { appendFileSync, closeSync, ftruncateSync, openSync, readFileSync, writeFileSync, writeSync } from 'fs'
import { resolve } from 'path'

const SHAKA_DIST_DIR = resolve(import.meta.dirname, '../node_modules/shaka-player/dist')

function fixTypes() {
let fixedTypes = false

let fileHandleNormal
try {
fileHandleNormal = openSync(`${SHAKA_DIST_DIR}/shaka-player.ui.d.ts`, 'a+')

const contents = readFileSync(fileHandleNormal, 'utf-8')

// This script is run after every `yarn install`, even if shaka-player wasn't updated
// So we want to check first, if we actually need to make any changes
// or if the ones from the previous run are still intact
if (!contents.includes('export default shaka')) {
appendFileSync(fileHandleNormal, 'export default shaka;\n')

fixedTypes = true
}
} finally {
if (typeof fileHandleNormal !== 'undefined') {
closeSync(fileHandleNormal)
}
}

let fileHandleDebug
try {
fileHandleDebug = openSync(`${SHAKA_DIST_DIR}/shaka-player.ui.debug.d.ts`, 'a+')

const contents = readFileSync(fileHandleDebug, 'utf-8')

// This script is run after every `yarn install`, even if shaka-player wasn't updated
// So we want to check first, if we actually need to make any changes
// or if the ones from the previous run are still intact
if (!contents.includes('export default shaka')) {
appendFileSync(fileHandleDebug, 'export default shaka;\n')

fixedTypes = true
}
} finally {
if (typeof fileHandleDebug !== 'undefined') {
closeSync(fileHandleDebug)
}
}

if (fixedTypes) {
console.log('Fixed shaka-player types')
}
}

async function removeRobotoFont() {
let cssFileHandle
try {
cssFileHandle = openSync(`${SHAKA_DIST_DIR}/controls.css`, 'r+')

let cssContents = readFileSync(cssFileHandle, 'utf-8')

const beforeReplacement = cssContents.length
cssContents = cssContents.replace(/@font-face\{font-family:Roboto;[^}]+\}/, '')

if (cssContents.length !== beforeReplacement) {
ftruncateSync(cssFileHandle)
writeSync(cssFileHandle, cssContents, 0, 'utf-8')

console.log('Removed shaka-player Roboto font, so it uses ours')
}
} finally {
if (typeof cssFileHandle !== 'undefined') {
closeSync(cssFileHandle)
}
}
}

async function replaceAndDownloadMaterialIconsFont() {
let cssFileHandle
try {
cssFileHandle = openSync(`${SHAKA_DIST_DIR}/controls.css`, 'r+')

let cssContents = readFileSync(cssFileHandle, 'utf-8')

const fontFaceRegex = /@font-face{font-family:'Material Icons Round'[^}]+format\('opentype'\)}/

if (fontFaceRegex.test(cssContents)) {
const cssResponse = await fetch('https://fonts.googleapis.com/icon?family=Material+Icons+Round', {
headers: {
// Without the user-agent it returns the otf file instead of the woff2 one
'user-agent': 'Firefox/125.0'
}
})

const text = await cssResponse.text()

let newFontCSS = text.match(/(@font-face\s*{[^}]+})/)[1].replaceAll('\n', '')


const urlMatch = newFontCSS.match(/https:\/\/fonts\.gstatic\.com\/s\/materialiconsround\/(?<version>[^\/]+)\/[^.]+\.(?<extension>[\w]+)/)

const url = urlMatch[0]
const { version, extension } = urlMatch.groups

const fontResponse = await fetch(url)
const fontContent = new Uint8Array(await fontResponse.arrayBuffer())

const filename = `shaka-materialiconsround-${version}.${extension}`
writeFileSync(`${SHAKA_DIST_DIR}/${filename}`, fontContent)

newFontCSS = newFontCSS.replace(url, `./${filename}`)

cssContents = cssContents.replace(fontFaceRegex, newFontCSS)

ftruncateSync(cssFileHandle)
writeSync(cssFileHandle, cssContents, 0, 'utf-8')

console.log('Changed shaka-player Material Icons Rounded font to use the smaller woff2 format instead of otf')
console.log('Downloaded shaka-player Material Icons Rounded font')
}
} catch (e) {
console.error(e)
} finally {
if (typeof cssFileHandle !== 'undefined') {
closeSync(cssFileHandle)
}
}
}

fixTypes()
await removeRobotoFont()
await replaceAndDownloadMaterialIconsFont()
37 changes: 31 additions & 6 deletions _scripts/webpack.renderer.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const ProcessLocalesPlugin = require('./ProcessLocalesPlugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const {
SHAKA_LOCALE_MAPPINGS,
SHAKA_LOCALES_PREBUNDLED,
SHAKA_LOCALES_TO_BE_BUNDLED
} = require('./getShakaLocales')

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

Expand Down Expand Up @@ -122,7 +127,9 @@ const config = {
'process.env.SUPPORTS_LOCAL_API': true,
'process.env.LOCALE_NAMES': JSON.stringify(processLocalesPlugin.localeNames),
'process.env.GEOLOCATION_NAMES': JSON.stringify(readdirSync(path.join(__dirname, '..', 'static', 'geolocations')).map(filename => filename.replace('.json', ''))),
'process.env.SWIPER_VERSION': `'${swiperVersion}'`
'process.env.SWIPER_VERSION': `'${swiperVersion}'`,
'process.env.SHAKA_LOCALE_MAPPINGS': JSON.stringify(SHAKA_LOCALE_MAPPINGS),
'process.env.SHAKA_LOCALES_PREBUNDLED': JSON.stringify(SHAKA_LOCALES_PREBUNDLED)
}),
new HtmlWebpackPlugin({
excludeChunks: ['processTaskWorker'],
Expand All @@ -143,7 +150,21 @@ const config = {
transformAll: (assets) => {
return Buffer.concat(assets.map(asset => asset.data))
}
}
},
// Don't need to copy them in dev mode,
// as we configure WebpackDevServer to serve them
...(isDevMode ? [] : [
{
from: path.join(__dirname, '../node_modules/shaka-player/ui/locales', `{${SHAKA_LOCALES_TO_BE_BUNDLED.join(',')}}.json`).replaceAll('\\', '/'),
to: path.join(__dirname, '../dist/static/shaka-player-locales'),
context: path.join(__dirname, '../node_modules/shaka-player/ui/locales'),
transform: {
transformer: (input) => {
return JSON.stringify(JSON.parse(input.toString('utf-8')))
}
}
}
])
]
})
],
Expand All @@ -156,14 +177,18 @@ const config = {

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

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

if (isDevMode) {
// hack to pass it through to the dev-runner.js script
// gets removed there before the config object is passed to webpack
config.SHAKA_LOCALES_TO_BE_BUNDLED = SHAKA_LOCALES_TO_BE_BUNDLED
}

module.exports = config
Loading

0 comments on commit 4921676

Please sign in to comment.