Last active
March 8, 2025 22:41
-
-
Save httpJunkie/8c7cc970cfcdd4189bdeabf6f6a43a13 to your computer and use it in GitHub Desktop.
playlist-2-YouTube
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import tempfile | |
import shutil | |
import sys | |
from mutagen.mp3 import MP3 | |
from pydub import AudioSegment | |
import ffmpeg | |
def get_middle_time(input_file, duration): | |
audio = MP3(input_file) | |
total_length = audio.info.length | |
if total_length < duration: | |
return 0 # If track is shorter than desired clip length, keep it whole | |
return (total_length - duration) / 2 | |
def create_mixcloud_playlist(playlist_file, output_file): | |
with open(playlist_file, "r") as f: | |
tracks = [line.strip() for line in f if line.strip() and not line.startswith("#")] | |
with open(output_file, "w") as out: | |
out.write("#\tTrack Number\tArtist\tTrack Title\n") # Corrected header | |
for i, track in enumerate(tracks, start=1): | |
artist, title = os.path.splitext(os.path.basename(track))[0].split(" - ") | |
out.write(f"{i:02d}.\t{artist} - {title}\n") # Format as Artist - Title | |
print(f"Mixcloud playlist saved as {output_file}") | |
def append_tracks(playlist_file, middle_duration, image_file=None, format_mixcloud=False, show_full_path=False): | |
if format_mixcloud: | |
# Generate the Mixcloud-formatted playlist and exit | |
output_playlist = os.path.splitext(playlist_file)[0] + "_mixcloud_playlist.txt" | |
create_mixcloud_playlist(playlist_file, output_playlist) | |
return # Exit after generating the playlist | |
temp_dir = tempfile.mkdtemp() | |
output_file = os.path.splitext(playlist_file)[0] + "_setlist.mp3" | |
final_audio = AudioSegment.silent(duration=0) | |
seen_tracks = set() | |
with open(playlist_file, "r") as f: | |
tracks = [line.strip() for line in f if line.strip() and not line.startswith("#")] | |
for i, track in enumerate(tracks, start=1): | |
track_name = os.path.basename(track) # Get the full track filename | |
artist, title = os.path.splitext(track_name)[0].split(" - ") | |
# Only print the full path if the flag is set, otherwise print just Artist - Title | |
if show_full_path: | |
print(f"Writing track: {track_name}") | |
else: | |
print(f"Writing track: {artist} - {title}") | |
if track in seen_tracks: | |
user_input = input(f"Duplicate track found: {track_name}\n(Y) Include only once, (N) Allow duplicates: ") | |
if user_input.strip().lower() != "y": | |
final_audio += AudioSegment.from_mp3(track) | |
continue | |
seen_tracks.add(track) | |
start_time = get_middle_time(track, middle_duration) | |
audio_segment = AudioSegment.from_mp3(track) | |
trimmed_audio = audio_segment[start_time * 1000 : (start_time + middle_duration) * 1000] | |
final_audio += trimmed_audio | |
print("Tracks processed, creating final mixes...") | |
final_audio.export(output_file, format="mp3") | |
print(f"Final mix saved as {output_file}") | |
if image_file: | |
video_output = os.path.splitext(output_file)[0] + ".mp4" | |
# Explicitly specify the image and audio input streams | |
image_input = ffmpeg.input(image_file, loop=1, t=final_audio.duration_seconds) | |
audio_input = ffmpeg.input(output_file) | |
# Combine the inputs and output the video with audio | |
ffmpeg.output(image_input, audio_input, video_output, vcodec='libx264', acodec='aac').run() | |
print(f"Video created: {video_output}") | |
shutil.rmtree(temp_dir) | |
print("Temporary directory cleaned up successfully.") | |
if __name__ == "__main__": | |
if len(sys.argv) < 2: | |
print("Usage: python script.py <playlist.m3u8> [duration] [image] [--formatPlaylistMixcloud] [--showFullAudioPath]") | |
sys.exit(1) | |
playlist_file = sys.argv[1] | |
middle_duration = int(sys.argv[2]) if len(sys.argv) > 2 and not sys.argv[2].startswith("--") else None | |
image_file = sys.argv[3] if len(sys.argv) > 3 and not sys.argv[3].startswith("--") else None | |
format_mixcloud = "--formatPlaylistMixcloud" in sys.argv | |
show_full_path = "--showFullAudioPath" in sys.argv | |
append_tracks(playlist_file, middle_duration, image_file, format_mixcloud, show_full_path) | |
""" | |
## Usage Instructions for mp3append.py | |
### 1. Generate an audio file of all tracks appended: | |
This will concatenate all tracks in the playlist into a single audio file. | |
Usage: | |
python3 mp3append.py <playlist_file.m3u8> | |
### 2. Export only the X number of seconds from the middle of each track: | |
This will create an audio file with only the specified middle duration of each track in the playlist. | |
Usage: | |
python3 mp3append.py <playlist_file.m3u8> <middle_duration_in_seconds> | |
### 3. Export a video along with the audio file for upload to YouTube (or other platforms): | |
This will create a video where the specified image is looped for the duration of the audio. The audio file will include the middle section of each track. | |
Usage: | |
python3 mp3append.py <playlist_file.m3u8> <middle_duration_in_seconds> <image_file> | |
### 4. Format a playlist for Mixcloud: | |
This option will output a Mixcloud-friendly text file formatted with track details, ready for use in Mixcloud uploads. | |
Usage: | |
python3 mp3append.py <playlist_file.m3u8> --formatPlaylistMixcloud | |
### 5. Show full audio file path during processing: | |
By default, only the track name (artist - title) is shown during processing. This flag will show the full file path instead. | |
Usage: | |
python3 mp3append.py <playlist_file.m3u8> --showFullAudioPath | |
### 6. Prevent duplicate tracks from being appended: | |
If a duplicate track is detected in the playlist, you will be prompted to decide whether to overwrite it or allow duplication. | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment