花潮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-21 22:57 编辑
简明指南:
一、制作
① 在大文本框放入一行一句的歌词,不留空行;
② 在小文本框放入音频地址;
③ 点击播放器上的播放按钮,再点暂停可在小文本框得到花潮格式lrc,点双上箭头按钮,歌词“上屏”,继续操作直至结束。
二、转换
将如下格式的lrc歌词
[秒:分.毫秒]歌词
[秒:分.毫秒][秒:分.毫秒]...[秒:分.毫秒]歌词
['秒:分.毫秒','歌词']
["秒:分.毫秒","歌词"]
复制到大文本框,并在小文本框输入音频地址,然后点击小文本框右边的 ”lrc转换“ 按钮。
三、测试
此工作模式指检验花潮格式lrc与歌曲同步情况。大文本框中放入 lrcAr 数组的主体部分,小文本框放入对应的歌曲地址,准备就绪点 “lrc效果测试” 按钮。
打包:
占位一 占位二 引发问题的原因找到:字母 i 的问题!
一个坑跳了几次——之前碰上过的问题这回又碰上一次: for 循环语句中,习惯性也是规范性地使用了步进变量 i,这没问题,但当处理数组需要用到变量 i 时,问题就来了,中括号里放个字母 i 被论坛DZ程序视为 ubb 代码处理,是论坛斜体字保留符号。试看:
花潮LRC在线
本程序代码中有三处 for 循环。其实 for 循环效率还是挺高的,用小写字母 i 做for的步进变量也是规范,现在只能改改了,用 j 替代 i, 不会被论坛的 ubb 处理模块处理。
最新版本的 Discuz! 下这个问题已经不存在。 在线测试了一下,OK、不过我偷懒就半首音乐{:4_170:}准备吃饭去了,来不及了 这个是花潮的专利产品了{:4_173:} 小辣椒 发表于 2022-6-18 17:38
这个是花潮的专利产品了
本应如此 小辣椒 发表于 2022-6-18 17:30
在线测试了一下,OK、不过我偷懒就半首音乐准备吃饭去了,来不及了
制作功能没什么大变化,和原来的差不多。亮点是加入了两个其他功能。 马黑黑 发表于 2022-6-18 17:55
制作功能没什么大变化,和原来的差不多。亮点是加入了两个其他功能。
看见了,我也是下载收藏了
黑黑我吃饭了,晚上见 小辣椒 发表于 2022-6-18 17:59
看见了,我也是下载收藏了
黑黑我吃饭了,晚上见
俺也要吃饭了 醉美水芙蓉 发表于 2022-6-18 17:57
有空玩玩!谢谢黑黑老师分享!老师辛苦了!
{:4_190:} 马黑黑 发表于 2022-6-18 17:55
制作功能没什么大变化,和原来的差不多。亮点是加入了两个其他功能。
对,加了转换,还加了测试,现在是真的完美了{:4_199:} 转换还没试过,我先试试看。。。 就是,测试或者转换的时候,能看到歌曲进行的时间,不能点击上屏的么?测试了一下,还没弄懂怎么玩的。 没看懂。{:5_103:} 东篱闲人 发表于 2022-6-18 19:34
没看懂。
预览一下就懂 红影 发表于 2022-6-18 19:03
对,加了转换,还加了测试,现在是真的完美了
测试版本,看看有什么问题 红影 发表于 2022-6-18 19:16
就是,测试或者转换的时候,能看到歌曲进行的时间,不能点击上屏的么?测试了一下,还没弄懂怎么玩的。
上屏仅是制作模式的功能,转换和测试无需上屏,但可以手动修改大文本框里的相关信息