changeset 136:da4f7200665f default tip

buncha shit
author Paper <paper@tflc.us>
date Sat, 07 Mar 2026 18:04:10 -0500
parents 0c3cd90e91f7
children
files animeregex.py copy-aac-fixup.py create.py decode-mixed-mode.c split-aac.py
diffstat 5 files changed, 201 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/animeregex.py	Sat Mar 07 18:04:10 2026 -0500
@@ -0,0 +1,12 @@
+import os
+import re
+
+for i in os.listdir("."):
+    if i.endswith(".mkv"):
+        regex = re.search("\[(?P<group>.*?)\] (?P<anime>.+?) - (?P<nc>[A-z]+|\d+)? ?(?P<episode>\d+)?", i)
+        if regex is None:
+            continue
+        if regex.group("episode") is None:
+            os.rename(i, regex.group("anime") + " - " + regex.group("episode").lstrip("0") + ".mkv")
+        else:
+            os.rename(i, regex.group("anime") + " - " + regex.group("nc") + " " + regex.group("episode").lstrip("0") + ".mkv")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/copy-aac-fixup.py	Sat Mar 07 18:04:10 2026 -0500
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+import glob
+import subprocess
+import termios
+
+oldtty = termios.tcgetattr(0)
+
+# list of Popen classes to wait on
+# this allows us to run metaflac independently on
+# a huge list of files concurrently
+processes = list()
+
+i = 1
+
+# glob the files in order
+files = glob.glob("*.aac")
+files.sort()
+for g in files:
+	processes.append(subprocess.Popen(["ffmpeg", "-i", g, "-c", "copy", "-metadata", "track=%d" % i, g + ".m4a"]))
+	i += 1
+
+for p in processes:
+	p.wait()
+
+# ffmpeg fucks the terminal, restore it back
+termios.tcsetattr(0, termios.TCSANOW, oldtty)
--- a/create.py	Sat Jan 24 15:10:05 2026 -0500
+++ b/create.py	Sat Mar 07 18:04:10 2026 -0500
@@ -6,6 +6,9 @@
 import argparse
 import json
 import subprocess
+import os
+import math #ceil
+import typing
 
 def build_vf(blur) -> list[str]:
 	if blur:
@@ -14,82 +17,84 @@
 	return ["-vf", "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2"]
 
 # Build filter string
-def build_filter_string(length: int, cover: bool) -> str:
-    f = ""
-    i = 1 if cover else 0
-    for x in range(length):
-        f += ("[%d:0]" % (x + i))
-    f += ("concat=n=%d:v=0:a=1[out]" % length)
-    return f
+def build_filter_string(length: int, offset: int) -> str:
+	f = ""
+	i = offset
+	for x in range(length):
+		f += ("[%d:0]" % (x + i))
+	f += ("concat=n=%d:v=0:a=1[out]" % length)
+	return f
 
-def build_arguments_list(audio_files: list[str], cover, output, blur) -> list:
-    args = ["ffmpeg", "-y"]
-    if not cover is None:
-        args.extend(["-r", "1", "-loop", "1", "-i", cover])
-    # I want you to play that song again
-    for f in audio_files:
-        args.extend(["-i", f])
-    args.extend(["-filter_complex", build_filter_string(len(audio_files), False if cover is None else True), "-map", "[out]"])
-    if not cover is None:
-        # Letterbox to 1920x1080
-        args.extend(["-map", "0:v", "-tune", "stillimage", "-c:v", "libx264"])
-        args.extend(build_vf(blur))
-    args.extend(["-shortest"])
-    args.append(output + ".mkv")
-    return args
+def build_arguments_list(audio_files: list[str], cover: typing.Optional[str], output: str, blur: bool, duration: float) -> list:
+	args = ["ffmpeg", "-y"]
+	# I want you to play that song again
+	if not cover is None:
+		args.extend(["-r", "1", "-loop", "1", "-i", cover])
+	for f in audio_files:
+		args.extend(["-i", f])
+	args.extend(["-filter_complex", build_filter_string(len(audio_files), 1 if cover else 0), "-map", "[out]"])
+	if not cover is None:
+		# Letterbox to 1920x1080
+		args.extend(["-map", "0:v",
+		             "-tune", "stillimage",
+		             "-c:v", "libx264",
+		             # Add a second to account for inconsistencies in durations
+		             "-t", "%f" % (duration + 1.0)])
+		args.extend(build_vf(blur))
+	args.append(output + ".mkv")
+	return args
 
 
 # Returns a Popen object that should be waited on
