Alist 增加视频跳转链接页面自动定位到指定时间播放的功能

Alist 增加视频跳转链接页面自动定位到指定时间播放的功能

功能介绍:

  1. 在 Alist 页面复制播放的视频链接到剪切板,链接中自动附上当前已播放的时间
  2. 把链接粘贴到思源笔记中
  3. 点击刚才粘贴的视频链接,自动跳转到 Alist 页面并自动定位到刚才已播放的时间点

效果:

r80.gif

代码如下(把以下代码放到 alist 管理页面,设置-》全局-》自定义内容里即可)

<script>
(function() {
    // 监听哪些视频格式
    const videos = ['.mp4','.avi', '.webm', '.ogg'];
    // 监听哪些音频格式
    const audios = ['.mp3', '.wav', '.m4a'];
  
    // 监听视频格式
    observeElementExist('a[href^="iina://"]', a => {
        if(!videos.some(extension => location.pathname.endsWith(extension))){
            return;
        }
        const shareBtn = document.createElement('button');
        shareBtn.textContent = "复制";
        shareBtn.style.padding = '0px 15px';
        shareBtn.style.cursor = 'pointer';
        shareBtn.onclick = () => {
            const title = document.querySelector('nav ol li:last-child').textContent;
            const video = document.querySelector('video');
            const time = video.currentTime;
            const text = `[${title} [${convertSecondsToMinutesAndSeconds(time)}]](${genUrlParameter(location.href, 'time', time)})`;
            copyToClipboard(text);
            shareBtn.textContent = "已复制";
            setTimeout(() => { shareBtn.textContent = "复制"; }, 1500);
        };
        // 将shareBtn插入到目标a元素之前
        a.parentElement.insertBefore(shareBtn, a);

        //获取URL参数并调整到对应的时间
        const time = parseFloat(getUrlParameter(location.href, 'time'));
        if(time){
            // 去掉上次播放提示
            const lastPlayTips = document.querySelector('.art-layer.art-layer-auto-playback');
            if(lastPlayTips){
                let count = 0;
                const timer = setInterval(()=>{
                    count++;
                    if(count>50) clearInterval(timer);
                    if(lastPlayTips.style.display === 'flex') {
                        lastPlayTips.style.display = 'none';
                        clearInterval(timer);
                    }
                }, 100);
            }
            // 视频跳转时间
            const video = document.querySelector('video');
            video.currentTime = time;
        }
    });
  
    //监听音频格式化(不支持获取当前时间,因为无法获取aplayer播放器实例)
    observeElementExist('.aplayer-music', el => {
        if(el.dataset.loaded === 'true') return;
        el.dataset.loaded = true;
        if(!audios.some(extension => location.pathname.endsWith(extension))){
            return;
        }
        el.style.overflow = 'visible';
        const shareBtn = document.createElement('button');
        shareBtn.textContent = "复制";
        shareBtn.style.padding = '0px 5px';
        shareBtn.style.cursor = 'pointer';
        shareBtn.style.float = 'right';
        shareBtn.onclick = () => {
            const title = el.querySelector('.aplayer-title').textContent;
            const text = `[${title}](${location.href})`;
            copyToClipboard(text);
            shareBtn.textContent = "已复制";
            setTimeout(() => { shareBtn.textContent = "复制"; }, 1500);
        };
        el.appendChild(shareBtn);
    });

    function getUrlParameter(url, param) {
        const urlParams = new URLSearchParams(new URL(url).search);
        return urlParams.get(param);
    }
    function genUrlParameter(url, param, value) {
        const urlParams = new URLSearchParams(new URL(url).search);
        urlParams.set(param, value);
        const newUrl = url.split('?')[0] + '?' + urlParams.toString();
        return newUrl;
    }
    function convertSecondsToMinutesAndSeconds(seconds) {
        let minutes = Math.floor(seconds / 60);
        const secondsRemaining = Math.floor(seconds % 60);
  
        // 格式化分秒数
        const formattedSeconds = secondsRemaining.toString().padStart(2, '0');
        minutes = minutes.toString().padStart(2, '0');
        return `${minutes}:${formattedSeconds}`;
    }
    function copyToClipboard(contents) {
        if ('clipboard' in navigator) {
            navigator.clipboard.writeText(contents);
            return;
        }
        const textarea = document.createElement('textarea');
        textarea.value = contents;
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
    }
    function observeElementExist(selector, callback) {
        const handleMutations = (mutationsList, observer) => {
            for (let mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach(node => {
                        if (node.matches && node.matches(selector)) {
                            callback(node);
                        } else if (node && node.querySelector && node.querySelector(selector)) {
                            callback(node.querySelector(selector));
                        }
                    });
                }
            }
        };
  
        // 创建一个MutationObserver实例
        const config = { attributes: false, childList: true, subtree: true };
        const observer = new MutationObserver(handleMutations);
  
        // 选择需要监听的父节点
        const targetNode = document.body; // 或者选择其他合适的父节点
  
        // 开始监听目标节点的变化
        observer.observe(targetNode, config);
    }
})();
</script>

关联 https://github.com/loonghfut/siyuan-alist/issues/2#issuecomment-2428711820

image.png

留下你的脚步
推荐阅读