aboutsummaryrefslogtreecommitdiffstats
path: root/grabnsplit-project/src
diff options
context:
space:
mode:
authorEddy Pedroni <epedroni@pm.me>2026-10-22 17:09:53 +0200
committerEddy Pedroni <epedroni@pm.me>2026-10-22 17:09:53 +0200
commit9048b18b47d903990be169a238d7835bb11a5047 (patch)
treeed232dc930408a0732fe75f5955c6df9bcf2d995 /grabnsplit-project/src
parentda27828f8e52b71581886fb2f25489a82a904469 (diff)
grabnsplit script
Diffstat (limited to 'grabnsplit-project/src')
-rw-r--r--grabnsplit-project/src/grabnsplit.py99
1 files changed, 99 insertions, 0 deletions
diff --git a/grabnsplit-project/src/grabnsplit.py b/grabnsplit-project/src/grabnsplit.py
new file mode 100644
index 0000000..c4409dc
--- /dev/null
+++ b/grabnsplit-project/src/grabnsplit.py
@@ -0,0 +1,99 @@
+import click
+from pathlib import Path
+
+SAMPLE_RATE = "48000"
+FB_URL = "https://files.0xf7.com"
+
+def download(yt_url: str, destination: Path) -> None:
+ import yt_dlp
+
+ options = {
+ "format": "bestaudio/best",
+ "outtmpl": str(destination),
+ "playlist_items": "1",
+ "postprocessors": [
+ {
+ "key": "FFmpegExtractAudio",
+ "preferredcodec": "wav"
+ }
+ ],
+ "postprocessor_args": [
+ "-ar", SAMPLE_RATE,
+ ],
+ }
+
+ with yt_dlp.YoutubeDL(options) as downloader:
+ downloader.download([yt_url])
+
+def split(original: Path, destination: Path) -> None:
+ from demucs.api import Separator
+ from demucs.audio import save_audio
+
+ separator = Separator(model="htdemucs_6s")
+
+ origin, separated = separator.separate_audio_file(original)
+
+ for stem_name, audio in separated.items():
+ output_file = destination / f"{stem_name}.wav"
+ save_audio(
+ audio,
+ str(output_file),
+ samplerate=separator.samplerate,
+ )
+
+def combine(destination: Path, name: str) -> None:
+ from ffmpeg import FFmpeg
+
+ inputs = []
+ options = {
+ "map": [],
+ "c:a": "libmp3lame",
+ "b:a": "320k",
+ "ar": SAMPLE_RATE
+ }
+
+ stems = [
+ ("vocals.wav", "Vocals"),
+ ("guitar.wav", "Guitars"),
+ ("piano.wav", "Piano"),
+ ("bass.wav", "Bass"),
+ ("drums.wav", "Drums"),
+ ("other.wav", "Other"),
+ ]
+
+ ffmpeg = FFmpeg().option("y")
+
+ for i, stem in enumerate(stems):
+ #inputs.append(ffmpeg.input(str(destination / stem[0])))
+ ffmpeg.input(str(destination / stem[0]))
+ options["map"].append(f"{i}:a")
+ options[f"metadata:s:a:{i}"] = f"title={stem[1]}"
+
+ ffmpeg.output(str(destination / f"{name}.mka"), options)
+ ffmpeg.execute()
+
+def upload(file_path: Path) -> None:
+ from requests import post
+ from os import getenv
+
+ api_key = post(f"{FB_URL}/api/login", json={"username":getenv("ST_USER"), "password":getenv("ST_PASS")}).content
+ url = f"{FB_URL}/api/resources/songs/{file_path.name}"
+ with open(file_path, "rb") as file:
+ post(url, headers={"X-Auth" : api_key}, data=file).raise_for_status()
+
+@click.command()
+@click.argument("url", required=True)
+@click.argument("output_file", required=True)
+@click.option("--work_dir", type=click.Path())
+def main(url: str, output_file: str, work_dir: Path):
+ from tempfile import TemporaryDirectory
+ with TemporaryDirectory(prefix="grabnsplit") as temp:
+ dir = Path(work_dir if work_dir is not None else temp)
+
+ original = dir / "original.wav"
+
+ download(url, original.parent / original.stem)
+ split(original, dir)
+ combine(dir, output_file)
+ upload(dir / f"{output_file}.mka")
+