mirror of
https://gitea.pjck.top/Cookies/CookiesChartConverter.git
synced 2026-02-14 21:17:28 +08:00
Compare commits
4 Commits
5a082b63a4
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| bd69ee2b9c | |||
| 0e029febdd | |||
| e73568a1fe | |||
| e85f7e86ee |
29
convert.py
29
convert.py
@@ -8,7 +8,7 @@ from acb2mp3 import convert_awb_to_wav, convert_wav_to_mp3
|
|||||||
from search import search_music_by_id
|
from search import search_music_by_id
|
||||||
from pv_decode import dat_to_mp4
|
from pv_decode import dat_to_mp4
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
# 假设你已实现以下函数
|
# 假设你已实现以下函数
|
||||||
|
|
||||||
def build_maidata_txt(
|
def build_maidata_txt(
|
||||||
@@ -136,11 +136,28 @@ def convert_to_simai_folder(result,output_folder):
|
|||||||
# 示例调用
|
# 示例调用
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
for i in range(11838,11851):
|
music_ids = [834,799]
|
||||||
res = search_music_by_id(str(i))
|
output_folder = "result"
|
||||||
|
max_workers = 6 # 根据 CPU 和硬盘负载合理设置线程数
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||||
|
futures = {}
|
||||||
|
for mid in music_ids:
|
||||||
|
res = search_music_by_id(str(mid))
|
||||||
if res is None:
|
if res is None:
|
||||||
continue
|
continue
|
||||||
logger.info(res)
|
logger.info(f"提交任务: {mid}")
|
||||||
logger.info("Converting...")
|
future = executor.submit(convert_to_simai_folder, res, output_folder)
|
||||||
convert_to_simai_folder(res,"/Volumes/Ventoy/Converts")
|
futures[future] = mid
|
||||||
|
|
||||||
|
for future in as_completed(futures):
|
||||||
|
mid = futures[future]
|
||||||
|
try:
|
||||||
|
result = future.result()
|
||||||
|
logger.info(f"{mid} 处理完成")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"{mid} 处理出错: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,24 @@
|
|||||||
import os
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
from fractions import Fraction
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
|
def ratio_to_str(width, height, max_denominator=20):
|
||||||
|
"""将宽高比转换为 a:b 的形式"""
|
||||||
|
# 确保分子 > 分母
|
||||||
|
if width >= height:
|
||||||
|
ratio = Fraction(width, height).limit_denominator(max_denominator)
|
||||||
|
else:
|
||||||
|
ratio = Fraction(height, width).limit_denominator(max_denominator)
|
||||||
|
|
||||||
|
a, b = ratio.numerator, ratio.denominator
|
||||||
|
# 由于上面取了 max(width, height),要对应宽:高
|
||||||
|
if width >= height:
|
||||||
|
return f"{a}:{b}"
|
||||||
|
else:
|
||||||
|
return f"{b}:{a}"
|
||||||
|
|
||||||
def get_video_resolution(video_path):
|
def get_video_resolution(video_path):
|
||||||
"""获取视频的宽高信息"""
|
"""获取视频的宽高信息"""
|
||||||
@@ -13,7 +31,15 @@ def get_video_resolution(video_path):
|
|||||||
return width, height
|
return width, height
|
||||||
|
|
||||||
def calculate_padding(width, height):
|
def calculate_padding(width, height):
|
||||||
"""计算填充黑边,使其变成 1:1(正方形)"""
|
"""计算填充黑边,使其变成 1:1(正方形)。
|
||||||
|
如果接近4:3或1:1比例(90%以内),则直接返回0。
|
||||||
|
"""
|
||||||
|
aspect_ratio = width / height if width >= height else height / width
|
||||||
|
|
||||||
|
# 如果接近 4:3 或 1:1,就不填充
|
||||||
|
if (0.9 <= aspect_ratio <= 1.1) or (1.3 <= aspect_ratio <= 1.5):
|
||||||
|
return max(width, height), 0, 0
|
||||||
|
|
||||||
max_side = max(width, height) # 以最大边长作为正方形边长
|
max_side = max(width, height) # 以最大边长作为正方形边长
|
||||||
pad_x = (max_side - width) // 2
|
pad_x = (max_side - width) // 2
|
||||||
pad_y = (max_side - height) // 2
|
pad_y = (max_side - height) // 2
|
||||||
@@ -25,7 +51,7 @@ def process_video(input_file, output_file):
|
|||||||
target_size, pad_x, pad_y = calculate_padding(width, height)
|
target_size, pad_x, pad_y = calculate_padding(width, height)
|
||||||
|
|
||||||
if pad_x == 0 and pad_y == 0:
|
if pad_x == 0 and pad_y == 0:
|
||||||
print("视频已经是 1:1,无需填充。")
|
logger.info(f"视频比例是 {ratio_to_str(width,height)},无需填充。")
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg", "-i", input_file,
|
"ffmpeg", "-i", input_file,
|
||||||
"-c:v", "h264_videotoolbox",
|
"-c:v", "h264_videotoolbox",
|
||||||
@@ -34,7 +60,7 @@ def process_video(input_file, output_file):
|
|||||||
output_file
|
output_file
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
print(f"填充黑边,使视频变为 {target_size}x{target_size}")
|
logger.info(f"视频比例是 {ratio_to_str(width,height)},填充黑边,使视频变为 {target_size}x{target_size}")
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"ffmpeg", "-i", input_file,
|
"ffmpeg", "-i", input_file,
|
||||||
"-vf", f"pad={target_size}:{target_size}:{pad_x}:{pad_y}:black",
|
"-vf", f"pad={target_size}:{target_size}:{pad_x}:{pad_y}:black",
|
||||||
@@ -48,7 +74,7 @@ def process_video(input_file, output_file):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if len(sys.argv) < 3:
|
if len(sys.argv) < 3:
|
||||||
print("用法: python pv_convert.py 输入文件 输出文件")
|
logger.info("用法: python pv_convert.py 输入文件 输出文件")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
input_file = sys.argv[1]
|
input_file = sys.argv[1]
|
||||||
|
|||||||
36
search.py
36
search.py
@@ -47,7 +47,9 @@ def search_music_by_id(search_id):
|
|||||||
# 曲绘(查 jacket 文件夹)
|
# 曲绘(查 jacket 文件夹)
|
||||||
jacket_dir = os.path.join(rd, "AssetBundleImages", "jacket")
|
jacket_dir = os.path.join(rd, "AssetBundleImages", "jacket")
|
||||||
music_num = int(music_id)
|
music_num = int(music_id)
|
||||||
if music_num >= 10000:
|
if music_num >= 100000:
|
||||||
|
jacket_ab = f"ui_jacket_{(music_num-100000) - 10000:06d}.ab"
|
||||||
|
elif music_num >= 10000:
|
||||||
jacket_ab = f"ui_jacket_{music_num - 10000:06d}.ab"
|
jacket_ab = f"ui_jacket_{music_num - 10000:06d}.ab"
|
||||||
else:
|
else:
|
||||||
jacket_ab = f"ui_jacket_{music_num:06d}.ab"
|
jacket_ab = f"ui_jacket_{music_num:06d}.ab"
|
||||||
@@ -68,7 +70,9 @@ def search_music_by_id(search_id):
|
|||||||
# 音频文件(SoundData)
|
# 音频文件(SoundData)
|
||||||
sound_dir = os.path.join(rd, "SoundData")
|
sound_dir = os.path.join(rd, "SoundData")
|
||||||
music_num = int(music_id)
|
music_num = int(music_id)
|
||||||
if music_num >= 10000:
|
if music_num >= 100000:
|
||||||
|
audio_prefix = f"music{(music_num-100000) - 10000:06d}"
|
||||||
|
elif music_num >= 10000:
|
||||||
audio_prefix = f"music{music_num - 10000:06d}"
|
audio_prefix = f"music{music_num - 10000:06d}"
|
||||||
else:
|
else:
|
||||||
audio_prefix = f"music{music_num:06d}"
|
audio_prefix = f"music{music_num:06d}"
|
||||||
@@ -88,7 +92,9 @@ def search_music_by_id(search_id):
|
|||||||
# 视频 dat 文件(MovieData)
|
# 视频 dat 文件(MovieData)
|
||||||
movie_dir = os.path.join(rd, "MovieData")
|
movie_dir = os.path.join(rd, "MovieData")
|
||||||
music_num = int(music_id)
|
music_num = int(music_id)
|
||||||
if music_num >= 10000:
|
if music_num >= 100000:
|
||||||
|
dat_name = f"{(music_num-100000) - 10000:06d}.dat"
|
||||||
|
elif music_num >= 10000:
|
||||||
dat_name = f"{music_num - 10000:06d}.dat"
|
dat_name = f"{music_num - 10000:06d}.dat"
|
||||||
else:
|
else:
|
||||||
dat_name = f"{music_num:06d}.dat"
|
dat_name = f"{music_num:06d}.dat"
|
||||||
@@ -103,6 +109,30 @@ def search_music_by_id(search_id):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def list_all_music():
|
||||||
|
music_list = []
|
||||||
|
for asset_dir in os.listdir(streaming_assets):
|
||||||
|
root_dir = os.path.join(streaming_assets, asset_dir)
|
||||||
|
music_dir = os.path.join(root_dir, "music")
|
||||||
|
if not os.path.isdir(music_dir):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for music_subdir in os.listdir(music_dir):
|
||||||
|
sub_path = os.path.join(music_dir, music_subdir)
|
||||||
|
music_xml_path = os.path.join(sub_path, "Music.xml")
|
||||||
|
if not os.path.isfile(music_xml_path):
|
||||||
|
continue
|
||||||
|
|
||||||
|
music_id, name, artist, notes, version_name = parse_music_xml(music_xml_path)
|
||||||
|
music_list.append({
|
||||||
|
"id": music_id,
|
||||||
|
"name": name,
|
||||||
|
"artist": artist,
|
||||||
|
"version": version_name
|
||||||
|
})
|
||||||
|
|
||||||
|
return music_list
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user