no-name-here commited on
Commit
fc7d210
Β·
verified Β·
1 Parent(s): 57c76dc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +137 -207
app.py CHANGED
@@ -1,235 +1,165 @@
1
- """
2
- Telegram File Method Converter Bot
3
- ===================================
4
- Send any file β†’ bot stores the file_id
5
- Use /as <method> to resend it using a different Telegram method.
6
 
7
- Supported methods:
8
- photo, video, audio, document, voice, video_note,
9
- animation, sticker
10
-
11
- Usage:
12
- 1. Send any file/media to the bot.
13
- 2. Then send: /as video
14
- The bot will forward the same file using send_video()
15
- """
16
-
17
- import telebot
18
- import os
19
-
20
- # BOT_TOKEN = os.environ.get("BOT_TOKEN", "YOUR_BOT_TOKEN_HERE")
21
-
22
- # bot = telebot.TeleBot(BOT_TOKEN)
23
 
24
- # ── per-user state ────────────────────────────────────────────────────────────
25
  # { user_id: {"file_id": str, "original_method": str, "file_name": str} }
26
- user_files: dict[int, dict] = {}
27
 
28
- # ── method β†’ (send_func_name, extra_kwargs) ──────────────────────────────────
29
  METHOD_MAP = {
30
- "photo": ("send_photo", {}),
31
- "video": ("send_video", {}),
32
- "audio": ("send_audio", {}),
33
- "document": ("send_document", {}),
34
- "voice": ("send_voice", {}),
35
- "video_note": ("send_video_note", {}),
36
- "animation": ("send_animation", {}),
37
- "sticker": ("send_sticker", {}),
38
  }
39
 
40
- # Compatibility warnings (source β†’ target)
41
  WARNINGS = {
42
- ("photo", "video"): "⚠️ Photoβ†’Video: Telegram may reject this; a photo is not a video stream.",
43
- ("video", "photo"): "⚠️ Videoβ†’Photo: Telegram may reject this; a video is not a static image.",
44
- ("audio", "video"): "⚠️ Audioβ†’Video: No visual stream β€” Telegram will likely reject this.",
45
- ("audio", "voice"): "⚠️ Audioβ†’Voice: Must be OGG/Opus; other formats may fail.",
46
- ("voice", "audio"): "⚠️ Voiceβ†’Audio: Should work but voice notes are OGG-encoded.",
47
- ("video", "video_note"): "⚠️ Videoβ†’VideoNote: Must be a square MP4 ≀1 min; may fail otherwise.",
48
- ("document","photo"): "⚠️ Documentβ†’Photo: Only works if the file is an actual image.",
49
- ("document","video"): "⚠️ Documentβ†’Video: Only works if the file is an actual video.",
50
- ("document","audio"): "⚠️ Documentβ†’Audio: Only works if the file is an actual audio file.",
51
- ("document","sticker"): "⚠️ Documentβ†’Sticker: Must be a valid WebP/TGS sticker file.",
52
  }
53
 
54
 