-def run_ffmpeg(audio_files: list[str], cover, output, blur) -> subprocess.Popen:
-    args = build_arguments_list(audio_files, cover, output, blur)
-    print(args)
-    return subprocess.Popen(args)
+def run_ffmpeg(audio_files: list[str], cover: typing.Optional[str], output: str, blur: bool, duration: float) -> subprocess.Popen:
+	args = build_arguments_list(audio_files, cover, output, blur, duration)
+	print(args)
+	return subprocess.Popen(args)
 
 
 # Returns a Popen object that should be waited on.
 # stdout is also piped...
 def run_ffprobe(audio_file: str) -> subprocess.Popen:
-    return subprocess.Popen(["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", audio_file], stdout=subprocess.PIPE, text=True)
+	return subprocess.Popen(["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", audio_file], stdout=subprocess.PIPE, text=True)
 
 
-def get_title_from_tags(j, default: str) -> str:
-    # Is there an easier way to do this...?
-    for tag in j:
-        if tag.lower() == "title":
-            return j[tag]
+def get_title_from_tags(j: list, default: str) -> str:
+	# Is there an easier way to do this...?
+	for tag in j:
+		if tag.lower() == "title":
+			return j[tag]
 
-    # Ugh
-    return default
+	# Ugh
+	return default
 
 def doit(audio_files: list[str], cover, output, blur) -> int:
-    ffprobes = [run_ffprobe(x) for x in audio_files]
-    ffmpeg = run_ffmpeg(audio_files, cover, output, blur)
+	dur = 0.0
 
-    # Wait for all ffprobe processes  to finish their jobs
-    for f in ffprobes:
-        f.wait()
+	ffprobes = [run_ffprobe(x) for x in audio_files]
 
