sudo-soldier commited on
Commit
0849a69
·
verified ·
1 Parent(s): c846fe2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +109 -131
app.py CHANGED
@@ -1,143 +1,121 @@
1
- import os
2
  import gradio as gr
3
- import yt_dlp
4
- from pydub import AudioSegment
5
- import re
6
  import subprocess
 
 
 
7
 
8
- # Ensure static directory exists for storing audio files
9
- DOWNLOAD_DIR = "static"
10
- os.makedirs(DOWNLOAD_DIR, exist_ok=True)
11
 
12
- def sanitize_filename(filename):
13
- """Sanitize filenames to avoid special characters."""
14
- return re.sub(r'[^a-zA-Z0-9_-]', '_', filename)
15
 
16
- def process_youtube_or_audio(url, uploaded_audio, start_time, end_time):
 
 
 
17
  try:
18
- filename = None
19
- song_name = None
20
-
21
- print(f"Processing URL: {url}")
22
- print(f"Uploaded audio: {uploaded_audio}")
23
- print(f"Start time: {start_time}, End time: {end_time}")
24
-
25
- # Download from YouTube if URL is provided
26
- if url:
27
- print("Downloading from YouTube...")
28
- ydl_opts = {
29
- 'format': 'bestaudio/best',
30
- 'outtmpl': f'{DOWNLOAD_DIR}/%(id)s.%(ext)s',
31
- 'cookiefile': 'cookies.txt',
32
- 'noplaylist': True,
33
- }
34
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
35
- info = ydl.extract_info(url, download=True)
36
- filename = os.path.join(DOWNLOAD_DIR, f"{info['id']}.webm")
37
- song_name = sanitize_filename(info['title'])
38
-
39
- # Use uploaded audio if available
40
- elif uploaded_audio:
41
- print("Processing uploaded audio...")
42
- filename = uploaded_audio
43
- song_name = "uploaded_audio"
44
-
45
- # If no valid file exists, return an error
46
- if not filename or not os.path.exists(filename):
47
- print(f"Error: No valid file found at {filename}")
48
- return None, None
49
-
50
- # Load and trim audio
51
- audio = AudioSegment.from_file(filename)
52
- start_time_ms = max(0, min(start_time * 1000, len(audio)))
53
- end_time_ms = max(start_time_ms, min(end_time * 1000, len(audio)))
54
-
55
- trimmed_audio = audio[start_time_ms:end_time_ms]
56
-
57
- # Export trimmed audio as MP3
58
- mp3_filename = f"{DOWNLOAD_DIR}/{song_name}.mp3"
59
- trimmed_audio.export(mp3_filename, format="mp3")
60
-
61
- # Convert MP3 to M4R for iPhone
62
- m4a_filename = f"{DOWNLOAD_DIR}/{song_name}.m4a"
63
- try:
64
- subprocess.run([
65
- 'ffmpeg', '-i', mp3_filename, '-vn', '-acodec', 'aac', '-b:a', '192k', m4a_filename
66
- ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30, check=True)
67
- except subprocess.TimeoutExpired:
68
- print("Error: ffmpeg took too long to process the file.")
69
- return None, None
70
- except subprocess.CalledProcessError as e:
71
- print(f"ffmpeg error: {e}")
72
- return None, None
73
-
74
- # Rename to M4R format for iPhone ringtones
75
- m4r_filename = f"{DOWNLOAD_DIR}/{song_name}.m4r"
76
- if os.path.exists(m4a_filename):
77
- os.rename(m4a_filename, m4r_filename)
78
- print(f"Files saved: {mp3_filename}, {m4r_filename}")
79
- return mp3_filename, m4r_filename
80
  else:
81
- print("Error: M4A file not created.")
82
- return None, None
 
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  except Exception as e:
85
- print(f"Error: {e}")
86
- return None, None
87
-
88
-
89
- # === GRADIO UI ===
90
- with gr.Blocks(css="""
91
- body { font-family: Arial, sans-serif; text-align: center; }
92
- .light-btn { background-color: #ADD8E6; color: #333; border: 2px solid #ccc; padding: 10px 20px; font-size: 16px; cursor: pointer; }
93
- .light-btn:hover { background-color: #87CEFA; }
94
- """) as interface:
95
-
96
- gr.HTML("""
97
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
98
- <h1><i class="fas fa-music"></i>&nbsp;PYTR</h1>
99
- <p>Python YouTube Ringtones. Enter a YouTube URL or upload audio to create ringtones.</p>
100
- <p>
101
- <a href="https://ringtones.JesseJesse.xyz" target="_blank">Ringtones</a>&nbsp;&nbsp;&nbsp;
102
- <a href="https://pub-c1de1cb456e74d6bbbee111ba9e6c757.r2.dev/iphone.png" target="_blank">iPhone xfers</a>&nbsp;&nbsp;&nbsp;
103
- <a href="https://youtube.com" target="_blank">YouTube</a>
104
- </p>
105
- """)
106
-
107
- with gr.Row():
108
- with gr.Column(scale=1, min_width=250):
109
- gr.HTML('<label><i class="fas fa-link"></i>&nbsp;YouTube URL</label>')
110
- youtube_url = gr.Textbox(placeholder="Enter the URL here...", show_label=False)
111
-
112
- with gr.Column(scale=1, min_width=250):
113
- gr.HTML('<label><i class="fas fa-upload"></i>&nbsp;Upload Audio</label>')
114
- audio_upload = gr.File(label="Upload Audio", type="filepath", show_label=False)
115
-
116
- with gr.Row():
117
- gr.HTML("<h3>Trim Audio (Optional)</h3>")
118
-
119
- with gr.Row():
120
- start_time = gr.Slider(0, 20, value=0, label="Start Time (seconds)")
121
- end_time = gr.Slider(1, 20, value=20, label="End Time (seconds)")
122
-
123
- with gr.Row():
124
- process_button = gr.Button("Create Ringtones", elem_classes="light-btn")
125
-
126
- with gr.Row():
127
- with gr.Column(scale=1, min_width=250):
128
- gr.HTML('<label>&nbsp;Android Ringtone</label>')
129
- mp3_download = gr.File(label="Android")
130
- android_instructions = gr.Textbox(label="Install", placeholder="Move the .mp3 file to the ringtones folder", lines=2)
131
-
132
- with gr.Column(scale=1, min_width=250):
133
- gr.HTML('<label>&nbsp;iPhone Ringtone</label>')
134
- iphone_ringtone = gr.File(label="Apple")
135
- iphone_instructions = gr.Textbox(label="Install", placeholder="Open GarageBand on your iPhone. Import the .m4r file and set it as a ringtone.", lines=4)
136
-
137
- process_button.click(process_youtube_or_audio, inputs=[youtube_url, audio_upload, start_time, end_time], outputs=[mp3_download, iphone_ringtone])
138
-
139
- # Launch with queue for stability
140
- interface.queue().launch(share=True, server_port=7860)
141
 
142
 
143
 
 
 
1
  import gradio as gr
 
 
 
2
  import subprocess
3
+ import os
4
+ import logging
5
+ import pyperclip
6
 
7
+ logging.basicConfig(level=logging.INFO)
 
 
8
 
9
+ DOWNLOAD_FOLDER = os.path.expanduser("./Downloads")
 
 
10
 
11
+ def create_readme():
12
+ """Creates a readme.txt file with the specified text"""
13
+ readme_path = os.path.join(DOWNLOAD_FOLDER, 'readme.txt')
14
+
15
  try:
16
+ with open(readme_path, 'w') as readme_file:
17
+ readme_file.write("Android copy the .mp3 to the ringtones folder and reboot device. iPhone drag and drop the .m4r file in iTunes and sync device.")
18
+ return f"readme.txt created at: {readme_path}"
19
+ except Exception as e:
20
+ return f"Failed to create readme.txt: {str(e)}"
21
+
22
+ def download_video(url):
23
+ try:
24
+ output_path = os.path.join(DOWNLOAD_FOLDER, '%(title)s.mp4')
25
+ command = ['yt-dlp', '-f', 'mp4', '-o', output_path, url]
26
+ process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
27
+ stdout, stderr = process.communicate()
28
+
29
+ if process.returncode == 0:
30
+ video_filename = get_video_filename(output_path)
31
+ if video_filename:
32
+ return f"Video downloaded: {video_filename}\n" + create_readme()
33
+ else:
34
+ return "Error: Video file not found."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  else:
36
+ return f"Error downloading video: {stderr.decode()}"
37
+ except Exception as e:
38
+ return f"Failed to download video: {str(e)}"
39
 
40
+ def android_download():
41
+ try:
42
+ video_filename = get_video_filename(f'{DOWNLOAD_FOLDER}/%(title)s.mp4')
43
+ if video_filename:
44
+ command = ['ffmpeg', '-i', video_filename, '-t', '20', '-q:a', '0', '-map', 'a', f'{DOWNLOAD_FOLDER}/AndroidRingtone.mp3']
45
+ process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
46
+ stdout, stderr = process.communicate()
47
+
48
+ if process.returncode == 0:
49
+ return "Android ringtone created successfully"
50
+ else:
51
+ return f"Error creating Android ringtone: {stderr.decode()}"
52
+ else:
53
+ return "Error: Video file not found for Android ringtone."
54
+ except Exception as e:
55
+ return f"Failed to create Android ringtone: {str(e)}"
56
+
57
+ def iphone_download():
58
+ try:
59
+ command = ['ffmpeg', '-i', f'{DOWNLOAD_FOLDER}/AndroidRingtone.mp3', '-t', '20', '-acodec', 'aac', '-b:a', '128k', '-f', 'mp4', f'{DOWNLOAD_FOLDER}/iPhoneRingtone.m4r']
60
+ process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
61
+ stdout, stderr = process.communicate()
62
+
63
+ if process.returncode == 0:
64
+ return "iPhone ringtone created successfully"
65
+ else:
66
+ return f"Error creating iPhone ringtone: {stderr.decode()}"
67
  except Exception as e:
68
+ return f"Failed to create iPhone ringtone: {str(e)}"
69
+
70
+ def get_video_filename(output_path):
71
+ """Finds and returns the actual downloaded filename"""
72
+ title = os.path.basename(output_path).replace('%(title)s', '').strip()
73
+ video_filename = os.path.join(DOWNLOAD_FOLDER, f"{title}.mp4")
74
+
75
+ if os.path.exists(video_filename):
76
+ return video_filename
77
+ else:
78
+ for file in os.listdir(DOWNLOAD_FOLDER):
79
+ if file.endswith(".mp4"):
80
+ return os.path.join(DOWNLOAD_FOLDER, file)
81
+
82
+ return None
83
+
84
+ def paste_from_clipboard():
85
+ """Get URL from clipboard"""
86
+ return pyperclip.paste()
87
+
88
+ def clear_input():
89
+ """Clear the input and output"""
90
+ return "", ""
91
+
92
+ # Gradio interface functions
93
+ def download_video_ui(url):
94
+ return download_video(url)
95
+
96
+ def android_ringtone_ui():
97
+ return android_download()
98
+
99
+ def iphone_ringtone_ui():
100
+ return iphone_download()
101
+
102
+ # Build the Gradio interface
103
+ iface = gr.Interface(
104
+ fn=download_video_ui,
105
+ inputs=gr.Textbox(label="Enter YouTube URL", placeholder="Paste URL here"),
106
+ outputs=gr.Textbox(label="Status"),
107
+ live=True
108
+ )
109
+
110
+ # Add additional buttons for Android and iPhone ringtone creation
111
+ iface.add_component(gr.Button("Create Android Ringtone", variant="primary").click(android_ringtone_ui, outputs="status"))
112
+ iface.add_component(gr.Button("Create iPhone Ringtone", variant="primary").click(iphone_ringtone_ui, outputs="status"))
113
+ iface.add_component(gr.Button("Paste URL from Clipboard", variant="secondary").click(paste_from_clipboard, inputs="url", outputs="url"))
114
+ iface.add_component(gr.Button("Clear", variant="secondary").click(clear_input, outputs=["url", "status"]))
115
+
116
+ # Launch the Gradio interface on Hugging Face
117
+ iface.launch(share=True)
118
+
 
 
 
 
 
119
 
120
 
121