seawolf2357 commited on
Commit
0c29456
·
verified ·
1 Parent(s): 5f23031

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +183 -23
app.py CHANGED
@@ -5,33 +5,193 @@ import os
5
  API_KEY = os.getenv("YOUTUBE_API_KEY")
6
  youtube = build("youtube", "v3", developerKey=API_KEY)
7
 
8
- def search_videos(keyword, max_results=10):
9
- request = youtube.search().list(
10
- q=keyword,
11
- part="snippet",
12
- type="video",
13
- order="viewCount", # 조회수 순
14
- maxResults=max_results
15
- )
16
- response = request.execute()
17
-
18
- results = []
19
- for item in response["items"]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  video_id = item["id"]["videoId"]
21
- title = item["snippet"]["title"]
22
- channel = item["snippet"]["channelTitle"]
 
 
 
 
 
23
  url = f"https://youtube.com/watch?v={video_id}"
24
- results.append(f"**{title}**\n채널: {channel}\n{url}\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
- return "\n".join(results)
 
27
 
28
  with gr.Blocks() as demo:
29
- gr.Markdown("## YouTube 인기 영상 검색")
30
- keyword = gr.Textbox(label="검색어")
31
- count = gr.Slider(5, 50, value=10, step=5, label="결과 수")
32
- btn = gr.Button("검색")
33
- output = gr.Markdown()
 
 
 
 
 
 
 
 
 
34
 
35
- btn.click(search_videos, [keyword, count], output)
 
36
 
37
- demo.launch()
 
5
  API_KEY = os.getenv("YOUTUBE_API_KEY")
6
  youtube = build("youtube", "v3", developerKey=API_KEY)
7
 
8
+ # 국가 코드
9
+ COUNTRIES = {
10
+ "전세계": "",
11
+ "한국": "KR",
12
+ "미국": "US",
13
+ "일본": "JP",
14
+ "영국": "GB",
15
+ "독일": "DE",
16
+ "프랑스": "FR",
17
+ "인도": "IN",
18
+ "브라질": "BR",
19
+ }
20
+
21
+ # 언어 코드
22
+ LANGUAGES = {
23
+ "전체": "",
24
+ "한국어": "ko",
25
+ "영어": "en",
26
+ "일본어": "ja",
27
+ "중국어": "zh",
28
+ "스페인어": "es",
29
+ "독일어": "de",
30
+ "프랑스어": "fr",
31
+ }
32
+
33
+ # 정렬 기준
34
+ SORT_OPTIONS = {
35
+ "조회수 순": "viewCount",
36
+ "최신순": "date",
37
+ "관련성 순": "relevance",
38
+ "평점 순": "rating",
39
+ }
40
+
41
+ # 기간 필터
42
+ DATE_OPTIONS = {
43
+ "전체 기간": "",
44
+ "오늘": "today",
45
+ "이번 주": "thisWeek",
46
+ "이번 달": "thisMonth",
47
+ "올해": "thisYear",
48
+ }
49
+
50
+ def format_count(count):
51
+ if count >= 1000000000:
52
+ return f"{count/1000000000:.1f}B"
53
+ elif count >= 1000000:
54
+ return f"{count/1000000:.1f}M"
55
+ elif count >= 1000:
56
+ return f"{count/1000:.1f}K"
57
+ return str(count)
58
+
59
+ def search_videos(keyword, country, language, sort_by, date_filter, max_results):
60
+ if not keyword.strip():
61
+ return "검색어를 입력하세요."
62
+
63
+ # 검색 요청
64
+ search_params = {
65
+ "q": keyword,
66
+ "part": "snippet",
67
+ "type": "video",
68
+ "order": SORT_OPTIONS[sort_by],
69
+ "maxResults": int(max_results),
70
+ }
71
+
72
+ if COUNTRIES[country]:
73
+ search_params["regionCode"] = COUNTRIES[country]
74
+ if LANGUAGES[language]:
75
+ search_params["relevanceLanguage"] = LANGUAGES[language]
76
+
77
+ # 기간 필터
78
+ if date_filter != "전체 기간":
79
+ from datetime import datetime, timedelta
80
+ now = datetime.utcnow()
81
+ if date_filter == "오늘":
82
+ after = now - timedelta(days=1)
83
+ elif date_filter == "이번 주":
84
+ after = now - timedelta(weeks=1)
85
+ elif date_filter == "이번 달":
86
+ after = now - timedelta(days=30)
87
+ elif date_filter == "올해":
88
+ after = now - timedelta(days=365)
89
+ search_params["publishedAfter"] = after.strftime("%Y-%m-%dT%H:%M:%SZ")
90
+
91
+ response = youtube.search().list(**search_params).execute()
92
+
93
+ if not response.get("items"):
94
+ return "검색 결과가 없습니다."
95
+
96
+ # 비디오 ID 수집
97
+ video_ids = [item["id"]["videoId"] for item in response["items"]]
98
+ channel_ids = [item["snippet"]["channelId"] for item in response["items"]]
99
+
100
+ # 비디오 상세 정보 (조회수, 좋아요 등)
101
+ video_details = youtube.videos().list(
102
+ id=",".join(video_ids),
103
+ part="statistics,contentDetails"
104
+ ).execute()
105
+
106
+ # 채널 상세 정보 (구독자 수)
107
+ channel_details = youtube.channels().list(
108
+ id=",".join(list(set(channel_ids))),
109
+ part="statistics"
110
+ ).execute()
111
+
112
+ # 채널 구독자 매핑
113
+ channel_subs = {}
114
+ for ch in channel_details.get("items", []):
115
+ sub_count = ch["statistics"].get("subscriberCount", "비공개")
116
+ if sub_count != "비공개":
117
+ sub_count = format_count(int(sub_count))
118
+ channel_subs[ch["id"]] = sub_count
119
+
120
+ # 비디오 통계 매핑
121
+ video_stats = {}
122
+ for v in video_details.get("items", []):
123
+ stats = v["statistics"]
124
+ video_stats[v["id"]] = {
125
+ "views": format_count(int(stats.get("viewCount", 0))),
126
+ "likes": format_count(int(stats.get("likeCount", 0))),
127
+ "comments": format_count(int(stats.get("commentCount", 0))),
128
+ "duration": v["contentDetails"]["duration"],
129
+ }
130
+
131
+ # HTML 결과 생성
132
+ html = '<div style="display:flex; flex-direction:column; gap:15px;">'
133
+
134
+ for i, item in enumerate(response["items"], 1):
135
  video_id = item["id"]["videoId"]
136
+ snippet = item["snippet"]
137
+ channel_id = snippet["channelId"]
138
+
139
+ title = snippet["title"]
140
+ channel = snippet["channelTitle"]
141
+ thumbnail = snippet["thumbnails"]["medium"]["url"]
142
+ published = snippet["publishedAt"][:10]
143
  url = f"https://youtube.com/watch?v={video_id}"
144
+
145
+ stats = video_stats.get(video_id, {})
146
+ views = stats.get("views", "N/A")
147
+ likes = stats.get("likes", "N/A")
148
+ comments = stats.get("comments", "N/A")
149
+ subs = channel_subs.get(channel_id, "N/A")
150
+
151
+ html += f'''
152
+ <div style="display:flex; gap:15px; padding:10px; border:1px solid #ddd; border-radius:8px; background:#f9f9f9;">
153
+ <a href="{url}" target="_blank">
154
+ <img src="{thumbnail}" style="width:200px; border-radius:5px;">
155
+ </a>
156
+ <div style="flex:1;">
157
+ <a href="{url}" target="_blank" style="font-weight:bold; font-size:16px; color:#1a0dab; text-decoration:none;">
158
+ {i}. {title}
159
+ </a>
160
+ <p style="margin:5px 0; color:#555;">
161
+ <b>채널:</b> {channel} &nbsp;|&nbsp; <b>구독자:</b> {subs}
162
+ </p>
163
+ <p style="margin:5px 0; color:#333;">
164
+ <b>조회수:</b> {views} &nbsp;|&nbsp;
165
+ <b>좋아요:</b> {likes} &nbsp;|&nbsp;
166
+ <b>댓글:</b> {comments}
167
+ </p>
168
+ <p style="margin:5px 0; color:#888; font-size:12px;">
169
+ <b>게시일:</b> {published}
170
+ </p>
171
+ </div>
172
+ </div>
173
+ '''
174
 
175
+ html += '</div>'
176
+ return html
177
 
178
  with gr.Blocks() as demo:
179
+ gr.Markdown("## YouTube 인기 영상 검색")
180
+
181
+ with gr.Row():
182
+ keyword = gr.Textbox(label="검색", placeholder="검색어 입력...")
183
+ btn = gr.Button("검색", variant="primary")
184
+
185
+ with gr.Row():
186
+ country = gr.Dropdown(list(COUNTRIES.keys()), value="전세계", label="국가/지역")
187
+ language = gr.Dropdown(list(LANGUAGES.keys()), value="전체", label="언어")
188
+ sort_by = gr.Dropdown(list(SORT_OPTIONS.keys()), value="조회수 순", label="정렬")
189
+ date_filter = gr.Dropdown(list(DATE_OPTIONS.keys()), value="전체 기간", label="기간")
190
+ max_results = gr.Slider(5, 50, value=10, step=5, label="결과 수")
191
+
192
+ output = gr.HTML()
193
 
194
+ btn.click(search_videos, [keyword, country, language, sort_by, date_filter, max_results], output)
195
+ keyword.submit(search_videos, [keyword, country, language, sort_by, date_filter, max_results], output)
196
 
197
+ demo.launch()