UNPKG

@lzwme/m3u8-dl

Version:

A free, open-source, and powerful m3u8 video batch downloader with multi-threaded downloading, play-while-downloading, WebUI management, video parsing, and more.

303 lines (286 loc) 12.5 kB
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>M3U8 Player</title> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta content="width=device-width, initial-scale=1.0, viewport-fit=cover" name="viewport" /> <link rel="shortcut icon" href="logo.png"> <style> body { margin: 0; padding: 0; } #dplayer { width: 100vw; height: 100vh; } </style> </head> <body> <div id="dplayer"></div> <script src="https://s4.zstatic.net/ajax/libs/hls.js/1.5.18/hls.min.js" integrity="sha512-hARxLWym80kd0Bzl5/93OuW1ujaKfvmJ90yTKak/RB67JuNIjtErU2H7H3bteyfzMuqiSK0tXarT7eK6lEWBBA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script> const playUrl = location.href.split('url=')[1]; if (!playUrl) { document.getElementById('dplayer').innerText = '请传入播放地址参数 url='; } else { const CDN_CONFIG = { // m3u8Demo: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8', dplayer: 'https://s4.zstatic.net/ajax/libs/dplayer/1.26.0/DPlayer.min.js', artplayer: [ 'https://s4.zstatic.net/ajax/libs/artplayer/5.3.0/artplayer.min.js', 'https://fastly.jsdelivr.net/npm/artplayer-plugin-hls-control/dist/artplayer-plugin-hls-control.min.js', 'https://fastly.jsdelivr.net/npm/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.min.js', ], } const T = { data: { playType: playUrl.includes('dplayer') ? 'dplayer' : 'artplayer', videoUrl: decodeURIComponent(playUrl), dpInc: null, artInc: null, }, play(videoUrl, playType) { if (videoUrl && videoUrl !== T.data.videoUrl) T.data.videoUrl = videoUrl; if (playType && playType !== T.data.playType) T.data.playType = playType; if (!['dplayer', 'artplayer'].includes(T.data.playType)) T.data.playType = 'artplayer'; if (T.data.playType === 'dplayer') { return T.dplayer(T.data.videoUrl); } else { return T.artplayer(T.data.videoUrl); } }, async loadJS(url) { if (Array.isArray(url)) { for (const u of url) await T.loadJS(u); return; } if (document.querySelector(`script[src="${url}"]`)) return; return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = url; script.onload = resolve; script.onerror = reject; document.body.appendChild(script); }).catch(e => console.error(e)); }, sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }, async dplayer(videoUrl) { if (T.data.dpInc) { T.data.dpInc.destroy(); T.data.dpInc = null; await T.sleep(100); } else { await T.loadJS(CDN_CONFIG.dplayer); } const dp = new DPlayer({ container: document.getElementById('dplayer'), autoplay: true, airplay: true, theme: '#FADFA3', loop: true, screenshot: true, hotkey: true, chromecast: true, preload: 'auto', playbackSpeed: [0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4, 8], video: { url: videoUrl, type: 'auto', }, pluginOptions: { hls: {}, }, contextmenu: [ { text: '在线播放器', link: 'https://m3u8-player.lzw.me' }, { text: '在线下载器', link: 'https://m3u8-downloader.lzw.me' }, ], }); dp.on('ended', () => { console.log('[dplayer]播放完毕', videoUrl); T.next_video(); }); T.data.dpInc = dp; return dp; }, /** 使用 artplayer 播放 */ async artplayer(videoUrl) { let art = T.data.artInc; // 从 videoUrl 提取文件类型 let type = ['.mp4', '.mkv', '.avi', '.mov', '.wmv', '.flv', '.webm', '.m4v', '.m3u8', '.ogg', '.flv', '.webm'].find(d => videoUrl.includes(d)) || 'm3u8'; if (type.startsWith('.')) type = type.slice(1); if (art) { art.url = videoUrl; art.type = type; art.playbackRate = +art.storage.get('playbackRate') || 1; return art; } await T.loadJS(CDN_CONFIG.artplayer); Artplayer.PLAYBACK_RATE = [0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4, 8, 16]; Artplayer.SEEK_STEP = 10; // 快进步长,单位秒 Artplayer.FAST_FORWARD_VALUE = 3; // 快进倍速 art = new Artplayer({ container: document.getElementById('dplayer'), url: videoUrl, // 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8', // airplay: true, // 是否显示AirPlay功能。效果并不好 aspectRatio: true, // 是否显示视频长宽比功能 autoplay: true, autoOrientation: true, // autoMini: true, // 当播放器滚动到浏览器视口以外时,自动进入 迷你播放 模式 autoPlayback: true, // 是否使用自动 回放功能 // autoSize: true, // 自动调整播放器尺寸 fastForward: true, flip: true, // 是否显示视频翻转功能 fullscreen: true, // 是否在底部控制栏里显示播放器 窗口全屏 按钮 fullscreenWeb: true, // 是否在底部控制栏里显示播放器 网页全屏 按钮 lock: true, miniProgressBar: true, pip: true, // 是否在底部控制栏里显示 画中画 的开关按钮 playbackRate: true, // 是否显示视频播放速度功能 playsInline: true, // 在移动端是否使用 playsInline 模式 screenshot: true, setting: true, theme: '#39f', type, plugins: [ window.artplayerPluginHlsControl && artplayerPluginHlsControl({ quality: { // Show qualitys in control control: document.body.clientWidth > 768, // Show qualitys in setting setting: true, // Get the quality name from level getName: level => level.height + 'P', // I18n title: 'Quality', auto: 'Auto', }, audio: { // Show audios in control control: false, // Show audios in setting setting: true, // Get the audio name from track getName: track => track.name, // I18n title: 'Audio', auto: 'Auto', }, }), window.artplayerPluginAutoThumbnail && artplayerPluginAutoThumbnail({ width: 160, number: 100, scale: 1, }), ].filter(Boolean), customType: { m3u8: function playM3u8(video, url, art) { if (Hls.isSupported()) { if (art.hls) art.hls.destroy(); const hls = new Hls(); hls.loadSource(url); hls.attachMedia(video); art.hls = hls; art.on('destroy', () => hls.destroy()); } else if (video.canPlayType('application/vnd.apple.mpegurl')) { video.src = url; } else { art.notice.show = 'Unsupported playback format: m3u8'; } }, flv: function playFlv(video, url, art) { if (flvjs.isSupported()) { if (art.flv) art.flv.destroy(); const flv = flvjs.createPlayer({ type: 'flv', url }); flv.attachMediaElement(video); flv.load(); art.flv = flv; art.on('destroy', () => flv.destroy()); } else { art.notice.show = 'Unsupported playback format: flv'; } }, }, controls: [{ name: "previous-button", index: 10, position: "left", html: '<svg fill="none" stroke-width="2" xmlns="http://www.w3.org/2000/svg" height="22" width="22" class="icon icon-tabler icon-tabler-player-track-prev-filled" width="1em" height="1em" viewBox="0 0 24 24" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" style="overflow: visible; color: currentcolor;"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M20.341 4.247l-8 7a1 1 0 0 0 0 1.506l8 7c.647 .565 1.659 .106 1.659 -.753v-14c0 -.86 -1.012 -1.318 -1.659 -.753z" stroke-width="0" fill="currentColor"></path><path d="M9.341 4.247l-8 7a1 1 0 0 0 0 1.506l8 7c.647 .565 1.659 .106 1.659 -.753v-14c0 -.86 -1.012 -1.318 -1.659 -.753z" stroke-width="0" fill="currentColor"></path></svg>', tooltip: "Previous", click: function () { T.previous_video() }, }, { name: "next-button", index: 11, position: "left", html: '<svg fill="none" stroke-width="2" xmlns="http://www.w3.org/2000/svg" height="22" width="22" class="icon icon-tabler icon-tabler-player-track-next-filled" width="1em" height="1em" viewBox="0 0 24 24" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" style="overflow: visible; color: currentcolor;"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M2 5v14c0 .86 1.012 1.318 1.659 .753l8 -7a1 1 0 0 0 0 -1.506l-8 -7c-.647 -.565 -1.659 -.106 -1.659 .753z" stroke-width="0" fill="currentColor"></path><path d="M13 5v14c0 .86 1.012 1.318 1.659 .753l8 -7a1 1 0 0 0 0 -1.506l-8 -7c-.647 -.565 -1.659 -.106 -1.659 .753z" stroke-width="0" fill="currentColor"></path></svg>', tooltip: "Next", click: function () { T.next_video() }, }], contextmenu: [ // { index: 80, html: 'M3U8在线播放器', click: () => window.open(`https://m3u8-player.lzw.me`, '_blank') }, { index: 99, html: 'M3U8在线下载器', click: () => window.open(`https://m3u8-downloader.lzw.me`, '_blank') }, ], }); art.on('video:ended', () => { console.log('[artplayer]播放完毕', videoUrl); T.next_video(); }); art.on('video:ratechange', () => { // console.log('[artplayer]播放进度', art.playbackRate); art.storage.set('playbackRate', art.playbackRate); }); art.on('ready', () => { art.playbackRate = +art.storage.get('playbackRate') || 1; art.contextmenu.remove('version'); }); // console.log('[artplayer]播放器初始化完成', art); T.data.artInc = art; return art; }, previous_video() { T.postMessage({ action: 'previous', url: T.data.videoUrl, playType: T.data.playType }); }, next_video() { T.postMessage({ action: 'next', url: T.data.videoUrl, playType: T.data.playType }); }, postMessage(message) { if (window.sef === window.parent) { return; } else { window.parent.postMessage(message, '*'); } }, init() { if (window.sef !== window.parent) { // 监听来自父窗口的消息 window.addEventListener('message', (event) => { const data = event.data; if (!data || typeof data !== 'object') return; if (data.url) { T.data.videoUrl = data.url; if (data.playType) T.data.playType = data.playType; T.play(); } }); } return T.play(); } }; T.init(); window.T = T; } </script> </body> </html>