OPlayer UI
Install
npm i @oplayer/ui
<!-- Recommend -->
<script src="https://cdn.jsdelivr.net/npm/@oplayer/core@latest/dist/index.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@oplayer/ui@latest/dist/index.min.js"></script>
<!-- or just one **@oplayer/ui version updated with core** -->
<!-- <script src="https://cdn.jsdelivr.net/npm/@oplayer/core@latest/dist/index.ui.js"></script> -->
<!-- or **@oplayer/core version updated with ui** -->
<!-- <script src="https://cdn.jsdelivr.net/npm/@oplayer/ui@latest/dist/index.ui.js"></script> -->
Basic
const player = OPlayer.make('#player', {
source: {
title: '君の名は',
src: 'https://oplayer.vercel.app/君の名は.mp4',
poster: 'https://cdn.jsdelivr.net/gh/shiyiya/QI-ABSL@master/o/poster.png'
}
})
.use([OUI()])
.create()
Thumbnails
// single
thumbnails = {
number: 100,
src: 'https://cdn.jsdelivr.net/gh/shiyiya/QI-ABSL@master/o/thumbnails.jpg'
}
// multipe & grid
thumbnails = {
src: ['1.jpg', '2,jpg'],
x: 10,
y: 10,
number: 192
}
Subtitle
OUI({
subtitle: {
source: [
{
name: 'en',
src: 'your-subtitle-file-path',
default: localStorage.getItem('pre-subtitle') == 'your-subtitle-file-path'
},
{
name: 'en-us',
src: 'your-subtitle-file-path',
default: localStorage.getItem('pre-subtitle') == 'your-subtitle-file-path'
}
],
offset: 0, // delay any seconds
onChange(source) {
// persistedstate
localStorage.setItem('pre-subtitle', source.src)
if (source.src == 'abc') {
// or custom fetch
return yourFetch(`https://abc.com/subtile/${source.src}`, { mode: 'cors' })
}
}
}
})
How to display title ?
const player = OPlayer.make('#player', {
source: {
title: '君の名は' // required
// ...
}
})
.use([OUI({ theme: { controller: { header: true /* required */ } } })])
.create()
Add custom menu
{
menu: [
{
name: 'Quality(清晰度)',
key: 'Quality', // for select
position: 'bottom', // or top
children: [
{
name: 'FHD',
default: true,
value: 'https://oplayer.vercel.app/君の名は.mp4'
},
{
name: 'HD',
value: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8'
},
{
name: 'SD',
value: 'https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd'
}
],
onChange({ value }) {
player.changeQuality({ src: value })
}
}
]
}
//or
player.context.menu.register([])
Add custom setting
{
settings: [
'loop', // Build-in
'speed', // Build-in
{
// Custom
key: 'KEY',
type: 'selector', // or 'switcher'
name: 'name',
icon: 'icon',
children: [
{ name: 'a', value: 'a', default: true },
{ name: 'b', value: 'b', default: false }
],
onChange: ({ value }) => {
// do something
}
}
]
}
//or
player.context.menu.register([])
Highlight
{
highlight: {
color: '#fff', //default
source: [
{ time: 12, text: '谁でもいいはずなのに' },
{ time: 34, text: '夏の想い出がまわる' },
{ time: 58, text: 'こんなとこにあるはずもないのに' },
{ time: 88, text: '--终わり--' }
]
}
}
Methods
All methods on player.context.ui
// - Update subtitle
player.context.ui.subtitle.changeSource([])
// - Update highlight
player.context.ui.changHighlightSource([])
// - Update thumbnails
player.context.ui.changThumbnails('src')
// - Register menu
player.context.ui.menu.register({})
player.context.ui.menu.unregister('key')
player.context.ui.menu.select('key', 'index')
// - Register setting
player.context.ui.setting.register({})
player.context.ui.setting.unregister('key')
player.context.ui.setting.updateLabel('key', 'text')
player.context.ui.setting.select('key', 'index')
// - Display error,notice
player.emit('error', { message: 'msg', code: 'number' })
player.context.ui.notice('hello')
keyboard
↑
volume +10%↓
volume -10%←
seek -5s→
seek +5sspace
|enter
play or pauses
catch a screenshotf
toggle full-screenw
toggle full-screen webm
toggle mutec
toggle setting panel
watermark
const ui = OUI({
theme: {
watermark: {
src: '/your/path/logo.jpg',
style: {
position: 'absolute',
// want make screenshot include watermark?
// set positioning here, not css. [top, left, right, bottom]
top: '10px',
right: '10px',
width: '200px',
height: 'auto'
},
attrs: {
class: 'watermark'
// crossOrigin: 'anonymous'
// etc.
}
}
}
})
Add next,previous button
Events
type UIEventName = 'controlsshown' | 'controlshidden' | 'backward' | 'previous' | 'next'