File size: 4,992 Bytes
69b885f
4cb4020
 
6f15580
ba8996d
6f15580
09d1e4c
 
ba8996d
5595d22
ba8996d
 
 
 
22d9057
5595d22
ba8996d
5595d22
ba8996d
 
 
5595d22
ba8996d
 
5595d22
ba8996d
 
 
5595d22
 
 
 
 
 
 
 
 
 
 
 
 
ba8996d
 
 
 
5595d22
 
 
 
ba8996d
5595d22
ba8996d
 
 
 
 
 
 
 
 
10f6ba8
ba8996d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0d3ebe0
ba8996d
 
 
 
 
10f6ba8
 
ba8996d
5595d22
ba8996d
 
 
 
 
 
 
 
 
 
 
 
5595d22
ba8996d
 
 
5595d22
ba8996d
 
 
 
 
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
import streamlit as st
import asyncio
import subprocess
import threading
import time
from datetime import datetime
from TikTokLive import TikTokLiveClient

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# โš™๏ธ ุงู„ุฅุนุฏุงุฏุงุช
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

BROADCASTERS = [
    {
        "tiktok": "@dharialshammarii0",
        "stream_key": "p0ep-37wz-q3yg-7twf-3acb",
    },
    # ุฃุถู ุงู„ู…ุฒูŠุฏ ุจู†ูุณ ุงู„ุชู†ุณูŠู‚
]

YT_RTMP_BASE = "rtmp://a.rtmp.youtube.com/live2/"
POLL_INTERVAL = 60  # ุซุงู†ูŠุฉ ุจูŠู† ูƒู„ ูุญุต

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ๐Ÿš€ ุฏูˆุงู„ ุงู„ุจุซ ุงู„ุฌุฏูŠุฏุฉ (ุจุฏูˆู† streamlink)
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

def stream_broadcaster(tiktok_username, stream_key):
    """
    ุชุณุชุฎุฏู… yt-dlp ู„ุงุณุชุฎุฑุงุฌ ุงู„ุจุซุŒ ูˆุชู…ุฑูŠุฑู‡ ุฅู„ู‰ ffmpeg ู„ู„ู†ุณุฎ ุงู„ู…ุจุงุดุฑ ุฅู„ู‰ ูŠูˆุชูŠูˆุจ.
    """
    # ุฑุงุจุท ู‚ู†ุงุฉ TikTok
    url = f"https://www.tiktok.com/{tiktok_username}/live"

    # ุฃู…ุฑ yt-dlp: ุงุณุชุฎุฑุงุฌ ุฃูุถู„ ุฌูˆุฏุฉ ูˆุฅุฎุฑุงุฌู‡ุง ุฅู„ู‰ stdout
    yt_dlp_cmd = f'yt-dlp -f best -o - "{url}"'

    # ุฃู…ุฑ ffmpeg: ุงุณุชู‚ุจุงู„ ุงู„ุฏูู‚ ู…ู† stdin ูˆู†ุณุฎู‡ ู…ุจุงุดุฑุฉ ู„ู€ RTMP
    ffmpeg_cmd = (
        f"ffmpeg -hide_banner -loglevel error "
        f"-re -i pipe:0 "
        f"-c:v copy -c:a copy "
        f"-f flv {YT_RTMP_BASE}{stream_key}"
    )

    # ุฏู…ุฌ ุงู„ุฃู…ุฑูŠู† ููŠ ุณุทุฑ ูˆุงุญุฏ
    full_cmd = f"{yt_dlp_cmd} | {ffmpeg_cmd}"

    print(f"๐Ÿ”ด ุจุฏุก ุจุซ {tiktok_username} ุนุจุฑ yt-dlp...")
    try:
        proc = subprocess.Popen(full_cmd, shell=True)
        proc.wait()
        print(f"โน๏ธ ุงู†ุชู‡ู‰ ุจุซ {tiktok_username}")
    except Exception as e:
        print(f"โŒ ุฎุทุฃ ุฃุซู†ุงุก ุจุซ {tiktok_username}: {e}")

def monitor_and_stream():
    """ุงู„ู…ุฑุงู‚ุจุฉ ุงู„ู…ุณุชู…ุฑุฉ ูˆุชุดุบูŠู„ ุงู„ุจุซ ุนู†ุฏ ุงู„ุญุงุฌุฉ"""
    active_threads = {}

    while True:
        for broadcaster in BROADCASTERS:
            tiktok = broadcaster["tiktok"]
            key = broadcaster["stream_key"]

            try:
                client = TikTokLiveClient(unique_id=tiktok)
                is_live = asyncio.run(client.is_live())
            except Exception as e:
                print(f"โš ๏ธ ุชุนุฐุฑ ูุญุต {tiktok}: {e}")
                continue

            if is_live and tiktok not in active_threads:
                t = threading.Thread(
                    target=stream_broadcaster,
                    args=(tiktok, key),
                    daemon=True,
                )
                t.start()
                active_threads[tiktok] = t
            elif not is_live and tiktok in active_threads:
                del active_threads[tiktok]

        time.sleep(POLL_INTERVAL)

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ๐ŸŽฌ ุจุฏุก ุงู„ู…ุฑุงู‚ุจุฉ ููŠ ุงู„ุฎู„ููŠุฉ
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

if "monitor_started" not in st.session_state:
    monitor_thread = threading.Thread(
        target=monitor_and_stream,
        name="TikTokMonitor",
        daemon=True,
    )
    monitor_thread.start()
    st.session_state.monitor_started = True

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ๐ŸŽจ ูˆุงุฌู‡ุฉ ุงู„ู…ุณุชุฎุฏู…
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

st.set_page_config(page_title="TikTok 2 YouTube", page_icon="๐Ÿ”ด")
st.title("๐Ÿ”ด ู†ุธุงู… ุงู„ุจุซ ุงู„ุชู„ู‚ุงุฆูŠ (ุงู„ุญู„ ุงู„ู†ู‡ุงุฆูŠ)")
st.markdown("### ุงู„ุญุณุงุจุงุช ุงู„ู…ุฑุงู‚ุจุฉ:")
for b in BROADCASTERS:
    st.write(f"- {b['tiktok']}")
st.success("ุงู„ู†ุธุงู… ูŠุนู…ู„ ููŠ ุงู„ุฎู„ููŠุฉ. ูŠู…ูƒู†ูƒ ุฅุบู„ุงู‚ ุงู„ุตูุญุฉ.")
st.caption(f"ุขุฎุฑ ุชุญุฏูŠุซ: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")