aboutsummaryrefslogtreecommitdiffstats
path: root/grabnsplit-project/src/grabnsplit.py
blob: c4409dc92c1e89a416206271fa7bd10389d0c833 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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")