吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1134|回复: 22
收起左侧

[其他原创] 汽某音乐歌词获取脚本

  [复制链接]
xinchenmetx 发表于 2026-2-18 09:39

由于个人需要,顺手写了汽某音乐歌词提取脚本

会把网页上的歌词数组转换成LRC/卡拉OK歌词

打开分享链接 - 拓展菜单运行脚本

// ==UserScript==
// @name         歌词提取器
// @namespace    https://www.52pojie.cn/home.php?mod=follow&uid=1289557
// @version      114.514
// @description  顺手写的,能用就行
// @AuThor       52pj【xinchenmetx】
// @match        不知道是什么网站QwQ
// @Icon         https://s11.ax1x.com/2024/01/24/pFetIiR.png
// @license      GPL-3.0
// @run-at       document-end
// @grant        GM_registerMenuCommand
// ==UserScript==

(function() {
    'use strict';

    console.log('[歌词提取器] 已加载 - 快捷键: Ctrl+Shift+L');

    // 歌词转换
    const Converter = {
        msToTime(ms) {
            if (ms < 0 || ms > 999999999) ms = 0;
            const t = ms / 1000;
            const m = Math.floor(t / 60).toString().padStart(2, '0');
            const s = Math.floor(t % 60).toString().padStart(2, '0');
            const c = Math.floor((t % 1) * 100).toString().padStart(2, '0');
            return `[${m}:${s}.${c}]`;
        },

        toLRC(s) {
            return s.map(i => {
                if (i.type === 'lrc') {
                    if (i.text.includes('作曲')) return `[ar:${i.text.replace('作曲:', '')}]`;
                    if (i.text.includes('作词')) return `[au:${i.text.replace('作词:', '')}]`;
                    if (i.text.includes('贡献者')) return `[by:${i.text.replace('滚动歌词&翻译贡献者:', '')}]`;
                }
                return `${this.msToTime(i.startMs)}${i.text}`;
            }).join('\n');
        },

        toELRC(s) {
            return s.map(i => {
                if (i.type === 'lrc') {
                    if (i.text.includes('作曲')) return `[ar:${i.text.replace('作曲:', '')}]`;
                    if (i.text.includes('作词')) return `[au:${i.text.replace('作词:', '')}]`;
                    if (i.text.includes('贡献者')) return `[by:${i.text.replace('滚动歌词&翻译贡献者:', '')}]`;
                }
                let line = this.msToTime(i.startMs);
                if (i.words?.length > 1) {
                    i.words.forEach(w => line += `<${this.msToTime(w.startMs).slice(1, -1)}>${w.text}`);
                } else {
                    line += i.text;
                }
                return line;
            }).join('\n');
        },

        toKRC(s) {
            return s.map(i => {
                const dur = i.endMs - i.startMs;
                let words = '';
                if (i.words?.length) {
                    i.words.forEach(w => words += `<${w.startMs - i.startMs},${w.endMs - w.startMs}>${w.text}`);
                } else {
                    words = `<0,${dur}>${i.text}`;
                }
                return `[${i.startMs},${dur}]${words}`;
            }).join('\n');
        }
    };

    // 提取数据
    function getLyrics() {
        try {
            const d = unsafeWindow._ROUTER_DATA?.loaderData?.track_page?.audioWithLyricsOption?.lyrics;
            if (d?.sentences) return d;
        } catch(e) {}

        document.querySelectorAll('script:not([src])').forEach(s => {
            const t = s.textContent;
            if (t.includes('"lyricType"') && t.includes('"sentences"')) {
                const m = t.match(/\{[^}]*"lyricType"[^}]*"sentences"[^}]*\}/);
                if (m) return JSON.parse(m[0]);
            }
        });
        return null;
    }

    // 获取歌曲信息
    function getInfo(sentences) {
        const info = { title: '未知歌曲', artist: '未知艺术家' };
        const t = document.querySelector('title')?.textContent || '';
        const m = t.match(/(.+?)\s*[-–]\s*(.+)/);
        if (m) { info.title = m[1].trim(); info.artist = m[2].trim(); }

        try {
            const tr = unsafeWindow._ROUTER_DATA?.loaderData?.track_page?.trackInfo;
            if (tr) {
                info.title = tr.name || info.title;
                info.artist = tr.artist?.name || info.artist;
            }
        } catch(e) {}

        sentences?.forEach(s => {
            if (s.type === 'lrc' && s.text.includes('作曲')) info.artist = s.text.replace('作曲:', '');
        });
        return info;
    }

    // 复制功能 - 使用多种方法
    function doCopy(text) {
        return new Promise((resolve, reject) => {
            // 1: 现代 Clipboard API
            if (navigator.clipboard && window.isSecureContext) {
                navigator.clipboard.writeText(text).then(resolve).catch(() => {
                    // 失败则使用方法2
                    fallbackCopy();
                });
            } else {
                fallbackCopy();
            }

            // 2: 传统 execCommand
            function fallbackCopy() {
                const ta = document.createElement('textarea');
                ta.value = text;
                ta.style.cssText = 'position:fixed;top:0;left:0;opacity:0;pointer-events:none;z-index:-1;';
                document.body.appendChild(ta);
                ta.focus();
                ta.select();

                try {
                    const success = document.execCommand('copy');
                    document.body.removeChild(ta);
                    if (success) resolve();
                    else reject(new Error('execCommand failed'));
                } catch (err) {
                    document.body.removeChild(ta);
                    reject(err);
                }
            }
        });
    }

    // 显示提示
    function showTip(btn, text) {
        const orig = btn.textContent;
        const origBg = btn.style.background;
        btn.textContent = text;
        btn.style.background = '#10b981';
        btn.disabled = true;

        setTimeout(() => {
            btn.textContent = orig;
            btn.style.background = origBg;
            btn.disabled = false;
        }, 1200);
    }

    // 当前数据存储
    let currentData = null;
    let currentFormats = null;

    // 创建界面
    function createUI() {
        const data = getLyrics();
        if (!data) {
            alert('未找到歌词数据!请确保页面正在播放歌曲且歌词已加载。');
            return;
        }

        currentData = data;
        const s = data.sentences;
        const info = getInfo(s);
        currentFormats = [
            { name: 'LRC', desc: '标准格式,通用播放器', content: Converter.toLRC(s) },
            { name: 'ELRC', desc: '增强格式,逐字高亮', content: Converter.toELRC(s) },
            { name: 'KRC', desc: '酷狗格式,精确卡拉OK', content: Converter.toKRC(s) }
        ];

        // 移除旧界面
        const old = document.getElementById('lyric-tool');
        if (old) old.remove();

        // 创建遮罩和容器
        const overlay = document.createElement('div');
        overlay.id = 'lyric-tool';

        const box = document.createElement('div');
        box.className = 'lyric-box';
        box.onclick = (e) => e.stopPropagation();

        box.innerHTML = `
            <style>
                #lyric-tool {
                    position: fixed;
                    top: 0; left: 0; right: 0; bottom: 0;
                    background: rgba(0,0,0,0.5);
                    z-index: 999999;
                    display: flex;
                    align-items: flex-end;
                    justify-content: center;
                    font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
                }
                @media(min-width:640px){
                    #lyric-tool{align-items:center}
                }
                .lyric-box {
                    background: #fff;
                    width: 100%;
                    max-width: 480px;
                    max-height: 90vh;
                    border-radius: 20px 20px 0 0;
                    overflow: hidden;
                    display: flex;
                    flex-direction: column;
                    animation: slideUp 0.25s ease;
                }
                @media(min-width:640px){
                    .lyric-box{border-radius:16px;max-height:85vh}
                }
                @keyframes slideUp {
                    from {transform:translateY(100%);opacity:0}
                    to {transform:translateY(0);opacity:1}
                }
                .lyric-head {
                    background: linear-gradient(90deg,#00b894,#00cec9);
                    color: #fff;
                    padding: 16px 20px;
                    position: relative;
                    flex-shrink: 0;
                }
                .lyric-head h3 {
                    margin: 0;
                    font-size: 18px;
                    font-weight: 700;
                }
                .lyric-head p {
                    margin: 4px 0 0;
                    font-size: 13px;
                    opacity: 0.9;
                    white-space: nowrap;
                    overflow: hidden;
                    text-overflow: ellipsis;
                }
                .lyric-close {
                    position: absolute;
                    top: 12px;
                    right: 12px;
                    width: 32px;
                    height: 32px;
                    border: none;
                    background: rgba(255,255,255,0.2);
                    color: #fff;
                    border-radius: 50%;
                    font-size: 18px;
                    cursor: pointer;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                }
                .lyric-close:hover{background:rgba(255,255,255,0.3)}
                .lyric-body {
                    padding: 16px 20px;
                    overflow-y: auto;
                    flex: 1;
                }
                .lyric-meta {
                    display: grid;
                    grid-template-columns: 1fr 1fr;
                    gap: 12px;
                    margin-bottom: 16px;
                    padding-bottom: 16px;
                    border-bottom: 1px solid #f0f0f0;
                }
                .lyric-meta-item {
                    font-size: 13px;
                    color: #666;
                }
                .lyric-meta-item strong {
                    display: block;
                    color: #333;
                    font-size: 15px;
                    margin-top: 2px;
                }
                .lyric-list {
                    display: flex;
                    flex-direction: column;
                    gap: 12px;
                }
                .lyric-item {
                    border: 1px solid #e8e8e8;
                    border-radius: 12px;
                    overflow: hidden;
                }
                .lyric-item-hd {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    padding: 12px 14px;
                    background: #fafafa;
                }
                .lyric-item-title {
                    display: flex;
                    align-items: center;
                    gap: 8px;
                }
                .lyric-tag {
                    background: #00b894;
                    color: #fff;
                    padding: 2px 8px;
                    border-radius: 4px;
                    font-size: 12px;
                    font-weight: 700;
                }
                .lyric-tag.elrc{background:#0984e3}
                .lyric-tag.krc{background:#e17055}
                .lyric-item-desc {
                    font-size: 12px;
                    color: #999;
                }
                .lyric-copy {
                    border: none;
                    background: #dfe6e9;
                    color: #2d3436;
                    padding: 8px 16px;
                    border-radius: 20px;
                    font-size: 13px;
                    font-weight: 600;
                    cursor: pointer;
                    transition: all 0.2s;
                    min-width: 60px;
                }
                .lyric-copy:hover{background:#b2bec3}
                .lyric-copy:active{transform:scale(0.95)}
                .lyric-text {
                    padding: 12px 14px;
                    background: #2d3436;
                    color: #81ecec;
                    font-family: "SF Mono",Monaco,monospace;
                    font-size: 11px;
                    line-height: 1.6;
                    max-height: 100px;
                    overflow: auto;
                    white-space: pre-wrap;
                    word-break: break-all;
                }
                .lyric-foot {
                    padding: 12px 20px;
                    background: #fafafa;
                    border-top: 1px solid #f0f0f0;
                    display: flex;
                    gap: 10px;
                    flex-shrink: 0;
                }
                .lyric-btn {
                    flex: 1;
                    border: none;
                    padding: 12px;
                    border-radius: 8px;
                    font-size: 14px;
                    font-weight: 600;
                    cursor: pointer;
                    transition: all 0.2s;
                }
                .lyric-btn:hover{opacity:0.9}
                .lyric-btn:active{transform:scale(0.98)}
                .lyric-btn-json {
                    background: #00b894;
                    color: #fff;
                }
                .lyric-btn-close {
                    background: #dfe6e9;
                    color: #636e72;
                }
            </style>
            <div class="lyric-head">
                <h3>🎵 歌词提取器</h3>
                <p>${info.title} - ${info.artist}</p>
                <button class="lyric-close">×</button>
            </div>
            <div class="lyric-body">
                <div class="lyric-meta">
                    <div class="lyric-meta-item">总行数<strong>${s.length}行</strong></div>
                    <div class="lyric-meta-item">逐字支持<strong>${s.some(x=>x.words?.length>1)?'✅':'❌'}</strong></div>
                </div>
                <div class="lyric-list">
                    ${currentFormats.map((f,i)=>`
                        <div class="lyric-item">
                            <div class="lyric-item-hd">
                                <div class="lyric-item-title">
                                    <span class="lyric-tag ${f.name.toLowerCase()}">${f.name}</span>
                                    <span class="lyric-item-desc">${f.desc}</span>
                                </div>
                                <button class="lyric-copy" data-idx="${i}">复制</button>
                            </div>
                            <div class="lyric-text">${f.content.substring(0,120)}${f.content.length>120?'...':''}</div>
                        </div>
                    `).join('')}
                </div>
            </div>
            <div class="lyric-foot">
                <button class="lyric-btn lyric-btn-json" id="btn-json">📋 复制原始JSON</button>
                <button class="lyric-btn lyric-btn-close" id="btn-close">关闭</button>
            </div>
        `;

        overlay.appendChild(box);
        document.body.appendChild(overlay);

        // 绑定事件 - 使用事件委托确保可靠
        // 关闭按钮
        box.querySelector('.lyric-close').onclick = () => overlay.remove();
        box.querySelector('#btn-close').onclick = () => overlay.remove();
        overlay.onclick = () => overlay.remove();

        // 复制格式按钮
        box.querySelectorAll('.lyric-copy').forEach(btn => {
            btn.onclick = function(e) {
                e.stopPropagation();
                const idx = parseInt(this.getAttribute('data-idx'));
                const content = currentFormats[idx].content;

                doCopy(content).then(() => {
                    showTip(this, '✓ 已复制');
                }).catch(err => {
                    console.error('复制失败:', err);
                    showTip(this, '✗ 失败');
                });
            };
        });

        // 复制JSON按钮
        box.querySelector('#btn-json').onclick = function(e) {
            e.stopPropagation();
            const jsonStr = JSON.stringify(currentData, null, 2);

            doCopy(jsonStr).then(() => {
                showTip(this, '✓ JSON已复制');
            }).catch(err => {
                console.error('复制失败:', err);
                showTip(this, '✗ 复制失败');
            });
        };
    }

    // 注册菜单
    GM_registerMenuCommand('🎵 提取歌词', createUI);

    // 快捷键
    document.addEventListener('keydown', e => {
        if (e.ctrlKey && e.shiftKey && e.key === 'L') {
            e.preventDefault();
            createUI();
        }
    });

})();


