萌新的第一个项目: 为朋友的emby服务器添加番剧截图功能
emby简介
Emby(原名Media Browser)是一个主从式架构的媒体服务器软件,可以用来整理服务器上的视频和音频,并将音频和视频流式传输到客户端设备。
起源
那是一个风和日丽的下午,我一如既往的打开emby,点进还热乎着的⟪我心危⟫最新一集….映入眼帘的便是山田的美颜(什么小学生作文),马上使用windows+shift+s开始截图并把图片发给好基友。很快我就发现,这种截图方式并不方便,于是脑子里萌生了一个想法:为什么不在emby中嵌入一个截图按钮呢?
计划已定,开始实施
基本思路
查阅资料可知,实现网页播放器截图的步骤有四步:
- 创建2d canvas画布
- 用drawImage方法绘制当前视频帧图
- 将图像转化为dataURL格式或Blob对象
- 下载url/保存到剪贴板
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const videoElem = document.getElementsByClassName('htmlvideoplayer')[0];
const canvas = document.createElement('canvas');
const [w, h] = [videoElem.videoWidth, videoElem.videoHeight]; canvas.width = w; canvas.height = h;
canvas.getContext('2d').drawImage(videoElem, 0, 0, w, h);
|
const dataURL = canvas.toDataURL('image/png')
1 2 3 4 5 6 7 8 9 10 11 12 13
| function canvasToBlob(canvas) { return new Promise((resolve) => { canvas.toBlob((blob) => { const reader = new FileReader(); reader.readAsDataURL(blob); reader.onload = () => { const imageUrl = reader.result; resolve(imageUrl); } }, 'image/png', 1); }) }
|
当你在本地(使用 file:// 协议)加载 HTML 文件时,浏览器将其视为来自 null 原始域的请求,因此不允许访问本地视频文件。这通常被称为跨源资源共享(CORS)限制。
你可以启动一个本地live server,或者将视频文件上传到web服务器上,这样就可以用HTTP/HTTPS协议访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
const aElem = document.createElement('a'); aElem.href = imageUrl; aElem.download = 'screenshot.webp' aElem.click();
canvasToBlob(canvas).then((blob) => { const item = new ClipboardItem({ 'image/png': blob }); navigator.clipboard.write([item]).then(() => { console.log('截图已复制到剪贴板'); }).catch(err => { console.error('无法复制截图到剪贴板', err); }); });
|
添加截图按钮
好了,大体思路和框架都已建成,接下来就要对html动手了。
用css选择器把emby播放器下方的按钮所在div的class属性找出来,然后把它作为我们截图按钮的父节点记录下来,最后用js的appendChild方法实现截图按钮的插入。
当然,也不要忘记用innerHTML把svg图像绑定到按钮上。
这样一来就大功告成了,源码如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function tryGetBtnArea() { return document.querySelector('.view:not(.hide) .videoOsdBottom-maincontrols .videoOsdBottom-buttons') }
function tryBindScreenshotBtn(parentElem) { const newBtn = document.createElement('button'); newBtn.addEventListener('click', async (e) => { const dataUrl = await screenshot(); if (!dataUrl) { console.error('获取截图失败: 未找到视频') return; } download_image(dataUrl); }) newBtn.innerHTML = xxx; parentElem.appendChild(newBtn); console.warn('截图插件载入成功') }
|
最终效果


xc
everything is better than nothing
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 xc's Blog!