Merge branch 'main' of git.opencomputing.cn:yumoqing/bricks
This commit is contained in:
commit
30b9040c63
47516
3parties/dash.all.min.js
vendored
47516
3parties/dash.all.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,7 +1,7 @@
|
||||
SOURCES=" page_data_loader.js factory.js uitypesdef.js utils.js uitype.js \
|
||||
i18n.js widget.js layout.js bricks.js image.js html.js splitter.js \
|
||||
jsoncall.js myoperator.js scroll.js menu.js popup.js camera.js modal.js running.js \
|
||||
markdown_viewer.js video.js audio.js toolbar.js tab.js \
|
||||
markdown_viewer.js audio.js toolbar.js tab.js \
|
||||
input.js registerfunction.js button.js accordion.js dataviewer.js \
|
||||
tree.js multiple_state_image.js dynamiccolumn.js form.js message.js conform.js \
|
||||
paging.js datagrid.js iframe.js cols.js echartsext.js \
|
||||
@ -10,7 +10,7 @@ SOURCES=" page_data_loader.js factory.js uitypesdef.js utils.js uitype.js \
|
||||
llm_dialog.js llm.js websocket.js datarow.js tabular.js continueaudio.js \
|
||||
line.js pie.js bar.js gobang.js period.js iconbarpage.js \
|
||||
keypress.js asr.js webspeech.js countdown.js progressbar.js \
|
||||
qaframe.js svg.js "
|
||||
qaframe.js svg.js videoplayer.js "
|
||||
echo ${SOURCES}
|
||||
cat ${SOURCES} > ../dist/bricks.js
|
||||
# uglifyjs --compress --mangle -- ../dist/bricks.js > ../dist/bricks.min.js
|
||||
|
||||
@ -515,3 +515,71 @@ hr {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.video-container {
|
||||
position: relative;
|
||||
width: 80%;
|
||||
max-width: 1000px;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.video-element {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.controls {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
padding: 10px 15px;
|
||||
transition: opacity 0.3s;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.controls:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
accent-color: #ff0000;
|
||||
}
|
||||
|
||||
.controls-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.play-pause, .mute, .fullscreen {
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.volume, .playback-speed, .audio-track-select {
|
||||
font-size: 14px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.fullscreen {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@ -34,6 +34,8 @@
|
||||
--->
|
||||
|
||||
<script src="{{entire_url('/bricks/3parties/recorder.wav.min.js')}}"></script>
|
||||
<script src="https://sage.opencomputing.cn/bricks/3parties/hls.js"></script>
|
||||
<script src="https://sage.opencomputing.cn/bricks/3parties/dash.all.min.js"></script>
|
||||
<script src="{{entire_url('/bricks/bricks.js')}}"></script>
|
||||
<script src="{{entire_url('/js/myapp.js')}}"></script>
|
||||
<script>
|
||||
|
||||
@ -289,17 +289,29 @@ bricks.Tree = class extends bricks.VScrollPanel {
|
||||
this.update_node();
|
||||
break;
|
||||
default:
|
||||
if ((opts.selected_data || opts.checked_data) && ! this.selected_node){
|
||||
if (opts.selected_data && ! this.selected_node){
|
||||
var w = new bricks.Error({title:'Error', message:'No selected node found'});
|
||||
w.open();
|
||||
return;
|
||||
}
|
||||
console.log('opts=', opts);
|
||||
var d = null;
|
||||
if (opts.checked_data){
|
||||
d = this.checked_data
|
||||
} else if (opts.selected_data){
|
||||
d = this.selected_node.user_data
|
||||
if (opts.checked_data && ! this.checked_data){
|
||||
var w = new bricks.Error({title:'Error', message:'No checked node found'});
|
||||
w.open();
|
||||
return;
|
||||
}
|
||||
var d = {};
|
||||
if (opts.selected_data){
|
||||
d = this.selected_node.user_data;
|
||||
} else if (opts.checked_data){
|
||||
d = this.checked_data;
|
||||
} else {
|
||||
if (this.selected_node){
|
||||
d = this.selected_node.user_data;
|
||||
} else if (this.checked_data) {
|
||||
d = this.checked_data;
|
||||
} else {
|
||||
d = this.opts.params;
|
||||
}
|
||||
}
|
||||
d.meta_data = {
|
||||
referer: this.id,
|
||||
|
||||
@ -702,6 +702,30 @@ function blobToBase64(blob) {
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
/*
|
||||
opts = {
|
||||
css:
|
||||
id
|
||||
}
|
||||
*/
|
||||
bricks.dom_create = function(tag, opts){
|
||||
var e = document.createElement(tag);
|
||||
if (opts.css){
|
||||
var arr = css.split(' ');
|
||||
arr.forEach(c =>{
|
||||
e.classList.add(c);
|
||||
});
|
||||
}
|
||||
if (opts.id){
|
||||
e.id = opts.id;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
bricks.element_from_html = function(html){
|
||||
var e = document.createElement('div');
|
||||
e.outerHTML = html;
|
||||
return e;
|
||||
}
|
||||
/*
|
||||
// 使用队列
|
||||
const queue = new Queue();
|
||||
|
||||
@ -1,230 +1,68 @@
|
||||
|
||||
var bricks = window.bricks || {}
|
||||
/*
|
||||
use hls to play m3u8
|
||||
https://cdn.jsdelivr.net/npm/hls.js@latest
|
||||
use dash to play dash
|
||||
https://cdn.dashjs.org/latest/dash.all.min.js
|
||||
https://cdn.dashjs.org/latest/dash.all.min.js
|
||||
*/
|
||||
|
||||
bricks VideoPlayer = class extends bricks.VBox {
|
||||
bricks.VideoPlayer = class extends bricks.VBox {
|
||||
/*
|
||||
opts:
|
||||
url: video source
|
||||
autoplay:true or false
|
||||
*/
|
||||
constructor(opts) {
|
||||
super(opts)
|
||||
this.video = videoElement;
|
||||
this.set_css('video-container');
|
||||
this.dom_element.innerHTML = `<video id="video" class="video-element"></video>
|
||||
<div class="controls">
|
||||
<div class="progress-container">
|
||||
<input type="range" class="progress-bar" value="0" step="0.0001" />
|
||||
</div>
|
||||
<div class="controls-bottom">
|
||||
<button class="play-pause">▶</button>
|
||||
<div class="volume-container">
|
||||
<button class="mute">🔊</button>
|
||||
<input type="range" class="volume" min="0" max="1" step="0.01" value="1" />
|
||||
</div>
|
||||
<span class="time">00:00 / 00:00</span>
|
||||
<div class="speed-container">
|
||||
<select class="playback-speed">
|
||||
<option value="0.5">0.5x</option>
|
||||
<option value="0.75">0.75x</option>
|
||||
<option value="1" selected>1x</option>
|
||||
<option value="1.25">1.25x</option>
|
||||
<option value="1.5">1.5x</option>
|
||||
<option value="2">2x</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="audio-tracks">
|
||||
<select class="audio-track-select"></select>
|
||||
</div>
|
||||
<button class="fullscreen">⛶</button>
|
||||
</div>
|
||||
</div>`
|
||||
this.video = this.dom_element.querySelector('.video-element');
|
||||
this.controls = this.dom_element.querySelector('.controls');
|
||||
|
||||
this.hls = null;
|
||||
this.dashPlayer = null;
|
||||
|
||||
this.audioTrackSelect = document.getElementById('audioTrackSelect');
|
||||
this.timeDisplay = document.getElementById('timeDisplay');
|
||||
/*
|
||||
this.initEventListeners();
|
||||
this.initTrackChangeHandler();
|
||||
*/
|
||||
}
|
||||
create(){
|
||||
this.dom_element = document.createElement('video', {controls: true});
|
||||
}
|
||||
// 播放指定 URL 的视频
|
||||
load(src) {
|
||||
const video = this.video;
|
||||
this.playPauseBtn = this.controls.querySelector('.play-pause');
|
||||
this.muteBtn = this.controls.querySelector('.mute');
|
||||
this.volumeInput = this.controls.querySelector('.volume');
|
||||
this.progressBar = this.controls.querySelector('.progress-bar');
|
||||
this.timeDisplay = this.controls.querySelector('.time');
|
||||
this.speedSelect = this.controls.querySelector('.playback-speed');
|
||||
this.audioTrackSelect = this.controls.querySelector('.audio-track-select');
|
||||
this.fullscreenBtn = this.controls.querySelector('.fullscreen');
|
||||
|
||||
// 销毁之前的播放器实例
|
||||
this.destroy();
|
||||
|
||||
// 判断视频类型
|
||||
if (Hls.isSupported() && src.endsWith('.m3u8')) {
|
||||
this.loadHLS(src);
|
||||
} else if (src.endsWith('.mpd')) {
|
||||
this.loadDASH(src);
|
||||
} else {
|
||||
// 普通视频(MP4/WebM/Ogg)
|
||||
video.src = src;
|
||||
video.load();
|
||||
this.setupEventHandlers();
|
||||
}
|
||||
this.bind('domon', this.init.bind(this));
|
||||
this.bind('domoff', this.destroy.bind(this));
|
||||
}
|
||||
|
||||
loadHLS(src) {
|
||||
this.hls = new Hls();
|
||||
this.hls.loadSource(src);
|
||||
this.hls.attachMedia(this.video);
|
||||
this.hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||
this.video.play().catch(e => console.warn("自动播放被阻止", e));
|
||||
this.setupEventHandlers();
|
||||
this.updateAudioTracks();
|
||||
});
|
||||
this.hls.on(Hls.Events.ERROR, (event, data) => {
|
||||
if (data.fatal) {
|
||||
console.error('HLS 错误:', data);
|
||||
if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
|
||||
this.hls.startLoad();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadDASH(src) {
|
||||
this.dashPlayer = dashjs.MediaPlayer().create();
|
||||
this.dashPlayer.initialize(this.video, src, true);
|
||||
this.dashPlayer.on('error', (e) => {
|
||||
console.error('DASH 播放出错:', e);
|
||||
});
|
||||
this.setupEventHandlers();
|
||||
setTimeout(() => this.updateAudioTracks(), 1000); // 延迟获取音轨
|
||||
}
|
||||
|
||||
setupEventHandlers() {
|
||||
const video = this.video;
|
||||
|
||||
video.addEventListener('play', () => this.onPlay());
|
||||
video.addEventListener('pause', () => this.onPause());
|
||||
video.addEventListener('timeupdate', () => this.onTimeUpdate());
|
||||
video.addEventListener('loadedmetadata', () => this.onLoadedMetadata());
|
||||
video.addEventListener('ended', () => this.onEnded());
|
||||
video.addEventListener('error', (e) => this.onError(e));
|
||||
}
|
||||
|
||||
// 事件回调
|
||||
onPlay() {
|
||||
console.log('视频开始播放');
|
||||
}
|
||||
|
||||
onPause() {
|
||||
console.log('视频暂停');
|
||||
}
|
||||
|
||||
onTimeUpdate() {
|
||||
const { currentTime, duration } = this.video;
|
||||
this.timeDisplay.textContent = `${this.formatTime(currentTime)} / ${this.formatTime(duration)}`;
|
||||
}
|
||||
|
||||
onLoadedMetadata() {
|
||||
console.log('元数据加载完成');
|
||||
this.updateAudioTracks();
|
||||
}
|
||||
|
||||
onEnded() {
|
||||
console.log('视频播放结束');
|
||||
}
|
||||
|
||||
onError(e) {
|
||||
console.error('视频播放错误:', e);
|
||||
}
|
||||
|
||||
// 音轨切换支持
|
||||
updateAudioTracks() {
|
||||
const select = this.audioTrackSelect;
|
||||
select.innerHTML = ''; // 清空
|
||||
|
||||
const tracks = this.getAudioTracks();
|
||||
|
||||
if (tracks.length === 0) {
|
||||
const option = document.createElement('option');
|
||||
option.textContent = '无可用音轨';
|
||||
option.disabled = true;
|
||||
select.appendChild(option);
|
||||
select.disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
select.disabled = false;
|
||||
|
||||
tracks.forEach((track, index) => {
|
||||
const option = document.createElement('option');
|
||||
option.value = index;
|
||||
option.textContent = track.label || track.language || `音轨 ${index + 1}`;
|
||||
select.appendChild(option);
|
||||
});
|
||||
|
||||
// 默认选中第一个
|
||||
select.value = 0;
|
||||
this.bindAudioTrackChange();
|
||||
}
|
||||
|
||||
getAudioTracks() {
|
||||
const video = this.video;
|
||||
|
||||
// DASH 情况:使用 dash.js API
|
||||
if (this.dashPlayer) {
|
||||
const audioTracks = this.dashPlayer.getTracksFor('audio');
|
||||
return audioTracks.map(t => ({
|
||||
label: t.label || t.lang,
|
||||
language: t.lang,
|
||||
_track: t
|
||||
}));
|
||||
}
|
||||
|
||||
// HLS 情况:使用 hls.js 的 audio tracks
|
||||
if (this.hls && this.hls.audioTracks.length > 0) {
|
||||
return this.hls.audioTracks.map(track => ({
|
||||
label: track.name || track.lang,
|
||||
language: track.lang,
|
||||
_track: track
|
||||
}));
|
||||
}
|
||||
|
||||
// 原生 HTMLTrackElement(较少见,主要用于 <track kind="audio">)
|
||||
const nativeTracks = Array.from(video.audioTracks || []);
|
||||
if (nativeTracks.length > 0) {
|
||||
return nativeTracks.map(track => ({
|
||||
label: track.label || track.language,
|
||||
language: track.language,
|
||||
_track: track
|
||||
}));
|
||||
}
|
||||
|
||||
// fallback:返回主音轨
|
||||
return [{ label: '主音轨', language: 'und' }];
|
||||
}
|
||||
|
||||
bindAudioTrackChange() {
|
||||
this.audioTrackSelect.removeEventListener('change', this.handleAudioTrackChange.bind(this));
|
||||
this.audioTrackSelect.addEventListener('change', this.handleAudioTrackChange.bind(this));
|
||||
}
|
||||
|
||||
handleAudioTrackChange() {
|
||||
const selectedIndex = parseInt(this.audioTrackSelect.value, 10);
|
||||
const tracks = this.getAudioTracks();
|
||||
const selected = tracks[selectedIndex];
|
||||
|
||||
if (this.hls && selected._track && selected._track.id !== undefined) {
|
||||
this.hls.currentLevel = -1; // 确保视频流不变
|
||||
this.hls.audioTrack = selected._track.id;
|
||||
}
|
||||
|
||||
if (this.dashPlayer && selected._track) {
|
||||
this.dashPlayer.setCurrentTrack(selected._track);
|
||||
}
|
||||
|
||||
// 对于原生音轨(较少见)
|
||||
if (selected._track && selected._track.enabled !== undefined) {
|
||||
Array.from(this.video.audioTracks).forEach(t => {
|
||||
t.enabled = (t === selected._track);
|
||||
});
|
||||
}
|
||||
|
||||
console.log('切换到音轨:', selected);
|
||||
}
|
||||
|
||||
// 工具函数:格式化时间
|
||||
formatTime(seconds) {
|
||||
const s = Math.floor(seconds % 60).toString().padStart(2, '0');
|
||||
const m = Math.floor((seconds / 60) % 60).toString().padStart(2, '0');
|
||||
const h = Math.floor(seconds / 3600).toString().padStart(2, '0');
|
||||
return seconds >= 3600 ? `${h}:${m}:${s}` : `${m}:${s}`;
|
||||
}
|
||||
|
||||
// 播放/暂停控制
|
||||
togglePlay() {
|
||||
if (this.video.paused) {
|
||||
this.video.play().catch(e => console.warn("播放失败:", e));
|
||||
} else {
|
||||
this.video.pause();
|
||||
}
|
||||
}
|
||||
|
||||
// 销毁当前播放器实例
|
||||
destroy() {
|
||||
destroy(){
|
||||
if (this.hls) {
|
||||
this.hls.destroy();
|
||||
this.hls = null;
|
||||
@ -233,25 +71,247 @@ bricks VideoPlayer = class extends bricks.VBox {
|
||||
this.dashPlayer.reset();
|
||||
this.dashPlayer = null;
|
||||
}
|
||||
this.video.src = ''; // 清空
|
||||
}
|
||||
init() {
|
||||
this.loadVideo(this.opts.url); // 可替换为 mp4 / m3u8 / mpd
|
||||
this.bindEvents();
|
||||
this.updateUI();
|
||||
if (this.opts.autoplay && this.video.paused){
|
||||
this.playPauseBtn.click();
|
||||
}
|
||||
}
|
||||
|
||||
loadVideo(src) {
|
||||
// 销毁旧播放器
|
||||
this.destroy()
|
||||
|
||||
if (src.endsWith('.m3u8') || src.includes('m3u8')) {
|
||||
if (Hls.isSupported()) {
|
||||
this.hls = new Hls();
|
||||
this.hls.loadSource(src);
|
||||
this.hls.attachMedia(this.video);
|
||||
this.hls.on(Hls.Events.MANIFEST_PARSED, () => this.onLoaded());
|
||||
} else {
|
||||
console.error('HLS not supported');
|
||||
}
|
||||
} else if (src.endsWith('.mpd') || src.includes('mpd')) {
|
||||
this.dashPlayer = dashjs.MediaPlayer().create();
|
||||
this.dashPlayer.initialize(this.video, src, true);
|
||||
this.dashPlayer.on('manifestParsed', () => this.onLoaded());
|
||||
} else {
|
||||
// 普通视频
|
||||
this.video.src = src;
|
||||
this.video.addEventListener('loadedmetadata', () => this.onLoaded());
|
||||
}
|
||||
}
|
||||
|
||||
onLoaded() {
|
||||
this.updateAudioTracks();
|
||||
this.updateUI();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
// 播放/暂停
|
||||
this.playPauseBtn.addEventListener('click', () => {
|
||||
if (this.video.paused) {
|
||||
this.video.play();
|
||||
} else {
|
||||
this.video.pause();
|
||||
}
|
||||
});
|
||||
|
||||
// 静音切换
|
||||
this.muteBtn.addEventListener('click', () => {
|
||||
this.video.muted = !this.video.muted;
|
||||
this.updateMuteUI();
|
||||
});
|
||||
|
||||
// 音量变化
|
||||
this.volumeInput.addEventListener('input', (e) => {
|
||||
this.video.volume = e.target.value;
|
||||
this.video.muted = this.video.volume === 0;
|
||||
this.updateMuteUI();
|
||||
});
|
||||
|
||||
// 进度条拖动
|
||||
this.progressBar.addEventListener('input', (e) => {
|
||||
const time = e.target.value * this.video.duration;
|
||||
this.video.currentTime = time;
|
||||
});
|
||||
|
||||
// 播放速度
|
||||
this.speedSelect.addEventListener('change', (e) => {
|
||||
this.video.playbackRate = parseFloat(e.target.value);
|
||||
});
|
||||
|
||||
// 音轨切换
|
||||
this.audioTrackSelect.addEventListener('change', (e) => {
|
||||
const index = parseInt(e.target.value);
|
||||
if (this.video.audioTracks) {
|
||||
for (let i = 0; i < this.video.audioTracks.length; i++) {
|
||||
this.video.audioTracks[i].enabled = i === index;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 全屏
|
||||
this.fullscreenBtn.addEventListener('click', () => {
|
||||
if (this.dom_element.requestFullscreen) {
|
||||
this.dom_element.requestFullscreen();
|
||||
} else if (this.dom_element.webkitRequestFullscreen) {
|
||||
this.dom_element.webkitRequestFullscreen();
|
||||
}
|
||||
});
|
||||
|
||||
// 视频事件
|
||||
this.video.addEventListener('play', () => this.updatePlayPauseUI());
|
||||
this.video.addEventListener('pause', () => this.updatePlayPauseUI());
|
||||
this.video.addEventListener('timeupdate', () => this.updateProgress());
|
||||
this.video.addEventListener('durationchange', () => this.updateProgress());
|
||||
this.video.addEventListener('volumechange', () => {
|
||||
this.updateMuteUI();
|
||||
this.volumeInput.value = this.video.volume;
|
||||
});
|
||||
this.video.addEventListener('loadedmetadata', () => {
|
||||
this.updateAudioTracks();
|
||||
});
|
||||
this.video.addEventListener('seeking', () => {
|
||||
this.progressBar.value = this.video.currentTime / this.video.duration;
|
||||
});
|
||||
}
|
||||
|
||||
updateUI() {
|
||||
this.updatePlayPauseUI();
|
||||
this.updateMuteUI();
|
||||
this.updateProgress();
|
||||
this.volumeInput.value = this.video.volume;
|
||||
}
|
||||
|
||||
updatePlayPauseUI() {
|
||||
this.playPauseBtn.textContent = this.video.paused ? '▶' : '❚❚';
|
||||
}
|
||||
|
||||
updateMuteUI() {
|
||||
this.muteBtn.textContent = this.video.muted || this.video.volume === 0 ? '🔇' : '🔊';
|
||||
}
|
||||
|
||||
updateProgress() {
|
||||
const percent = this.video.duration ? this.video.currentTime / this.video.duration : 0;
|
||||
this.progressBar.value = percent;
|
||||
this.timeDisplay.textContent = `${this.formatTime(this.video.currentTime)} / ${this.formatTime(this.video.duration || 0)}`;
|
||||
}
|
||||
|
||||
updateAudioTracks() {
|
||||
this.audioTrackSelect.innerHTML = '';
|
||||
if (this.video.audioTracks && this.video.audioTracks.length > 0) {
|
||||
for (let i = 0; i < this.video.audioTracks.length; i++) {
|
||||
const track = this.video.audioTracks[i];
|
||||
const option = document.createElement('option');
|
||||
option.value = i;
|
||||
option.textContent = track.label || `音轨 ${i + 1}`;
|
||||
if (track.enabled) option.selected = true;
|
||||
this.audioTrackSelect.appendChild(option);
|
||||
}
|
||||
} else {
|
||||
const option = document.createElement('option');
|
||||
option.textContent = '无音轨';
|
||||
option.disabled = true;
|
||||
this.audioTrackSelect.appendChild(option);
|
||||
}
|
||||
}
|
||||
|
||||
formatTime(seconds) {
|
||||
const s = Math.floor(seconds % 60);
|
||||
const m = Math.floor((seconds / 60) % 60);
|
||||
const h = Math.floor(seconds / 3600);
|
||||
return h > 0
|
||||
? `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
|
||||
: `${m}:${s.toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
}
|
||||
bricks.Iptv = class extends bricks.VBox {
|
||||
/*
|
||||
{
|
||||
iptv_data_url:
|
||||
playok_url:
|
||||
playfailed_url:
|
||||
}
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
schedule_once(this.build_subwidgets.bind(this), 0.1);
|
||||
}
|
||||
async build_subwidgets(){
|
||||
console.log('build_subwidgets called');
|
||||
if (!this.user_data){
|
||||
var jc = new bricks.HttpJson();
|
||||
this.deviceid = bricks.deviceid('iptv')
|
||||
this.user_data = await jc.httpcall(this.iptv_data_url, {
|
||||
params:{
|
||||
deviceid:this.deviceid
|
||||
},
|
||||
method:'GET'
|
||||
});
|
||||
}
|
||||
console.log('this.user_data =', this.user_data);
|
||||
this.video = new bricks.VideoPlayer({
|
||||
autoplay:true,
|
||||
url:this.user_data.url
|
||||
});
|
||||
this.title_w = new bricks.Text({text:this.user_data.tv_name, wrap:false});
|
||||
this.add_widget(this.title_w);
|
||||
this.add_widget(this.video);
|
||||
this.video.bind('play_ok', this.report_play_ok.bind(this));
|
||||
this.video.bind('play_failed', this.report_play_failed.bind(this));
|
||||
}
|
||||
async report_play_ok(){
|
||||
console.log(this.user_data, 'channel playing ...', this.playok_url);
|
||||
if (this.playok_url){
|
||||
var ht = new bricks.HttpText();
|
||||
var resp = ht.httpcall(this.playok_url,{
|
||||
params:{
|
||||
deviceid:this.deviceid,
|
||||
channelid:this.user_data.id
|
||||
},
|
||||
method:"GET"
|
||||
});
|
||||
if (resp != 'Error'){
|
||||
console.log('report playok ok');
|
||||
} else {
|
||||
console.log('report playok failed');
|
||||
}
|
||||
} else {
|
||||
console.log('this.playok_url not defined', this.playok_url);
|
||||
}
|
||||
}
|
||||
async report_play_failed(){
|
||||
console.log(this.user_data, 'channel play failed ...');
|
||||
if (this.playfailed_url){
|
||||
var ht = new bricks.HttpText();
|
||||
var resp = ht.httpcall(this.playfailed_url,{
|
||||
params:{
|
||||
deviceid:this.deviceid,
|
||||
channelid:this.user_data.id
|
||||
},
|
||||
method:"GET"
|
||||
});
|
||||
if (resp != 'Error'){
|
||||
console.log('report playfailed ok');
|
||||
} else {
|
||||
console.log('report playfailed failed');
|
||||
}
|
||||
} else {
|
||||
console.log('this.playfailed_url not defined', this.playfailed_url);
|
||||
}
|
||||
}
|
||||
setValue(data){
|
||||
this.user_data = data;
|
||||
this.title_w.set_text(data.tv_name);
|
||||
this.video.set_url(data.url);
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化播放器
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const video = document.getElementById('videoPlayer');
|
||||
const player = new VideoPlayer(video);
|
||||
|
||||
// 绑定播放/暂停按钮
|
||||
document.getElementById('playPause').addEventListener('click', () => {
|
||||
player.togglePlay();
|
||||
});
|
||||
|
||||
// 示例:自动加载一个 m3u8 视频(替换为你的实际链接)
|
||||
// player.load('https://example.com/stream.m3u8');
|
||||
|
||||
// 或者加载 DASH
|
||||
// player.load('https://example.com/stream.mpd');
|
||||
|
||||
// 或者普通 MP4
|
||||
player.load('https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4');
|
||||
});
|
||||
bricks.Factory.register('Iptv', bricks.Iptv);
|
||||
bricks.Factory.register('VideoPlayer', bricks.VideoPlayer);
|
||||
bricks.Factory.register('Video', bricks.VideoPlayer);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user