134 lines
3.6 KiB
Python
134 lines
3.6 KiB
Python
import argparse
|
|
import os
|
|
import pprint
|
|
import shelve
|
|
import traceback
|
|
from typing import Counter, Dict, List, Optional
|
|
|
|
import simfile
|
|
from simfile.notes import NoteData
|
|
from simfile.notes.group import group_notes
|
|
from simfile.notes.timed import time_notes
|
|
from simfile.ssc import SSCChart
|
|
from simfile.timing.engine import TimingData
|
|
from simfile.timing.displaybpm import displaybpm
|
|
|
|
|
|
class SimfileError:
|
|
context: str
|
|
traceback: Optional[str]
|
|
|
|
def __init__(self, context: str):
|
|
self.context = context
|
|
self.traceback = traceback.format_exc()
|
|
|
|
def __repr__(self):
|
|
return f"{self.context}: {self.traceback}"
|
|
|
|
|
|
def check_simfile(filename: str) -> List[SimfileError]:
|
|
errors = []
|
|
try:
|
|
sim = simfile.open(filename)
|
|
except Exception:
|
|
errors.append(SimfileError("parse"))
|
|
return errors
|
|
|
|
timing_data = None
|
|
try:
|
|
timing_data = TimingData.from_simfile(sim)
|
|
except Exception:
|
|
errors.append(SimfileError("timing"))
|
|
|
|
try:
|
|
displaybpm(sim)
|
|
except Exception:
|
|
errors.append(SimfileError("displaybpm"))
|
|
|
|
for c, chart in enumerate(sim.charts):
|
|
try:
|
|
note_data = NoteData.from_chart(chart)
|
|
except Exception:
|
|
errors.append(SimfileError(f"chart {c} note_data"))
|
|
try:
|
|
for _ in group_notes(note_data, join_heads_to_tails=True):
|
|
pass
|
|
except Exception:
|
|
errors.append(SimfileError(f"chart {c} group_notes"))
|
|
|
|
if isinstance(chart, SSCChart):
|
|
try:
|
|
displaybpm(sim, chart)
|
|
except Exception:
|
|
errors.append(SimfileError(f"chart {c} displaybpm"))
|
|
|
|
# skip the remaining chart tests if timing data parsing failed
|
|
if timing_data is None:
|
|
continue
|
|
|
|
if isinstance(chart, SSCChart):
|
|
try:
|
|
timing_data = TimingData.from_simfile(sim, chart)
|
|
except Exception:
|
|
errors.append(SimfileError(f"chart {c} timing"))
|
|
|
|
try:
|
|
for _ in time_notes(note_data, timing_data):
|
|
pass
|
|
except Exception:
|
|
errors.append(SimfileError(f"chart {c} timed_notes"))
|
|
|
|
return errors
|
|
|
|
|
|
def scan_directory(path: str, simfile_errors: Dict[str, List[SimfileError]]):
|
|
stats = Counter()
|
|
for entry in os.scandir(path):
|
|
if simfile_errors.get(entry.path) == []:
|
|
stats["skipped"] += 1
|
|
continue
|
|
if entry.is_dir():
|
|
stats.update(scan_directory(entry.path, simfile_errors))
|
|
elif any(entry.name.endswith(ext) for ext in (".sm", ".ssc")):
|
|
errors = check_simfile(entry.path)
|
|
stats["checked"] += 1
|
|
simfile_errors[entry.path] = errors
|
|
if errors:
|
|
stats["error"] += 1
|
|
pprint.pprint({"path": entry.path, "errors": errors})
|
|
else:
|
|
stats["success"] += 1
|
|
|
|
return stats
|
|
|
|
|
|
def dir_path(string):
|
|
if os.path.isdir(string):
|
|
return string
|
|
else:
|
|
raise ValueError("dir_path: not a directory")
|
|
|
|
|
|
def main():
|
|
argparser = argparse.ArgumentParser()
|
|
argparser.add_argument(
|
|
"directory",
|
|
help="directory of simfiles to scan",
|
|
type=dir_path,
|
|
)
|
|
argparser.add_argument(
|
|
"-s",
|
|
"--shelf",
|
|
help="shelf file to use",
|
|
default=f"shelf-{simfile.__version__}",
|
|
)
|
|
args = argparser.parse_args()
|
|
|
|
with shelve.open(args.shelf) as simfile_errors:
|
|
stats = scan_directory(args.directory, simfile_errors)
|
|
for k, v in stats.items():
|
|
print(k, v)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|