@ -27,15 +27,14 @@ DST_OVERWRITE: bool = config.get("libconv", "overwrite") == "true"
DRY_RUN : bool = config . get ( " libconv " , " dry_run " ) != " false "
DRY_RUN : bool = config . get ( " libconv " , " dry_run " ) != " false "
DEDUCE_METADATA : bool = config . get ( " libconv " , " deduce_metadata " ) == " true "
DEDUCE_METADATA : bool = config . get ( " libconv " , " deduce_metadata " ) == " true "
FFMPEG_LOCATION : str = config . get ( " ffmpeg " , " location " )
FFMPEG_LOCATION : str = config . get ( " ffmpeg " , " location " )
FFMPEG_OPTS : str = config . get ( " ffmpeg " , " options " )
THREADS : int = int ( config . get ( " libconv " , " threads " ) )
FFMPEG_OPTS : List [ str ] = config . get ( " ffmpeg " , " options " ) . split ( " , " )
if DST_OVERWRITE :
if DST_OVERWRITE :
FFMPEG_OPTS + = " -y"
FFMPEG_OPTS . append ( " -y " )
logging . basicConfig ( level = logging . INFO )
logging . basicConfig ( level = logging . INFO )
cmd_list : List [ str ] = [ ]
cmd_list = [ ]
# ----------------------------------------------------------------- #
# ----------------------------------------------------------------- #
# file and folder operations
# file and folder operations
@ -50,10 +49,9 @@ def mkdir(path: str):
if not DRY_RUN :
if not DRY_RUN :
os . makedirs ( path , exist_ok = True )
os . makedirs ( path , exist_ok = True )
def execute ( command : str ) :
def execute ( command : List [ str ] ) :
logging . debug ( f " execute: {command} " )
logging . debug ( f " execute: {command} " )
if not DRY_RUN :
cmd_list . append ( command )
cmd_list . append ( command )
# ----------------------------------------------------------------- #
# ----------------------------------------------------------------- #
# cue sheet processing
# cue sheet processing
@ -76,22 +74,24 @@ def cue_sheet_processor(path: str):
try :
try :
data = FFCueSplitter ( sheet [ 0 ] , dry = DRY_RUN , outputdir = dst_folder , suffix = DST_FILE_EXT , overwrite = DST_OVERWRITE , ffmpeg_cmd = FFMPEG_LOCATION , ffmpeg_add_params = FFMPEG_OPTS )
data = FFCueSplitter ( sheet [ 0 ] , dry = DRY_RUN , outputdir = dst_folder , suffix = DST_FILE_EXT , overwrite = DST_OVERWRITE , ffmpeg_cmd = FFMPEG_LOCATION , ffmpeg_add_params = FFMPEG_OPTS )
data . open_cuefile ( )
data . open_cuefile ( )
args = data . ffmpeg_arguments ( ) [ " arguments " ]
args = data . ffmpeg_arguments ( )
except :
except :
logging . error ( f " Error during parsing of cuesheet {path} - trying file processor " )
logging . error ( f " Cuesheet parsing of {path} resulted in error. Trying file processor. " )
file_processor ( path )
file_processor ( path )
return
return
for arg in args :
for arg in args :
arg_end = arg . find ( " -y " )
filename = arg [ arg_end + 5 : - 1 ]
arg = arg [ : arg_end ]
execute ( f " {arg} \" {dst_folder}{filename} \" " )
prepared = [ ]
prepared . append ( FFMPEG_LOCATION )
prepared . extend ( arg [ : - 1 ] )
prepared . extend ( FFMPEG_OPTS )
prepared . append ( f " \" {dst_folder}/{arg[-1]}.{DST_FILE_EXT} \" " )
execute ( prepared )
# ----------------------------------------------------------------- #
# ----------------------------------------------------------------- #
# basic "folder contains audio files" processing
# basic "folder contains audio files" processing
def metadata_from_folder ( path : str ) - > str :
def metadata_from_folder ( path : str ) - > List [ str ] :
# this method has to be adapted to your individual folder structure
# this method has to be adapted to your individual folder structure
# if there is none then do nothing as by default this is not used
# if there is none then do nothing as by default this is not used
if not DEDUCE_METADATA :
if not DEDUCE_METADATA :
@ -105,11 +105,14 @@ def metadata_from_folder(path: str) -> str:
album_name = re . sub ( r ' [ ]* \ (.*? \ ) ' , ' ' , folders [ - 1 ] )
album_name = re . sub ( r ' [ ]* \ (.*? \ ) ' , ' ' , folders [ - 1 ] )
comment = folders [ - 1 ] . replace ( album_name , " " ) . replace ( " ( " , " " ) . replace ( " ) " , " " ) . replace ( " " , " " )
comment = folders [ - 1 ] . replace ( album_name , " " ) . replace ( " ( " , " " ) . replace ( " ) " , " " ) . replace ( " " , " " )
logging . debug ( f " got metadata: album={album_name} comment={comment} artist={folders[-2]} genre={folders[-3]} " )
return f " -metadata ALBUM= \" {album_name} \" -metadata COMMENT= \" {comment} \" -metadata ARTIST= \" {folders[-2]} \" -metadata GENRE= \" {folders[-3]} \" "
return [
f " -metadata ALBUM= \" {album_name} \" " ,
f " -metadata COMMENT= \" {comment} \" " ,
f " -metadata ARTIST= \" {folders[-2]} \" " ,
f " -metadata GENRE= \" {folders[-3]} \" "
]
def metadata_from_file ( filename : str ) - > str :
def metadata_from_file ( filename : str ) - > List [ str ] :
title = " "
title = " "
number = " "
number = " "
@ -126,7 +129,10 @@ def metadata_from_file(filename: str) -> str:
else :
else :
logging . debug ( f " file {filename} matched no metadata regex " )
logging . debug ( f " file {filename} matched no metadata regex " )
return f " -metadata TITLE= \" {title} \" -metadata TRACK= \" {number} \" "
return [
f " -metadata TITLE= \" {title} \" " ,
f " -metadata TRACK= \" {number} \" "
]
def file_processor ( path : str ) :
def file_processor ( path : str ) :
dst_folder , preexisting = prepare_destination ( path )
dst_folder , preexisting = prepare_destination ( path )
@ -141,7 +147,15 @@ def file_processor(path: str):
for file in files :
for file in files :
filename = get_filename ( file , path )
filename = get_filename ( file , path )
file_metadata = metadata_from_file ( filename [ 1 : ] )
file_metadata = metadata_from_file ( filename [ 1 : ] )
execute ( f " \" {FFMPEG_LOCATION} \" -i \" {file} \" {FFMPEG_OPTS} {album_metadata} {file_metadata} \" {dst_folder + filename}.{DST_FILE_EXT} \" " )
command = [ ]
command . append ( FFMPEG_LOCATION )
command . append ( " -i " )
command . append ( f " \" {file} \" " )
command . extend ( album_metadata )
command . extend ( file_metadata )
command . extend ( FFMPEG_OPTS )
command . append ( f " \" {dst_folder}/{filename}.{DST_FILE_EXT} \" " )
execute ( command )
# ----------------------------------------------------------------- #
# ----------------------------------------------------------------- #
# Iteration over library folders and preparation
# Iteration over library folders and preparation
@ -215,16 +229,16 @@ def process_folder(path: str):
scan_folder ( path )
scan_folder ( path )
def execute_command_list ( ) :
def execute_command_list ( ) :
logging . info ( f " Executing all {len(cmd_list)} commands with {THREADS} parallel threads " )
logging . info ( f " Executing all {len(cmd_list)} commands " )
if DRY_RUN :
if DRY_RUN :
logging . info ( " Skipping execution as we are dry-running. Printing list as debug-info. " )
logging . info ( " Skipping execution as we are dry-running. Printing list as debug-info. " )
logging . debug ( str ( cmd_list ) )
logging . debug ( str ( cmd_list ) )
return
return
Parallel ( n_jobs = THREADS ) (
delayed ( os . system ) ( cmd ) for cmd in cmd_list
)
for cmd in cmd_list :
cmd = " " . join ( cmd )
subprocess . run ( cmd , shell = True )
if __name__ == " __main__ " :
if __name__ == " __main__ " :
logging . info ( f " Using settings from {CONFIG_FILE} " )
logging . info ( f " Using settings from {CONFIG_FILE} " )