mirror of
https://github.com/qwerfd2/OverRide-Server.git
synced 2026-10-11 16:58:13 +03:00
ready for v5
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import cv2
|
||||
import os
|
||||
|
||||
video_file = input("Enter the name of the video file: 输入视频文件名称 ")
|
||||
|
||||
if not os.path.isfile(video_file) or not video_file.endswith('.mp4'):
|
||||
print("The file does not exist or is not an MP4 file. 文件不存在或不是mp4")
|
||||
exit()
|
||||
|
||||
id_string = input("Enter an ID string: 输入命名用ID")
|
||||
frame_rate = float(input("Enter the frame rate: 输入帧率"))
|
||||
|
||||
output_dir = input("Enter the output directory: 输入保存文件夹目录")
|
||||
|
||||
if not os.path.exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
cap = cv2.VideoCapture(video_file)
|
||||
|
||||
video_frame_rate = cap.get(cv2.CAP_PROP_FPS)
|
||||
|
||||
if frame_rate > video_frame_rate:
|
||||
frame_rate = video_frame_rate
|
||||
|
||||
original_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
||||
original_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
||||
|
||||
desired_width = 480
|
||||
desired_height = 270
|
||||
|
||||
interval = int(video_frame_rate / frame_rate)
|
||||
|
||||
frame_count = 0
|
||||
saved_count = 0
|
||||
|
||||
while cap.isOpened():
|
||||
ret, frame = cap.read()
|
||||
|
||||
if not ret:
|
||||
break
|
||||
|
||||
if frame.shape[1] != desired_width or frame.shape[0] != desired_height:
|
||||
frame = cv2.resize(frame, (desired_width, desired_height))
|
||||
|
||||
if frame_count % interval == 0:
|
||||
output_path = os.path.join(output_dir, f"{id_string}_{saved_count + 1}.jpg")
|
||||
cv2.imwrite(output_path, frame)
|
||||
saved_count += 1
|
||||
|
||||
frame_count += 1
|
||||
|
||||
cap.release()
|
||||
|
||||
print(f"Extracted {saved_count} frames and saved to {output_dir}.")
|
||||
print(f"已提取 {saved_count} 帧并保存到了 {output_dir}.")
|
||||
Binary file not shown.
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Music Name",
|
||||
"artist": "Music Artist",
|
||||
"isJapanese": false,
|
||||
"bpm": 167,
|
||||
"sync_6k": "0/0/0/-1400",
|
||||
"sync_4k": "0/0/0",
|
||||
"diff_6k": "0/0/0/18",
|
||||
"diff_4k": "0/0/0",
|
||||
"charter_6k": "-/-/-/charterA",
|
||||
"charter_4k": "-/-/-",
|
||||
"mp3": "song",
|
||||
"preview": "-1/-1",
|
||||
"bga": "-1400/24/3559"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
This is a test placeholder file
|
||||
@@ -0,0 +1 @@
|
||||
This is a test placeholder file
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
@@ -0,0 +1,439 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
import zipfile
|
||||
from shutil import rmtree
|
||||
from msvcrt import getch
|
||||
import ctypes
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
|
||||
lastfile = "N/A"
|
||||
version = "Final"
|
||||
date = "November 5th, 2019"
|
||||
|
||||
try:
|
||||
ctypes.windll.kernel32.SetConsoleTitleW(f"Malody to osu!mania Converter v{version}") #https://stackoverflow.com/questions/7387276
|
||||
|
||||
if getattr(sys, 'frozen', False):
|
||||
os.chdir(os.path.dirname(sys.executable))
|
||||
#https://codeday.me/ko/qa/20190316/78831.html
|
||||
|
||||
print(f"Malody to osu!mania Converter v{version}")
|
||||
print(date)
|
||||
print("by Jakads\n\n")
|
||||
|
||||
def choose():
|
||||
choice = getch().decode()
|
||||
while choice not in 'yYnN':
|
||||
choice = getch().decode()
|
||||
|
||||
if choice in 'nN':
|
||||
return 0
|
||||
|
||||
else:
|
||||
return 1
|
||||
|
||||
"""
|
||||
if len(sys.argv) > 1 and sys.argv[1] == '--:update': #added ":" to disallow user to view this message by dragging in files
|
||||
#checks the first condition first so it will not give IndexError
|
||||
if os.path.isfile(sys.argv[2]):
|
||||
os.remove(sys.argv[2])
|
||||
else:
|
||||
print(f'[X] Failed to remove the temporary batch file({sys.argv[2]}). Please remove it manually. This message is not supposed to be shown.\n')
|
||||
print(f"[O] Successfully updated to v{version}! :D\n[!] Would you like to check out the changelog? (Y/N)\n")
|
||||
if choose():
|
||||
webbrowser.open('https://github.com/jakads/Malody-to-Osumania#changelog')
|
||||
del sys.argv[1], sys.argv[1] #Deleting second element twice actually deletes second and third
|
||||
|
||||
print("(i) Checking for new updates . . .")
|
||||
try:
|
||||
latest = requests.get('https://github.com/jakads/Malody-to-Osumania/raw/master/version.txt')
|
||||
latest.raise_for_status()
|
||||
print(f"\n(i) Latest Version = v{latest.text}")
|
||||
|
||||
if latest.text != version:
|
||||
print("\n[!] New update is available! Would you like to download? (Y/N)")
|
||||
if not choose():
|
||||
print("(i) Skipping the update.\n\n")
|
||||
|
||||
else:
|
||||
print("(i) Downloading . . .")
|
||||
exe = requests.get("https://github.com/jakads/Malody-to-Osumania/raw/master/convert.exe", stream=True)
|
||||
exe.raise_for_status()
|
||||
total = int(exe.headers.get('content-length'))
|
||||
progress = tqdm(total=total, unit='B', unit_scale=True, unit_divisor=1024, ncols=80) #https://github.com/tqdm/tqdm/wiki/How-to-make-a-great-Progress-Bar
|
||||
rand=''.join(random.choice(string.ascii_letters + string.digits) for i in range(16)) #https://pynative.com/python-generate-random-string/
|
||||
filename=os.path.basename(sys.executable)
|
||||
with open(f"{rand}.exe", 'wb') as f: #https://stackoverflow.com/questions/37573483
|
||||
for chunk in exe.iter_content(chunk_size=8192):
|
||||
if chunk:
|
||||
progress.update(8192)
|
||||
f.write(chunk)
|
||||
with open(f'{rand}.bat', 'w', encoding='utf-8') as f:
|
||||
f.write('\n'.join(['@echo off',
|
||||
'echo (i) Restarting . . .',
|
||||
"echo (i) All the files you've dragged in will be converted very soon!",
|
||||
'timeout /t 5 /nobreak >nul',
|
||||
f'del "{filename}"',
|
||||
f'rename {rand}.exe "{filename}"',
|
||||
'cls',
|
||||
'"{0}" --:update {1}.bat {2}'.format(filename, rand, ' '.join(f'"{file}\"' for file in sys.argv[1:]) if len(sys.argv)>1 else '')])) #https://stackoverflow.com/questions/12007686
|
||||
os.startfile(f'{rand}.bat')
|
||||
sys.exit()
|
||||
|
||||
else:
|
||||
print("\n[O] Your program is as good as new! We're good to go.\n\n")
|
||||
except Exception as e:
|
||||
print("\n[!] Error while connecting:", e)
|
||||
print("\n[!] Connection to GitHub failed. Will just continue...\n\n")
|
||||
"""
|
||||
|
||||
def recursive_file_gen(mydir):
|
||||
for root, dirs, files in os.walk(mydir):
|
||||
for file in files:
|
||||
yield os.path.join(root, file)
|
||||
#https://stackoverflow.com/questions/2865278
|
||||
|
||||
def convert(i, bgtmp, soundtmp):
|
||||
lastfile = f'{i} (Crashed while reading)'
|
||||
|
||||
try:
|
||||
with open(f'{i}',encoding='utf-8') as mc:
|
||||
mcFile = json.loads(mc.read())
|
||||
mcFile['meta']['mode']
|
||||
except:
|
||||
print(f"[!] FileWarning: {os.path.basename(i)} is not a valid .mc file. Ignoring...")
|
||||
return 1
|
||||
|
||||
if not mcFile['meta']['mode'] == 0:
|
||||
print(f"[!] KeyWarning: {os.path.basename(i)} is not a Key difficulty. Ignoring...")
|
||||
return 1
|
||||
|
||||
ms = lambda beats, bpm, offset: 1000*(60/bpm)*beats+offset
|
||||
beat = lambda beat: beat[0] + beat[1]/beat[2] #beats = [measure, nth beat, divisor]
|
||||
col = lambda column, keys: int(512*(2*column+1)/(2*keys))
|
||||
|
||||
SVMap = False
|
||||
|
||||
line = mcFile['time']
|
||||
meta = mcFile['meta']
|
||||
note = mcFile['note']
|
||||
if 'effect' in mcFile and len(mcFile['effect'])>0:
|
||||
sv = mcFile['effect']
|
||||
SVMap = True
|
||||
soundnote = {}
|
||||
|
||||
keys = meta["mode_ext"]["column"]
|
||||
|
||||
for x in note:
|
||||
if x.get('type',0):
|
||||
soundnote = x
|
||||
|
||||
bpm = [line[0]['bpm']]
|
||||
bpmoffset = [-soundnote.get('offset',0)]
|
||||
|
||||
if len(line)>1:
|
||||
j=0
|
||||
lastbeat=line[0]['beat']
|
||||
for x in line[1:]:
|
||||
bpm.append(x['bpm'])
|
||||
bpmoffset.append(ms(beat(x['beat'])-beat(lastbeat),line[j]['bpm'],bpmoffset[j]))
|
||||
j+=1
|
||||
lastbeat=x['beat']
|
||||
|
||||
global title, artist #I know using global is a bad practice but c'mon
|
||||
title = meta["song"]["title"]
|
||||
artist = meta["song"]["artist"]
|
||||
|
||||
preview = meta.get('preview',-1)
|
||||
titleorg = meta['song'].get('titleorg',title)
|
||||
artistorg = meta['song'].get('artistorg',artist)
|
||||
|
||||
background = meta["background"]
|
||||
if not background=="": bgtmp.append(f'{os.path.dirname(i)}\\{background}')
|
||||
sound = soundnote["sound"]
|
||||
if not sound=="": soundtmp.append(f'{os.path.dirname(i)}\\{sound}')
|
||||
creator = meta["creator"]
|
||||
version = meta["version"]
|
||||
|
||||
lastfile = f'{i} (Crashed while converting)'
|
||||
|
||||
with open(f'{os.path.splitext(i)[0]}.osu',mode='w',encoding='utf-8') as osu:
|
||||
osuformat = ['osu file format v14',
|
||||
'',
|
||||
'[General]',
|
||||
f'AudioFilename: {sound}',
|
||||
'AudioLeadIn: 0',
|
||||
f'PreviewTime: {preview}',
|
||||
'Countdown: 0',
|
||||
'SampleSet: Soft',
|
||||
'StackLeniency: 0.7',
|
||||
'Mode: 3',
|
||||
'LetterboxInBreaks: 0',
|
||||
'SpecialStyle: 0',
|
||||
'WidescreenStoryboard: 0',
|
||||
'',
|
||||
'[Editor]',
|
||||
'DistanceSpacing: 1.2',
|
||||
'BeatDivisor: 4',
|
||||
'GridSize: 8',
|
||||
'TimelineZoom: 2.4',
|
||||
'',
|
||||
'[Metadata]',
|
||||
f'Title:{title}',
|
||||
f'TitleUnicode:{titleorg}',
|
||||
f'Artist:{artist}',
|
||||
f'ArtistUnicode:{artistorg}',
|
||||
f'Creator:{creator}',
|
||||
f'Version:{version}',
|
||||
'Source:Malody',
|
||||
'Tags:Malody Convert by Jakads',
|
||||
'BeatmapID:0',
|
||||
'BeatmapSetID:-1',
|
||||
'',
|
||||
'[Difficulty]',
|
||||
'HPDrainRate:8',
|
||||
f'CircleSize:{keys}',
|
||||
'OverallDifficulty:8',
|
||||
'ApproachRate:5',
|
||||
'SliderMultiplier:1.4',
|
||||
'SliderTickRate:1',
|
||||
'',
|
||||
'[Events]',
|
||||
'//Background and Video events',
|
||||
f'0,0,\"{background}\",0,0',
|
||||
'',
|
||||
'[TimingPoints]\n']
|
||||
osu.write('\n'.join(osuformat))
|
||||
#https://thrillfighter.tistory.com/310
|
||||
|
||||
bpmcount = len(bpm)
|
||||
for x in range(bpmcount):
|
||||
osu.write(f'{bpmoffset[x]},{60000/bpm[x]},{int(line[x].get("sign",4))},1,0,0,1,0\n')
|
||||
|
||||
if SVMap:
|
||||
for n in sv:
|
||||
j=0
|
||||
|
||||
for b in line:
|
||||
if beat(b['beat']) > beat(n['beat']):
|
||||
j+=1
|
||||
else:
|
||||
continue
|
||||
|
||||
j=bpmcount-j-1
|
||||
|
||||
if int(ms(beat(n["beat"]), bpm[j], bpmoffset[j])) >= bpmoffset[0]:
|
||||
osu.write(f'{ms(beat(n["beat"])-beat(line[j]["beat"]), bpm[j], bpmoffset[j])},-{100/abs(n["scroll"]) if n["scroll"]!=0 else "1E+308"},{int(line[j].get("sign",4))},1,0,0,0,0\n')
|
||||
|
||||
osu.write('\n\n[HitObjects]')
|
||||
|
||||
for n in note:
|
||||
if not n.get('type',0) == 0:
|
||||
continue
|
||||
|
||||
j=0
|
||||
k=0
|
||||
|
||||
for b in line:
|
||||
if beat(b['beat']) > beat(n['beat']):
|
||||
j+=1
|
||||
else:
|
||||
continue
|
||||
|
||||
if not n.get('endbeat') == None:
|
||||
for b in line:
|
||||
if beat(b['beat']) > beat(n['endbeat']):
|
||||
k+=1
|
||||
else:
|
||||
continue
|
||||
|
||||
j=bpmcount-j-1
|
||||
k=bpmcount-k-1
|
||||
|
||||
if int(ms(beat(n["beat"]), bpm[j], bpmoffset[j])) >= 0:
|
||||
osu.write(f'\n{col(n["column"], keys)},192,{int(ms(beat(n["beat"])-beat(line[j]["beat"]), bpm[j], bpmoffset[j]))}')
|
||||
|
||||
if n.get('endbeat') == None: #Regular Note
|
||||
osu.write(',1,0,0:0:0:')
|
||||
else: #Long Note
|
||||
osu.write(f',128,0,{int(ms(beat(n["endbeat"])-beat(line[k]["beat"]), bpm[k], bpmoffset[k]))}:0:0:0:')
|
||||
|
||||
if n.get('sound') == None:
|
||||
osu.write('0:')
|
||||
else: #Hitsound Note
|
||||
osu.write('{0}:{1}'.format(n['vol'],n['sound'].replace('"','')))
|
||||
return 0
|
||||
|
||||
def compress(compressname, name, bglist, soundlist):
|
||||
osz = zipfile.ZipFile(f'{compressname}.osz','w')
|
||||
|
||||
for i in name:
|
||||
lastfile = f'{i} (Crashed while compressing)'
|
||||
osz.write(f'{os.path.splitext(i)[0]}.osu', f'{os.path.basename(i)}.osu')
|
||||
os.remove(f'{os.path.splitext(i)[0]}.osu')
|
||||
print(f'[O] Compressed: {os.path.splitext(i)[0]}.osu')
|
||||
if not len(bglist)==0:
|
||||
for i in bglist:
|
||||
lastfile = f'{i} (Crashed while compressing)'
|
||||
if os.path.isfile(i):
|
||||
osz.write(i, os.path.basename(i))
|
||||
print(f'[O] Compressed: {os.path.basename(i)}')
|
||||
else:
|
||||
print(f'[!] {os.path.basename(i)} is not found and thus not compressed.')
|
||||
if not len(soundlist)==0:
|
||||
for i in soundlist:
|
||||
lastfile = f'{i} (Crashed while compressing)'
|
||||
if os.path.isfile(i):
|
||||
osz.write(i, os.path.basename(i))
|
||||
print(f'[O] Compressed: {os.path.basename(i)}\n')
|
||||
else:
|
||||
print(f'[!] {os.path.basename(i)} is not found and thus not compressed.')
|
||||
osz.close()
|
||||
oszname.append(f'{compressname}.osz')
|
||||
|
||||
if len(sys.argv)<=1:
|
||||
print("(i) Drag .mc or .mcz/.zip files into this program to convert them to .osu or .osz!")
|
||||
print("(i) Press any key to exit.")
|
||||
getch()
|
||||
sys.exit()
|
||||
|
||||
MCDragged = False
|
||||
MCValid = False
|
||||
ZIPDragged = False
|
||||
#FolderDragged = False
|
||||
mcname = []
|
||||
zipname = []
|
||||
foldername = []
|
||||
oszname = []
|
||||
|
||||
mctmp = []
|
||||
print('(i) Checking file validity . . .\n')
|
||||
for x in sys.argv[1:]:
|
||||
lastfile = f'{x} (Crashed while checking)'
|
||||
isMCZ = False
|
||||
if os.path.isdir(x):
|
||||
#zipname.append(os.path.splitext(x)[0])
|
||||
#FolderDragged = True
|
||||
print(f"[!] FileWarning: {os.path.basename(x)} is a directory, not a file. Ignoring...")
|
||||
elif not os.path.isfile(x):
|
||||
print(f"[!] FileWarning: {os.path.basename(x)} is not found. You normally aren't supposed to see this message. Ignoring...")
|
||||
elif os.path.splitext(x)[1].lower() == ".mc":
|
||||
mctmp.append(x)
|
||||
MCDragged = True
|
||||
elif os.path.splitext(x)[1].lower() in [".mcz", ".zip"]:
|
||||
if os.path.splitext(x)[1].lower() == ".mcz":
|
||||
isMCZ = True
|
||||
os.rename(x, f'{os.path.splitext(x)[0]}.zip')
|
||||
x = f'{os.path.splitext(x)[0]}.zip'
|
||||
mcz = zipfile.ZipFile(x)
|
||||
mcz.extractall(os.path.splitext(x)[0])
|
||||
mcz.close()
|
||||
if isMCZ:
|
||||
os.rename(x, f'{os.path.splitext(x)[0]}.mcz')
|
||||
zipname.append(os.path.splitext(x)[0])
|
||||
ZIPDragged = True
|
||||
else:
|
||||
print(f"[!] FileWarning: The file type of {os.path.basename(x)} is not supported. Ignoring...")
|
||||
|
||||
if MCDragged:
|
||||
mcname.append(mctmp)
|
||||
|
||||
if not MCDragged and not ZIPDragged:
|
||||
#print("\n[X] FILEERROR: None of the files you've dragged in are supported. This program only accepts .mc, .mcz, .zip files, or folders with them.")
|
||||
print("\n[X] FILEERROR: None of the files you've dragged in are supported. This program only accepts .mc, .mcz, or .zip files.")
|
||||
print("(i) Press any key to exit.")
|
||||
getch()
|
||||
sys.exit()
|
||||
|
||||
title = ""
|
||||
artist = ""
|
||||
mctitle = ""
|
||||
mcartist = ""
|
||||
bglist = []
|
||||
soundlist = []
|
||||
|
||||
print("\n\n(i) Converting . . .\n")
|
||||
|
||||
#Converting to .osu (dragged .mc files)
|
||||
if MCDragged:
|
||||
bgtmp = []
|
||||
soundtmp = []
|
||||
for i in mcname[0][:]: #https://stackoverflow.com/questions/7210578
|
||||
if not convert(i, bgtmp, soundtmp):
|
||||
print(f'[O] Converted: {os.path.basename(i)}')
|
||||
MCValid = True
|
||||
else:
|
||||
mcname[0].remove(i)
|
||||
mctitle = title
|
||||
mcartist = artist
|
||||
bglist.append(bgtmp)
|
||||
soundlist.append(soundtmp)
|
||||
|
||||
|
||||
#Converting to .osu (dragged .mcz/.zip files)
|
||||
if ZIPDragged:
|
||||
for folder in zipname:
|
||||
print(f'\n\n(i) Converting {os.path.basename(folder)} . . .\n')
|
||||
c=0
|
||||
bgtmp = []
|
||||
soundtmp = []
|
||||
mctmp = []
|
||||
filelist = list(recursive_file_gen(folder))
|
||||
for files in filelist:
|
||||
if os.path.splitext(files)[1] == ".mc":
|
||||
if not convert(files, bgtmp, soundtmp):
|
||||
print(f'[O] Converted: {os.path.basename(files)}')
|
||||
c+=1
|
||||
MCValid = True
|
||||
mctmp.append(files)
|
||||
if c>0:
|
||||
foldername.append(folder)
|
||||
bglist.append(bgtmp)
|
||||
soundlist.append(soundtmp)
|
||||
mcname.append(mctmp)
|
||||
|
||||
if not MCValid:
|
||||
print("\n[X] FILEERROR: None of the files you've dragged are supported.")
|
||||
print("(i) Press any key to exit.")
|
||||
getch()
|
||||
sys.exit()
|
||||
|
||||
print('\n\n(i) All the supported .mc files have been converted to .osu!\n(i) Either close the program now and move the files manually,\n(i) or press Enter to compress all into .osz.')
|
||||
getch()
|
||||
|
||||
print('\n\n\n(i) Compressing . . .\n')
|
||||
#Compress to .osz (dragged .mc files as single mapset)
|
||||
if MCDragged:
|
||||
compress(f'{mcartist} - {mctitle}', mcname[0], set(bglist[0]), set(soundlist[0]))
|
||||
|
||||
if ZIPDragged:
|
||||
i = 1 if MCDragged else 0
|
||||
for folder in zipname:
|
||||
print(f'\n(i) Compressing {os.path.basename(folder)} . . .\n')
|
||||
compress(f'{os.path.basename(folder)}', mcname[i], set(bglist[i]), set(soundlist[i]))
|
||||
i+=1
|
||||
rmtree(folder)
|
||||
|
||||
print('\n(i) The following .osz files have been created! Run the files to add the maps to osu! automatically.\n')
|
||||
for i in oszname:
|
||||
print(f'* {i}')
|
||||
print('\n(i) Press any key to exit.')
|
||||
getch()
|
||||
|
||||
except Exception as e:
|
||||
print(f'\n\n\n[X] FATAL ERROR : {repr(e)}\n')
|
||||
traceback.print_exc()
|
||||
crashlog = f'CrashLog_{datetime.now().strftime("%Y%m%d%H%M%S")}.log'
|
||||
with open(crashlog,mode='w',encoding='utf-8') as crash:
|
||||
crash.write('lol rip xd\n\n')
|
||||
crash.write(f"Target File: {lastfile}\n")
|
||||
crash.write("If you would like to tell the dev about this issue, please attach the file above if available (and the whole folder too if possible) with this crash report.\n")
|
||||
crash.write('DO NOT EDIT ANYTHING WRITTEN HERE.\n\n')
|
||||
crash.write(traceback.format_exc())
|
||||
print(f'\n[X] The crash log has been saved as {crashlog}.')
|
||||
print('[X] Please tell the dev about this!')
|
||||
print('(i) Press any key to exit.')
|
||||
getch()
|
||||
exit()
|
||||
@@ -0,0 +1,5 @@
|
||||
bga maker: instruction in main readme. Just follow the prompt.
|
||||
|
||||
malody to osu: open .mcz as zip, drag .mc chart file on to convert.exe. An osu file will be saved in the directory.
|
||||
|
||||
osu to bms: run `python osu.py -i *input .osu file path*`. A .bms file will be saved in the directory. Note the name of the file might change as it is defined internally in the input file.
|
||||
Reference in New Issue
Block a user