PYTR / app.py
sudo-soldier's picture
Update app.py
c846fe2 verified
raw
history blame
5.81 kB
import os
import gradio as gr
import yt_dlp
from pydub import AudioSegment
import re
import subprocess
# Ensure static directory exists for storing audio files
DOWNLOAD_DIR = "static"
os.makedirs(DOWNLOAD_DIR, exist_ok=True)
def sanitize_filename(filename):
"""Sanitize filenames to avoid special characters."""
return re.sub(r'[^a-zA-Z0-9_-]', '_', filename)
def process_youtube_or_audio(url, uploaded_audio, start_time, end_time):
try:
filename = None
song_name = None
print(f"Processing URL: {url}")
print(f"Uploaded audio: {uploaded_audio}")
print(f"Start time: {start_time}, End time: {end_time}")
# Download from YouTube if URL is provided
if url:
print("Downloading from YouTube...")
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': f'{DOWNLOAD_DIR}/%(id)s.%(ext)s',
'cookiefile': 'cookies.txt',
'noplaylist': True,
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=True)
filename = os.path.join(DOWNLOAD_DIR, f"{info['id']}.webm")
song_name = sanitize_filename(info['title'])
# Use uploaded audio if available
elif uploaded_audio:
print("Processing uploaded audio...")
filename = uploaded_audio
song_name = "uploaded_audio"
# If no valid file exists, return an error
if not filename or not os.path.exists(filename):
print(f"Error: No valid file found at {filename}")
return None, None
# Load and trim audio
audio = AudioSegment.from_file(filename)
start_time_ms = max(0, min(start_time * 1000, len(audio)))
end_time_ms = max(start_time_ms, min(end_time * 1000, len(audio)))
trimmed_audio = audio[start_time_ms:end_time_ms]
# Export trimmed audio as MP3
mp3_filename = f"{DOWNLOAD_DIR}/{song_name}.mp3"
trimmed_audio.export(mp3_filename, format="mp3")
# Convert MP3 to M4R for iPhone
m4a_filename = f"{DOWNLOAD_DIR}/{song_name}.m4a"
try:
subprocess.run([
'ffmpeg', '-i', mp3_filename, '-vn', '-acodec', 'aac', '-b:a', '192k', m4a_filename
], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30, check=True)
except subprocess.TimeoutExpired:
print("Error: ffmpeg took too long to process the file.")
return None, None
except subprocess.CalledProcessError as e:
print(f"ffmpeg error: {e}")
return None, None
# Rename to M4R format for iPhone ringtones
m4r_filename = f"{DOWNLOAD_DIR}/{song_name}.m4r"
if os.path.exists(m4a_filename):
os.rename(m4a_filename, m4r_filename)
print(f"Files saved: {mp3_filename}, {m4r_filename}")
return mp3_filename, m4r_filename
else:
print("Error: M4A file not created.")
return None, None
except Exception as e:
print(f"Error: {e}")
return None, None
# === GRADIO UI ===
with gr.Blocks(css="""
body { font-family: Arial, sans-serif; text-align: center; }
.light-btn { background-color: #ADD8E6; color: #333; border: 2px solid #ccc; padding: 10px 20px; font-size: 16px; cursor: pointer; }
.light-btn:hover { background-color: #87CEFA; }
""") as interface:
gr.HTML("""
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<h1><i class="fas fa-music"></i>&nbsp;PYTR</h1>
<p>Python YouTube Ringtones. Enter a YouTube URL or upload audio to create ringtones.</p>
<p>
<a href="https://ringtones.JesseJesse.xyz" target="_blank">Ringtones</a>&nbsp;&nbsp;&nbsp;
<a href="https://pub-c1de1cb456e74d6bbbee111ba9e6c757.r2.dev/iphone.png" target="_blank">iPhone xfers</a>&nbsp;&nbsp;&nbsp;
<a href="https://youtube.com" target="_blank">YouTube</a>
</p>
""")
with gr.Row():
with gr.Column(scale=1, min_width=250):
gr.HTML('<label><i class="fas fa-link"></i>&nbsp;YouTube URL</label>')
youtube_url = gr.Textbox(placeholder="Enter the URL here...", show_label=False)
with gr.Column(scale=1, min_width=250):
gr.HTML('<label><i class="fas fa-upload"></i>&nbsp;Upload Audio</label>')
audio_upload = gr.File(label="Upload Audio", type="filepath", show_label=False)
with gr.Row():
gr.HTML("<h3>Trim Audio (Optional)</h3>")
with gr.Row():
start_time = gr.Slider(0, 20, value=0, label="Start Time (seconds)")
end_time = gr.Slider(1, 20, value=20, label="End Time (seconds)")
with gr.Row():
process_button = gr.Button("Create Ringtones", elem_classes="light-btn")
with gr.Row():
with gr.Column(scale=1, min_width=250):
gr.HTML('<label>&nbsp;Android Ringtone</label>')
mp3_download = gr.File(label="Android")
android_instructions = gr.Textbox(label="Install", placeholder="Move the .mp3 file to the ringtones folder", lines=2)
with gr.Column(scale=1, min_width=250):
gr.HTML('<label>&nbsp;iPhone Ringtone</label>')
iphone_ringtone = gr.File(label="Apple")
iphone_instructions = gr.Textbox(label="Install", placeholder="Open GarageBand on your iPhone. Import the .m4r file and set it as a ringtone.", lines=4)
process_button.click(process_youtube_or_audio, inputs=[youtube_url, audio_upload, start_time, end_time], outputs=[mp3_download, iphone_ringtone])
# Launch with queue for stability
interface.queue().launch(share=True, server_port=7860)