izuemon commited on
Commit
63326c9
·
verified ·
1 Parent(s): 26fb022

Update watcher.py

Browse files
Files changed (1) hide show
  1. watcher.py +73 -36
watcher.py CHANGED
@@ -2,6 +2,9 @@ import os
2
  import re
3
  import time
4
  import json
 
 
 
5
  import requests
6
  from datetime import datetime, timezone
7
  from bs4 import BeautifulSoup
@@ -74,8 +77,8 @@ def fetch_download_links(youtube_url):
74
  results = []
75
  for btn in buttons:
76
  url = btn.get("data-url")
77
- quality = btn.get("data-quality") # 例: 1080p / 720p / None
78
- has_audio = btn.get("data-has-audio") # "true" / "false" / None
79
 
80
  if not url:
81
  continue
@@ -88,38 +91,62 @@ def fetch_download_links(youtube_url):
88
 
89
  return results
90
 
91
- def build_links(items):
92
- lines = []
93
- for item in items:
94
- url = item["url"]
95
- quality = item["quality"]
96
- has_audio = item["has_audio"]
97
-
98
- audio_label = ""
99
- if has_audio == "false":
100
- audio_label = "(映像のみ)"
101
- elif has_audio == "true":
102
- audio_label = "(音声付き)"
103
-
104
- line = f'<link type="url" value="{url}"> {quality} {audio_label}</link>'
105
- lines.append(line)
106
 
107
- return "\n".join(lines)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
  def send_to_channel(text):
110
  payload = {
111
  "requestId": f"desk-web-{int(time.time() * 1000)}",
112
  "blocks": [
113
- {
114
- "type": "text",
115
- "value": text
116
- }
117
  ],
118
- "buttons": None,
119
- "form": None,
120
- "webPage": None,
121
- "files": None,
122
- "customPayload": None
123
  }
124
 
125
  res = requests.post(
@@ -165,23 +192,33 @@ def main():
165
  time.sleep(10)
166
  continue
167
 
168
- text = latest_msg["plainText"]
169
- youtube_id = extract_youtube_id(text)
170
  if not youtube_id:
171
  time.sleep(10)
172
  continue
173
 
174
  youtube_url = f"https://www.youtube.com/watch?v={youtube_id}"
175
-
176
  items = fetch_download_links(youtube_url)
177
- if not items:
178
- print("ダウンロードリンクが取得できませんでした")
 
179
  time.sleep(10)
180
  continue
181
 
182
- message_text = build_links(items)
183
- send_to_channel(message_text)
184
- print("送信完了")
 
 
 
 
 
 
 
 
 
 
 
185
 
186
  except Exception as e:
187
  print("エラー:", e)
@@ -189,4 +226,4 @@ def main():
189
  time.sleep(15)
190
 
191
  if __name__ == "__main__":
192
- main()
 
2
  import re
3
  import time
4
  import json
5
+ import shutil
6
+ import tempfile
7
+ import subprocess
8
  import requests
9
  from datetime import datetime, timezone
10
  from bs4 import BeautifulSoup
 
77
  results = []
78
  for btn in buttons:
79
  url = btn.get("data-url")
80
+ quality = btn.get("data-quality")
81
+ has_audio = btn.get("data-has-audio")
82
 
83
  if not url:
84
  continue
 
91
 
92
  return results
93
 
94
+ # ===== 最高画質映像 + 音声を選択 =====
95
+ def select_best_video_and_audio(items):
96
+ video_items = []
97
+ audio_item = None
 
 
 
 
 
 
 
 
 
 
 
98
 
99
+ for item in items:
100
+ if item["quality"] == "audio":
101
+ audio_item = item
102
+ elif item["has_audio"] == "false":
103
+ m = re.match(r"(\d+)p", item["quality"])
104
+ if m:
105
+ video_items.append((int(m.group(1)), item))
106
+
107
+ if not video_items or not audio_item:
108
+ return None, None
109
+
110
+ video_items.sort(key=lambda x: x[0], reverse=True)
111
+ return video_items[0][1], audio_item
112
+
113
+ # ===== ファイルダウンロード =====
114
+ def download_file(url, path):
115
+ with requests.get(url, stream=True, timeout=60) as r:
116
+ r.raise_for_status()
117
+ with open(path, "wb") as f:
118
+ for chunk in r.iter_content(chunk_size=8192):
119
+ f.write(chunk)
120
+
121
+ # ===== ffmpeg 結合 =====
122
+ def merge_video_audio(video_path, audio_path, output_path):
123
+ cmd = [
124
+ "ffmpeg",
125
+ "-y",
126
+ "-i", video_path,
127
+ "-i", audio_path,
128
+ "-c:v", "copy",
129
+ "-c:a", "aac",
130
+ output_path
131
+ ]
132
+ subprocess.run(cmd, check=True)
133
+
134
+ # ===== file.io アップロード =====
135
+ def upload_to_fileio(file_path):
136
+ with open(file_path, "rb") as f:
137
+ r = requests.post("https://file.io", files={"file": f}, timeout=60)
138
+ r.raise_for_status()
139
+ data = r.json()
140
+ if not data.get("success"):
141
+ raise RuntimeError("file.io アップロード失敗")
142
+ return data["link"]
143
 
144
  def send_to_channel(text):
145
  payload = {
146
  "requestId": f"desk-web-{int(time.time() * 1000)}",
147
  "blocks": [
148
+ {"type": "text", "value": text}
 
 
 
149
  ],
 
 
 
 
 
150
  }
151
 
152
  res = requests.post(
 
192
  time.sleep(10)
193
  continue
194
 
195
+ youtube_id = extract_youtube_id(latest_msg["plainText"])
 
196
  if not youtube_id:
197
  time.sleep(10)
198
  continue
199
 
200
  youtube_url = f"https://www.youtube.com/watch?v={youtube_id}"
 
201
  items = fetch_download_links(youtube_url)
202
+
203
+ video_item, audio_item = select_best_video_and_audio(items)
204
+ if not video_item:
205
  time.sleep(10)
206
  continue
207
 
208
+ with tempfile.TemporaryDirectory() as tmp:
209
+ video_path = os.path.join(tmp, "video.mp4")
210
+ audio_path = os.path.join(tmp, "audio.m4a")
211
+ output_path = os.path.join(tmp, "merged.mp4")
212
+
213
+ download_file(video_item["url"], video_path)
214
+ download_file(audio_item["url"], audio_path)
215
+
216
+ merge_video_audio(video_path, audio_path, output_path)
217
+
218
+ link = upload_to_fileio(output_path)
219
+ send_to_channel(f"🎬 結合済み動画(最高画質)\n{link}")
220
+
221
+ print("送信完了:", link)
222
 
223
  except Exception as e:
224
  print("エラー:", e)
 
226
  time.sleep(15)
227
 
228
  if __name__ == "__main__":
229
+ main()