Update app.py
Browse files
app.py
CHANGED
@@ -5,10 +5,8 @@ from collections import defaultdict
|
|
5 |
import datetime
|
6 |
import re
|
7 |
import requests
|
8 |
-
import
|
9 |
-
|
10 |
-
# νμ΄μ§ ꡬμ±μ 'wide'λ‘ μ€μ νμ¬ μ¬λ°± μ΅μν
|
11 |
-
st.set_page_config(layout="wide")
|
12 |
|
13 |
# Streamlit μ λͺ© λ° μ€λͺ
|
14 |
st.title("VOD μ±ν
ν¬λ‘€λ¬")
|
@@ -17,6 +15,10 @@ st.write("VOD URLμ μ
λ ₯νκ³ μ±ν
λ°μ΄ν°λ₯Ό ν¬λ‘€λ§ν©λλ€.")
|
|
17 |
# URL μ
λ ₯ λ°κΈ°
|
18 |
vod_url = st.text_input("VOD URL μ
λ ₯")
|
19 |
|
|
|
|
|
|
|
|
|
20 |
# μ±ν
ν¬λ‘€λ§ ν¨μ
|
21 |
def crawl_chats(vod_url):
|
22 |
# URL μ€μ
|
@@ -41,7 +43,6 @@ def crawl_chats(vod_url):
|
|
41 |
chat_counts = defaultdict(int)
|
42 |
laugh_counts = defaultdict(int)
|
43 |
total_chats_collected = 0 # μ΄ μμ§λ μ±ν
κ°μ
|
44 |
-
start_time = time.time() # ν¬λ‘€λ§ μμ μκ° κΈ°λ‘
|
45 |
|
46 |
# μ±ν
λ°μ΄ν°λ₯Ό μμ°¨μ μΌλ‘ μμ²νμ¬ κ°μ Έμ€κΈ°
|
47 |
status_text = st.empty() # μν λ©μμ§ μΆλ ₯μ©
|
@@ -98,14 +99,7 @@ def crawl_chats(vod_url):
|
|
98 |
laugh_counts[minute_key] += 1
|
99 |
|
100 |
total_chats_collected += len(chats)
|
101 |
-
|
102 |
-
# ν¬λ‘€λ§ κ²½κ³Ό μκ° κ³μ°
|
103 |
-
elapsed_time = time.time() - start_time
|
104 |
-
elapsed_minutes = int(elapsed_time // 60)
|
105 |
-
elapsed_seconds = int(elapsed_time % 60)
|
106 |
-
|
107 |
-
# μν λ©μμ§ μ
λ°μ΄νΈ (μ΄ μ±ν
κ°μμ κ²½κ³Ό μκ° νμ)
|
108 |
-
status_text.text(f"νμ¬κΉμ§ μμ§λ μ±ν
λ©μμ§ κ°μ: {total_chats_collected} | κ²½κ³Ό μκ°: {elapsed_minutes}λΆ {elapsed_seconds}μ΄")
|
109 |
|
110 |
# λ€μ μμ²μ μν΄ playerMessageTime νλΌλ―Έν° μ
λ°μ΄νΈ
|
111 |
next_time = data["content"].get("nextPlayerMessageTime")
|
@@ -115,6 +109,46 @@ def crawl_chats(vod_url):
|
|
115 |
|
116 |
return "\n".join(chat_logs), chat_counts, laugh_counts
|
117 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
# λ²νΌμ λλ μ λ μ±ν
ν¬λ‘€λ§ μμ
|
119 |
if 'chat_logs' not in st.session_state:
|
120 |
st.session_state['chat_logs'] = None
|
@@ -162,7 +196,7 @@ if st.session_state['chat_logs']:
|
|
162 |
fig.add_trace(go.Scatter(
|
163 |
x=df['μκ°'],
|
164 |
y=df['μ 체 μ±ν
κ°μ'],
|
165 |
-
mode='lines',
|
166 |
name='μ 체 μ±ν
κ°μ',
|
167 |
line=dict(color='blue'),
|
168 |
hovertemplate='%{x} - μ 체 μ±ν
κ°μ: %{y}<extra></extra>'
|
@@ -172,7 +206,7 @@ if st.session_state['chat_logs']:
|
|
172 |
fig.add_trace(go.Scatter(
|
173 |
x=df['μκ°'],
|
174 |
y=df['γ
γ
γ
γ
μ±ν
κ°μ'],
|
175 |
-
mode='lines',
|
176 |
name='γ
γ
γ
γ
μ±ν
κ°μ',
|
177 |
line=dict(color='red'),
|
178 |
hovertemplate='%{x} - γ
γ
γ
γ
μ±ν
κ°μ: %{y}<extra></extra>'
|
@@ -181,16 +215,22 @@ if st.session_state['chat_logs']:
|
|
181 |
# κ·Έλν λ μ΄μμ μ€μ
|
182 |
fig.update_layout(
|
183 |
title="λΆλΉ μ±ν
λ° γ
γ
γ
γ
μ±ν
κ°μ",
|
184 |
-
height=600, # κ·Έλνμ λμ΄λ₯Ό ν€μ
|
185 |
xaxis_title="μκ°",
|
186 |
yaxis_title="μ±ν
κ°μ",
|
187 |
-
xaxis=dict(
|
188 |
-
showticklabels=False # xμΆ μκ° λ μ΄λΈ μ¨κΉ
|
189 |
-
),
|
190 |
hovermode="x unified", # λ§μ°μ€λ₯Ό μ¬λ Έμ λ ν΄λΉ xμΆμμ ν΄ν νμ
|
191 |
-
showlegend=True,
|
192 |
-
margin=dict(l=50, r=50, t=100, b=100)
|
193 |
)
|
194 |
|
195 |
-
# κ·Έλν μΆλ ₯
|
196 |
-
st.plotly_chart(fig, use_container_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
import datetime
|
6 |
import re
|
7 |
import requests
|
8 |
+
import yt_dlp
|
9 |
+
import os
|
|
|
|
|
10 |
|
11 |
# Streamlit μ λͺ© λ° μ€λͺ
|
12 |
st.title("VOD μ±ν
ν¬λ‘€λ¬")
|
|
|
15 |
# URL μ
λ ₯ λ°κΈ°
|
16 |
vod_url = st.text_input("VOD URL μ
λ ₯")
|
17 |
|
18 |
+
# μ νλ μκ°λλ₯Ό μ μ₯ν 곡κ°
|
19 |
+
if 'selected_times' not in st.session_state:
|
20 |
+
st.session_state['selected_times'] = []
|
21 |
+
|
22 |
# μ±ν
ν¬λ‘€λ§ ν¨μ
|
23 |
def crawl_chats(vod_url):
|
24 |
# URL μ€μ
|
|
|
43 |
chat_counts = defaultdict(int)
|
44 |
laugh_counts = defaultdict(int)
|
45 |
total_chats_collected = 0 # μ΄ μμ§λ μ±ν
κ°μ
|
|
|
46 |
|
47 |
# μ±ν
λ°μ΄ν°λ₯Ό μμ°¨μ μΌλ‘ μμ²νμ¬ κ°μ Έμ€κΈ°
|
48 |
status_text = st.empty() # μν λ©μμ§ μΆλ ₯μ©
|
|
|
99 |
laugh_counts[minute_key] += 1
|
100 |
|
101 |
total_chats_collected += len(chats)
|
102 |
+
status_text.text(f"νμ¬κΉμ§ μμ§λ μ±ν
λ©μμ§ κ°μ: {total_chats_collected}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
|
104 |
# λ€μ μμ²μ μν΄ playerMessageTime νλΌλ―Έν° μ
λ°μ΄νΈ
|
105 |
next_time = data["content"].get("nextPlayerMessageTime")
|
|
|
109 |
|
110 |
return "\n".join(chat_logs), chat_counts, laugh_counts
|
111 |
|
112 |
+
# ν΄λ¦ν μκ°λλ₯Ό μ ν λ° μΆλ ₯
|
113 |
+
def handle_time_selection(click_data):
|
114 |
+
if click_data:
|
115 |
+
selected_time = click_data['points'][0]['x']
|
116 |
+
if selected_time not in st.session_state['selected_times']:
|
117 |
+
st.session_state['selected_times'].append(selected_time)
|
118 |
+
|
119 |
+
# μ νλ μκ°λλ₯Ό νμ λ° μμ κΈ°λ₯
|
120 |
+
def display_selected_times():
|
121 |
+
if st.session_state['selected_times']:
|
122 |
+
st.write("### μ νλ μκ°λ")
|
123 |
+
for time in st.session_state['selected_times']:
|
124 |
+
col1, col2 = st.columns([9, 1])
|
125 |
+
col1.write(f"{time}")
|
126 |
+
if col2.button("X", key=f"remove_{time}"):
|
127 |
+
st.session_state['selected_times'].remove(time)
|
128 |
+
|
129 |
+
# yt-dlpλ₯Ό μ¬μ©νμ¬ μ νλ μκ°λμ μμμ λ€μ΄λ‘λ
|
130 |
+
def download_clips():
|
131 |
+
if st.session_state['selected_times']:
|
132 |
+
st.write("### μμ λ€μ΄λ‘λ")
|
133 |
+
for idx, start_time in enumerate(st.session_state['selected_times']):
|
134 |
+
start_time_obj = datetime.datetime.strptime(start_time, '%H:%M:%S')
|
135 |
+
end_time_obj = start_time_obj + datetime.timedelta(minutes=1)
|
136 |
+
|
137 |
+
# μμ μκ°κ³Ό λ μκ°μ HH:MM:SS νμμΌλ‘ λ³ν
|
138 |
+
start_time_str = start_time_obj.strftime('%H:%M:%S')
|
139 |
+
end_time_str = end_time_obj.strftime('%H:%M:%S')
|
140 |
+
|
141 |
+
# yt-dlp λ€μ΄λ‘λ λͺ
λ Ήμ΄ μ€ν
|
142 |
+
output_filename = f"clip_{idx + 1}.mp4"
|
143 |
+
ydl_opts = {
|
144 |
+
'outtmpl': output_filename,
|
145 |
+
'download_sections': [f"*{start_time_str}-{end_time_str}"]
|
146 |
+
}
|
147 |
+
|
148 |
+
st.write(f"λ€μ΄λ‘λ μ€: {start_time_str} ~ {end_time_str} | νμΌλͺ
: {output_filename}")
|
149 |
+
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
150 |
+
ydl.download([vod_url])
|
151 |
+
|
152 |
# λ²νΌμ λλ μ λ μ±ν
ν¬λ‘€λ§ μμ
|
153 |
if 'chat_logs' not in st.session_state:
|
154 |
st.session_state['chat_logs'] = None
|
|
|
196 |
fig.add_trace(go.Scatter(
|
197 |
x=df['μκ°'],
|
198 |
y=df['μ 체 μ±ν
κ°μ'],
|
199 |
+
mode='lines',
|
200 |
name='μ 체 μ±ν
κ°μ',
|
201 |
line=dict(color='blue'),
|
202 |
hovertemplate='%{x} - μ 체 μ±ν
κ°μ: %{y}<extra></extra>'
|
|
|
206 |
fig.add_trace(go.Scatter(
|
207 |
x=df['μκ°'],
|
208 |
y=df['γ
γ
γ
γ
μ±ν
κ°μ'],
|
209 |
+
mode='lines',
|
210 |
name='γ
γ
γ
γ
μ±ν
κ°μ',
|
211 |
line=dict(color='red'),
|
212 |
hovertemplate='%{x} - γ
γ
γ
γ
μ±ν
κ°μ: %{y}<extra></extra>'
|
|
|
215 |
# κ·Έλν λ μ΄μμ μ€μ
|
216 |
fig.update_layout(
|
217 |
title="λΆλΉ μ±ν
λ° γ
γ
γ
γ
μ±ν
κ°μ",
|
|
|
218 |
xaxis_title="μκ°",
|
219 |
yaxis_title="μ±ν
κ°μ",
|
220 |
+
xaxis=dict(showticklabels=False), # xμΆ μκ° λ μ΄λΈ μ¨κΉ
|
|
|
|
|
221 |
hovermode="x unified", # λ§μ°μ€λ₯Ό μ¬λ Έμ λ ν΄λΉ xμΆμμ ν΄ν νμ
|
222 |
+
showlegend=True,
|
223 |
+
margin=dict(l=50, r=50, t=100, b=100)
|
224 |
)
|
225 |
|
226 |
+
# κ·Έλν μΆλ ₯ λ° ν΄λ¦ μ΄λ²€νΈ μ²λ¦¬
|
227 |
+
st.plotly_chart(fig, use_container_width=True)
|
228 |
+
click_data = st.plotly_chart(fig).get_current_click()
|
229 |
+
handle_time_selection(click_data)
|
230 |
+
|
231 |
+
# μ νλ μκ°λ νμ
|
232 |
+
display_selected_times()
|
233 |
+
|
234 |
+
# λ€μ΄λ‘λ λ²νΌ νμ
|
235 |
+
if st.button("μ νλ μκ°λμ μμ λ€μ΄λ‘λ"):
|
236 |
+
download_clips()
|