izuemon commited on
Commit
794f7a6
·
verified ·
1 Parent(s): 677e8ae

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -199
app.py CHANGED
@@ -1,225 +1,107 @@
 
1
  import os
2
- import re
3
- import time
4
- import json
5
  import requests
6
  import subprocess
7
- from datetime import datetime, timezone
8
- from bs4 import BeautifulSoup
9
-
10
- # ===== Channel.io 設定 =====
11
- GET_URL = "https://desk-api.channel.io/desk/channels/200605/groups/519217/messages"
12
- POST_URL = GET_URL
13
-
14
- PARAMS = {
15
- "sortOrder": "desc",
16
- "limit": 36,
17
- "logFolded": "false",
18
- }
19
-
20
- X_ACCOUNT = os.getenv("channeliotokenbot2")
21
- if not X_ACCOUNT:
22
- raise RuntimeError("環境変数 channeliotokenbot2 が設定されていません")
23
-
24
- HEADERS_GET = {
25
- "accept": "application/json",
26
- "accept-language": "ja",
27
- "x-account": X_ACCOUNT,
28
- }
29
-
30
- HEADERS_POST = {
31
- "accept": "application/json",
32
- "accept-language": "ja",
33
- "content-type": "application/json",
34
- "x-account": X_ACCOUNT,
35
- }
36
-
37
- # ===== ssyoutube =====
38
- SSYOUTUBE_URL = "https://ssyoutube.online/yt-video-detail/"
39
-
40
- # ===== tflink =====
41
- TFLINK_UPLOAD_URL = "https://tflink.example/upload" # ここを実際のURLに置き換え
42
- TFLINK_API_KEY = os.getenv("TFLINK_API_KEY")
43
- if not TFLINK_API_KEY:
44
- raise RuntimeError("環境変数 TFLINK_API_KEY が設定されていません")
45
-
46
- # ===== Utils =====
47
- def parse_updated_at(value):
48
- if isinstance(value, (int, float)):
49
- return datetime.fromtimestamp(value / 1000, tz=timezone.utc)
50
- elif isinstance(value, str):
51
- return datetime.fromisoformat(value.replace("Z", "+00:00"))
52
- return None
53
-
54
- def extract_youtube_id(text):
55
- patterns = [
56
- r"v=([A-Za-z0-9_-]{11})",
57
- r"youtu\.be/([A-Za-z0-9_-]{11})",
58
- ]
59
- for p in patterns:
60
- m = re.search(p, text)
61
- if m:
62
- return m.group(1)
63
- return None
64
-
65
- # ===== ssyoutube HTML 解析 =====
66
- def fetch_download_links(youtube_url):
67
- res = requests.post(
68
- SSYOUTUBE_URL,
69
- data={"videoURL": youtube_url},
70
- timeout=30,
71
- headers={
72
- "User-Agent": "Mozilla/5.0",
73
- "Referer": "https://ssyoutube.online/",
74
- }
75
- )
76
- res.raise_for_status()
77
-
78
- soup = BeautifulSoup(res.text, "lxml")
79
- buttons = soup.select("button[data-url]")
80
-
81
- results = []
82
- for btn in buttons:
83
- url = btn.get("data-url")
84
- quality = btn.get("data-quality")
85
- has_audio = btn.get("data-has-audio")
86
-
87
- if not url:
88
- continue
89
-
90
- results.append({
91
- "url": url,
92
- "quality": quality or "audio",
93
- "has_audio": has_audio,
94
- })
95
-
96
- return results
97
-
98
- # ===== ファイル操作 =====
99
- def download_file(url, filename):
100
- res = requests.get(url, stream=True)
101
- res.raise_for_status()
102
- with open(filename, "wb") as f:
103
- for chunk in res.iter_content(chunk_size=8192):
104
- f.write(chunk)
105
-
106
- # ===== ffmpeg 結合 =====
107
- def merge_video_audio(video_path, audio_path, output_path):
108
- cmd = [
109
- "ffmpeg", "-y",
110
- "-i", video_path,
111
- "-i", audio_path,
112
- "-c:v", "copy",
113
- "-c:a", "aac",
114
- output_path
115
- ]
116
- subprocess.run(cmd, check=True)
117
-
118
- # ===== tflink アップロード =====
119
- def upload_to_tflink(filepath):
120
- with open(filepath, "rb") as f:
121
- res = requests.post(
122
- TFLINK_UPLOAD_URL,
123
- headers={"Authorization": f"Bearer {TFLINK_API_KEY}"},
124
- files={"file": f},
125
  )
