Skip to content

Commit

Permalink
Merge pull request #2
Browse files Browse the repository at this point in the history
enhancements/enhance-code
  • Loading branch information
asaah18 authored Sep 15, 2024
2 parents f90eeba + 2bbbb20 commit b14cde1
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 70 deletions.
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -161,5 +161,10 @@ cython_debug/
.idea/


removing_music.log
./removing_music.log

/input/*
!/input/.gitkeep

/output/*
!/output/.gitkeep
File renamed without changes.
141 changes: 72 additions & 69 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,69 +4,78 @@
from itertools import chain
from pathlib import Path

logging.basicConfig(
encoding='utf-8',
format='%(asctime)s - %(levelname)s - %(message)s',
level=logging.INFO,
handlers=[
logging.FileHandler("removing_music.log", encoding='utf-8'),
logging.StreamHandler(sys.stdout)
]
)

def process_file(original_video: Path):

def cleanup(no_music_sound: Path, original_video: Path) -> None:
"""
removes music from videos in input folder
:return: True if there's no file to process, which marks the end of the mass process
delete Intermediate audio files and original video
"""
try:
logging.info(f'Processing file "{original_video.name}"')
logging.info(f'"{original_video.name}": deleting original video...')
original_video.unlink()
logging.info(f'"{original_video.name}": original video deleted successfully')
logging.info(f'"{original_video.name}": deleting vocal sound...')
for file in [file for file in no_music_sound.parent.iterdir()]:
file.unlink()
no_music_sound.parent.rmdir()
logging.info(f'"{original_video.name}": vocal sound deleted successfully')

no_music_sound: Path = Path(f'separated/htdemucs/{original_video.stem}/vocals.mp3')
if no_music_sound.exists():
logging.info(f'"{original_video.name}": vocal already separated, skipping separating vocal')
else:
logging.info(f'"{original_video.name}": start separating vocal...')
# TODO: export vocal sound as `wav` extension
remove_music_command: list[str] = ['pipenv', 'run', 'demucs', '--mp3', '--two-stems=vocals',
original_video.absolute()]
completed_process = subprocess.run(remove_music_command, encoding='utf-8', text=True,
capture_output=True,
check=True)
# raise exception if vocal sound is not created, exception raised manually
# because demucs command doesn't return error code
if not no_music_sound.exists():
raise subprocess.CalledProcessError(returncode=1,
cmd=completed_process.args,
output=completed_process.stdout,
stderr=completed_process.stderr)
logging.info(f'"{original_video.name}": vocal seperated successfully')
# 3- replace the sound of the video with the no music version,
# and save the new video in folder 'output'
# if not already done
no_music_video: Path = Path(f'output/{original_video.name}')
if no_music_video.exists():
logging.info(
f'"{original_video.name}": a video with no music already exists, skipping creating a new video')
else:
logging.info(f'"{original_video.name}": creating a new video with no music...')
create_no_music_video_command: list[str] = ['ffmpeg', '-i', original_video.absolute(),
'-i', no_music_sound.absolute(),
'-c:v', 'copy', '-map', '0:v:0', '-map', '1:a:0',
no_music_video.absolute()]
subprocess.run(create_no_music_video_command, encoding='utf-8', text=True, capture_output=True, check=True)
logging.info(f'"{original_video.name}": a new video with no music has been created')
# clean up
logging.info(f'"{original_video.name}": deleting original video...')
original_video.unlink()
logging.info(f'"{original_video.name}": original video deleted successfully')
logging.info(f'"{original_video.name}": deleting vocal sound...')
for file in [file for file in no_music_sound.parent.iterdir()]:
file.unlink()
no_music_sound.parent.rmdir()
logging.info(f'"{original_video.name}": vocal sound deleted successfully')
except subprocess.CalledProcessError as error:
logging.exception(error.stderr)
raise error
except KeyboardInterrupt as error:
logging.exception('the process was stopped by user')
raise error
except BaseException as error:
logging.exception('Unexpected error happened')
raise error

def create_video_without_music(no_music_sound: Path, original_video: Path) -> Path:
"""
replace the sound of the video with the no music version,
and save the new video in folder 'output'
if not already done
"""
no_music_video: Path = Path(f'output/{original_video.name}')
if no_music_video.exists():
logging.info(
f'"{original_video.name}": a video with no music already exists, skipping creating a new video')
else:
logging.info(f'"{original_video.name}": Processing finished')
logging.info(f'"{original_video.name}": creating a new video with no music...')
create_no_music_video_command: list[str] = ['ffmpeg', '-i', original_video.absolute(),
'-i', no_music_sound.absolute(),
'-c:v', 'copy', '-map', '0:v:0', '-map', '1:a:0',
no_music_video.absolute()]
subprocess.run(create_no_music_video_command, encoding='utf-8', text=True, capture_output=True, check=True)
logging.info(f'"{original_video.name}": a new video with no music has been created')
return no_music_video


def separate_vocal(original_video: Path) -> Path:
"""
separate vocal from music using demucs machine learning algorithm
:exception subprocess.CalledProcessError
"""
no_music_sound: Path = Path(f'separated/htdemucs/{original_video.stem}/vocals.mp3')
if no_music_sound.exists():
logging.info(f'"{original_video.name}": vocal already separated, skipping separating vocal')
else:
logging.info(f'"{original_video.name}": start separating vocal...')
# TODO: export vocal sound as `wav` extension
remove_music_command: list[str] = ['pipenv', 'run', 'demucs', '--mp3', '--two-stems=vocals',
original_video.absolute()]
completed_process = subprocess.run(remove_music_command, encoding='utf-8', text=True,
capture_output=True,
check=True)
# raise exception if vocal sound is not created, exception raised manually
# because demucs command doesn't return error code
if not no_music_sound.exists():
raise subprocess.CalledProcessError(returncode=1,
cmd=completed_process.args,
output=completed_process.stdout,
stderr=completed_process.stderr)
logging.info(f'"{original_video.name}": vocal seperated successfully')
return no_music_sound


def get_original_video() -> Path | None:
Expand All @@ -79,20 +88,14 @@ def get_original_video() -> Path | None:


def main() -> None:
logging.basicConfig(
encoding='utf-8',
format='%(asctime)s - %(levelname)s - %(message)s',
level=logging.INFO,
handlers=[
logging.FileHandler("removing_music.log", encoding='utf-8'),
logging.StreamHandler(sys.stdout)
]
)

logging.info('Mass processing started')

while original_video := get_original_video():
process_file(original_video)
logging.info(f'Processing file "{original_video.name}"')
no_music_sound: Path = separate_vocal(original_video)
create_video_without_music(no_music_sound, original_video)
cleanup(no_music_sound, original_video)
logging.info(f'"{original_video.name}": Processing finished')
else:
logging.info("There's no file to process")

Expand Down
Empty file added output/.gitkeep
Empty file.

0 comments on commit b14cde1

Please sign in to comment.