55
- def detect_method(message: telebot.types.Message) -> tuple[str, str]:
56
- """Return (method_name, file_id) for whatever was sent."""
57
- if message.photo:
58
- return "photo", message.photo[-1].file_id
59
- if message.video:
60
- return "video", message.video.file_id
61
- if message.audio:
62
- return "audio", message.audio.file_id
63
- if message.voice:
64
- return "voice", message.voice.file_id
65
- if message.video_note:
66
- return "video_note", message.video_note.file_id
67
- if message.animation:
68
- return "animation", message.animation.file_id
69
- if message.sticker:
70
- return "sticker", message.sticker.file_id
71
- if message.document:
72
- return "document", message.document.file_id
73
- return None, None
74
-
75
-
76
- def send_as(chat_id: int, file_id: str, method: str, caption: str = None):
77
- """Call the appropriate send_* method with the given file_id."""
78
- func_name, extra = METHOD_MAP[method]
79
- func = getattr(bot, func_name)
80
-
81
- # Build kwargs
82
- kwargs = {**extra}
83
-
84
- # The second positional argument name varies per method
85
- FILE_ARG = {
86
- "send_photo": "photo",
87
- "send_video": "video",
88
- "send_audio": "audio",
89
- "send_document": "document",
90
- "send_voice": "voice",
91
- "send_video_note": "video_note",
92
- "send_animation": "animation",
93
- "send_sticker": "sticker",
94
- }
95
- file_arg = FILE_ARG[func_name]
96
- kwargs[file_arg] = file_id
97
-
98
- # Only some methods support caption
99
- if caption and method not in ("sticker", "video_note"):
100
- kwargs["caption"] = caption
101
-
102
- func(chat_id, **kwargs)
103
-
104
-
105
- # ── handlers ──────────────────────────────────────────────────────────────────
106
-
107
- @bot.message_handler(commands=["start", "help"])
108
- def cmd_start(message: telebot.types.Message):
109
- bot.reply_to(message, (
110
- "πŸ‘‹ *File Method Converter Bot*\n\n"
111
- "Send me *any file or media* and I'll remember it.\n"
112
- "Then use:\n"
113
- " `/as <method>` β€” resend it with a different Telegram method\n\n"
114
- "*Available methods:*\n"
115
- "`photo` Β· `video` Β· `audio` Β· `document`\n"
116
- "`voice` Β· `video_note` Β· `animation` Β· `sticker`\n\n"
117
- "Example: after sending a video file as a document, type\n"
118
- "`/as video`\n\n"
119
- "⚠️ The bot will warn you about potentially incompatible conversions "
120
- "but will *always try anyway*."
121
- ), parse_mode="Markdown")
122
-
123
-
124
- @bot.message_handler(content_types=[
125
- "photo", "video", "audio", "voice", "video_note",
126
- "animation", "sticker", "document"
127
- ])
128
- def receive_file(message: telebot.types.Message):
129
- method, file_id = detect_method(message)
130
- if not file_id:
131
- bot.reply_to(message, "❌ Could not extract a file_id from this message.")
132
- return
133
-
134
- # Get a friendly name if available
135
- file_name = ""
136
- if message.document and message.document.file_name:
137
- file_name = f" (`{message.document.file_name}`)"
138
-
139
- user_files[message.from_user.id] = {
140
- "file_id": file_id,
141
- "original_method": method,
142
- "file_name": file_name,
143
  }
144
 
145
- bot.reply_to(message, (
146
- f"βœ… Got your *{method}*{file_name}!\n\n"
147
- f"Now send `/as <method>` to resend it using a different method.\n"
148
- f"Available: `photo`, `video`, `audio`, `document`, `voice`, "
149
- f"`video_note`, `animation`, `sticker`"
150
- ), parse_mode="Markdown")
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
- @bot.message_handler(commands=["as"])
154
- def cmd_as(message: telebot.types.Message):
155
- uid = message.from_user.id
156
 
157
- if uid not in user_files:
158
- bot.reply_to(message, "❌ Send me a file first, then use /as <method>.")
159
- return
160
 
161
- parts = message.text.strip().split()
162
- if len(parts) < 2:
163
- bot.reply_to(message, "Usage: `/as <method>`\nExample: `/as video`", parse_mode="Markdown")
164
- return
165
 
166
- target_method = parts[1].lower()
 
 
167
 
168
- if target_method not in METHOD_MAP:
169
- bot.reply_to(
170
- message,
171
- f"❌ Unknown method `{target_method}`.\n"
172
- f"Choose from: `" + "`, `".join(METHOD_MAP.keys()) + "`",
173
- parse_mode="Markdown"
174
- )
175
- return
176
-
177
- info = user_files[uid]
178
- file_id = info["file_id"]
179
- original_method = info["original_method"]
180
- file_name = info.get("file_name", "")
181
-
182
- # Check for warning
183
- warning = WARNINGS.get((original_method, target_method), "")
184
- if original_method == target_method:
185
- warning = "ℹ️ Source and target method are the same β€” forwarding anyway."
186
-
187
- # Send warning first (if any)
188
- if warning:
189
- bot.reply_to(message, warning)
190
-
191
- # Try sending
192
- try:
193
- caption = f"πŸ“Ž Re-sent as `{target_method}`{file_name} (was `{original_method}`)"
194
- send_as(message.chat.id, file_id, target_method, caption)
195
- except Exception as e:
196
- bot.reply_to(
197
- message,
198
- f"❌ *Telegram rejected this conversion.*\n\n"
199
- f"`{original_method}` β†’ `{target_method}` failed:\n`{e}`\n\n"
200
- f"Try a different method or send the file in its native format.",
201
- parse_mode="Markdown"
202
- )
203
 
 
 
 
 
 
204
 
