From 198e33002f78f191a5dd5ba0a6e181069b45396d Mon Sep 17 00:00:00 2001 From: Ivan Ogasawara Date: Tue, 29 Aug 2023 11:25:00 -0400 Subject: [PATCH 1/2] feat: Add the flag --lang for the voice command --- README.md | 12 ++++++++++++ src/artbox/voices.py | 16 ++-------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 8e1019c..1be4424 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,18 @@ $ artbox voice text-to-audio \ --output-path /tmp/artbox/voice.mp3 ``` +If you need to generate the audio for different language, you can use +the flag `--lang`: + +```bash +$ echo "Bom dia, mundo!" > /tmp/artbox/text.md +$ artbox voice text-to-audio \ + --title artbox \ + --text-path /tmp/artbox/text.md \ + --output-path /tmp/artbox/voice.mp3 \ + --lang pt +``` + ### Download a youtube video ```bash diff --git a/src/artbox/voices.py b/src/artbox/voices.py index c6a08da..c26baf3 100644 --- a/src/artbox/voices.py +++ b/src/artbox/voices.py @@ -3,24 +3,11 @@ ref: https://thepythoncode.com/article/convert-text-to-speech-in-python """ - -import re - -from pathlib import Path - import gtts from artbox.base import ArtBox -def slugify(s): - s = s.lower().strip() - s = re.sub(r"[^\w\s-]", "", s) - s = re.sub(r"[\s_-]+", "-", s) - s = re.sub(r"^-+|-+$", "", s) - return s - - class Voice(ArtBox): """Set of methods for handing audio voices.""" @@ -28,6 +15,7 @@ def text_to_audio(self) -> None: """Convert text to audio voice.""" title: str = self.args.get("title", "") text_path: str = self.args.get("text-path", "") + lang: str = self.args.get("lang", "en") if not title: raise Exception("Argument `title` not given") @@ -38,5 +26,5 @@ def text_to_audio(self) -> None: with open(text_path, "r") as f: text = f.read() - tts = gtts.gTTS(text, lang="en", slow=False) + tts = gtts.gTTS(text, lang=lang, slow=False) tts.save(str(self.output_path)) From a9289b217dfec31000e4efb0befb92aac99ea4ff Mon Sep 17 00:00:00 2001 From: Ivan Ogasawara Date: Tue, 29 Aug 2023 11:50:24 -0400 Subject: [PATCH 2/2] Fix initial issues from linter --- src/artbox/cli.py | 3 --- src/artbox/sounds.py | 3 +-- src/artbox/videos.py | 9 ++++---- tests/test_audios.py | 13 ------------ tests/test_sounds.py | 50 +++++++++++++++++++++++++++----------------- tests/test_videos.py | 38 +++++++++++++++++++++++---------- tests/test_voices.py | 21 +++++++++++++++++++ 7 files changed, 85 insertions(+), 52 deletions(-) delete mode 100644 tests/test_audios.py create mode 100644 tests/test_voices.py diff --git a/src/artbox/cli.py b/src/artbox/cli.py index 5674374..75ddbb1 100644 --- a/src/artbox/cli.py +++ b/src/artbox/cli.py @@ -1,10 +1,7 @@ """Cli functions to define the arguments and to call Makim.""" import argparse -import os import sys -from pathlib import Path - from artbox import __version__ from artbox.sounds import Sound from artbox.videos import Video diff --git a/src/artbox/sounds.py b/src/artbox/sounds.py index 978b877..1fdfbfb 100644 --- a/src/artbox/sounds.py +++ b/src/artbox/sounds.py @@ -2,7 +2,6 @@ import json from math import log2 -from pathlib import Path import aubio import noisereduce as nr @@ -292,7 +291,7 @@ def extract_notes_from_mp3(self) -> list: # Convert frequency to musical note and add to the list if frequency > 0: # Ignore zero frequencies (silence) - note = frequency_to_note(frequency) + note = self.frequency_to_note(frequency) notes.append(note) with open(output_notes, "w") as f: diff --git a/src/artbox/videos.py b/src/artbox/videos.py index cc02328..02504e8 100644 --- a/src/artbox/videos.py +++ b/src/artbox/videos.py @@ -1,8 +1,8 @@ """ +Set of tools for video handling. + ref: https://github.com/ethand91/python-youtube/blob/master/main.py """ -from pathlib import Path - from moviepy.editor import AudioFileClip, VideoFileClip from pytube import YouTube @@ -10,6 +10,8 @@ class Video(ArtBox): + """Set of tools for handing videos.""" + def download_from_youtube(self): """Download a youtube video.""" video_url = self.args.get("url", "") @@ -22,7 +24,7 @@ def download_from_youtube(self): try: video.download(str(self.output_path)) - except: + except Exception: print("Failed to download video") print("Video was downloaded successfully") @@ -88,7 +90,6 @@ def extract_audio(self) -> None: def remove_audio(self) -> None: """Remove the audio from an MP4 file.""" - # Load the video video = VideoFileClip(str(self.input_path)) diff --git a/tests/test_audios.py b/tests/test_audios.py deleted file mode 100644 index ef29d8a..0000000 --- a/tests/test_audios.py +++ /dev/null @@ -1,13 +0,0 @@ -import pytest - - -@pytest.mark.skip -def test_audio() -> None: - audio = Audio() - texts_path = MEDIA_PATH / "texts" - - with open(texts_path / "totk.txt") as f: - text = f.read() - - title = "The Legend of Zelda Tears of the Kingdom" - audio.convert(title, text) diff --git a/tests/test_sounds.py b/tests/test_sounds.py index 7ef9125..7d5d0b0 100644 --- a/tests/test_sounds.py +++ b/tests/test_sounds.py @@ -1,38 +1,50 @@ +"""Set of tests for the sounds module.""" +from pathlib import Path + import pytest from artbox.sounds import Sound +TMP_PATH = Path("/tmp/artbox") + + +@pytest.mark.fixture +def sound(): + """Create a fixture for the Sound object.""" + return Sound() + @pytest.mark.skip -def test_extract(): - # Example usage - videos_path = VIDEOS_PATH / "Super Mario Theme EPIC VERSION.mp4" - output_path = MEDIA_PATH / "sounds" / "smb-epic-theme.mp3" - extract_audio(str(videos_path), str(output_path)) +def test_extract(sound): + """Test the extraction audio from a video.""" + videos_path = TMP_PATH / "Super Mario Theme EPIC VERSION.mp4" + output_path = TMP_PATH / "sounds" / "smb-epic-theme.mp3" + sound.extract_audio(str(videos_path), str(output_path)) @pytest.mark.skip -def test_extract_notes_from_mp3(): - # Example usage - mp3_path = MEDIA_PATH / "sounds" / "tok-audio.mp3" - output_notes = MEDIA_PATH / "notes" / "tok-audio.txt" - notes = extract_notes_from_mp3(str(mp3_path), str(output_notes)) +def test_extract_notes_from_mp3(sound): + """Test the extraction of notes from mp3 file.""" + mp3_path = TMP_PATH / "sounds" / "tok-audio.mp3" + output_notes = TMP_PATH / "notes" / "tok-audio.txt" + notes = sound.extract_notes_from_mp3(str(mp3_path), str(output_notes)) print("Detected notes:", notes) @pytest.mark.skip -def test_generate_melody(): - notes_path = MEDIA_PATH / "notes" / "tok-audio.txt" - generate_melody(notes_path, total_duration=3.54 * 60) +def test_generate_melody(sound): + """Test the melody generation from notes.""" + notes_path = TMP_PATH / "notes" / "tok-audio.txt" + sound.generate_melody(notes_path, total_duration=3.54 * 60) @pytest.mark.skip -def test_convert_to_8bit_audio(): - # Example usage +def test_convert_to_8bit_audio(sound): + """Test the audio conversion to 8bits style.""" videos_path = ( - MEDIA_PATH + TMP_PATH / "videos" - / "The Legend of Zelda Tears of the Kingdom – Official Trailer 3.mp4" + / "The Legend of Zelda Tears of the Kingdom - Official Trailer 3.mp4" ) - output_path = MEDIA_PATH / "sounds" / "tok8bits.mp3" - convert_to_8bit_audio(str(videos_path), str(output_path)) + output_path = TMP_PATH / "sounds" / "tok8bits.mp3" + sound.convert_to_8bit_audio(str(videos_path), str(output_path)) diff --git a/tests/test_videos.py b/tests/test_videos.py index 8c268fa..0d5c105 100644 --- a/tests/test_videos.py +++ b/tests/test_videos.py @@ -1,32 +1,48 @@ +"""Set of tests for the videos module.""" +from pathlib import Path + import pytest from artbox.videos import Video +TMP_PATH = Path("/tmp/artbox") + + +@pytest.mark.fixture +def video(): + """Create a fixture for the Video object.""" + return Video() + @pytest.mark.skip -def test_combine_video_audio(): +def test_combine_video_and_audio(video): + """Test the function that combines video and audio.""" # Example usage - # "The Legend of Zelda Tears of the Kingdom – Official Trailer 3.mp4" - video_path = RESULTS_PATH / "peachs-no-audio.mp4" - audio_path = SOUNDS_PATH / "smb-epic-theme.mp3" - output_path = RESULTS_PATH / "peachs-with-music.mp4" - combine_video_audio(str(video_path), str(audio_path), str(output_path)) + # "The Legend of Zelda Tears of the Kingdom - Official Trailer 3.mp4" + video_path = TMP_PATH / "peachs-no-audio.mp4" + audio_path = TMP_PATH / "smb-epic-theme.mp3" + output_path = TMP_PATH / "peachs-with-music.mp4" + video.combine_video_and_audio( + str(video_path), str(audio_path), str(output_path) + ) @pytest.mark.skip -def test_download(): +def test_download_from_youtube(video): + """Test the method that downloads videos from youtube.""" # "https://www.youtube.com/watch?v=uHGShqcAHlQ" for url in [ "https://youtube.com/shorts/gmutDetnBLQ", "https://youtube.com/watch?v=6pjbaE98ftU", ]: - download(url) + video.download_from_youtube(url) @pytest.mark.skip -def test_remove_audio(): - input_file = VIDEOS_PATH / ( +def test_remove_audio(video): + """Test the function that removes audio from a video.""" + input_file = TMP_PATH / ( "Princess Peachs Training Course in The Super Mario Bros Movie.mp4" ) output_file = "peachs-no-audio.mp4" - remove_audio(input_file, RESULTS_PATH / output_file) + video.remove_audio(input_file, TMP_PATH / output_file) diff --git a/tests/test_voices.py b/tests/test_voices.py new file mode 100644 index 0000000..8d42f89 --- /dev/null +++ b/tests/test_voices.py @@ -0,0 +1,21 @@ +"""Set of tests for the voices module.""" +from pathlib import Path + +import pytest + +from artbox.voices import Voice + +TMP_PATH = Path("/tmp/artbox") + + +@pytest.mark.skip +def test_voice_text_conversion() -> None: + """Test the conversion from text to audio.""" + audio = Voice() + texts_path = TMP_PATH / "texts" + + with open(texts_path / "totk.txt") as f: + text = f.read() + + title = "The Legend of Zelda Tears of the Kingdom" + audio.convert(title, text)