feat: build
This commit is contained in:
9
music_kraken/audio/__init__.py
Normal file
9
music_kraken/audio/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from . import metadata
|
||||
from . import codec
|
||||
|
||||
AudioMetadata = metadata.AudioMetadata
|
||||
write_many_metadata = metadata.write_many_metadata
|
||||
write_metadata = metadata.write_metadata
|
||||
write_metadata_to_target = metadata.write_metadata_to_target
|
||||
|
||||
correct_codec = codec.correct_codec
|
57
music_kraken/audio/codec.py
Normal file
57
music_kraken/audio/codec.py
Normal file
@@ -0,0 +1,57 @@
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple
|
||||
from tqdm import tqdm
|
||||
from ffmpeg_progress_yield import FfmpegProgress
|
||||
|
||||
from ..utils.config import main_settings, logging_settings
|
||||
from ..objects import Target
|
||||
|
||||
|
||||
LOGGER = logging_settings["codex_logger"]
|
||||
|
||||
|
||||
def correct_codec(target: Target, bitrate_kb: int = main_settings["bitrate"], audio_format: str = main_settings["audio_format"], interval_list: List[Tuple[float, float]] = None):
|
||||
if not target.exists:
|
||||
LOGGER.warning(f"Target doesn't exist: {target.file_path}")
|
||||
return
|
||||
|
||||
interval_list = interval_list or []
|
||||
|
||||
bitrate_b = int(bitrate_kb / 1024)
|
||||
|
||||
output_target = Target(
|
||||
file_path=Path(str(target.file_path) + "." + audio_format)
|
||||
)
|
||||
|
||||
# get the select thingie
|
||||
# https://stackoverflow.com/questions/50594412/cut-multiple-parts-of-a-video-with-ffmpeg
|
||||
aselect_list: List[str] = []
|
||||
|
||||
start = 0
|
||||
next_start = 0
|
||||
for end, next_start in interval_list:
|
||||
aselect_list.append(f"between(t,{start},{end})")
|
||||
start = next_start
|
||||
aselect_list.append(f"gte(t,{next_start})")
|
||||
|
||||
select = f"aselect='{'+'.join(aselect_list)}',asetpts=N/SR/TB"
|
||||
|
||||
# build the ffmpeg command
|
||||
ffmpeg_command = [
|
||||
str(main_settings["ffmpeg_binary"]),
|
||||
"-i", str(target.file_path),
|
||||
"-af", select,
|
||||
"-b", str(bitrate_b),
|
||||
str(output_target.file_path)
|
||||
]
|
||||
|
||||
# run the ffmpeg command with a progressbar
|
||||
ff = FfmpegProgress(ffmpeg_command)
|
||||
with tqdm(total=100, desc=f"removing {len(interval_list)} segments") as pbar:
|
||||
for progress in ff.run_command_with_progress():
|
||||
pbar.update(progress-pbar.n)
|
||||
|
||||
LOGGER.debug(ff.stderr)
|
||||
|
||||
output_target.copy_content(target)
|
||||
output_target.delete()
|
88
music_kraken/audio/metadata.py
Normal file
88
music_kraken/audio/metadata.py
Normal file
@@ -0,0 +1,88 @@
|
||||
import mutagen
|
||||
from mutagen.id3 import ID3, Frame
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
import logging
|
||||
|
||||
from ..utils.config import logging_settings
|
||||
from ..objects import Song, Target, Metadata
|
||||
|
||||
|
||||
LOGGER = logging_settings["tagging_logger"]
|
||||
|
||||
|
||||
class AudioMetadata:
|
||||
def __init__(self, file_location: str = None) -> None:
|
||||
self._file_location = None
|
||||
|
||||
self.frames: ID3 = ID3()
|
||||
|
||||
if file_location is not None:
|
||||
self.file_location = file_location
|
||||
|
||||
def add_metadata(self, metadata: Metadata):
|
||||
for value in metadata:
|
||||
"""
|
||||
https://www.programcreek.com/python/example/84797/mutagen.id3.ID3
|
||||
"""
|
||||
self.frames.add(value)
|
||||
|
||||
def add_song_metadata(self, song: Song):
|
||||
self.add_metadata(song.metadata)
|
||||
|
||||
def save(self, file_location: Path = None):
|
||||
LOGGER.debug(f"saving following frames: {self.frames.pprint()}")
|
||||
|
||||
if file_location is not None:
|
||||
self.file_location = file_location
|
||||
|
||||
if self.file_location is None:
|
||||
raise Exception("no file target provided to save the data to")
|
||||
self.frames.save(self.file_location, v2_version=4)
|
||||
|
||||
def set_file_location(self, file_location: Path):
|
||||
# try loading the data from the given file. if it doesn't succeed the frame remains empty
|
||||
try:
|
||||
self.frames.load(file_location, v2_version=4)
|
||||
LOGGER.debug(f"loaded following from \"{file_location}\"\n{self.frames.pprint()}")
|
||||
except mutagen.MutagenError:
|
||||
LOGGER.warning(f"couldn't find any metadata at: \"{self.file_location}\"")
|
||||
self._file_location = file_location
|
||||
|
||||
file_location = property(fget=lambda self: self._file_location, fset=set_file_location)
|
||||
|
||||
|
||||
def write_metadata_to_target(metadata: Metadata, target: Target):
|
||||
if not target.exists:
|
||||
return
|
||||
|
||||
id3_object = AudioMetadata(file_location=target.file_path)
|
||||
id3_object.add_metadata(metadata)
|
||||
id3_object.save()
|
||||
|
||||
|
||||
def write_metadata(song: Song, ignore_file_not_found: bool = True):
|
||||
target: Target
|
||||
for target in song.target:
|
||||
if not target.exists:
|
||||
if ignore_file_not_found:
|
||||
continue
|
||||
else:
|
||||
raise ValueError(f"{song.target.file} not found")
|
||||
|
||||
id3_object = AudioMetadata(file_location=target.file_path)
|
||||
id3_object.add_song_metadata(song=song)
|
||||
id3_object.save()
|
||||
|
||||
|
||||
def write_many_metadata(song_list: List[Song]):
|
||||
for song in song_list:
|
||||
write_metadata(song=song, ignore_file_not_found=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("called directly")
|
||||
filepath = "/home/lars/Music/deathcore/Archspire/Bleed the Future/Bleed the Future.mp3"
|
||||
|
||||
audio_metadata = AudioMetadata(file_location=filepath)
|
||||
print(audio_metadata.frames.pprint())
|
Reference in New Issue
Block a user