Match locales in a better way and port support from Piped for multilingual videos

This commit is contained in:
root
2022-11-27 00:28:56 +05:30
parent d1de8ea282
commit e91ec77bb9
6 changed files with 86 additions and 46 deletions
+1
View File
@@ -17,6 +17,7 @@
"@fontsource/noto-sans-tc": "^4.5.11",
"@fontsource/nunito-sans": "^4.5.9",
"@fontsource/roboto": "^4.5.8",
"@formatjs/intl-localematcher": "^0.2.31",
"@mdi/js": "^6.9.96",
"antar-hinted": "https://bafybeifmuaik6ozj65yoy443khijb6d5pqkmi4dwgykfzfvymtvc57mo6i.ipfs.cf-ipfs.com/?filename=hinted-antar-web.tar",
"axios": "^0.27.2",
+30 -8
View File
@@ -15,9 +15,9 @@
</template>
<script>
import muxjs from 'mux.js'
import shaka from 'shaka-player/dist/shaka-player.ui.js'
import 'shaka-player/dist/controls.css'
import * as LocaleMatcher from '@formatjs/intl-localematcher'
import { DashUtils } from '@/tools/DashUtils'
import '@/components/Player.scss'
@@ -28,7 +28,11 @@ import '@fontsource/roboto/latin.css'
import { setupKeybindings } from 'psychic-tiny-keys'
window.muxjs = muxjs
if (!window.muxjs) {
import('mux.js').then(m => {
window.muxjs = m
})
}
export default {
props: {
@@ -142,8 +146,7 @@ export default {
const url = new URL(uri)
const headers = request.headers
if (
url.host.endsWith('.googlevideo.com') ||
(url.host.endsWith('.lbryplayer.xyz') && (this.$store.getters['prefs/getPreferenceBoolean']('proxyLBRY', true) || headers.Range))
url.host.endsWith('.googlevideo.com') || (url.host.endsWith('.lbryplayer.xyz') && (this.$store.getters['prefs/getPreferenceBoolean']('proxyLBRY', true) || headers.Range))
) {
url.searchParams.set('host', url.host)
url.host = proxyHost
@@ -215,8 +218,17 @@ export default {
this.destroy()
this.$ui = new shaka.ui.Overlay(localPlayer, this.$refs.container, videoEl)
const overflowMenuButtons = [
'quality',
'language',
'captions',
'picture_in_picture',
'playback_rate',
'airplay'
]
const config = {
overflowMenuButtons: ['quality', 'captions', 'picture_in_picture', 'playback_rate'],
overflowMenuButtons,
seekBarColors: {
base: 'rgba(255, 255, 255, 0.3)',
buffered: 'rgba(255, 255, 255, 0.54)',
@@ -250,21 +262,31 @@ export default {
if (qualityConds) this.$player.configure('abr.enabled', false)
player.load(uri, 0, mime).then(() => {
let bestFitLanguage
{
const langs = player.getAudioLanguages()
bestFitLanguage = LocaleMatcher.match([this.$i18n.locale], langs, 'en')
player.selectAudioLanguage(bestFitLanguage)
}
if (qualityConds) {
let leastDiff = Number.MAX_VALUE
let bestStream = null
let bestAudio = 0
const tracks = player
.getVariantTracks()
.filter(track => track.language === bestFitLanguage || track.language === 'und')
// Choose the best audio stream
if (quality >= 480) {
player.getVariantTracks().forEach(track => {
tracks.forEach(track => {
const audioBandwidth = track.audioBandwidth
if (audioBandwidth > bestAudio) bestAudio = audioBandwidth
})
}
player
.getVariantTracks()
tracks
.sort((a, b) => a.bandwidth - b.bandwidth)
.forEach(stream => {
if (stream.audioBandwidth < bestAudio) return
@@ -44,6 +44,9 @@ export default {
},
methods: {
async loadPlaylists () {
if (!this.$store.getters['auth/isCurrentlyAuthenticated']) {
return
}
this.playlistItems = (await this.$store.dispatch('auth/makeRequest', {
method: 'GET',
path: '/user/playlists'
+2 -9
View File
@@ -1,6 +1,7 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import TimeAgo from 'javascript-time-ago'
import * as LocaleMatcher from '@formatjs/intl-localematcher'
import store from '@/store'
import ENTranslations from '@/translations/en.json'
@@ -164,15 +165,7 @@ export async function changeLocale (lang) {
function initializeLocalLocale () {
let lang = window.localStorage.getItem('LOCALE')
if (lang == null) {
for (const possible of navigator.languages) {
if (SUPPORTED_LANGUAGES.includes(possible)) {
lang = possible
break
}
}
if (lang == null) {
lang = 'en'
}
lang = LocaleMatcher.match(navigator.languages, SUPPORTED_LANGUAGES, 'en')
}
return changeLocale(lang)
}
+42 -28
View File
@@ -1,11 +1,11 @@
// Based of https://github.com/GilgusMaximus/yt-dash-manifest-generator/blob/master/src/DashGenerator.js
import xml from 'xml-js'
import { json2xml } from 'xml-js'
const DashUtils = {
generate_dash_file_from_formats (VideoFormats, VideoLength) {
const generatedJSON = this.generate_xmljs_json_from_data(VideoFormats, VideoLength)
return xml.json2xml(generatedJSON)
return json2xml(generatedJSON)
},
generate_xmljs_json_from_data (VideoFormatArray, VideoLength) {
return {
@@ -39,55 +39,69 @@ const DashUtils = {
},
generate_adaptation_set (VideoFormatArray) {
const adaptationSets = []
const mimeTypes = []
const mimeObjects = [[]]
// sort the formats by mime types
const mimeAudioObjs = []
VideoFormatArray.forEach(videoFormat => {
// the dual formats should not be used
if (videoFormat.mimeType.indexOf('video') !== -1 && !videoFormat.videoOnly) {
return
}
// if these properties are not available, then we skip it because we cannot set these properties
// if (!(videoFormat.hasOwnProperty('initRange') && videoFormat.hasOwnProperty('indexRange'))) {
// return
// }
const audioTrackId = videoFormat.audioTrackId
const mimeType = videoFormat.mimeType
const mimeTypeIndex = mimeTypes.indexOf(mimeType)
if (mimeTypeIndex > -1) {
mimeObjects[mimeTypeIndex].push(videoFormat)
} else {
mimeTypes.push(mimeType)
mimeObjects.push([])
mimeObjects[mimeTypes.length - 1].push(videoFormat)
for (let i = 0; i < mimeAudioObjs.length; i++) {
const mimeAudioObj = mimeAudioObjs[i]
if (mimeAudioObj.audioTrackId === audioTrackId && mimeAudioObj.mimeType === mimeType) {
mimeAudioObj.videoFormats.push(videoFormat)
return
}
}
mimeAudioObjs.push({
audioTrackId,
mimeType,
videoFormats: [videoFormat]
})
})
// for each MimeType generate a new Adaptation set with Representations as sub elements
for (let i = 0; i < mimeTypes.length; i++) {
let isVideoFormat = false
mimeAudioObjs.forEach(mimeAudioObj => {
const adapSet = {
type: 'element',
name: 'AdaptationSet',
attributes: {
id: i,
mimeType: mimeTypes[i],
id: mimeAudioObj.audioTrackId,
lang: mimeAudioObj.audioTrackId?.substr(0, 2),
mimeType: mimeAudioObj.mimeType,
startWithSAP: '1',
subsegmentAlignment: 'true'
},
elements: []
}
if (!mimeTypes[i].includes('audio')) {
adapSet.attributes.scanType = 'progressive'
let isVideoFormat = false
if (mimeAudioObj.mimeType.includes('video')) {
isVideoFormat = true
}
mimeObjects[i].forEach(format => {
if (isVideoFormat) {
adapSet.attributes.scanType = 'progressive'
}
for (let i = 0; i < mimeAudioObj.videoFormats.length; i++) {
const videoFormat = mimeAudioObj.videoFormats[i]
if (isVideoFormat) {
adapSet.elements.push(this.generate_representation_video(format))
adapSet.elements.push(this.generate_representation_video(videoFormat))
} else {
adapSet.elements.push(this.generate_representation_audio(format))
adapSet.elements.push(this.generate_representation_audio(videoFormat))
}
})
}
adaptationSets.push(adapSet)
}
})
return adaptationSets
},
generate_representation_audio (Format) {
+8 -1
View File
@@ -1033,6 +1033,13 @@
resolved "https://registry.yarnpkg.com/@fontsource/roboto/-/roboto-4.5.8.tgz#56347764786079838faf43f0eeda22dd7328437f"
integrity sha512-CnD7zLItIzt86q4Sj3kZUiLcBk1dSk81qcqgMGaZe7SQ1P8hFNxhMl5AZthK1zrDM5m74VVhaOpuMGIL4gagaA==
"@formatjs/intl-localematcher@^0.2.31":
version "0.2.31"
resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.31.tgz#aada2b1e58211460cedba56889e3c489117eb6eb"
integrity sha512-9QTjdSBpQ7wHShZgsNzNig5qT3rCPvmZogS/wXZzKotns5skbXgs0I7J8cuN0PPqXyynvNVuN+iOKhNS2eb+ZA==
dependencies:
tslib "2.4.0"
"@hapi/hoek@^9.0.0":
version "9.3.0"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
@@ -6699,7 +6706,7 @@ tsconfig-paths@^3.14.1:
minimist "^1.2.6"
strip-bom "^3.0.0"
tslib@^2.0.3, tslib@^2.1.0:
tslib@2.4.0, tslib@^2.0.3, tslib@^2.1.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==