吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2171|回复: 30
收起左侧

[Python 原创] 双语歌曲LRC歌词文件整理

  [复制链接]
wzvideni 发表于 2023-11-12 20:16
本帖最后由 wzvideni 于 2023-11-20 14:15 编辑

双语歌曲LRC歌词文件整理

2023:11:20更新:

  1. 修改删除[offset:0]的判断,添加被之前删除[offset:0],加入判断如果在时间轴[00:00]前不存在offset标签自动添加[offset:0]
  2. 添加翻译时间轴的矫正,毫秒差在10ms内的判断为同一时间轴

强迫症犯了,自己写的一个双语歌词歌曲LRC歌词文件的自动整理程序,会递归整理输入目录下的所有LRC文件,代码如下:

import os
import re

# 无用内容元组
useless = ('', '\\\\', '//')

def lyrics_editor(lrc_path):
    # 新建一个空的歌词字典,键为时间轴或者歌曲信息,值为值为歌词列表(列表是为了存歌词翻译)
    lrc_map = {}
    with (open(lrc_path, encoding='utf-8') as lrc):
        # 如果有歌词和翻译时间轴不对应的情况,在修正后,将不对应的键添加进del_timeline列表统一删除
        del_timeline = list()
        # 逐行读取:“[00:00.00]这里是歌词”
        for line in lrc:
            # 判断读取行是否为空白字符(换行符),过滤空白行
            if not line.isspace():
                # 匹配时间轴:“[00:00.00]”
                timeline = re.search(r'\[.*]', line).group()
                # 将读取行中的时间轴和歌词末尾的换行符清除后则为歌词
                lyrics = line.replace(timeline, '').strip()
                # 如果时间轴中包含“by”、”offset“、”kana“其中的一个并且起始索引都为1,此标签大部分为垃圾信息,跳过循环
                if timeline.find('by') == 1 or timeline.find('kana') == 1:
                    continue
                # 如果歌词内容在无用内容元组中或者包含“QQ音乐”、跳过循环
                if lyrics in useless or lyrics.find('QQ音乐') != -1:
                    # 如果不是时间轴中包含“ti”、”ar“、”al“其中的一个并且起始索引都为1则表示读取的是歌曲的相关信息,则跳过循环
                    if not (timeline.find('ti') == 1 or timeline.find('offset') == 1 or timeline.find(
                            'ar') == 1 or timeline.find('al') == 1):
                        continue

                # 时间轴不存在歌词字典中则表示现在为写入原歌词阶段
                if timeline not in lrc_map:
                    # 将时间轴为键,歌词为值存入歌词字典,其中歌词以列表的形式存储
                    lrc_map[timeline] = list()
                    lrc_map[timeline].append(lyrics)
                    # 以下部分是校正时间轴的代码
                    # 分割时间轴对应的分
                    timeline_minutes = timeline[1:3]
                    # 分割时间轴对应的秒
                    timeline_seconds = timeline[4:6]
                    # 分割时间轴对应的毫秒
                    timeline_millisecond = timeline[7:9]
                    # 如果分割时间轴对应的分是数字就表示是时间轴
                    if timeline_minutes.isdigit():
                        # 遍历歌词字典查找是否有歌词和键不匹配的情况
                        for key, value in lrc_map.items():
                            # 分割键对应的分
                            minutes = key[1:3]
                            # 分割键对应的秒
                            seconds = key[4:6]
                            # 分割键对应的毫秒
                            millisecond = key[7:9]
                            # 继续判断是否是数字
                            if minutes.isdigit():
                                # 分秒一定要相同
                                if timeline_minutes == minutes and timeline_seconds == seconds:
                                    # 判断毫秒差绝对值不超过10ms,则表示翻译时间轴不对应并找到了正确的时间轴
                                    if abs(int(timeline_millisecond) - int(millisecond)) < 10:
                                        # 如果当前歌词不存在于歌词字典才继续,防止重复添加
                                        if lyrics not in lrc_map[key]:
                                            # 把时间轴添加进入将要删除的时间轴列表
                                            del_timeline.append(timeline)
                                            # 往正确的时间轴写入翻译
                                            lrc_map[key].append(lyrics)

                # 否则时间轴存在歌词字典中则表示现在为写入歌词翻译阶段
                else:
                    # 如果歌词翻译不在键对应的歌词列表中则添加进去,防止重复添加
                    if lyrics not in lrc_map[timeline]:
                        # 将歌词添加到键对应的值列表中
                        lrc_map[timeline].append(lyrics)

    for del_key in del_timeline:
        del lrc_map[del_key]

    # 清空原文件歌词内容
    with open(lrc_path, 'w') as lrc:
        lrc.truncate(0)
    offset_flag = 1
    last_key = ''
    # 遍历歌词字典
    for key, value in lrc_map.items():
        # 在00:00.00前写入换行符,分隔歌曲信息和歌词
        if offset_flag == 1:
            if key.find('00:00') == 1:
                # 查找00:00.00是否存在offset,不存在则自动添加
                if last_key.find('offset') == 1:
                    with open(lrc_path, 'a', encoding='utf-8') as lrc:
                        lrc.write('\n')
                else:
                    with open(lrc_path, 'a', encoding='utf-8') as lrc:
                        lrc.write('[offset:0]\n\n')
                offset_flag = 0
        # 当前歌词值列表长度大于1(即存在翻译时)就额外在歌词和翻译前添加一个换行符
        # 写入前换行便于和歌曲信息隔开来(但是仅限于翻译存在时可以很好地分隔开来)
        if len(value) > 1:
            with open(lrc_path, 'a', encoding='utf-8') as lrc:
                lrc.write('\n')
        # 遍历当前时间轴键的歌词列表把时间轴和歌词拼接后写入歌词文件
        for lyrics in value:
            with open(lrc_path, 'a', encoding='utf-8') as lrc:
                lrc.write(f'{key}{lyrics}\n')
        last_key = key

