File size: 4,980 Bytes
2c19cb5
105e5dd
 
 
 
dd81a22
105e5dd
f12b5ee
105e5dd
 
 
 
cab48b5
105e5dd
 
419ec35
105e5dd
 
 
 
419ec35
105e5dd
 
 
 
 
 
 
 
 
 
 
cab48b5
105e5dd
 
 
 
 
 
 
419ec35
c79f358
cab48b5
c25ac20
 
 
 
419ec35
c25ac20
 
c79f358
419ec35
c25ac20
419ec35
 
105e5dd
419ec35
105e5dd
419ec35
dd81a22
cab48b5
 
 
105e5dd
419ec35
dd81a22
cab48b5
dd81a22
716ee4b
105e5dd
 
 
 
 
3eaaa26
a3cf940
 
c79f358
0f01192
c79f358
 
 
 
 
 
cab48b5
a3cf940
0f01192
cab48b5
 
 
 
 
3eaaa26
30a9d88
f12b5ee
cab48b5
 
105e5dd
 
 
1d91f2c
723b668
885477c
6ed23fa
1d91f2c
885477c
105e5dd
419ec35
 
 
 
c25ac20
 
419ec35
105e5dd
f12b5ee
105e5dd
 
 
c70cbee
 
cab48b5
105e5dd
 
c70cbee
 
cab48b5
105e5dd
419ec35
105e5dd
2c19cb5
cab48b5
c25ac20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import os
import gradio as gr
import yt_dlp
from pydub import AudioSegment
import re
import subprocess


if not os.path.exists("downloads"):
    os.makedirs("downloads")

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, recorded_audio, start_time, end_time):
    try:
        filename = None
        song_name = None

        # Download YouTube audio
        if url:
            ydl_opts = {
                'format': 'bestaudio/best',
                'outtmpl': 'downloads/%(id)s.%(ext)s',
                'cookiefile': 'cookies.txt'
            }
            with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                info = ydl.extract_info(url, download=True)
                filename = os.path.join('downloads', f"{info['id']}.webm")
                song_name = sanitize_filename(info['title'])

        # Handle recorded audio
        elif recorded_audio:
            filename = recorded_audio
            song_name = "recorded_audio"
        
        if not filename or not os.path.exists(filename):
            return None, None

        # Load audio file
        audio = AudioSegment.from_file(filename)

        # Convert seconds to milliseconds for pydub
        start_time_ms = start_time * 1000
        end_time_ms = end_time * 1000

        # Ensure valid trimming times
        start_time_ms = max(0, min(start_time_ms, len(audio)))
        end_time_ms = max(start_time_ms, min(end_time_ms, len(audio)))

        # Trim the audio
        trimmed_audio = audio[start_time_ms:end_time_ms]

        # Convert to MP3
        mp3_filename = f"downloads/{song_name}.mp3"
        trimmed_audio.export(mp3_filename, format="mp3")

        # Convert to M4R (iPhone format)
        m4a_filename = f"downloads/{song_name}.m4a"
        subprocess.run([
            'ffmpeg', '-i', mp3_filename, '-vn', '-acodec', 'aac', '-b:a', '192k', m4a_filename
        ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

        # Rename to M4R
        m4r_filename = f"downloads/{song_name}.m4r"
        os.rename(m4a_filename, m4r_filename)

        return os.path.abspath(mp3_filename), os.path.abspath(m4r_filename)

    except Exception as e:
        print(f"Error: {e}")
        return None, None


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 record 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 Xfer</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-microphone"></i>&nbsp;Record Audio</label>')
            audio_record = gr.Audio(sources=["microphone"], 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="Swipe left and open GarageBand. Long-press the ringtone file, select share, then choose 'Ringtone' to export.", lines=2)

    process_button.click(process_youtube_or_audio, inputs=[youtube_url, audio_record, start_time, end_time], outputs=[mp3_download, iphone_ringtone])

interface.launch(share=True)