haraberget commited on
Commit
99ccaff
·
verified ·
1 Parent(s): 46bb5e2

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +107 -0
  2. requirements.txt +2 -0
  3. watch_history.json +22 -0
app.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ import re
3
+ import time
4
+ import json
5
+ import os
6
+ import gradio as gr
7
+ import pandas as pd
8
+
9
+ HISTORY_FILE = "watch_history.json"
10
+ HISTORY_HEADERS = ["Timestamp", "Video ID", "URL"]
11
+
12
+ def load_history() -> list:
13
+ """Load watch history from JSON."""
14
+ if os.path.exists(HISTORY_FILE):
15
+ with open(HISTORY_FILE, "r", encoding="utf-8") as f:
16
+ data = json.load(f)
17
+ return [[d.get("Timestamp"), d.get("Video ID"), d.get("URL")] for d in data]
18
+ return []
19
+
20
+ def save_history(history: list):
21
+ """Save readable JSON to disk."""
22
+ data = [{"Timestamp": r[0], "Video ID": r[1], "URL": r[2]} for r in history]
23
+ with open(HISTORY_FILE, "w", encoding="utf-8") as f:
24
+ json.dump(data, f, indent=2)
25
+
26
+ watch_history = load_history()
27
+
28
+ def extract_video_id(url: str) -> str | None:
29
+ pattern = r"(?:v=|youtu\.be/|embed/)([a-zA-Z0-9_-]{11})"
30
+ match = re.search(pattern, url)
31
+ return match.group(1) if match else None
32
+
33
+ def generate_embed_html(url: str) -> str:
34
+ """Generate embeddable YouTube iframe."""
35
+ video_id = extract_video_id(url)
36
+ if not video_id:
37
+ return "<p style='color:red;'>Invalid YouTube URL.</p>"
38
+ embed_url = f"https://www.youtube.com/embed/{video_id}?autoplay=1"
39
+ return f"""
40
+ <iframe width="720" height="405"
41
+ src="{embed_url}"
42
+ title="YouTube Live Stream"
43
+ frameborder="0"
44
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
45
+ allowfullscreen></iframe>
46
+ """
47
+
48
+ def update_history(url: str, current_table) -> list:
49
+ """Add or update timestamp entry in history."""
50
+ # Convert DataFrame to list-of-lists
51
+ if isinstance(current_table, pd.DataFrame):
52
+ current_table = current_table.values.tolist()
53
+
54
+ video_id = extract_video_id(url)
55
+ if not video_id:
56
+ return current_table
57
+
58
+ timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
59
+ updated = [r for r in current_table if r[1] != video_id]
60
+ updated.insert(0, [timestamp, video_id, url])
61
+ save_history(updated)
62
+ return updated
63
+
64
+ def watch_video(url: str, current_table) -> tuple[str, list]:
65
+ """Play video and update log."""
66
+ if not url:
67
+ return "<p style='color:red;'>Please enter a valid YouTube URL.</p>", current_table
68
+ return generate_embed_html(url), update_history(url, current_table)
69
+
70
+ def clear_history() -> list:
71
+ save_history([])
72
+ return []
73
+
74
+ def replay_from_log(evt: gr.SelectData, current_table):
75
+ """Replay video from history row click."""
76
+ if isinstance(current_table, pd.DataFrame):
77
+ current_table = current_table.values.tolist()
78
+ row_index = evt.index[0]
79
+ try:
80
+ url = current_table[row_index][2]
81
+ return generate_embed_html(url), update_history(url, current_table)
82
+ except (IndexError, TypeError, KeyError):
83
+ return "<p style='color:red;'>Invalid selection.</p>", current_table
84
+
85
+ with gr.Blocks(title="YouTube Live Watcher") as demo:
86
+ gr.Markdown("# 🎥 YouTube Live Stream Viewer")
87
+ gr.Markdown("Paste a YouTube live URL or click from history to replay — timestamps auto-update.")
88
+
89
+ with gr.Row():
90
+ url_input = gr.Textbox(label="YouTube Live URL", placeholder="https://www.youtube.com/watch?v=...")
91
+ watch_button = gr.Button("▶️ Watch Live")
92
+ clear_button = gr.Button("🧹 Clear History")
93
+
94
+ output_html = gr.HTML(label="Live Stream")
95
+ history_output = gr.DataFrame(
96
+ headers=HISTORY_HEADERS,
97
+ label="📜 Watch History (Click to replay)",
98
+ interactive=False,
99
+ value=watch_history
100
+ )
101
+
102
+ watch_button.click(fn=watch_video, inputs=[url_input, history_output], outputs=[output_html, history_output])
103
+ clear_button.click(fn=clear_history, outputs=history_output)
104
+ history_output.select(fn=replay_from_log, inputs=history_output, outputs=[output_html, history_output])
105
+
106
+ if __name__ == "__main__":
107
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio
2
+ pandas
watch_history.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "Timestamp": "2025-10-29 19:26:16",
4
+ "Video ID": "PNhwNhOXsIk",
5
+ "URL": "\t\nhttps://www.youtube.com/watch?v=PNhwNhOXsIk"
6
+ },
7
+ {
8
+ "Timestamp": "2025-10-29 19:26:16",
9
+ "Video ID": "zD9UQOX139U",
10
+ "URL": "https://www.youtube.com/watch?v=zD9UQOX139U"
11
+ },
12
+ {
13
+ "Timestamp": "2025-10-29 19:08:57",
14
+ "Video ID": "Q8A7zD9zFT0",
15
+ "URL": "\t\n\t\nhttps://www.youtube.com/watch?v=Q8A7zD9zFT0"
16
+ },
17
+ {
18
+ "Timestamp": "2025-10-29 19:08:57",
19
+ "Video ID": "xwGJfiqUETY",
20
+ "URL": "\t\nhttps://www.youtube.com/watch?v=xwGJfiqUETY"
21
+ }
22
+ ]