mirror of
https://github.com/lifegpc/pythonscript.git
synced 2026-06-21 18:54:19 +08:00
update convert_lrc.py
This commit is contained in:
113
convert_lrc.py
113
convert_lrc.py
@@ -1,6 +1,7 @@
|
|||||||
from getopt import gnu_getopt as getopt, GetoptError
|
from getopt import gnu_getopt as getopt, GetoptError
|
||||||
|
from math import floor
|
||||||
from os.path import basename, dirname, join, splitext
|
from os.path import basename, dirname, join, splitext
|
||||||
from re import compile, search
|
from re import compile, Match, search
|
||||||
from sys import argv, exit
|
from sys import argv, exit
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
try:
|
try:
|
||||||
@@ -13,12 +14,10 @@ except ImportError:
|
|||||||
RSSBOTLIB_NOTFOUND = '''rssbotlib not found.
|
RSSBOTLIB_NOTFOUND = '''rssbotlib not found.
|
||||||
The source code is available at https://github.com/lifegpc/ffmpeg-study/tree/master/rssbotlib''' # noqa: E501
|
The source code is available at https://github.com/lifegpc/ffmpeg-study/tree/master/rssbotlib''' # noqa: E501
|
||||||
DUR_REG = compile(r'^(?P<sign>[\+-])?(((?P<h>\d+):)?((?P<min>\d+):))?(?P<sec>\d+)(\.(?P<ms>\d+))?$') # noqa: E501
|
DUR_REG = compile(r'^(?P<sign>[\+-])?(((?P<h>\d+):)?((?P<min>\d+):))?(?P<sec>\d+)(\.(?P<ms>\d+))?$') # noqa: E501
|
||||||
|
LRCDUR_REG = compile(r'\[(((?P<h>\d+):)?((?P<min>\d+):))?(?P<sec>\d+)(\.(?P<ms>\d+))?\]') # noqa: E501
|
||||||
|
|
||||||
|
|
||||||
def prase_duration(s: str) -> float:
|
def convert_dur(r: Match) -> float:
|
||||||
r = search(DUR_REG, s)
|
|
||||||
if r is None:
|
|
||||||
raise ValueError(f'Can not parse duration "{s}"')
|
|
||||||
rd = r.groupdict()
|
rd = r.groupdict()
|
||||||
t = int(rd['sec'])
|
t = int(rd['sec'])
|
||||||
if rd['ms']:
|
if rd['ms']:
|
||||||
@@ -27,11 +26,18 @@ def prase_duration(s: str) -> float:
|
|||||||
t += int(rd['min']) * 60
|
t += int(rd['min']) * 60
|
||||||
if rd['h']:
|
if rd['h']:
|
||||||
t += int(rd['h']) * 3600
|
t += int(rd['h']) * 3600
|
||||||
if rd['sign'] == '-':
|
if 'sign' in rd and rd['sign'] == '-':
|
||||||
t = -t
|
t = -t
|
||||||
return t
|
return t
|
||||||
|
|
||||||
|
|
||||||
|
def prase_duration(s: str) -> float:
|
||||||
|
r = search(DUR_REG, s)
|
||||||
|
if r is None:
|
||||||
|
raise ValueError(f'Can not parse duration "{s}"')
|
||||||
|
return convert_dur(r)
|
||||||
|
|
||||||
|
|
||||||
def generate_good_filename(meta: AVDict) -> Optional[str]:
|
def generate_good_filename(meta: AVDict) -> Optional[str]:
|
||||||
m = meta.to_dict()
|
m = meta.to_dict()
|
||||||
if 'title' in m and 'artist' in m:
|
if 'title' in m and 'artist' in m:
|
||||||
@@ -40,6 +46,71 @@ def generate_good_filename(meta: AVDict) -> Optional[str]:
|
|||||||
return f"{m['title']}.lrc"
|
return f"{m['title']}.lrc"
|
||||||
|
|
||||||
|
|
||||||
|
class Lyric:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self._l = []
|
||||||
|
self._meta = []
|
||||||
|
self._bom = False
|
||||||
|
self._has_dur = True
|
||||||
|
|
||||||
|
def parse(self, fn: str):
|
||||||
|
li = []
|
||||||
|
me = []
|
||||||
|
with open(fn, 'r', encoding='UTF-8') as f:
|
||||||
|
t = f.read(1)
|
||||||
|
if t == '\ufeff':
|
||||||
|
self._bom = True
|
||||||
|
else:
|
||||||
|
f.seek(0, 0)
|
||||||
|
ll = f.readlines(1)
|
||||||
|
while len(ll) > 0:
|
||||||
|
for i in ll:
|
||||||
|
i = i.rstrip('\n')
|
||||||
|
if self._has_dur:
|
||||||
|
tre = LRCDUR_REG.finditer(i)
|
||||||
|
re: List[Match] = []
|
||||||
|
for tmp in tre:
|
||||||
|
re.append(tmp)
|
||||||
|
if len(re) == 0:
|
||||||
|
if i.startswith('[') and i.endswith(']'):
|
||||||
|
me.append(i[1:-1])
|
||||||
|
else:
|
||||||
|
if len(li) == 0:
|
||||||
|
self._has_dur = False
|
||||||
|
li.append(i)
|
||||||
|
else:
|
||||||
|
print(f'Ignored "{i}"')
|
||||||
|
else:
|
||||||
|
d = i[re[-1].end():]
|
||||||
|
for r in re:
|
||||||
|
li.append({'time': round(convert_dur(r), 2),
|
||||||
|
'data': d})
|
||||||
|
else:
|
||||||
|
if i.startswith('[') and i.endswith(']'):
|
||||||
|
me.append(i[1:-1])
|
||||||
|
else:
|
||||||
|
li.append(i)
|
||||||
|
ll = f.readlines(1)
|
||||||
|
self._l = li
|
||||||
|
self._meta = me
|
||||||
|
|
||||||
|
def save(self, fn: str):
|
||||||
|
with open(fn, 'w', encoding='UTF-8') as f:
|
||||||
|
if self._bom:
|
||||||
|
f.write('\ufeff')
|
||||||
|
for m in self._meta:
|
||||||
|
f.write(f"[{m}]\n")
|
||||||
|
for i in self._l:
|
||||||
|
if isinstance(i, str):
|
||||||
|
f.write(f"{i}\n")
|
||||||
|
else:
|
||||||
|
t = round(i['time'] * 100)
|
||||||
|
m = floor(t / 6000)
|
||||||
|
s = floor((t % 6000) / 100)
|
||||||
|
ms = t % 100
|
||||||
|
f.write(f"[{m:02}:{s:02}.{ms:02}]{i['data']}\n")
|
||||||
|
|
||||||
|
|
||||||
class Cml:
|
class Cml:
|
||||||
def __init__(self, arg: List[str]) -> None:
|
def __init__(self, arg: List[str]) -> None:
|
||||||
self.output = None
|
self.output = None
|
||||||
@@ -136,7 +207,35 @@ def main() -> int:
|
|||||||
print(f'Get file name from input file: {output}')
|
print(f'Get file name from input file: {output}')
|
||||||
if cml.dir is not None:
|
if cml.dir is not None:
|
||||||
output = join(cml.dir, basename(output))
|
output = join(cml.dir, basename(output))
|
||||||
print(f'Replace output directory: {output}')
|
if cml.verbose:
|
||||||
|
print(f'Replace output directory: {output}')
|
||||||
|
lrc = Lyric()
|
||||||
|
lrc.parse(cml.input)
|
||||||
|
if not lrc._has_dur:
|
||||||
|
raise ValueError("This lyric file don't have timestamp.")
|
||||||
|
lrc._l.sort(key=lambda d: d['time'])
|
||||||
|
re = []
|
||||||
|
ltmp = 0
|
||||||
|
tmp = None
|
||||||
|
for i in lrc._l:
|
||||||
|
if tmp is not None:
|
||||||
|
re.append({'time': max(ltmp, round(i['time'] - 0.01, 2)),
|
||||||
|
'data': tmp})
|
||||||
|
tmp = None
|
||||||
|
s: str = i['data']
|
||||||
|
if s.find(' / ') > 0:
|
||||||
|
li = s.split(' / ', 1)
|
||||||
|
ltmp = i['time']
|
||||||
|
tmp = li[1]
|
||||||
|
re.append({'time': i['time'], 'data': li[0]})
|
||||||
|
else:
|
||||||
|
re.append(i.copy())
|
||||||
|
if tmp is not None:
|
||||||
|
if dur is not None:
|
||||||
|
re.append({'time': max(round(dur, 2), round(ltmp + 0.01, 2)),
|
||||||
|
'data': tmp})
|
||||||
|
lrc._l = re
|
||||||
|
lrc.save(output)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
2
tdlib.py
2
tdlib.py
@@ -12,7 +12,7 @@ from traceback import print_exc
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
tdjson_path = find_library('tdjson') or 'tdjson.dll'
|
tdjson_path = find_library('tdjson')
|
||||||
if tdjson_path is None:
|
if tdjson_path is None:
|
||||||
print("Can't find 'tdjson' library")
|
print("Can't find 'tdjson' library")
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|||||||
Reference in New Issue
Block a user