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")
|