126
- res.raise_for_status()
127
- data = res.json()
128
- return data.get("url")
129
-
130
- # ===== Channel.io 送信 =====
131
- def send_to_channel(text):
132
- payload = {
133
- "requestId": f"desk-web-{int(time.time() * 1000)}",
134
- "blocks": [
135
- {"type": "text", "value": text}
136
- ],
137
- "buttons": None,
138
- "form": None,
139
- "webPage": None,
140
- "files": None,
141
- "customPayload": None
142
- }
143
 
144
- res = requests.post(
145
- POST_URL,
146
- headers=HEADERS_POST,
147
- data=json.dumps(payload),
148
- timeout=30
149
- )
150
- res.raise_for_status()
151
 
152
- # ===== Main =====
153
- def main():
154
- while True:
155
- try:
156
- res = requests.get(GET_URL, headers=HEADERS_GET, params=PARAMS, timeout=30)
157
- res.raise_for_status()
158
 
159
- messages = res.json().get("messages", [])
160
- latest_msg = None
161
- latest_time = None
 
 
162
 
163
- for msg in messages:
164
- plain_text = msg.get("plainText")
165
- updated_at = msg.get("updatedAt")
 
166
 
167
- if not plain_text or updated_at is None:
168
- continue
 
 
 
169
 
170
- t = parse_updated_at(updated_at)
171
- if not t:
172
- continue
173
 
174
- if latest_time is None or t > latest_time:
175
- latest_time = t
176
- latest_msg = msg
 
177
 
178
- if not latest_msg:
179
- time.sleep(10)
180
- continue
181
 
182
- text = latest_msg["plainText"]
183
- youtube_id = extract_youtube_id(text)
184
- if not youtube_id:
185
- time.sleep(10)
186
- continue
187
 
188
- youtube_url = f"https://www.youtube.com/watch?v={youtube_id}"
189
- items = fetch_download_links(youtube_url)
190
 
191
- video_items = [i for i in items if i['has_audio'] == 'false']
192
- audio_items = [i for i in items if i['has_audio'] == 'true' and i['quality'] == 'audio']
 
 
 
193
 
194
- if not video_items or not audio_items:
195
- print("必要な動画/音声が取得できませんでした")
196
- time.sleep(10)
197
- continue
198
 
199
- # 高画質の動画を選択
200
- video_items.sort(key=lambda x: int(re.sub(r'[^0-9]', '', x['quality'])), reverse=True)
201
- video_url = video_items[0]['url']
202
- audio_url = audio_items[0]['url']
203
 
204
- video_file = "video.mp4"
205
- audio_file = "audio.m4a"
206
- output_file = "output.mp4"
 
207
 
208
- download_file(video_url, video_file)
209
- download_file(audio_url, audio_file)
210
 
211
- merge_video_audio(video_file, audio_file, output_file)
212
 
213
- tflink_url = upload_to_tflink(output_file)
 
 
 
 
214
 
215
- message_text = f"結合済み動画はこちら: {tflink_url}"
216
- send_to_channel(message_text)
217
- print("送信完了")
218
 
219
- except Exception as e:
220
- print("エラー:", e)
 
 
 
 
 
 
 
 
 
 
 
221
 
222
- time.sleep(15)
223
 
224
  if __name__ == "__main__":
225
- main()
 
 
 
