Skip to content

Commit

Permalink
hls: use brower lang for audio and subtitle
Browse files Browse the repository at this point in the history
  • Loading branch information
shiyiya committed Aug 26, 2024
1 parent 2c9d7eb commit d0953b5
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 136 deletions.
10 changes: 9 additions & 1 deletion examples/standalone/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ const player = Player.make<Ctx>('#player', {
}
}),
torrent(),
hls({ forceHLS: true, defaultQuality: 1080 }),
hls({ forceHLS: true }),
dash(),
mpegts(),
danmaku({
Expand All @@ -144,6 +144,14 @@ const player = Player.make<Ctx>('#player', {
new Playlist({
initialIndex: 0,
sources: [
{
title: 'hls - muti quality & subtitle & audio',
src: 'https://storage.googleapis.com/shaka-demo-assets/angel-one-hls/hls.m3u8'
},
{
title: 'dash - muti quality & subtitle & audio',
src: 'https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd'
},
{
title: 'HLS with SRT subtitle',
src: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default class I18n {
return false
})
}
if (!this.languages[this.lang]) this.lang = 'zh-CN'
if (!this.languages[this.lang]) this.lang = 'en'
}

get(key: string, ...arg: Array<string | number>): string {
Expand Down
26 changes: 13 additions & 13 deletions packages/danmaku/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ export default (options = {} as Options): PlayerPlugin => ({

if (opacity) $danmaku.style.opacity = `${opacity}`
if (options.enable == undefined) options.enable = true
let heatmapEnable = options.heatmap == undefined || options.heatmap || heatmap.length
let heatmapEnable = options.heatmap == undefined || options.heatmap

let loaded = false
const danmaku: DanmakuContext = new Danmaku({
container: $danmaku,
media: player.$video,
engine: engine,
comments: [],
speed: isMobile ? speed / 1.5 : speed
speed: isMobile ? speed / 1.5 : speed,
}) as any

danmaku.setFontSize = function setFontSize(value: number) {
Expand Down Expand Up @@ -139,7 +139,7 @@ export default (options = {} as Options): PlayerPlugin => ({
} else {
danmaku.hide()
}
}
},
},
{
name: player.locales.get('Heatmap'),
Expand All @@ -149,7 +149,7 @@ export default (options = {} as Options): PlayerPlugin => ({
onChange: (value: Boolean) => {
if (value) danmaku.heatmap?.enable()
else danmaku.heatmap?.disable()
}
},
},
{
type: 'selector',
Expand All @@ -158,12 +158,12 @@ export default (options = {} as Options): PlayerPlugin => ({
children: [0.5, 0.75, 1, 1.25].map((it) => ({
name: `${it * 100}%`,
value: it,
default: it == 1
default: it == 1,
})),
onChange: ({ value }: any) => {
options.fontSize = value
danmaku.setFontSize(value)
}
},
},
{
type: 'selector',
Expand All @@ -172,11 +172,11 @@ export default (options = {} as Options): PlayerPlugin => ({
children: [0.3, 0.5, 0.8, 1].map((it) => ({
name: `${it * 100}%`,
value: it,
default: it == (options?.opacity || 1)
default: it == (options?.opacity || 1),
})),
onChange: ({ value }: any) => {
$danmaku.style.opacity = value
}
},
},
{
type: 'selector',
Expand All @@ -185,15 +185,15 @@ export default (options = {} as Options): PlayerPlugin => ({
children: [25, 50, 80, 100].map((it) => ({
name: `${it}%`,
value: it,
default: it == area * 100
default: it == area * 100,
})),
onChange: ({ value }: any) => {
options.opacity = value
$danmaku.style.height = `${value}%`
danmaku.resize()
}
}
]
},
},
],
})
}

Expand All @@ -202,5 +202,5 @@ export default (options = {} as Options): PlayerPlugin => ({
if (displaySender && !isMobile) registerInput(player, danmaku, options)

return danmaku
}
},
})
50 changes: 0 additions & 50 deletions packages/hls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,56 +38,6 @@ npm i @oplayer/core @oplayer/hls hls.js
</script>
```

## Usage

```ts
export type Matcher = (video: HTMLVideoElement, source: Source, forceHLS: boolean) => boolean

// active inactive
export type Active = (
instance: Hls,
library: typeof import('hls.js/dist/hls.min.js')
) => void | ((instance: Hls, library: typeof import('hls.js/dist/hls.min.js')) => void)

export interface HlsPluginOptions {
matcher?: Matcher
/**
* config for hls.js
*
* @type {Partial<HlsConfig>}
*/
config?: Partial<HlsConfig>
/**
* force use hls.js
* @type {boolean} false
*/
forceHLS?: boolean
/**
* enable quality control for the HLS stream, does not apply to the native (iPhone) clients.
* default: true
*/
qualityControl?: boolean
/**
* control how the stream quality is switched. default: immediate
* @value immediate: Trigger an immediate quality level switch to new quality level. This will abort the current fragment request if any, flush the whole buffer, and fetch fragment matching with current position and requested quality level.
* @value smooth: Trigger a quality level switch for next fragment. This could eventually flush already buffered next fragment.
*/
qualitySwitch?: 'immediate' | 'smooth'
/**
* @default: false
*/
withBitrate?: boolean
/**
* @default: true
*/
audioControl?: boolean
/**
* @default: true
*/
textControl?: boolean
}
```

## Handle Hls.js Error

```ts
Expand Down
2 changes: 1 addition & 1 deletion packages/hls/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@oplayer/hls",
"version": "1.2.27-beta.0",
"version": "1.2.27-beta.1",
"description": "Hls plugin for oplayer",
"type": "module",
"main": "./dist/index.es.js",
Expand Down
131 changes: 76 additions & 55 deletions packages/hls/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { loadSDK, type Player, type PlayerPlugin, type RequiredPartial, type Source } from '@oplayer/core'
import type Hls from 'hls.js'
import type { ErrorData, HlsConfig, LevelSwitchedData } from 'hls.js'
import type { ErrorData, HlsConfig, LevelSwitchedData, Level, MediaPlaylist } from 'hls.js'

const PLUGIN_NAME = 'oplayer-plugin-hls'

Expand All @@ -12,10 +12,19 @@ export interface HlsPluginOptions {
matcher?: Matcher

/**
* -1 : auto
* default auto
*/
defaultQuality?: number
defaultQuality?: (levels: Level[]) => number

/**
* default browser language
*/
defaultAudio?: (tracks: MediaPlaylist[]) => number

/**
* default browser language
*/
defaultSubtitle?: (tracks: MediaPlaylist[]) => number

/**
* custom handle hls fatal error
Expand Down Expand Up @@ -91,7 +100,9 @@ class HlsPlugin implements PlayerPlugin {
withBitrate: false,
qualitySwitch: 'immediate',
matcher: defaultMatcher,
defaultQuality: -1
defaultQuality: () => -1,
defaultAudio: () => -1,
defaultSubtitle: () => -1
}

constructor(options?: HlsPluginOptions) {
Expand Down Expand Up @@ -192,35 +203,30 @@ const generateSetting = (player: Player, instance: Hls, options: HlsPlugin['opti
const ui = player.context.ui
if (options.qualityControl) {
instance.once(HlsPlugin.library.Events.LEVEL_LOADED, () => {
let defaultSelect = options.defaultQuality
if (instance.levels.length < 1) return
const defaultLevel = options.defaultQuality(instance.levels)
if (defaultLevel != -1) instance.currentLevel = defaultLevel

injectSetting({
icon: ui.icons.quality,
name: 'Quality',
settings() {
if (instance.levels.length > 1) {
return instance.levels.reduce(
(pre, level, i) => {
let name = (level.name || level.height).toString()
if (isFinite(+name)) name += 'p'
if (options.withBitrate) {
const kb = level.bitrate / 1000
const useMb = kb > 1000
const number = useMb ? (kb / 1000).toFixed(2) : Math.floor(kb)
name += ` (${number}${useMb ? 'm' : 'k'}bps)`
}

if (level.height <= options.defaultQuality) {
defaultSelect = i
}

pre.push({ name, default: instance.currentLevel == i, value: i })
return pre
},
[{ name: player.locales.get('Auto'), default: instance.autoLevelEnabled, value: -1 }]
)
}
return []
return instance.levels.reduce(
(pre, level) => {
let name = (level.name || level.height).toString()
if (isFinite(+name)) name += 'p'
if (options.withBitrate) {
const kb = level.bitrate / 1000
const useMb = kb > 1000
const number = useMb ? (kb / 1000).toFixed(2) : Math.floor(kb)
name += ` (${number}${useMb ? 'm' : 'k'}bps)`
}

pre.push({ name, default: defaultLevel == level.id, value: level.id })
return pre
},
[{ name: player.locales.get('Auto'), default: instance.autoLevelEnabled, value: -1 }]
)
},
onChange(it) {
if (options.qualitySwitch == 'immediate') {
Expand All @@ -232,8 +238,6 @@ const generateSetting = (player: Player, instance: Hls, options: HlsPlugin['opti
}
}
})

if (defaultSelect != -1) instance.currentLevel = defaultSelect
})

instance.on(
Expand All @@ -250,47 +254,64 @@ const generateSetting = (player: Player, instance: Hls, options: HlsPlugin['opti
)
}

if (options.audioControl)
instance.on(HlsPlugin.library.Events.LEVEL_LOADED, () => {
if (options.audioControl) {
instance.once(HlsPlugin.library.Events.LEVEL_LOADED, () => {
if (instance.audioTracks.length < 1) return

let defaultAudio: number | undefined = options.defaultAudio(instance.audioTracks)
if (defaultAudio == -1) {
defaultAudio = instance.audioTracks.find(({ lang }) => {
return lang === navigator.language || lang === navigator.language.split('-')[0]
})?.id
}

if (defaultAudio != -1 && defaultAudio != undefined) instance.audioTrack = defaultAudio

injectSetting({
icon: ui.icons.lang,
name: 'Language',
settings() {
if (instance.audioTracks.length > 1) {
return instance.audioTracks.map(({ name, lang, id }) => ({
name: lang || name,
default: instance.audioTrack == id,
value: id
}))
}
return []
return instance.audioTracks.map(({ name, lang, id }) => ({
name: lang || name,
default: defaultAudio == id,
value: id
}))
},
onChange(it) {
instance.audioTrack = it.value
}
})
})
}

if (options.textControl)
instance.on(HlsPlugin.library.Events.SUBTITLE_TRACK_LOADED, () => {
instance.once(HlsPlugin.library.Events.SUBTITLE_TRACK_LOADED, () => {
if (instance.subtitleTracks.length < 1) return

let defaultSubtitle: number | undefined = options.defaultSubtitle(instance.subtitleTracks)
if (defaultSubtitle == -1) {
defaultSubtitle = instance.audioTracks.find(({ lang }) => {
return lang === navigator.language || lang === navigator.language.split('-')[0]
})?.id
}

if (defaultSubtitle != -1 && defaultSubtitle != undefined) instance.subtitleTrack = defaultSubtitle

injectSetting({
icon: ui.icons.subtitle,
name: 'Subtitle',
settings() {
if (instance.subtitleTracks.length > 1) {
return instance.subtitleTracks.reduce(
(pre, { name, lang, id }) => {
pre.push({
name: lang || name,
default: instance.subtitleTrack == id,
value: id
})
return pre
},
[{ name: player.locales.get('Off'), default: !instance.subtitleDisplay, value: -1 }]
)
}
return []
return instance.subtitleTracks.reduce(
(pre, { name, lang, id }) => {
pre.push({
name: lang || name,
default: defaultSubtitle == id,
value: id
})
return pre
},
[{ name: player.locales.get('Off'), default: !instance.subtitleDisplay, value: -1 }]
)
},
onChange({ value }) {
if ((instance.subtitleDisplay = !(value == -1))) {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@oplayer/ui",
"version": "1.3.3-beta.6",
"version": "1.3.3-beta.7",
"description": "ui plugin for oplayer",
"type": "module",
"main": "./dist/index.es.js",
Expand Down
Loading

0 comments on commit d0953b5

Please sign in to comment.