def walk_path(input_path):
    # 统计更改的文件数量
    count = 0
    # 遍历目录
    for root, dirs, files in os.walk(input_path):
        # 循环目录中的文件
        for file in files:
            # 匹配*.lrc文件
            match = re.search(r'.*\.lrc$', os.path.join(root, file))
            # 匹配成功
            if match:
                # 获取路径
                lrc_path = match.group()
                # 执行编辑
                lyrics_editor(lrc_path)
                # 输出编辑完成的文件路径
                print(lrc_path)
                count += 1

    print(f'\n已处理数量:{count}')

if __name__ == '__main__':
    print('双语歌曲LRC歌词文件整理')
    # lrc文件所在目录
    path = input("请输入lrc文件所在目录的路径:")
    while path == '':
        path = input('路径不能为空:')
    walk_path(path)
    input('按任意键继续……')

整理前:

[ti:シュガーコート]
[ar:Dazbee (ダズビー)]
[al:シュガーコート]
[by:]
[offset:0]
[kana:1し1ささ1がわ1ま1お1きょく1ささ1がわ1ま1お2はだし1に1だ1ふ1お1いき1す1ほそ1て1あし1だる1じょう1しき1わす1とめ1がね1はず1じゅ1もん1さけ1い1くび1つめ1た1と1あい1ふう1せん1しぼ1ま1ちが1いのち1か1か1あい1ほ1かぜ1ほお1さ1ゆ1ぜん1ぶ1しっ1た1たか1な1むね1のう1こ1は1や1やまい1げ1こう1じ1こく1な1とき1あま1きら1くち1ぐせ1い1きず1うず1うず1くる1ほ1えい1えん1そら1しず1めい1てい1かん1いと1うば1ゆめ1み1いま1い1ふ1くび1つめ1た1と1し1げき1ほ1せん1こう1き1そだ1かさ1いき1ひと1じ1ごく1きみ]
[00:00.00]シュガーコート - Dazbee (ダズビー)
[00:00.74]词:笹川真生
[00:01.17]曲:笹川真生
[00:01.70]裸足のままどっか逃げ出したい?
[00:05.29]まだ腑に落ちたい?
[00:07.10]それでどうしたい?
[00:09.14]息ひとつさえうまく吸えないで
[00:12.58]その細い手足では怠いでしょう
...