20260218_092924.png

免费评分

参与人数 1吾爱币 +7 热心值 +1 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

chinawolf2000 发表于 2026-2-18 22:07
双十一 发表于 2026-2-18 13:29
试试这个软件,能下载MP3、MP4、还能下载歌词。

老大,这个在哪里能下到
双十一 发表于 2026-2-18 13:29
本帖最后由 双十一 于 2026-2-18 13:31 编辑

qsyy_2026-02-18_13-28-04.png

试试这个软件,能下载MP3、MP4、还能下载歌词。

免费评分

参与人数 1热心值 +1 收起 理由
dxin11 + 1 谢谢@Thanks!

查看全部评分

双十一 发表于 2026-2-19 23:24
chinawolf2000 发表于 2026-2-18 22:07
老大,这个在哪里能下到


分享时间有限,先保存先得。
https://pan.quark.cn/s/b17d7cd45380
 楼主| xinchenmetx 发表于 2026-2-18 09:49
别忘打开“允许运行脚本”

是这个 https://music.douyin.com/*
picoyiyi 发表于 2026-2-18 09:49
厉害!这样就不用自己去搜歌词了
yh141632 发表于 2026-2-18 10:46
感谢大佬!!!
fengqingzhi11 发表于 2026-2-18 11:02
几个平台都能写进去吗?
 楼主| xinchenmetx 发表于 2026-2-18 11:25
fengqingzhi11 发表于 2026-2-18 11:02
几个平台都能写进去吗?

其他平台已经有人发接口了。
xiong779 发表于 2026-2-18 14:38
厉害!这样就很方便下载跟歌词了,谢谢分享
无心凡尘 发表于 2026-2-18 14:45
厉害厉害!学习了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-3-8 11:51

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表