diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml
index 9f03b7b..2345dc7 100644
--- a/.github/workflows/pylint.yml
+++ b/.github/workflows/pylint.yml
@@ -28,4 +28,4 @@ jobs:
repository: .
commit_user_name: kaif-00z
commit_user_email: 88398455+kaif-00z@users.noreply.github.com
- commit_author: kaif-00z <88398455+kaif-00z@users.noreply.github.com>
\ No newline at end of file
+ commit_author: kaif-00z <88398455+kaif-00z@users.noreply.github.com>
diff --git a/.gitignore b/.gitignore
index a1b9cbb..30f8d21 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
.env
-__pycache__/
\ No newline at end of file
+__pycache__/
+test.py
\ No newline at end of file
diff --git a/.sample.env b/.sample.env
index e6c3e74..ec2e0d3 100644
--- a/.sample.env
+++ b/.sample.env
@@ -4,13 +4,18 @@ BOT_TOKEN=
MAIN_CHANNEL=-1001111
LOG_CHANNEL=-1001111
CLOUD_CHANNEL=-1001111
-REDIS_URI=
-REDIS_PASSWORD=
+FIREBASE_SERVICE_ACCOUNT_FILE=
+FIREBASE_URL=
OWNER=1872074304
BACKUP_CHANNEL=-1001111
# Optional Environment Variable
+API_ID=
+API_HASH=
+FORCESUB_CHANNEL_LINK=
+FORCESUB_CHANNEL=
+SESSION=
SEND_SCHEDULE=
THUMBNAIL=
CRF=
\ No newline at end of file
diff --git a/README.md b/README.md
index e229129..8a8a234 100644
--- a/README.md
+++ b/README.md
@@ -10,11 +10,19 @@
## Description Of Latest Update
+- Added Separate Anime Channel Upload
+- Click Here To See How Separate Anime Channel Upload Look.
+- Added Button Upload Support (File Store)
+- Click Here To See How Button Upload Look.
+- Added ForceSub
+- Added 480p Support
+- Added Broadcast
+- Major Modification In FFMPEG Code.
+- Modified Anime Searcher
+- Admin Panel Fixed
- ReWritten Whole Program (Fully OOPs Based)
- Optimized Core
- Added Heroku Support
-- Added Button Upload Support (File Store)
-- Click Here To See How Button Upload Look.
- Added Custom CRF Support
## Contributing
@@ -40,9 +48,9 @@
- `BOT_TOKEN` - Get This From @Botfather In Telegram.
-- `REDIS_URI` - Get This From redis.com
+- `FIREBASE_URL` - Get This From Firebase Realtime Database Console.
-- `REDIS_PASSWORD` - Get This From redis.com
+- `FIREBASE_SERVICE_ACCOUNT_FILE` - Get This From Firebase Realtime Database Console.
- `MAIN_CHANNEL` - ID of Channel Where Anime Will Upload.
@@ -54,6 +62,8 @@
### OPTIONAL VARIABLES
+- `SESSION` - Telethon Session String Of Your Telegram Account.
+
- `BACKUP_CHANNEL` - ID of Channel Where Anime Will Be Saved As BackUP if You Are Using Button Upload Option Then Make Sure To SET Backup Channel.
- `THUMBNAIL` - JPG/PNG Link of Thumbnail FIle.
@@ -78,7 +88,7 @@
## Commands
-[![Comand](https://graph.org/file/82176674097989fae68d4.png)](https://github.com/kaif-00z/AutoAnimeBot/)
+[![Comand](https://graph.org/file/ca8de14ba0b1d3b71af1f.jpg)](https://github.com/kaif-00z/AutoAnimeBot/)
**Uploading of Ongoing Animes Is Automatic**
diff --git a/app.json b/app.json
index c0f67fa..5022ce5 100644
--- a/app.json
+++ b/app.json
@@ -22,18 +22,24 @@
"value": ""
},
+ "SESSION": {
+ "description": "Telethon Session String",
+ "value": "",
+ "required": false
+ },
+
"OWNER": {
"description": "Get ur Id Of Telegram nd Paste Here.",
"value": ""
},
- "REDIS_URI": {
- "description": "Redis endpoint URL, from redislabs.com",
+ "FIREBASE_URL": {
+ "description": "Firebase endpoint URL, from Firebase Realtime Database",
"value": ""
},
- "REDIS_PASSWORD": {
- "description": "Redis endpoint password, from redislabs.com",
+ "FIREBASE_SERVICE_ACCOUNT_FILE": {
+ "description": "Firebase Service Account File Link, from Firebase Realtime Database",
"value": ""
},
diff --git a/auto_env_gen.py b/auto_env_gen.py
index fb9db3b..d71552b 100644
--- a/auto_env_gen.py
+++ b/auto_env_gen.py
@@ -19,13 +19,16 @@
DATA = {}
ENV = """
+API_ID={}
+API_HASH={}
BOT_TOKEN={}
+SESSION={}
MAIN_CHANNEL={}
LOG_CHANNEL={}
CLOUD_CHANNEL={}
BACKUP_CHANNEL={}
-REDIS_URI={}
-REDIS_PASSWORD={}
+FIREBASE_URL={}
+FIREBASE_SERVICE_ACCOUNT_FILE={}
OWNER={}
"""
@@ -35,21 +38,24 @@ async def generate_session_string():
api_hash = input("Enter your API_HASH: ")
if api_id and api_hash:
async with TelegramClient(StringSession(), api_id, api_hash) as client:
+ DATA["api_id"] = api_id
+ DATA["api_hash"] = api_hash
+ DATA["session"] = str(client.session.save())
return (str(client.session.save()), api_id, api_hash)
print("API_ID and HASH Not Found!")
sys.exit(1)
-def get_redis():
- redis_uri = input("Enter your Redis URI: ")
- redis_pass = input("Enter your Redis Password: ")
- if redis_uri and redis_pass:
- DATA["redis_uri"] = redis_uri
- DATA["redis_pass"] = redis_pass
+def get_firebase():
+ uri = input("Enter your Firebase Realtime Database Url: ")
+ _pass = input("Enter your Firebase Realtime Database Service Account File Link: ")
+ if uri and _pass:
+ DATA["firebase_uri"] = uri
+ DATA["firebase_pass"] = _pass
return True
else:
- DATA["redis_uri"] = ""
- DATA["redis_pass"] = ""
+ DATA["firebase_uri"] = ""
+ DATA["firebase_pass"] = ""
return False
@@ -72,13 +78,16 @@ async def create_channel(client, title):
def generate_env():
txt = ENV.format(
+ DATA["api_id"],
+ DATA["api_hash"],
DATA["bot_token"],
+ DATA["session"],
DATA["Ongoing Anime 2024"],
DATA["Ongoing Anime Logs"],
DATA["Ongoing Anime Samples And SS"],
DATA["Ongoing Anime Backup"],
- DATA.get("redis_uri") or "",
- DATA.get("redis_pass") or "",
+ DATA.get("firebase_uri") or "",
+ DATA.get("firebase_pass") or "",
DATA["owner_id"],
)
with open(".env", "w") as f:
@@ -160,10 +169,10 @@ async def auto_maker():
print(format_exc())
sys.exit(1)
print("Succesfully Created Channel...")
- db = get_redis()
+ db = get_firebase()
if not db:
print(
- "Generating .env Without Redis URI and Password. Now You Have To Add it Manually!"
+ "Generating .env Without Firebase URI and Service Account. Now You Have To Add it Manually!"
)
generate_env()
diff --git a/bot.py b/bot.py
index 1a3b5c5..03dc379 100644
--- a/bot.py
+++ b/bot.py
@@ -34,7 +34,7 @@
tools = Tools()
tools.init_dir()
-bot = Bot(None)
+bot = Bot()
dB = DataBase()
subsplease = SubsPlease(dB)
torrent = Torrent()
@@ -48,22 +48,24 @@
)
)
async def _start(event):
- msg_id = event.pattern_match.group(1)
xnx = await event.reply("`Please Wait...`")
+ msg_id = event.pattern_match.group(1)
+ dB.add_broadcast_user(event.sender_id)
if Var.FORCESUB_CHANNEL and Var.FORCESUB_CHANNEL_LINK:
is_user_joined = await bot.is_joined(Var.FORCESUB_CHANNEL, event.sender_id)
if is_user_joined:
pass
else:
return await xnx.edit(
- f"**Please Join {Var.FORCESUB_CHANNEL_LINK} To Use This Bot**",
+ f"**Please Join The Following Channel To Use This Bot π«‘**",
buttons=[
+ [Button.url("π JOIN CHANNEL", url=Var.FORCESUB_CHANNEL_LINK)],
[
Button.url(
"β»οΈ REFRESH",
url=f"https://t.me/{((await bot.get_me()).username)}?start={msg_id}",
)
- ]
+ ],
],
)
if msg_id:
@@ -78,8 +80,7 @@ async def _start(event):
await event.reply(file=[i for i in msg])
else:
if event.sender_id == Var.OWNER:
- await xnx.delete()
- return await event.reply(
+ return await xnx.edit(
"** < ADMIN PANEL > **",
buttons=admin.admin_panel(),
)
@@ -123,6 +124,16 @@ async def _(e):
await admin._btn_t(e)
+@bot.on(events.callbackquery.CallbackQuery(data="scul"))
+async def _(e):
+ await admin._sep_c_t(e)
+
+
+@bot.on(events.callbackquery.CallbackQuery(data="cast"))
+async def _(e):
+ await admin.broadcast_bt(e)
+
+
@bot.on(events.callbackquery.CallbackQuery(data="bek"))
async def _(e):
await e.edit(buttons=admin.admin_panel())
@@ -131,8 +142,24 @@ async def _(e):
async def anime(data):
try:
torr = [data.get("480p"), data.get("720p"), data.get("1080p")]
- poster = await tools._poster(bot, AnimeInfo(torr[0].title))
+ anime_info = AnimeInfo(torr[0].title)
+ poster = await tools._poster(bot, anime_info)
+ if dB.is_separate_channel_upload():
+ chat_info = await tools.get_chat_info(bot, anime_info, dB)
+ await poster.edit(
+ buttons=[
+ [
+ Button.url(
+ f"EPISODE {anime_info.data.get('episode_number', '')}".strip(),
+ url=chat_info["invite_link"],
+ )
+ ]
+ ]
+ )
+ poster = await tools._poster(bot, anime_info, chat_info["chat_id"])
btn = [[]]
+ original_upload = dB.is_original_upload()
+ button_upload = dB.is_button_upload()
for i in torr:
try:
filename = f"downloads/{i.title}"
@@ -143,8 +170,8 @@ async def anime(data):
bot,
dB,
{
- "original_upload": dB.is_original_upload(),
- "button_upload": dB.is_button_upload(),
+ "original_upload": original_upload,
+ "button_upload": button_upload,
},
filename,
AnimeInfo(i.title),
diff --git a/core/bot.py b/core/bot.py
index 01b6075..60d82c9 100644
--- a/core/bot.py
+++ b/core/bot.py
@@ -17,8 +17,10 @@
# credit to t.me/kAiF_00z (github.com/kaif-00z)
# little bit inspired from pyUltroid.BaseClient
+import asyncio
import sys
from logging import Logger
+from traceback import format_exc
from pyrogram import Client
from telethon import TelegramClient
@@ -29,7 +31,13 @@
AuthKeyDuplicatedError,
)
from telethon.errors.rpcerrorlist import UserNotParticipantError
-from telethon.tl.functions.channels import GetParticipantRequest
+from telethon.sessions import StringSession
+from telethon.tl.functions.channels import (
+ CreateChannelRequest,
+ EditPhotoRequest,
+ GetParticipantRequest,
+)
+from telethon.tl.functions.messages import ExportChatInviteRequest
from functions.config import Var
from libs.logger import LOGS, TelethonLogger
@@ -38,7 +46,6 @@
class Bot(TelegramClient):
def __init__(
self,
- session,
api_id=None,
api_hash=None,
bot_token=None,
@@ -54,7 +61,7 @@ def __init__(
kwargs["api_id"] = api_id or Var.API_ID
kwargs["api_hash"] = api_hash or Var.API_HASH
kwargs["base_logger"] = TelethonLogger
- super().__init__(session, **kwargs)
+ super().__init__(None, **kwargs)
self.pyro_client = Client(
name="pekka",
api_id=kwargs["api_id"],
@@ -62,6 +69,11 @@ def __init__(
bot_token=bot_token or Var.BOT_TOKEN,
in_memory=True,
)
+ self.user_client = None
+ if Var.SESSION:
+ self.user_client = TelegramClient(
+ StringSession(Var.SESSION), kwargs["api_id"], kwargs["api_hash"]
+ )
self.run_in_loop(self.start_client(bot_token=bot_token or Var.BOT_TOKEN))
def __repr__(self):
@@ -73,6 +85,8 @@ async def start_client(self, **kwargs):
self.logger.info("Trying to login.")
try:
await self.start(**kwargs)
+ if self.user_client:
+ await self.user_client.start()
await self.pyro_client.start()
except ApiIdInvalidError:
self.logger.critical("API ID and API_HASH combination does not match!")
@@ -92,6 +106,9 @@ async def start_client(self, **kwargs):
me = f"@{self.me.username}"
if self._log_at:
self.logger.info(f"Logged in as {me}")
+ if self.user_client:
+ user_me = await self.user_client.get_me()
+ self.logger.info(f"Logged in as @{user_me.username}")
self._bot = await self.is_bot()
async def upload_anime(self, file, caption, thumb=None, is_button=False):
@@ -109,11 +126,11 @@ async def upload_anime(self, file, caption, thumb=None, is_button=False):
)
return post
- async def upload_poster(self, file, caption):
+ async def upload_poster(self, file, caption, channel_id=None):
post = await self.send_file(
- Var.MAIN_CHANNEL,
+ channel_id if channel_id else Var.MAIN_CHANNEL,
file=file,
- caption=caption,
+ caption=caption or "",
)
return post
@@ -124,6 +141,55 @@ async def is_joined(self, channel_id, user_id):
except UserNotParticipantError:
return False
+ async def create_channel(self, title: str, logo=None):
+ try:
+ r = await self.user_client(
+ CreateChannelRequest(
+ title=title,
+ about="Powered By github.com/kaif-00z/AutoAnimeBot",
+ megagroup=False,
+ )
+ )
+ created_chat_id = r.chats[0].id
+ chat_id = int(f"-100{created_chat_id}")
+ await asyncio.sleep(2)
+ await self.user_client.edit_admin(
+ int(chat_id),
+ f"{((await self.get_me()).username)}",
+ post_messages=True,
+ edit_messages=True,
+ delete_messages=True,
+ ban_users=True,
+ pin_messages=True,
+ add_admins=True,
+ )
+ if logo:
+ try:
+ await self.user_client(
+ EditPhotoRequest(
+ chat_id, (await self.user_client.upload_file(logo))
+ )
+ )
+ except BaseException:
+ pass
+ return chat_id
+ except BaseException:
+ LOGS.error(format_exc())
+
+ async def generate_invite_link(self, channel_id):
+ try:
+ data = await self.user_client(
+ ExportChatInviteRequest(
+ peer=channel_id,
+ title=f"Generated By Ongoing Anime Bot",
+ request_needed=False,
+ usage_limit=None,
+ )
+ )
+ return data.link
+ except BaseException:
+ LOGS.error(format_exc())
+
def run_in_loop(self, function):
return self.loop.run_until_complete(function)
diff --git a/database/__init__.py b/database/__init__.py
index ab4d002..f43c6b4 100644
--- a/database/__init__.py
+++ b/database/__init__.py
@@ -18,38 +18,42 @@
from traceback import format_exc
-from redis import Redis
-
from functions.config import Var
+from libs.firebasewarp import FireDB
from libs.logger import LOGS
class DataBase:
def __init__(self):
try:
- LOGS.info("Trying Connect With Redis database")
- redis_info = Var.REDIS_URI.split(":")
- self.dB = Redis(
- host=redis_info[0],
- port=redis_info[1],
- password=Var.REDIS_PASS,
- charset="utf-8",
- decode_responses=True,
- )
- LOGS.info("Successfully Connected to Redis database")
+ LOGS.info("Trying Connect With Firebase Database")
+ self.dB = FireDB(Var)
+ LOGS.info("Successfully Connected to Firebase Database")
except Exception as error:
LOGS.exception(format_exc())
LOGS.critical(str(error))
exit()
- self.cache = {}
- self.re_cache()
+ self.cache = self.dB.getall()
+ LOGS.info(f"Succesfully Sync Database!!!")
def add_anime(self, name):
data = self.cache.get("ANIMES_UPLOADED") or []
if name not in data:
data.append(name)
self.cache["ANIMES_UPLOADED"] = data
- self.dB.set("ANIMES_UPLOADED", str(data))
+ self.dB.create_data("ANIMES_UPLOADED", data)
+
+ def toggle_separate_channel_upload(self):
+ data = self.cache.get("SEPARATE_CHANNEL_UPLOAD") or False
+ if data:
+ data = False
+ else:
+ data = True
+ self.cache["SEPARATE_CHANNEL_UPLOAD"] = data
+ self.dB.create_data("SEPARATE_CHANNEL_UPLOAD", data)
+
+ def is_separate_channel_upload(self):
+ return self.cache.get("SEPARATE_CHANNEL_UPLOAD") or False
def toggle_original_upload(self):
data = self.cache.get("OG_UPLOAD") or False
@@ -58,7 +62,7 @@ def toggle_original_upload(self):
else:
data = True
self.cache["OG_UPLOAD"] = data
- self.dB.set("OG_UPLOAD", str(data))
+ self.dB.create_data("OG_UPLOAD", data)
def is_original_upload(self):
return self.cache.get("OG_UPLOAD") or False
@@ -70,7 +74,7 @@ def toggle_button_upload(self):
else:
data = True
self.cache["BUTTON_UPLOAD"] = data
- self.dB.set("BUTTON_UPLOAD", str(data))
+ self.dB.create_data("BUTTON_UPLOAD", data)
def is_button_upload(self):
return self.cache.get("BUTTON_UPLOAD") or False
@@ -81,14 +85,26 @@ def is_anime_uploaded(self, name):
return True
return False
+ def add_anime_channel_info(self, title, _data):
+ data = self.cache.get("ANIME_CHANNEL_INFO") or {}
+ data.update({title: _data})
+ self.cache["ANIME_CHANNEL_INFO"] = data
+ self.dB.create_data(f"ANIME_CHANNEL_INFO/{title}", _data)
+
+ def get_anime_channel_info(self, title):
+ data = self.cache.get("ANIME_CHANNEL_INFO") or {}
+ if data.get(title):
+ return data[title]
+ return {}
+
def get_anime_uploaded_list(self):
return self.cache.get("ANIMES_UPLOADED") or []
- def store_items(self, _hash, list):
+ def store_items(self, _hash, _list):
data = self.cache.get("FILESTORE") or {}
- data.update({_hash: list})
+ data.update({_hash: _list})
self.cache["FILESTORE"] = data
- self.dB.set("FILESTORE", str(data))
+ self.dB.create_data(f"FILESTORE/{_hash}", _list)
def get_store_items(self, _hash):
data = self.cache.get("FILESTORE") or {}
@@ -96,7 +112,12 @@ def get_store_items(self, _hash):
return data[_hash]
return []
- def re_cache(self):
- for key in self.dB.keys():
- self.cache.update({key: eval(self.dB.get(key) or "[]")})
- LOGS.info(f"Succesfully Sync Database!!!")
+ def add_broadcast_user(self, user_id):
+ data = self.cache.get("BROADCAST") or []
+ if user_id not in data:
+ data.append(int(user_id))
+ self.cache["BROADCAST"] = data
+ self.dB.create_data("BROADCAST", data)
+
+ def get_broadcast_user(self):
+ return self.cache.get("BROADCAST") or []
diff --git a/functions/config.py b/functions/config.py
index 09f4eec..caf320b 100644
--- a/functions/config.py
+++ b/functions/config.py
@@ -25,11 +25,14 @@ class Var:
API_ID = config("API_ID", default=6, cast=int)
API_HASH = config("API_HASH", default="eb06d4abfb49dc3eeb1aeb98ae0f581e")
BOT_TOKEN = config("BOT_TOKEN", default=None)
+ SESSION = config("SESSION", default=None)
# Database Credentials
- REDIS_URI = config("REDIS_URI", default=None)
- REDIS_PASS = config("REDIS_PASSWORD", default=None)
+ FIREBASE_URL = config("FIREBASE_URL", default=None)
+ FIREBASE_SERVICE_ACCOUNT_FILE = config(
+ "FIREBASE_SERVICE_ACCOUNT_FILE", default=None
+ )
# Channels Ids
diff --git a/functions/info.py b/functions/info.py
index ebcfde9..a7c56e2 100644
--- a/functions/info.py
+++ b/functions/info.py
@@ -16,10 +16,9 @@
# if you are using this following code then don't forgot to give proper
# credit to t.me/kAiF_00z (github.com/kaif-00z)
-from datetime import datetime
+from traceback import format_exc
import anitopy
-import pytz
from libs.kitsu import RawAnimeInfo
from libs.logger import LOGS
@@ -31,14 +30,11 @@ def __init__(self, name):
self.CAPTION = """
**{}
βββββββββββββββ
-β£ Language : Japanese [English-Sub]
-β£ Quality : 480p, 720p, 1080p
-β£ Season : {}
-β£ Episode : {}
-βββββββββββββββ
-γ£ Next Airing Episode: {}
-γ£ Next Airing Episode Date: {}
-βββββββββββββββ**
+β£ Language:** `Japanese [ESub]`
+**β£ Quality:** `480p|720p|1080p`
+**β£ Season:** `{}`
+**β£ Episode:** `{}`
+**βββββββββββββββ**
"""
self.proper_name = self.get_proper_name_for_func(name)
self.name = name
@@ -48,9 +44,9 @@ async def get_english(self):
anime_name = self.data.get("anime_title")
try:
anime = (await self.kitsu.search(self.proper_name)) or {}
- return anime.get("english_title").strip() or anime_name
- except Exception as error:
- LOGS.error(str(error))
+ return anime.get("english_title") or anime_name
+ except BaseException:
+ LOGS.error(str(format_exc()))
return anime_name.strip()
async def get_poster(self):
@@ -58,8 +54,8 @@ async def get_poster(self):
if self.proper_name:
anime_poster = await self.kitsu.search(self.proper_name)
return anime_poster.get("poster_img") or None
- except Exception as error:
- LOGS.error(str(error))
+ except BaseException:
+ LOGS.error(str(format_exc()))
async def get_cover(self):
try:
@@ -68,29 +64,23 @@ async def get_cover(self):
if anime_poster.get("anilist_id"):
return anime_poster.get("anilist_poster")
return None
- except Exception as error:
- LOGS.error(str(error))
+ except BaseException:
+ LOGS.error(str(format_exc()))
async def get_caption(self):
try:
if self.proper_name or self.data:
- anime = (await self.kitsu.search(self.proper_name)) or {}
- next_ = anime.get("next_airing_ep", {})
return self.CAPTION.format(
- anime.get("english_title").strip() or self.data.get("anime_title"),
- self.data.get("anime_season") or 1,
- self.data.get("episode_number") or "N/A",
- next_.get("episode") or "N/A",
+ (await self.get_english()),
+ str(self.data.get("anime_season") or 1).zfill(2),
(
- datetime.fromtimestamp(
- next_.get("airingAt"), tz=pytz.timezone("Asia/Kolkata")
- ).strftime("%A, %B %d, %Y")
- if next_.get("airingAt")
+ str(self.data.get("episode_number")).zfill(2)
+ if self.data.get("episode_number")
else "N/A"
),
)
- except Exception as error:
- LOGS.error(str(error))
+ except BaseException:
+ LOGS.error(str(format_exc()))
return ""
async def rename(self, original=False):
@@ -115,6 +105,7 @@ async def rename(self, original=False):
return self.name
except Exception as error:
LOGS.error(str(error))
+ LOGS.exception(format_exc())
return self.name
def get_proper_name_for_func(self, name):
@@ -134,3 +125,4 @@ def get_proper_name_for_func(self, name):
return anime_name
except Exception as error:
LOGS.error(str(error))
+ LOGS.exception(format_exc())
diff --git a/functions/tools.py b/functions/tools.py
index 0faa095..86d4468 100644
--- a/functions/tools.py
+++ b/functions/tools.py
@@ -77,6 +77,7 @@ async def cover_dl(self, link):
await file.write(image)
return fn
except Exception as error:
+ LOGS.exception(format_exc())
LOGS.error(str(error))
async def mediainfo(self, file, bot):
@@ -98,12 +99,32 @@ async def mediainfo(self, file, bot):
)
return page.get("url")
except Exception as error:
+ LOGS.exception(format_exc())
LOGS.error(str(error))
- async def _poster(self, bot, anime_info):
+ async def _poster(self, bot, anime_info, channel_id=None):
thumb = await self.cover_dl((await anime_info.get_cover()))
caption = await anime_info.get_caption()
- return await bot.upload_poster(thumb or "assest/poster_not_found.jpg", caption)
+ return await bot.upload_poster(
+ thumb or "assest/poster_not_found.jpg",
+ caption,
+ channel_id if channel_id else None,
+ )
+
+ async def get_chat_info(self, bot, anime_info, dB):
+ try:
+ chat_info = dB.get_anime_channel_info(anime_info.proper_name)
+ if not chat_info:
+ chat_id = await bot.create_channel(
+ (await anime_info.get_english()),
+ (await self.cover_dl((await anime_info.get_poster()))),
+ )
+ invite_link = await bot.generate_invite_link(chat_id)
+ chat_info = {"chat_id": chat_id, "invite_link": invite_link}
+ dB.add_anime_channel_info(anime_info.proper_name, chat_info)
+ return chat_info
+ except BaseException:
+ LOGS.error(str(format_exc()))
def init_dir(self):
if not os.path.exists("thumb.jpg"):
@@ -143,7 +164,7 @@ async def rename_file(self, dl, out):
return True, out
async def compress(self, dl, out):
- cmd = f'''{Var.FFMPEG} -i """{dl}""" -metadata "Encoded By"="https://github.com/kaif-00z/AutoAnimeBot/" -preset ultrafast -c:v libx265 -crf {Var.CRF} -map 0:v -c:a aac -map 0:a -c:s copy -map 0:s? """{out}""" -y'''
+ cmd = f'''{Var.FFMPEG} -i """{dl}""" -metadata "Encoded By"="https://github.com/kaif-00z/AutoAnimeBot/" -map 0:v -map 0:a -map 0:s -c:v libx264 -x265-params 'bframes=8:psy-rd=1:ref=3:aq-mode=3:aq-strength=0.8:deblock=1,1' -pix_fmt yuv420p -crf {Var.CRF} -c:a libopus -b:a 32k -ac 2 -ab 32k -vbr 2 -level 3.1 -threads 2 -preset veryfast """{out}""" -y'''
process = await asyncio.create_subprocess_shell(
cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
)
@@ -234,3 +255,4 @@ async def gen_ss_sam(self, _hash, filename):
return _hash, out
except Exception as error:
LOGS.error(str(error))
+ LOGS.exception(format_exc())
diff --git a/functions/utils.py b/functions/utils.py
index f4976ab..a00eb17 100644
--- a/functions/utils.py
+++ b/functions/utils.py
@@ -16,9 +16,9 @@
# if you are using this following code then don't forgot to give proper
# credit to t.me/kAiF_00z (github.com/kaif-00z)
-from telethon import Button
+from telethon import Button, events
-from core.bot import Bot
+from core.bot import Bot, Var, asyncio
from database import DataBase
@@ -37,6 +37,8 @@ def admin_panel(self):
Button.inline("ποΈ Encode [Toogle]", data="entg"),
],
[Button.inline("π Button Upload [Toogle]", data="butg")],
+ [Button.inline("ποΈ Separate Channel Upload [Toogle]", data="scul")],
+ [Button.inline("π Broadcast", data="cast")],
]
return btn
@@ -65,10 +67,69 @@ async def _encode_t(self, e):
)
async def _btn_t(self, e):
- if self.db.is_button_upload:
+ if self.db.is_separate_channel_upload():
+ return await e.edit(
+ "`You Can't On/Off The Button Upload When Seprate Channel Is Enabled`",
+ buttons=self.back_btn(),
+ )
+ if self.db.is_button_upload():
self.db.toggle_button_upload()
return await e.edit(
- "`Successfully On The Button Upload`", buttons=self.back_btn()
+ "`Successfully Off The Button Upload`", buttons=self.back_btn()
)
self.db.toggle_button_upload()
- return await e.edit("`Successfully Off The Upload`", buttons=self.back_btn())
+ return await e.edit("`Successfully On The Upload`", buttons=self.back_btn())
+
+ async def _sep_c_t(self, e):
+ if Var.SESSION:
+ if self.db.is_button_upload():
+ if self.db.is_separate_channel_upload():
+ self.db.toggle_separate_channel_upload()
+ return await e.edit(
+ "`Successfully Off The Separate Channel Upload`",
+ buttons=self.back_btn(),
+ )
+ self.db.toggle_separate_channel_upload()
+ return await e.edit(
+ "`Successfully On The Separate Channel Upload`",
+ buttons=self.back_btn(),
+ )
+ else:
+ return await e.edit(
+ "`To Use The Separate Channel Upload First You Have To Enable Button Upload`",
+ buttons=self.back_btn(),
+ )
+ else:
+ return await e.edit(
+ "`To Use The Separate Channel Upload First You Have To Add SESSION Variable in The Bot",
+ buttons=self.back_btn(),
+ )
+
+ async def broadcast_bt(self, e):
+ users = self.db.get_broadcast_user()
+ await e.edit("**Please Use This Feature Responsibly β οΈ**")
+ await e.reply(
+ f"**Send a single Message To Broadcast π**\n\n**There are** `{len(users)}` **Users Currently Using Meππ»**.\n\nSend /cancel to Cancel Process."
+ )
+ async with e.client.conversation(e.sender_id) as cv:
+ reply = cv.wait_event(events.NewMessage(from_users=e.sender_id))
+ repl = await reply
+ await e.delete()
+ if repl.text and repl.text.startswith("/cancel"):
+ return await repl.reply("`Broadcast Cancelled`")
+ sent = await repl.reply("`π£οΈ Broadcasting Your Post...`")
+ done, er = 0, 0
+ for user in users:
+ try:
+ if repl.poll:
+ await repl.forward_to(int(user))
+ else:
+ await e.client.send_message(int(user), repl.message)
+ await asyncio.sleep(0.2)
+ done += 1
+ except BaseException as ex:
+ er += 1
+ print(ex)
+ await sent.edit(
+ f"**Broadcast Completed To** `{done}` **Users.**\n**Error in** `{er}` **Users.**"
+ )
diff --git a/libs/firebasewarp.py b/libs/firebasewarp.py
new file mode 100644
index 0000000..72f50a3
--- /dev/null
+++ b/libs/firebasewarp.py
@@ -0,0 +1,57 @@
+from traceback import format_exc
+
+import firebase_admin
+import requests
+from firebase_admin import db
+
+from libs.logger import LOGS
+
+
+def firebase_auth(Var):
+ if Var.FIREBASE_SERVICE_ACCOUNT_FILE and Var.FIREBASE_URL:
+ if not Var.FIREBASE_SERVICE_ACCOUNT_FILE.startswith("https://"):
+ LOGS.error("Firebase Service Account File Link is Wrong!")
+ exit()
+
+ service_acc = requests.get(Var.FIREBASE_SERVICE_ACCOUNT_FILE).json()
+
+ try:
+ cred = firebase_admin.credentials.Certificate(service_acc)
+ firebase_admin.initialize_app(cred, {"databaseURL": Var.FIREBASE_URL})
+ return db.reference()
+ except BaseException:
+ try:
+ return db.reference()
+ except BaseException:
+ LOGS.error(str(format_exc()))
+ exit()
+
+
+class FireDB:
+ def __init__(self, Var):
+ self.db = firebase_auth(Var)
+ if not self.db:
+ LOGS.info("Something Went Wrong With FireBase")
+ exit()
+
+ def getall(self):
+ return self.db.get() or {}
+
+ @property
+ def og(self):
+ return self.db
+
+ def create_data(self, path, data):
+ return self.db.child(path).set(data)
+
+ def read_data(self, path):
+ value = self.db.child(path).get()
+ if isinstance(value, list):
+ value = list(filter(lambda item: item is not None, value))
+ return value
+
+ def update_data(self, path, data):
+ return self.db.child(path).update(data)
+
+ def delete_data(self, path):
+ return self.db.child(path).delete()
diff --git a/libs/kitsu.py b/libs/kitsu.py
index ff6349c..2bde0a1 100644
--- a/libs/kitsu.py
+++ b/libs/kitsu.py
@@ -31,7 +31,7 @@ async def search(self, query: str):
except BaseException:
_raw_data = {}
if not raw_data:
- data = self.alt_anilist(query)
+ data = {} # self.alt_anilist(query)
return data
data = {}
data["anime_id"] = raw_data.get("id")
@@ -50,7 +50,7 @@ async def search(self, query: str):
# data["score"] = raw_data.get("attributes", {}).get("averageRating") or "N/A"
data["type"] = raw_data.get("attributes", {}).get("showType") or "TV"
data["runtime"] = raw_data.get("attributes", {}).get("episodeLength") or 24
- return {**data, **_raw_data}
+ return {**(data if data else {}), **(_raw_data if _raw_data else {})}
async def searcher(
self,
@@ -64,6 +64,8 @@ async def searcher(
links = (await data.json())["data"]
for index in range(len(links)):
res_data = await self.re_searcher(links[index]["links"]["self"])
+ if res_data["data"]["attributes"]["status"] == "tba":
+ continue
if "current" != res_data["data"]["attributes"]["status"]:
if (
res_data["data"]["attributes"]["endDate"]
diff --git a/libs/logger.py b/libs/logger.py
index 63614a0..0ca86ad 100644
--- a/libs/logger.py
+++ b/libs/logger.py
@@ -18,6 +18,7 @@
import asyncio
import logging
+from traceback import format_exc
from telethon import Button, TelegramClient
from telethon.errors.rpcerrorlist import FloodWaitError
@@ -41,7 +42,7 @@
"""
Auto Anime Bot
Β©οΈ t.me/kAiF_00z (github.com/kaif-00z)
- v0.0.6 (original)
+ v0.0.7 (original)
(2023-24)
[All Rigth Reserved]
@@ -109,4 +110,5 @@ async def report_error(self, msg, log=False):
except ConnectionError:
await self.client.connect()
except Exception as err:
+ LOGS.exception(format_exc())
LOGS.error(str(err))
diff --git a/requirements.txt b/requirements.txt
index 126029d..8e769a3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
python-decouple
-redis
+firebase-admin
lxml_html_clean
aiohttp
aiofiles