马黑黑 发表于 2022-6-18 13:24

花潮LRC在线(2022.6.25)

本帖最后由 马黑黑 于 2022-6-27 07:01 编辑 <br /><br /><style>
.outer { margin: auto; width: fit-content; height: fit-content; }
.outer h2 { margin: 10px; padding: 0; font: bold 1.5em sans-serif; text-align: center; }
.outer p { margin: 10px; }
.outer input { font: normal 16px sans-serif; }
.menu { margin: 0 0 -1px 8px; width: fit-content; height: fit-content; display: flex; position: relative; }
.item { width: 60px; height: 30px; font: normal 1em / 30px sans-serif; text-align: center; background: #fff; border: 1px solid; border-bottom: none; cursor: pointer; }
.item1 { border: none; border-bottom: 1px solid; background: none; }
#slip { width: 50px; text-align: center; }
#lrcText { padding: 10px; width: 736px; height: 400px; font: normal 16px / 26px sans-serif; resize: both; border: 1px solid; outline: none; }
#mUrl {         padding: 4px; width: 440px; font-size: 14px; }
#aud { display: none; outline: none; }
#audMsg { display: inline-block; margin-left: 12px; height: 54px; font: normal 1em / 54px sans-serif; }
#up, #copy { display: none; }
#check, #invert { width: 100px; }
</style>

<div class="outer">
        <h2>花潮LRC在线</h2>
        <div class="menu">
                <div class="item">制作</div>
                <div class="item item1">转换</div>
                <div class="item item1">测试</div>
        </div>
        <textarea id="lrcText" rows ="18" cols="60" placeholder="原始歌词"></textarea>
        <p>
                <input id="begin" type="button" value=" 开始 " />
                <input id="up" type="button" value=" ↑↑ " />
                <input id="copy" type="button" value=" 复制 " />
                <input id="mUrl" type="text" placeholder="音频地址" value="" />
                <label>误差值 : </label>
                <input id="slip" type="number" placeholder="0" value="0.2" min="0" max="1" step="0.1" />
                <input id="check" type="button" value="lrc效果测试" disabled />
                <input id="invert" type="button" value="lrc转换" style="display: none" />
        </p>
        <p style="display:flex">
                <audio id="aud" controls="controls"></audio>
                <span id="audMsg"></span>
        </p>
</div>

<script>
//更新时间 2022.6.25
let begin = document.querySelector('#begin'), copy = document.querySelector('#copy'),
        up = document.querySelector('#up'), check = document.querySelector('#check'),
        invert = document.querySelector('#invert'), lrcText = document.querySelector('#lrcText'),
        slip = document.querySelector('#slip'), audMsg = document.querySelector('#audMsg'),
        mUrl = document.querySelector('#mUrl'), items = document.querySelectorAll('.item');
let lrcArr = [], slipNum = , mode = 0, yp, idx, mkidx;
//模式切换
Array.from(items).forEach((ele,key) => {
        ele.onclick = () => {
                slip.value = slipNum;
                ele.className = 'item';
                mode = key;
                if(mode == 0) { //制作模式
                        lrcText.placeholder = '原始歌词';
                        items.className = items.className = 'item item1';
                        check.disabled = true;
                        begin.disabled = false;
                        check.style.display = 'inline-block';
                        invert.style.display = 'none';
                } else if(mode == 1){ //转换模式
                        lrcText.placeholder = 'mm:(.)ss.(:)ms → ss.ms';
                        items.className = items.className = 'item item1';
                        check.disabled = true;
                        check.style.display = 'none';
                        begin.disabled = true;
                        invert.style.display = 'inline-block';
                } else { //检验模式
                        lrcText.placeholder = '花潮lrc歌词同步测试';
                        items.className = items.className = 'item item1';
                        check.disabled = false;
                        check.style.display = 'inline-block';
                        begin.disabled = true;
                        invert.style.display = 'none';
                }
        }
});
//开始制作
begin.onclick =() => {
        if(lrcText.value == '' || mUrl.value == '') return false;
        getUrl(mUrl.value);
        lrcArr.length = 0;//清空数组
        idx = mkidx = 0;
        lrcArr = (lrcText.value).trim().split('\n');
        lrcText.value = 'let lrcAr = [\n';
        mUrl.value = lrcArr;
        begin.style.display = 'none';
        up.style.display = 'inline-block';
        aud.style.display = 'inline-block';
}
//lrc上屏
up.onclick = () => {
        if(idx == lrcArr.length - 1) {//最后一句
                lrcText.value += '\t' + mUrl.value.slice(0,-1) + '\n];';
                up.style.display = 'none';
                copy.style.display = 'inline-block';
                mUrl.value = aud.src;
        } else {
                lrcText.value += '\t' + mUrl.value + '\n';
        }
        lrcText.scrollTop = lrcText.scrollHeight;
        if(idx < lrcArr.length - 1) idx ++;
        mkidx ++;
        audMsg.innerText = audMsg.innerText.replace(/\/\s\d+/,'/ ' + mkidx);
        mUrl.value = lrcArr;
}
//复制
copy.onclick = () => {
        lrcText.select();
        document.execCommand('copy');
        mUrl.value = '已复制到剪切板';
        copy.style.display = 'none';
        begin.style.display = 'inline-block';
}
//lrc效果测试
check.onclick = () => {
        if(lrcText.value == '' || mUrl.value == '') return false;
        getUrl(mUrl.value);
        lrcArr.length = 0; //清空数组
        idx = 0; //重置数组标识
        let ar = lrcText.value.split('\n');
        for(j=0; j<ar.length; j++) {
                let str = ar.replace(/\['|'],|']|\["|"],|"]|\t|\s/g,'');
                let tmpar = str.split("','");
                if(tmpar.length > 1) lrcArr.push(tmpar);
        }
        aud.style.display = 'block';
        aud.src = mUrl.value;
        aud.play();
}
//转换
invert.onclick = () => {
        if(lrcText.value == '' || mUrl.value == '') return false;
        getUrl(mUrl.value);
        let str = 'let lrcAr = [\n';
        lrcArr.length = 0; //清空数组
        lrcArr = getLrcMsg(lrcText.value);
        for(x of lrcArr) str += "\t['" + x + "','" + x + "'],\n";
        str = str.substring(0, str.lastIndexOf(','));
        lrcText.value = str + '\n];';
}
//误差值改变
slip.onchange = () => {
        slipNum = slip.value;
        if(slipNum > 1) slipNum = 1;
        if(slipNum < -1) slipNum = -1;
}
//暂停监听: 仅制作
aud.addEventListener('pause', () =>{
        if(mode == 0){
                let time = (aud.currentTime - slipNum).toFixed(2);
                mUrl.value = `['${time}','${rep(lrcArr)}'],`;
        }
});
//进度监听
aud.addEventListener('timeupdate', () =>{
        audMsg.innerText = aud.duration + ' | ' + aud.currentTime + (mode == 0 ? ' [ 完成量: ' + lrcArr.length + ' / ' + mkidx + ' ]' : '');
        if(mode == 2){ //检测模式
                let tt = aud.currentTime ;
                for(j=0; j<lrcArr.length; j++){
                        if(tt >= lrcArr - slipNum){
                                mUrl.value = lrcArr;
                                selectText(lrcArr,lrcText);
                                if(lrcText.scrollTop < lrcText.scrollHeight) lrcText.scrollTop = j * lrcText.scrollHeight / (lrcArr.length + 2);
                        }
                }
        }
});
//播放结束监听
aud.addEventListener('ended', () => mUrl.value = yp);
//处理小角引号
let rep = (str) =>str.replace(/\'/g,"\'");
//转换函数 mm:(.)ss:(.)ms → ss.ms
function getLrcMsg(text) {
        let lrcAr = []; //返回的数组
        let calcRule = ; //不同数位的分钟运算规则
        for(x of text.split('\n')) {
                let ar = [];
                let re = /\d+[\.:]\d+([\.:]\d+)?/g; //匹配 mm:(.)ss:(.)ms
                let geci = x.replace(re,''); //找词
                if(geci) { //若有词
                        geci = geci.replace(/[\[\]\'\"\t,]s?/g,''); //过滤无用字符
                        let time = x.match(re); //找时间
                        if(time != null) {
                                for(y of time) {
                                        let tmp = y.match(/\d+/g);
                                        let sec = 0;
                                        for(z in tmp) sec += tmp * calcRule;
                                        sec -= slipNum;
                                        if(sec <0) sec = 0.00;
                                        ar = ;
                                        lrcAr.push(ar);
                                }
                        }
                }
        }
        lrcAr.sort((a,b)=> a - b); //排序
        return lrcAr;
}
//选中当前句时间
let selectText = (txt,ele) =>{
        let all = ele.value,
                start = all.search(txt),
                end = start + txt.length;
        ele.setSelectionRange(start,end);
        ele.focus();
}

function getUrl(url) {
        let reg = /\.?:wav|mp3|wma|ogg|aac|ape|flac$/;
        if(reg.test(url.toLowerCase())) yp = url.trim();
        aud.src = yp;
}
</script>

<hr>
<p><br>更新 :<span style="color: red">2022.6.25</span></p>
<p><br>下载 :<a href="https://www.huachaowang.com/forum.php?mod=attachment&aid=NDI1NTR8YmJiY2VmMjR8MTY1NjI4NDE4M3w3MTMwfDU2MzQ3">花潮LRC在线v3+N多帖子模板</a><br><br> </p>
<p>下载 :<a href="https://www.huachaowang.com/forum.php?mod=attachment&aid=NDI1MTN8ZjZjYTVmMmZ8MTY1NTgyMzQzN3w3MTMwfDYwNDk2">花潮LRC在线v2+N多帖子模板</a><br><br> </p>
<hr>

马黑黑 发表于 2022-6-18 13:24

本帖最后由 马黑黑 于 2022-6-21 22:57 编辑

简明指南:

一、制作

① 在大文本框放入一行一句的歌词,不留空行;
② 在小文本框放入音频地址;
③ 点击播放器上的播放按钮,再点暂停可在小文本框得到花潮格式lrc,点双上箭头按钮,歌词“上屏”,继续操作直至结束。

二、转换

将如下格式的lrc歌词

[秒:分.毫秒]歌词
[秒:分.毫秒][秒:分.毫秒]...[秒:分.毫秒]歌词
['秒:分.毫秒','歌词']
["秒:分.毫秒","歌词"]

复制到大文本框,并在小文本框输入音频地址,然后点击小文本框右边的 ”lrc转换“ 按钮。

三、测试

此工作模式指检验花潮格式lrc与歌曲同步情况。大文本框中放入 lrcAr 数组的主体部分,小文本框放入对应的歌曲地址,准备就绪点 “lrc效果测试” 按钮。

打包:

马黑黑 发表于 2022-6-18 13:24

占位一

马黑黑 发表于 2022-6-18 13:24

占位二

马黑黑 发表于 2022-6-18 17:13

引发问题的原因找到:字母 i 的问题!

一个坑跳了几次——之前碰上过的问题这回又碰上一次: for 循环语句中,习惯性也是规范性地使用了步进变量 i,这没问题,但当处理数组需要用到变量 i 时,问题就来了,中括号里放个字母 i 被论坛DZ程序视为 ubb 代码处理,是论坛斜体字保留符号。试看:

花潮LRC在线

本程序代码中有三处 for 循环。其实 for 循环效率还是挺高的,用小写字母 i 做for的步进变量也是规范,现在只能改改了,用 j 替代 i, 不会被论坛的 ubb 处理模块处理。

最新版本的 Discuz! 下这个问题已经不存在。

小辣椒 发表于 2022-6-18 17:30

在线测试了一下,OK、不过我偷懒就半首音乐{:4_170:}准备吃饭去了,来不及了

小辣椒 发表于 2022-6-18 17:38

这个是花潮的专利产品了{:4_173:}

马黑黑 发表于 2022-6-18 17:41

小辣椒 发表于 2022-6-18 17:38
这个是花潮的专利产品了

本应如此

马黑黑 发表于 2022-6-18 17:55

小辣椒 发表于 2022-6-18 17:30
在线测试了一下,OK、不过我偷懒就半首音乐准备吃饭去了,来不及了

制作功能没什么大变化,和原来的差不多。亮点是加入了两个其他功能。

醉美水芙蓉 发表于 2022-6-18 17:57

小辣椒 发表于 2022-6-18 17:59

马黑黑 发表于 2022-6-18 17:55
制作功能没什么大变化,和原来的差不多。亮点是加入了两个其他功能。

看见了,我也是下载收藏了

黑黑我吃饭了,晚上见

马黑黑 发表于 2022-6-18 18:12

小辣椒 发表于 2022-6-18 17:59
看见了,我也是下载收藏了

黑黑我吃饭了,晚上见

俺也要吃饭了

马黑黑 发表于 2022-6-18 18:13

醉美水芙蓉 发表于 2022-6-18 17:57
有空玩玩!谢谢黑黑老师分享!老师辛苦了!

{:4_190:}

红影 发表于 2022-6-18 19:03

马黑黑 发表于 2022-6-18 17:55
制作功能没什么大变化,和原来的差不多。亮点是加入了两个其他功能。

对,加了转换,还加了测试,现在是真的完美了{:4_199:}

红影 发表于 2022-6-18 19:04

转换还没试过,我先试试看。。。

红影 发表于 2022-6-18 19:16

就是,测试或者转换的时候,能看到歌曲进行的时间,不能点击上屏的么?测试了一下,还没弄懂怎么玩的。

东篱闲人 发表于 2022-6-18 19:34

没看懂。{:5_103:}

马黑黑 发表于 2022-6-18 19:57

东篱闲人 发表于 2022-6-18 19:34
没看懂。

预览一下就懂

马黑黑 发表于 2022-6-18 19:59

红影 发表于 2022-6-18 19:03
对,加了转换,还加了测试,现在是真的完美了

测试版本,看看有什么问题

马黑黑 发表于 2022-6-18 20:00

红影 发表于 2022-6-18 19:16
就是,测试或者转换的时候,能看到歌曲进行的时间,不能点击上屏的么?测试了一下,还没弄懂怎么玩的。

上屏仅是制作模式的功能,转换和测试无需上屏,但可以手动修改大文本框里的相关信息
页: [1] 2 3 4 5 6
查看完整版本: 花潮LRC在线(2022.6.25)