205
- @bot.message_handler(commands=["clear"])
206
- def cmd_clear(message: telebot.types.Message):
207
- user_files.pop(message.from_user.id, None)
208
- bot.reply_to(message, "πŸ—‘οΈ Cleared! Send a new file whenever you're ready.")
209
 
 
 
 
210
 
211
- @bot.message_handler(commands=["methods"])
212
- def cmd_methods(message: telebot.types.Message):
213
- methods_list = "\n".join(f" β€’ `{m}`" for m in METHOD_MAP)
214
- bot.reply_to(
215
- message,
216
- f"*Supported methods:*\n{methods_list}",
217
- parse_mode="Markdown"
218
- )
219
 
 
220
 
221
- # ── entry point ───────────────────────────────────────────────────────────────
222
- # if __name__ == "__main__":
223
- # print("Bot is running...")
224
- # bot.infinity_polling()
225
 
226
- app = FastAPI()
 
 
 
 
 
 
 
 
227
 
228
- @app.get("/")
229
- def root(): # β‘‘ health‑check hits this β†’ must return 200 quickly
230
- return {"status": "ok"}
 
231
 
232
- @app.on_event("startup")
233
- def startup():
234
- # Launch the bot *after* Uvicorn has started
235
- threading.Thread(target=bot.infinity_polling, daemon=True).start()
 
1
+ import logging
2
+ from fastapi import FastAPI, Request
 
 
 
3
 
4
+ app = FastAPI()
5
+ logging.basicConfig(level=logging.INFO)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
+ # ── per-user storage ─────────────────────────────────────────────
8
  # { user_id: {"file_id": str, "original_method": str, "file_name": str} }
9
+ user_files = {}
10
 
11
+ # ── method map ───────────────────────────────────────────────────
12
  METHOD_MAP = {
13
+ "photo": ("sendPhoto", "photo"),
14
+ "video": ("sendVideo", "video"),
15
+ "audio": ("sendAudio", "audio"),
16
+ "document": ("sendDocument", "document"),
17
+ "voice": ("sendVoice", "voice"),
18
+ "video_note": ("sendVideoNote", "video_note"),
19
+ "animation": ("sendAnimation", "animation"),
20
+ "sticker": ("sendSticker", "sticker"),
21
  }
22
 
23
+ # ── warnings ─────────────────────────────────────────────────────
24
  WARNINGS = {
25
+ ("photo", "video"): "⚠️ Photoβ†’Video may fail.",
26
+ ("video", "photo"): "⚠️ Videoβ†’Photo may fail.",
27
+ ("audio", "video"): "⚠️ Audioβ†’Video likely rejected.",
28
+ ("audio", "voice"): "⚠️ Audioβ†’Voice must be OGG/Opus.",
29
+ ("voice", "audio"): "⚠️ Voiceβ†’Audio usually works.",
30
+ ("video", "video_note"): "⚠️ Videoβ†’VideoNote must be square MP4 ≀1 min.",
31
+ ("document", "photo"): "⚠️ Documentβ†’Photo works only if image.",
32
+ ("document", "video"): "⚠️ Documentβ†’Video works only if real video.",
33
+ ("document", "audio"): "⚠️ Documentβ†’Audio works only if audio.",
34
+ ("document", "sticker"): "⚠️ Must be valid sticker file.",
35
  }
36
 
37
 
38
+ # ── helper response builders ─────────────────────────────────────
39
+ def send_message(chat_id, text, parse_mode="Markdown"):
40
+ return {
41
+ "method": "sendMessage",
42
+ "chat_id": chat_id,
43
+ "text": text,
44
+ "parse_mode": parse_mode
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  }
46
 
 
 
 
 
 
 
47
 
