Conversation
This plugin allows users to download media from Instagram, including reels, videos, photos, and carousels. It provides a command handler for the 'ig' command to initiate downloads.
There was a problem hiding this comment.
Pull request overview
Adds an Instagram media downloader command to the Ultroid plugins set, enabling users to fetch and upload reels/videos/photos/carousels directly into chats.
Changes:
- Introduces a new
.ig <instagram link>command handler. - Uses
yt-dlpto extract/download Instagram media and uploads results viafast_uploader. - Adds a custom progress hook to report download progress in-chat.
Comments suppressed due to low confidence (1)
plugins/utils.py:113
- Avoid bare
except:here; it will also swallowKeyboardInterrupt/SystemExitand makes debugging operational issues harder. CatchExceptionand consider logging the failure (at least at debug/error level) so rename/upload issues are diagnosable.
try:
os.rename(media_path, final_name)
except:
final_name = media_path
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if "instagram.com" not in url: | ||
| return await event.eor("**❌ Invalid Instagram link.**") |
There was a problem hiding this comment.
The Instagram URL validation if "instagram.com" not in url is vulnerable to false positives (e.g., https://instagram.com.evil.tld/...) and can reject/accept malformed inputs unpredictably. Prefer urllib.parse.urlparse(url) and validate hostname (e.g., instagram.com / www.instagram.com) similar to how plugins/twitter.py validates domains.
| # Ultroid - UserBot | ||
| # Instagram Downloader Plugin | ||
| # This file is part of < https://github.com/TeamUltroid/Ultroid/ > |
There was a problem hiding this comment.
This file implements the Instagram downloader, but it’s named plugins/utils.py. The startup exclude list already references an instagram plugin (see pyUltroid/__main__.py), so keeping this in utils.py makes it harder to manage/disable consistently and is confusing for maintenance. Consider renaming/moving this plugin to plugins/instagram.py (or update the exclusion mechanism accordingly).
| "nocheckcertificate": True, | ||
| "outtmpl": "%(id)s.%(ext)s", | ||
| "progress_hooks": [lambda d: asyncio.create_task(ig_progress(d, time.time(), msg))], | ||
| } |
There was a problem hiding this comment.
progress_hooks uses asyncio.create_task(...) but this file never imports asyncio, so it will raise NameError the first time the hook runs. Add the missing import (and keep it consistent with other plugins).
| "outtmpl": "%(id)s.%(ext)s", | ||
| "progress_hooks": [lambda d: asyncio.create_task(ig_progress(d, time.time(), msg))], | ||
| } |
There was a problem hiding this comment.
_download_ig runs inside run_async (thread pool). yt-dlp progress hooks are therefore executed in a worker thread, where asyncio.create_task() will fail with "no running event loop". Use a thread-safe bridge (e.g., asyncio.run_coroutine_threadsafe(..., event.client.loop) / capture the main loop) instead of create_task inside the hook.
| "outtmpl": "%(id)s.%(ext)s", | ||
| "progress_hooks": [lambda d: asyncio.create_task(ig_progress(d, time.time(), msg))], | ||
| } |
There was a problem hiding this comment.
The progress hook currently passes time.time() as start_time on every callback, which resets the timer and makes the 10-second throttling ineffective (it may try to edit on almost every hook call). Capture a single start_time once before starting the download and reuse it for all hook invocations.
| title = media.get("title") or "Instagram_Media" | ||
|
|
||
| # sanitizing title | ||
| if len(title) > 30: | ||
| title = title[:27] + "..." | ||
|
|
||
| # find file downloaded by yt-dlp | ||
| media_path = None | ||
| for f in glob.glob(f"{media_id}*"): | ||
| if not f.endswith(".jpg"): | ||
| media_path = f | ||
| break | ||
|
|
||
| if not media_path: | ||
| continue | ||
|
|
||
| # rename file | ||
| ext = "." + media_path.split(".")[-1] | ||
| final_name = f"{title}{ext}" | ||
|
|
||
| try: | ||
| os.rename(media_path, final_name) | ||
| except: | ||
| final_name = media_path |
There was a problem hiding this comment.
title is taken from remote metadata and is only truncated, not sanitized for filesystem safety. Characters like /, \, : or newlines can make os.rename fail or produce unintended paths. Use the project's filename sanitizer (e.g., check_filename) or explicitly strip/replace path separators and control characters before building final_name.
This plugin allows users to download media from Instagram, including reels, videos, photos, and carousels. It provides a command handler for the 'ig' command to initiate downloads.