1
+ from flask import Flask, request, jsonify, redirect, Response
2
  import os
 
 
 
3
  import requests
4
  import subprocess
5
+ import sys
6
+
7
+ app = Flask(__name__)
8
+
9
+ watcher_process = None
10
+
11
+ def start_watcher():
12
+ global watcher_process
13
+
14
+ if watcher_process is None or watcher_process.poll() is not None:
15
+ watcher_process = subprocess.Popen(
16
+ [sys.executable, "watcher.py"],
17
+ stdout=sys.stdout,
18
+ stderr=sys.stderr,
19
+ env=os.environ, # 環境変数を引き継ぐ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  )
21
+ print("watcher.py を起動しました")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
 
 
 
 
 
 
 
23
 
24
+ #----------
 
 
 
 
 
25
 
26
+ @app.route("/drive.com/files")
27
+ def index():
28
+ ip = request.remote_addr
29
+ print(f"アクセスIP: {ip}")
30
+ return redirect("https://drive.google.com/")
31
 
32
+ @app.route("/channel-io-managers")
33
+ def get_managers():
34
+ limit = request.args.get("limit")
35
+ since = request.args.get("since")
36
 
37
+ params = {}
38
+ if limit:
39
+ params["limit"] = limit
40
+ if since:
41
+ params["since"] = since
42
 
43
+ channel_id = request.args.get("channelid", "200605")
44
+ url = f"https://desk-api.channel.io/desk/channels/{channel_id}/managers"
 
45
 
46
+ headers = {
47
+ "accept": "application/json",
48
+ "x-account": os.getenv("channeliotokenmain"),
49
+ }
50
 
51
+ res = requests.get(url, headers=headers, params=params)
 
 
52
 
53
+ if res.status_code != 200:
54
+ return jsonify({"error": res.text}), res.status_code
 
 
 
55
 
56
+ return jsonify(res.json().get("managers", []))
 
57
 
58
+ @app.route("/cors-proxy", methods=["GET"])
59
+ def corsproxy():
60
+ url = request.args.get("url")
61
+ if not url:
62
+ return "url パラメータが必要です", 400
63
 
64
+ if not url.startswith(("http://", "https://")):
65
+ return "http または https のURLのみ使用できます", 400
 
 
66
 
67
+ resp = requests.get(url, headers=request.headers, timeout=60)
 
 
 
68
 
69
+ response = Response(resp.content, resp.status_code)
70
+ response.headers["Access-Control-Allow-Origin"] = "*"
71
+ response.headers["Access-Control-Allow-Headers"] = "*"
72
+ response.headers["Access-Control-Allow-Methods"] = "GET, POST, PATCH, OPTIONS"
73
 
74
+ if "Content-Type" in resp.headers:
75
+ response.headers["Content-Type"] = resp.headers["Content-Type"]
76
 
77
+ return response
78
 
79
+ @app.route("/cors-proxy", methods=["POST", "PATCH"])
80
+ def corsproxy_post():
81
+ url = request.args.get("url")
82
+ if not url:
83
+ return "url パラメータが必要です", 400
84
 
85
+ if not url.startswith(("http://", "https://")):
86
+ return "http または https のURLのみ使用できます", 400
 
87
 
88
+ resp = requests.request(
89
+ method=request.method,
90
+ url=url,
91
+ headers=request.headers,
92
+ data=request.data,
93
+ timeout=60,
94
+ )
95
+
96
+ headers = {
97
+ "Access-Control-Allow-Origin": "*",
98
+ "Access-Control-Allow-Headers": "*",
99
+ "Access-Control-Allow-Methods": "GET, POST, PATCH, OPTIONS",
100
+ }
101
 
102
+ return Response(resp.content, resp.status_code, headers=headers)
103
 
104
  if __name__ == "__main__":
105
+ if os.environ.get("WERKZEUG_RUN_MAIN") != "true":
106
+ start_watcher()
107
+ app.run(debug=True, host="0.0.0.0", port=7860)