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:
  Use the HLS manifests for live streams
  Update shaka-player to version 4.10.11
  Translated using Weblate (Japanese)
  Translated using Weblate (Japanese)
  Support authentication with the Basic scheme for Invidious instances (FreeTubeApp#5569)
  Translated using Weblate (Romanian)
  Translated using Weblate (Romanian)
  • Loading branch information
PikachuEXE committed Aug 26, 2024
2 parents 4921676 + 2ce0726 commit 863c4eb
Show file tree
Hide file tree
Showing 31 changed files with 346 additions and 171 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"path-browserify": "^1.0.1",
"portal-vue": "^2.1.7",
"process": "^0.11.10",
"shaka-player": "^4.10.10",
"shaka-player": "^4.10.11",
"swiper": "^11.1.9",
"vue": "^2.7.16",
"vue-i18n": "^8.28.2",
Expand Down
4 changes: 3 additions & 1 deletion src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ const IpcChannels = {
TOGGLE_REPLACE_HTTP_CACHE: 'toggle-replace-http-cache',

PLAYER_CACHE_GET: 'player-cache-get',
PLAYER_CACHE_SET: 'player-cache-set'
PLAYER_CACHE_SET: 'player-cache-set',

SET_INVIDIOUS_AUTHORIZATION: 'set-invidious-authorization'
}

const DBActions = {
Expand Down
88 changes: 69 additions & 19 deletions src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,15 +396,19 @@ function runApp() {
sameSite: 'no_restriction',
})

// make InnerTube requests work with the fetch function
// InnerTube rejects requests if the referer isn't YouTube or empty
const innertubeAndMediaRequestFilter = { urls: ['https://www.youtube.com/youtubei/*', 'https://*.googlevideo.com/videoplayback?*'] }

session.defaultSession.webRequest.onBeforeSendHeaders(innertubeAndMediaRequestFilter, ({ requestHeaders, url }, callback) => {
requestHeaders.Referer = 'https://www.youtube.com/'
requestHeaders.Origin = 'https://www.youtube.com'
const onBeforeSendHeadersRequestFilter = {
urls: ['https://*/*', 'http://*/*'],
types: ['xhr', 'media', 'image']
}
session.defaultSession.webRequest.onBeforeSendHeaders(onBeforeSendHeadersRequestFilter, ({ requestHeaders, url, webContents }, callback) => {
const urlObj = new URL(url)

if (url.startsWith('https://www.youtube.com/youtubei/')) {
// make InnerTube requests work with the fetch function
// InnerTube rejects requests if the referer isn't YouTube or empty
requestHeaders.Referer = 'https://www.youtube.com/'
requestHeaders.Origin = 'https://www.youtube.com'

// Make iOS requests work and look more realistic
if (requestHeaders['x-youtube-client-name'] === '5') {
delete requestHeaders.Referer
Expand All @@ -423,9 +427,18 @@ function runApp() {
requestHeaders['Sec-Fetch-Mode'] = 'same-origin'
requestHeaders['X-Youtube-Bootstrap-Logged-In'] = 'false'
}
} else {
} else if (urlObj.origin.endsWith('.googlevideo.com') && urlObj.pathname === '/videoplayback') {
requestHeaders.Referer = 'https://www.youtube.com/'
requestHeaders.Origin = 'https://www.youtube.com'

// YouTube doesn't send the Content-Type header for the media requests, so we shouldn't either
delete requestHeaders['Content-Type']
} else if (webContents) {
const invidiousAuthorization = invidiousAuthorizations.get(webContents.id)

if (invidiousAuthorization && url.startsWith(invidiousAuthorization.url)) {
requestHeaders.Authorization = invidiousAuthorization.authorization
}
}
// eslint-disable-next-line n/no-callback-literal
callback({ requestHeaders })
Expand All @@ -448,8 +461,10 @@ function runApp() {
const imageCache = new ImageCache()

protocol.handle('imagecache', (request) => {
const [requestUrl, rawWebContentsId] = request.url.split('#')

return new Promise((resolve, reject) => {
const url = decodeURIComponent(request.url.substring(13))
const url = decodeURIComponent(requestUrl.substring(13))
if (imageCache.has(url)) {
const cached = imageCache.get(url)

Expand All @@ -459,9 +474,22 @@ function runApp() {
return
}

let headers

if (rawWebContentsId) {
const invidiousAuthorization = invidiousAuthorizations.get(parseInt(rawWebContentsId))

if (invidiousAuthorization && url.startsWith(invidiousAuthorization.url)) {
headers = {
Authorization: invidiousAuthorization.authorization
}
}
}

const newRequest = net.request({
method: request.method,
url
url,
headers
})

// Electron doesn't allow certain headers to be set:
Expand Down Expand Up @@ -508,19 +536,20 @@ function runApp() {
})
})

const imageRequestFilter = { urls: ['https://*/*', 'http://*/*'] }
const imageRequestFilter = { urls: ['https://*/*', 'http://*/*'], types: ['image'] }
session.defaultSession.webRequest.onBeforeRequest(imageRequestFilter, (details, callback) => {
// the requests made by the imagecache:// handler to fetch the image,
// are allowed through, as their resourceType is 'other'
if (details.resourceType === 'image') {
// eslint-disable-next-line n/no-callback-literal
callback({
redirectURL: `imagecache://${encodeURIComponent(details.url)}`
})
} else {
// eslint-disable-next-line n/no-callback-literal
callback({})

let redirectURL = `imagecache://${encodeURIComponent(details.url)}`

if (details.webContents) {
redirectURL += `#${details.webContents.id}`
}

callback({
redirectURL
})
})

// --- end of `if experimentsDisableDiskCache` ---
Expand Down Expand Up @@ -971,6 +1000,21 @@ function runApp() {
await asyncFs.writeFile(filePath, new Uint8Array(value))
})

/** @type {Map<number, { url: string, authorization: string }>} */
const invidiousAuthorizations = new Map()

ipcMain.on(IpcChannels.SET_INVIDIOUS_AUTHORIZATION, (event, authorization, url) => {
if (!isFreeTubeUrl(event.senderFrame.url)) {
return
}

if (!authorization) {
invidiousAuthorizations.delete(event.sender.id)
} else if (typeof authorization === 'string' && typeof url === 'string') {
invidiousAuthorizations.set(event.sender.id, { authorization, url })
}
})

// ************************************************* //
// DB related IPC calls
// *********** //
Expand Down Expand Up @@ -1419,6 +1463,12 @@ function runApp() {
}
})

app.on('web-contents-created', (_, webContents) => {
webContents.once('destroyed', () => {
invidiousAuthorizations.delete(webContents.id)
})
})

/*
* Check if an argument was passed and send it over to the GUI (Linux / Windows).
* Remove freetube:// protocol if present
Expand Down
6 changes: 3 additions & 3 deletions src/renderer/components/ft-list-channel/ft-list-channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export default defineComponent({
}
},
computed: {
currentInvidiousInstance: function () {
return this.$store.getters.getCurrentInvidiousInstance
currentInvidiousInstanceUrl: function () {
return this.$store.getters.getCurrentInvidiousInstanceUrl
},
listType: function () {
return this.$store.getters.getListType
Expand Down Expand Up @@ -81,7 +81,7 @@ export default defineComponent({
// Can be prefixed with `https://` or `//` (protocol relative)
const thumbnailUrl = this.data.authorThumbnails[2].url

this.thumbnail = youtubeImageUrlToInvidious(thumbnailUrl, this.currentInvidiousInstance)
this.thumbnail = youtubeImageUrlToInvidious(thumbnailUrl, this.currentInvidiousInstanceUrl)

this.channelName = this.data.author
this.id = this.data.authorId
Expand Down
8 changes: 4 additions & 4 deletions src/renderer/components/ft-list-playlist/ft-list-playlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export default defineComponent({
backendPreference: function () {
return this.$store.getters.getBackendPreference
},
currentInvidiousInstance: function () {
return this.$store.getters.getCurrentInvidiousInstance
currentInvidiousInstanceUrl: function () {
return this.$store.getters.getCurrentInvidiousInstanceUrl
},

quickBookmarkPlaylistId() {
Expand Down Expand Up @@ -127,7 +127,7 @@ export default defineComponent({
parseInvidiousData: function () {
this.title = this.data.title
if (this.thumbnailCanBeShown) {
this.thumbnail = this.data.playlistThumbnail.replace('https://i.ytimg.com', this.currentInvidiousInstance).replace('hqdefault', 'mqdefault')
this.thumbnail = this.data.playlistThumbnail.replace('https://i.ytimg.com', this.currentInvidiousInstanceUrl).replace('hqdefault', 'mqdefault')
}
this.channelName = this.data.author
this.channelId = this.data.authorId
Expand Down Expand Up @@ -155,7 +155,7 @@ export default defineComponent({
if (this.thumbnailCanBeShown && this.data.videos.length > 0) {
const thumbnailURL = `https://i.ytimg.com/vi/${this.data.videos[0].videoId}/mqdefault.jpg`
if (this.backendPreference === 'invidious') {
this.thumbnail = thumbnailURL.replace('https://i.ytimg.com', this.currentInvidiousInstance)
this.thumbnail = thumbnailURL.replace('https://i.ytimg.com', this.currentInvidiousInstanceUrl)
} else {
this.thumbnail = thumbnailURL
}
Expand Down
10 changes: 5 additions & 5 deletions src/renderer/components/ft-list-video/ft-list-video.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ export default defineComponent({
return this.$store.getters.getBackendPreference
},

currentInvidiousInstance: function () {
return this.$store.getters.getCurrentInvidiousInstance
currentInvidiousInstanceUrl: function () {
return this.$store.getters.getCurrentInvidiousInstanceUrl
},

showPlaylists: function () {
Expand Down Expand Up @@ -183,7 +183,7 @@ export default defineComponent({
},

invidiousUrl: function () {
let videoUrl = `${this.currentInvidiousInstance}/watch?v=${this.id}`
let videoUrl = `${this.currentInvidiousInstanceUrl}/watch?v=${this.id}`
// `playlistId` can be undefined
if (this.playlistSharable) {
// `index` seems can be ignored
Expand All @@ -193,7 +193,7 @@ export default defineComponent({
},

invidiousChannelUrl: function () {
return `${this.currentInvidiousInstance}/channel/${this.channelId}`
return `${this.currentInvidiousInstanceUrl}/channel/${this.channelId}`
},

youtubeUrl: function () {
Expand Down Expand Up @@ -339,7 +339,7 @@ export default defineComponent({

let baseUrl
if (this.backendPreference === 'invidious') {
baseUrl = this.currentInvidiousInstance
baseUrl = this.currentInvidiousInstanceUrl
} else {
baseUrl = 'https://i.ytimg.com'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export default defineComponent({
backendPreference: function () {
return this.$store.getters.getBackendPreference
},
currentInvidiousInstance: function () {
return this.$store.getters.getCurrentInvidiousInstance
currentInvidiousInstanceUrl: function () {
return this.$store.getters.getCurrentInvidiousInstanceUrl
},
toBeAddedToPlaylistVideoList: function () {
return this.$store.getters.getToBeAddedToPlaylistVideoList
Expand Down Expand Up @@ -129,7 +129,7 @@ export default defineComponent({
if (this.playlist.videos.length > 0) {
const thumbnailURL = `https://i.ytimg.com/vi/${this.playlist.videos[0].videoId}/mqdefault.jpg`
if (this.backendPreference === 'invidious') {
this.thumbnail = thumbnailURL.replace('https://i.ytimg.com', this.currentInvidiousInstance)
this.thumbnail = thumbnailURL.replace('https://i.ytimg.com', this.currentInvidiousInstanceUrl)
} else {
this.thumbnail = thumbnailURL
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export default defineComponent({
backendPreference: function () {
return this.$store.getters.getBackendPreference
},
currentInvidiousInstance: function () {
return this.$store.getters.getCurrentInvidiousInstance
currentInvidiousInstanceUrl: function () {
return this.$store.getters.getCurrentInvidiousInstanceUrl
},
profileList: function () {
return this.$store.getters.getProfileList
Expand Down Expand Up @@ -76,7 +76,7 @@ export default defineComponent({
})
subscriptions.forEach((channel) => {
if (this.backendPreference === 'invidious') {
channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, this.currentInvidiousInstance)
channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, this.currentInvidiousInstanceUrl)
}
channel.selected = false
})
Expand All @@ -92,7 +92,7 @@ export default defineComponent({
})
subscriptions.forEach((channel) => {
if (this.backendPreference === 'invidious') {
channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, this.currentInvidiousInstance)
channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, this.currentInvidiousInstanceUrl)
}
channel.selected = false
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export default defineComponent({
backendPreference: function () {
return this.$store.getters.getBackendPreference
},
currentInvidiousInstance: function () {
return this.$store.getters.getCurrentInvidiousInstance
currentInvidiousInstanceUrl: function () {
return this.$store.getters.getCurrentInvidiousInstanceUrl
},
profileList: function () {
return this.$store.getters.getProfileList
Expand Down Expand Up @@ -71,7 +71,7 @@ export default defineComponent({
return index === -1
}).map((channel) => {
if (this.backendPreference === 'invidious') {
channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, this.currentInvidiousInstance)
channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, this.currentInvidiousInstanceUrl)
}
channel.selected = false
return channel
Expand All @@ -92,7 +92,7 @@ export default defineComponent({
return index === -1
}).map((channel) => {
if (this.backendPreference === 'invidious') {
channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, this.currentInvidiousInstance)
channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, this.currentInvidiousInstanceUrl)
}
channel.selected = false
return channel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1434,18 +1434,33 @@ export default defineComponent({

stats.bitrate = (newTrack.bandwidth / 1000).toFixed(2)

// for videos with multiple audio tracks, youtube.js appends the track id to the itag, to make it unique
stats.codecs.audioItag = newTrack.originalAudioId.split('-')[0]
stats.codecs.audioCodec = newTrack.audioCodec
// Combined audio and video HLS streams
if (newTrack.videoCodec.includes(',')) {
stats.codecs.audioItag = ''
stats.codecs.videoItag = ''

if (props.format === 'dash') {
stats.resolution.frameRate = newTrack.frameRate
const [audioCodec, videoCodec] = newTrack.videoCodec.split(',')

stats.codecs.videoItag = newTrack.originalVideoId
stats.codecs.videoCodec = newTrack.videoCodec
stats.codecs.audioCodec = audioCodec
stats.codecs.videoCodec = videoCodec

stats.resolution.frameRate = newTrack.frameRate
stats.resolution.width = newTrack.width
stats.resolution.height = newTrack.height
} else {
// for videos with multiple audio tracks, youtube.js appends the track id to the itag, to make it unique
stats.codecs.audioItag = newTrack.originalAudioId.split('-')[0]
stats.codecs.audioCodec = newTrack.audioCodec

if (props.format === 'dash') {
stats.resolution.frameRate = newTrack.frameRate

stats.codecs.videoItag = newTrack.originalVideoId
stats.codecs.videoCodec = newTrack.videoCodec

stats.resolution.width = newTrack.width
stats.resolution.height = newTrack.height
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@
v-if="format === 'audio'"
>{{ $t('Video.Player.Stats.CodecAudio', stats.codecs) }}</span>
<span
v-else
v-else-if="stats.codecs.audioItag && stats.codecs.videoItag"
>{{ $t('Video.Player.Stats.CodecsVideoAudio', stats.codecs) }}</span>
<span
v-else
>{{ $t('Video.Player.Stats.CodecsVideoAudioNoItags', stats.codecs) }}</span>
<br>
<span>{{ $t('Video.Player.Stats.Player Dimensions', stats.playerDimensions) }}</span>
<br>
Expand Down
Loading

0 comments on commit 863c4eb

Please sign in to comment.