48
+ def send_media(chat_id, method_name, field_name, file_id, caption=None):
49
+ response = {
50
+ "method": method_name,
51
+ "chat_id": chat_id,
52
+ field_name: file_id,
53
+ }
54
+ if caption and field_name not in ("sticker", "video_note"):
55
+ response["caption"] = caption
56
+ response["parse_mode"] = "Markdown"
57
+ return response
58
+
59
+
60
+ # ── detect incoming file ─────────────────────────────────────────
61
+ def detect_method(message):
62
+ if "photo" in message:
63
+ return "photo", message["photo"][-1]["file_id"], ""
64
+ if "video" in message:
65
+ return "video", message["video"]["file_id"], ""
66
+ if "audio" in message:
67
+ return "audio", message["audio"]["file_id"], ""
68
+ if "voice" in message:
69
+ return "voice", message["voice"]["file_id"], ""
70
+ if "video_note" in message:
71
+ return "video_note", message["video_note"]["file_id"], ""
72
+ if "animation" in message:
73
+ return "animation", message["animation"]["file_id"], ""
74
+ if "sticker" in message:
75
+ return "sticker", message["sticker"]["file_id"], ""
76
+ if "document" in message:
77
+ name = message["document"].get("file_name", "")
78
+ return "document", message["document"]["file_id"], f" (`{name}`)"
79
+ return None, None, ""
80
+
81
+
82
+ # ── webhook endpoint ─────────────────────────────────────────────
83
+ @app.post("/webhook")
84
+ async def telegram_webhook(request: Request):
85
+ update = await request.json()
86
+ logging.info(f"Update: {update}")
87
+
88
+ if "message" not in update:
89
+ return {"status": "ok"}
90
+
91
+ message = update["message"]
92
+ chat_id = message["chat"]["id"]
93
+ user_id = message["from"]["id"]
94
+ text = message.get("text", "")
95
+
96
+ # ── Commands ────────────────────���──────────────────────────
97
+ if text.startswith("/start") or text.startswith("/help"):
98
+ return send_message(chat_id,
99
+ "πŸ‘‹ *File Method Converter Bot*\n\n"
100
+ "Send any file.\n"
101
+ "Then use `/as <method>`.\n\n"
102
+ "*Methods:*\n"
103
+ "`photo` `video` `audio` `document`\n"
104
+ "`voice` `video_note` `animation` `sticker`\n\n"
105
+ "⚠️ No real conversion occurs."
106
+ )
107
 
108
+ if text.startswith("/methods"):
109
+ methods = "\n".join(f"β€’ `{m}`" for m in METHOD_MAP)
110
+ return send_message(chat_id, f"*Supported methods:*\n{methods}")
111
 
112
+ if text.startswith("/clear"):
113
+ user_files.pop(user_id, None)
114
+ return send_message(chat_id, "πŸ—‘οΈ Cleared. Send a new file.")
115
 
116
+ # ── /as command ────────────────────────────────────────────
117
+ if text.startswith("/as"):
118
+ if user_id not in user_files:
119
+ return send_message(chat_id, "❌ Send a file first.")
120
 
121
+ parts = text.split()
122
+ if len(parts) < 2:
123
+ return send_message(chat_id, "Usage: `/as <method>`")
124
 
125
+ target = parts[1].lower()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
+ if target not in METHOD_MAP:
128
+ return send_message(chat_id,
129
+ "❌ Unknown method.\nChoose from:\n" +
130
+ ", ".join(f"`{m}`" for m in METHOD_MAP)
131
+ )
132
 
133
+ info = user_files[user_id]
134
+ original = info["original_method"]
135
+ file_id = info["file_id"]
136
+ file_name = info["file_name"]
137
 
138
+ warning = WARNINGS.get((original, target), "")
139
+ if original == target:
140
+ warning = "ℹ️ Source and target are same."
141
 
142
+ if warning:
143
+ return send_message(chat_id, warning)
 
 
 
 
 
 
144
 
145
+ method_name, field_name = METHOD_MAP[target]
146
 
147
+ caption = f"πŸ“Ž Re-sent as `{target}`{file_name} (was `{original}`)"
148
+ return send_media(chat_id, method_name, field_name, file_id, caption)
 
 
149
 
150
+ # ── File reception ──────────────────────────────────────────
151
+ method, file_id, file_name = detect_method(message)
152
+
153
+ if file_id:
154
+ user_files[user_id] = {
155
+ "file_id": file_id,
156
+ "original_method": method,
157
+ "file_name": file_name,
158
+ }
159
 
160
+ return send_message(chat_id,
161
+ f"βœ… Got your *{method}*{file_name}\n\n"
162
+ "Now send `/as <method>`."
163
+ )
164
 
165
+ return {"status": "ok"}