[ti:シュガーコート]
[ar:Dazbee (ダズビー)]
[al:シュガーコート]
[by:]
[offset:0]
[kana:1し1ささ1がわ1ま1お1きょく1ささ1がわ1ま1お2はだし1に1だ1ふ1お1いき1す1ほそ1て1あし1だる1じょう1しき1わす1とめ1がね1はず1じゅ1もん1さけ1い1くび1つめ1た1と1あい1ふう1せん1しぼ1ま1ちが1いのち1か1か1あい1ほ1かぜ1ほお1さ1ゆ1ぜん1ぶ1しっ1た1たか1な1むね1のう1こ1は1や1やまい1げ1こう1じ1こく1な1とき1あま1きら1くち1ぐせ1い1きず1うず1うず1くる1ほ1えい1えん1そら1しず1めい1てい1かん1いと1うば1ゆめ1み1いま1い1ふ1くび1つめ1た1と1し1げき1ほ1せん1こう1き1そだ1かさ1いき1ひと1じ1ごく1きみ]
[00:00.00]QQ音乐享有本翻译作品的著作权
[00:00.74]//
[00:01.17]//
[00:01.70]想赤脚逃到某个地方吗
[00:05.29]想要了解更多吗
[00:07.10]然后呢 你想怎么做呢
[00:09.14]明明连正常呼吸都如此困难了
[00:12.58]你那纤细的四肢根本难以抵御吧
...

整理后:

[ti:シュガーコート]
[ar:Dazbee (ダズビー)]
[al:シュガーコート]
[00:00.00]シュガーコート - Dazbee (ダズビー)
[00:00.74]词:笹川真生
[00:01.17]曲:笹川真生

[00:01.70]裸足のままどっか逃げ出したい?
[00:01.70]想赤脚逃到某个地方吗

[00:05.29]まだ腑に落ちたい?
[00:05.29]想要了解更多吗

[00:07.10]それでどうしたい?
[00:07.10]然后呢 你想怎么做呢

[00:09.14]息ひとつさえうまく吸えないで
[00:09.14]明明连正常呼吸都如此困难了

[00:12.58]その細い手足では怠いでしょう
[00:12.58]你那纤细的四肢根本难以抵御吧


运行截图:

运行截图

运行截图


exe编译程序:
https://wwur.lanzout.com/iFHR71fe52yh

免费评分

参与人数 7吾爱币 +12 热心值 +7 收起 理由
ws001980 + 1 + 1 谢谢@Thanks!
wiltzy + 1 + 1 谢谢@Thanks!
zhangt729 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
MC心福 + 1 + 1 我很赞同!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Huibq120 + 1 我很赞同!
AuSun + 1 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

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

 楼主| wzvideni 发表于 2023-11-14 15:21
本帖最后由 wzvideni 于 2023-11-14 15:27 编辑
小小/ng 发表于 2023-11-14 14:53
还要规避这样的一样的,怎么搞

[Python] 纯文本查看 复制代码
import os.path
import re


def merge_subtitles(srt1, srt2, output):
    subtitles1 = list()
    subtitles2 = list()
    # 读取第一个字幕文件
    with open(srt1, encoding='utf-8') as lines:
        for line in lines:
            if not line.isspace():
                subtitles1.append(line)

    # 读取第二个字幕文件        
    with open(srt2, encoding='utf-8') as lines:
        for line in lines:
            if not line.isspace():
                subtitles2.append(line)

    # 合并字幕
    merged = []
    i1 = i2 = 0
    while i1 < len(subtitles1) and i2 < len(subtitles2):
        timeline = ''
        if i1 != 0:
            # 获取前一行的时间轴
            timeline = re.search(r'(\d+:\d+:\d+\.\d+)( --> )(\d+:\d+:\d+\.\d+)', subtitles1[i1 - 1])

        if timeline:
            if subtitles1[i1] != subtitles2[i2]:
                mix_english = re.search(r'[A-z]+', subtitles1[i1])
                if mix_english:
                    merged.append(subtitles2[i2])
                else:
                    # 添加第一行字幕
                    merged.append(subtitles1[i1])
                    # 添加第二行字幕
                    merged.append(subtitles2[i2])
            else:
                merged.append(subtitles1[i1])
            merged.append('\n')
        else:
            merged.append(subtitles1[i1])

        i1 += 1
        i2 += 1
    # 如果输出文件存在则清空
    if os.path.exists(output):
        with open(output, 'w') as lrc:
            lrc.truncate(0)
    # 写入合并后的字幕文件
    with open(output, 'w', encoding='utf-8') as f:
        f.writelines(merged)


if __name__ == '__main__':
    srt1 = 'ko.srt'
    srt2 = 'zh.srt'
    output = 'merged.srt'
    merge_subtitles(srt1, srt2, output)


词和翻译相同的只保留一个
混合英语的只保留了翻译

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
小小/ng + 1 + 1 用心讨论,共获提升!

查看全部评分

 楼主| wzvideni 发表于 2023-11-14 14:37
本帖最后由 wzvideni 于 2023-11-14 14:42 编辑
小小/ng 发表于 2023-11-14 13:51

