Fix conversion conflicts when both input and output filenames are same (#459)

* Workaround conversion conflicts by appending '.temp' to input filename

* Fix tests

* Add a test and some minor changes

* Update CHANGES.md
This commit is contained in:
Ritiek Malhotra
2019-01-02 18:54:27 +00:00
committed by GitHub
parent 1cf421960c
commit 53dd292b55
6 changed files with 78 additions and 28 deletions

View File

@@ -18,25 +18,46 @@ https://trac.ffmpeg.org/wiki/Encode/AAC
def song(input_song, output_song, folder, avconv=False, trim_silence=False):
""" Do the audio format conversion. """
convert = Converter(input_song, output_song, folder, trim_silence)
if avconv and trim_silence:
raise ValueError("avconv does not support trim_silence")
if not input_song == output_song:
log.info("Converting {0} to {1}".format(input_song, output_song.split(".")[-1]))
elif input_song.endswith(".m4a"):
log.info('Correcting container in "{}"'.format(input_song))
else:
return 0
convert = Converter(input_song, output_song, folder, delete_original=True)
if avconv:
exit_code, command = convert.with_avconv()
else:
exit_code, command = convert.with_ffmpeg()
exit_code, command = convert.with_ffmpeg(trim_silence=trim_silence)
return exit_code, command
class Converter:
def __init__(self, input_song, output_song, folder, trim_silence=False):
self.input_file = os.path.join(folder, input_song)
def __init__(self, input_song, output_song, folder, delete_original):
_, self.input_ext = os.path.splitext(input_song)
_, self.output_ext = os.path.splitext(output_song)
self.output_file = os.path.join(folder, output_song)
self.trim_silence = trim_silence
rename_to_temp = False
same_file = os.path.abspath(input_song) == os.path.abspath(output_song)
if same_file:
# FFmpeg/avconv cannot have the same file for both input and output
# This would happen when the extensions are same, so rename
# the input track to append ".temp"
log.debug('Input file and output file are going will be same during encoding, will append ".temp" to input file just before starting encoding to avoid conflict')
input_song = output_song + ".temp"
rename_to_temp = True
delete_original = True
self.input_file = os.path.join(folder, input_song)
self.rename_to_temp = rename_to_temp
self.delete_original = delete_original
def with_avconv(self):
if log.level == 10:
@@ -56,45 +77,48 @@ class Converter:
"-y",
]
if self.trim_silence:
log.warning("--trim-silence not supported with avconv")
if self.rename_to_temp:
os.rename(self.output_file, self.input_file)
log.debug(command)
return subprocess.call(command), command
code = subprocess.call(command)
def with_ffmpeg(self):
if self.delete_original:
log.debug('Removing original file: "{}"'.format(self.input_file))
os.remove(self.input_file)
return code, command
def with_ffmpeg(self, trim_silence=False):
ffmpeg_pre = "ffmpeg -y "
if not log.level == 10:
ffmpeg_pre += "-hide_banner -nostats -v panic "
_, input_ext = os.path.splitext(self.input_file)
_, output_ext = os.path.splitext(self.output_file)
ffmpeg_params = ""
if input_ext == ".m4a":
if output_ext == ".mp3":
if self.input_ext == ".m4a":
if self.output_ext == ".mp3":
ffmpeg_params = "-codec:v copy -codec:a libmp3lame -ar 44100 "
elif output_ext == ".webm":
elif self.output_ext == ".webm":
ffmpeg_params = "-codec:a libopus -vbr on "
elif output_ext == ".m4a":
ffmpeg_params = "-vn -acodec copy "
elif self.output_ext == ".m4a":
ffmpeg_params = "-acodec copy "
elif input_ext == ".webm":
if output_ext == ".mp3":
elif self.input_ext == ".webm":
if self.output_ext == ".mp3":
ffmpeg_params = "-codec:a libmp3lame -ar 44100 "
elif output_ext == ".m4a":
elif self.output_ext == ".m4a":
ffmpeg_params = "-cutoff 20000 -codec:a aac -ar 44100 "
if output_ext == ".flac":
if self.output_ext == ".flac":
ffmpeg_params = "-codec:a flac -ar 44100 "
# add common params for any of the above combination
ffmpeg_params += "-b:a 192k -vn "
ffmpeg_pre += " -i"
ffmpeg_pre += "-i "
if self.trim_silence:
if trim_silence:
ffmpeg_params += "-af silenceremove=start_periods=1 "
command = (
@@ -104,5 +128,14 @@ class Converter:
+ [self.output_file]
)
if self.rename_to_temp:
os.rename(self.output_file, self.input_file)
log.debug(command)
return subprocess.call(command), command
code = subprocess.call(command)
if self.delete_original:
log.debug('Removing original file: "{}"'.format(self.input_file))
os.remove(self.input_file)
return code, command