-    # Iterate the list again, and add up all the times.
-    # This also accounts for milliseconds etc. to be
-    # more accurate
-    with open(output + ".txt", "w", encoding="utf-8") as fw:
-        dur = 0.0
-        for f in ffprobes:
-            j = json.load(f.stdout)
-            fw.write("%d:%02d:%02d %s\n" % (int(dur) // 3600, int(dur) % 3600 // 60, int(dur) % 60, get_title_from_tags(j["format"]["tags"], "OOPS....")))
-            dur += float(j["format"]["duration"])
+	# Create output txt file with timestamps; we also use this duration
+	# to force ffmpeg to do the right thing instead of elongating our
+	# video
+	with open(output + ".txt", "w", encoding="utf-8") as fw:
+		for f in ffprobes:
+			f.wait()
+			j = json.load(f.stdout)
+			fw.write("%d:%02d:%02d %s\n" % (int(dur) // 3600, int(dur) % 3600 // 60, int(dur) % 60, get_title_from_tags(j["format"]["tags"], "OOPS....")))
+			dur += float(j["format"]["duration"])
 
-    # Finally, wait on the big ffmpeg process
-    ffmpeg.wait()
+	ffmpeg = run_ffmpeg(audio_files, cover, output, blur, dur)
+
+	# Finally, wait on the big ffmpeg process
+	ffmpeg.wait()
 
 def main() -> int:
-    parser = argparse.ArgumentParser(prog='create', description='Creates album videos', epilog='(c) paper 2025 all rights reversed')
-    parser.add_argument('-c', '--cover', required=True)
-    parser.add_argument('-o', '--output', required=True)
-    parser.add_argument('-b', '--blur', action='store_true')
-    parser.add_argument('audio', action='extend', nargs='+', type=str)
-    args = parser.parse_args()
-    doit(args.audio, args.cover, args.output, args.blur)
+	parser = argparse.ArgumentParser(prog='create', description='Creates album videos', epilog='(c) paper 2025 all rights reversed')
+	parser.add_argument('-c', '--cover', required=True)
+	parser.add_argument('-o', '--output', required=True)
+	parser.add_argument('-b', '--blur', action='store_true')
+	parser.add_argument('audio', action='extend', nargs='+', type=str)
+	args = parser.parse_args()
+	doit(args.audio, args.cover, args.output, args.blur)
 
 if __name__ == "__main__":
-    exit(main())
+	exit(main())
--- a/decode-mixed-mode.c	Sat Jan 24 15:10:05 2026 -0500
+++ b/decode-mixed-mode.c	Sat Mar 07 18:04:10 2026 -0500
@@ -2,6 +2,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <inttypes.h>
+#include <string.h>
 
 static void decode_size(unsigned long x)
 {
@@ -10,16 +11,31 @@
     printf("k%sByteCode", lut[x & 3]);
 }
 
-int main(int argc, char *argv[])
+static void func_header(unsigned long x, unsigned long off)
 {
-    unsigned long x;
+	unsigned long i;
+	int ret;
+
+	static const char *lut[] = {"void", "OMS_uint8", "OMS_uint16", "OMS_uint32"};
+
+	/* dont care */
+	x >>= 4;
 
-    if (argc < 2) {
-        fprintf(stderr, "usage: decrypt-mixed-call <param>\n");
-        return 1;
-    }
+	printf("%s OMS_Unknown0x%02lX(", lut[x & 3], off);
+	ret = !!(x & 3);
+	x >>= 2;
+
+	for (i = 1; x; i++, x >>= 2)
+		printf("%s%s p%ld", (i == 1) ? "" : ", ", lut[x & 3], i);
 
-    x = strtoul(argv[1], NULL, 0);
+	printf(")\n{\n\t");
+	if (ret) printf("return ");
+	printf("CallUniversalProc(OMS_InternalFuncTable[0x%02lX],\n\t\t", off);
+}
+
+static void gen(unsigned long x)
+{
+    unsigned long i;
 
     switch (x & 15) {
     case 0:
@@ -30,7 +46,7 @@
         break;
     case 2:
         printf("I'm too lazy for this!");
-        return 1;
+	break;
     case 5:
         printf("kThinkCStackBased");
         break;
@@ -47,8 +63,7 @@
         printf("kStackDispatchedPascalStackBased");
         break;
     default:
-        /* Invalid */
-        return 1;
+        return;
     }
 
     x >>= 4;
@@ -61,11 +76,56 @@
     x >>= 2;
 
     /* hopefully we're using stack, since that's the ONLY thing i'm handling */
-    for (uint32_t i = 1; i < 13 && x; i++, x >>= 2) {
-        printf(" | STACK_ROUTINE_PARAMETER(%" PRIu32 ", ", i);
+    for (i = 1; x; i++, x >>= 2) {
+        printf(" | STACK_ROUTINE_PARAMETER(%lu, ", i);
         decode_size(x);
         printf(")");
     }
+}
+
+void func_footer(unsigned long x)
+{
+	unsigned long i;
+
+	x >>= 6;
+
+	printf("\n\t");
+
+	for (i = 1; x; i++, x >>= 2)
+		printf(", p%lu", i);
+
+	printf(");\n}");
+}
+
+int main(int argc, char *argv[])
+{
+    unsigned long x;
+    int stubs;
+    int inarg;
+    unsigned long off;
+
+    if (argc < 2) {
+        fprintf(stderr, "usage: decrypt-mixed-call <param>\n");
+        return 1;
+    }
+
+    stubs = (argc > 2 && !strcmp(argv[1], "-gen-stub"));
+
+    if (stubs) {
+        inarg = 3;
+        off = strtoul(argv[2], NULL, 0);
+    } else
+        inarg = 1;
+
+    x = strtoul(argv[inarg], NULL, 0);
+
+    if (stubs) {
+        func_header(x, off);
+    }
+    gen(x);
+    if (stubs) {
+	func_footer(x);        
+    }
 
     puts("");
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/split-aac.py	Sat Mar 07 18:04:10 2026 -0500
@@ -0,0 +1,28 @@
+# We want to split the files, preserving their original compression with as few possible clicks.
+# This means we have to align all of our track offsets as frames.
+
+import sys
+
+
+def get_closest_aligned_time(target_time: float, sample_rate: float) -> int:
+	# Convert target time into an exact amount of samples first.
+	# We obviously can't have a fraction of a sample.
+	samples = int(round(target_time * sample_rate))
+
+	# Round to the nearest frame multiple. Note that AAC frames are
+	# *usually* (but not always) 1024 samples in size.
+	frames = samples - samples % 1024
+
+	return frames / sample_rate
+
+
+# sample rate is first argument
+sample_rate = float(sys.argv[1])
+
+# rest of the arguments are the times to align.
+# Hopefully giving these values as microseconds will help
+# ffmpeg realize it should cut along frame boundaries.
+for i in sys.argv[2:]:
+	x = get_closest_aligned_time(float(i), sample_rate)
+	print("%f\n" % x, end="")
+	print("%f," % x, end="")