[Python] 纯文本查看 复制代码

import os.path
import re


def merge_subtitles(srt1, srt2, output):
    subtitles1 = list()
    subtitles2 = list()
    # 读取第一个字幕文件
    with open(srt1, encoding='utf-8') as lines:
        for line in lines:
            if not line.isspace():
                subtitles1.append(line)

    # 读取第二个字幕文件        
    with open(srt2, encoding='utf-8') as lines:
        for line in lines:
            if not line.isspace():
                subtitles2.append(line)

    # 合并字幕
    merged = []
    i1 = i2 = 0
    while i1 < len(subtitles1) and i2 < len(subtitles2):
        timeline = ''
        if i1 != 0:
            # 获取前一行的时间轴
            timeline = re.search(r'(\d+:\d+:\d+\.\d+)( --> )(\d+:\d+:\d+\.\d+)', subtitles1[i1 - 1])

        if timeline:
            # 添加第一行字幕
            merged.append(subtitles1[i1])
            # 添加第二行字幕
            merged.append(subtitles2[i2])
            merged.append('\n')
        else:
            merged.append(subtitles1[i1])
            
        i1 += 1
        i2 += 1
    # 如果输出文件存在则清空
    if os.path.exists(output):
        with open(output, 'w') as lrc:
            lrc.truncate(0)
    # 写入合并后的字幕文件
    with open(output, 'w', encoding='utf-8') as f:
        f.writelines(merged)


if __name__ == '__main__':
    srt1 = 'ko.srt'
    srt2 = 'zh.srt'
    output = 'merged.srt'
    merge_subtitles(srt1, srt2, output)



这个样子吗?

1
00:00:38.000 --> 00:00:41.000
&#50612;&#46356;&#49436; &#50772;&#45768; &#54848;&#50672;&#55176;
突然来自于哪里

2
00:00:41.000 --> 00:00:44.000
&#44256;&#50836;&#54664;&#45912; &#49464;&#49345;&#51032; Crash
寂静世界的 Crash

3
00:00:44.000 --> 00:00:48.000
Chill Kill&#51032; &#46321;&#51109; &#47560;&#52824; Thunder
Chill Kill 的出现就像 Thunder

免费评分

参与人数 1吾爱币 +3 热心值 +1 收起 理由
小小/ng + 3 + 1 谢谢 @Thanks!

查看全部评分

Huibq120 发表于 2023-11-12 22:39
vethenc 发表于 2023-11-12 23:12
感谢分享,非常实用的,初略看了一下,没看懂,能否给个示例就更好了。
MC心福 发表于 2023-11-13 03:30
感谢分享
gxhc168 发表于 2023-11-13 06:59
感谢老大的分享
winxpnt 发表于 2023-11-13 08:11
这个不错,可以,感谢分享
头像被屏蔽
mokson 发表于 2023-11-13 08:16
提示: 作者被禁止或删除 内容自动屏蔽
仙鬼同拥 发表于 2023-11-13 08:52
vethenc 发表于 2023-11-12 23:12
感谢分享,非常实用的,初略看了一下,没看懂,能否给个示例就更好了。

没关系,我来当机器运行,给你转述一下运行流程。
第一部分:遍历提取LRC歌词中的歌名部分,具体的抓取条件可以去研究一下LRC各个标签的功能,就跟discuz论坛的功能代码,比如Fly飞行字、Size设置字体大小之类的。
第二部分:用各种过滤条件抓取到歌名之后,用歌名去撞库,判断该歌名对应的歌词是否为外语,如果是外语则标记为1
第三部分:对外语歌的歌词进行处理,主要有2种处理类型,1、对文件夹里存在歌名同名的两种歌词进行融合,比如《极乐净土》中文.lrc和《极乐净土》日文.lrc这是一首歌的两个歌词文件,他俩的头部艺术家信息是一样的,都是[name:极乐净土]、[art:美芽]这样的,这就被判断为同一首歌的两种语言歌词,然后融合处理就是把每一行相同时间标签的中文歌词穿插到原日文歌词里变成双行显示。2、对外语歌词进行翻译处理,以时间标签开头、换行结尾,断为一句歌词,逐句进行翻译,在每行原文歌词下面复制原时间标签,附上翻译歌词,组成双行显示
lwlonger 发表于 2023-11-13 08:59
高手,谢谢分享
abca 发表于 2023-11-13 09:16

这个不错,厉害厉害
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-24 18:34

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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