433 lines
18 KiB
Python
433 lines
18 KiB
Python
|
|
from lib.logging_data import logger
|
|
|
|
import discord
|
|
from discord import app_commands
|
|
from dotenv import load_dotenv
|
|
from lib.usk import USK
|
|
|
|
from datetime import datetime
|
|
import asyncio
|
|
|
|
from typing import Optional
|
|
import os
|
|
|
|
load_dotenv(".env")
|
|
|
|
if __name__ == "__main__":
|
|
console = logger(app_name="scheduler",log_dir="./log",gotify_config=os.getenv("gotify_token"),discord_config=os.getenv('DISCORD_CHANNEL_ID'))
|
|
console.log("Starting Unshackle Schedule Bot...")
|
|
# bot=ScheduleBot(console)
|
|
# console.client=bot
|
|
usk_scheduler = USK(console)
|
|
console.client=usk_scheduler
|
|
|
|
@usk_scheduler.event
|
|
async def on_ready():
|
|
# console.log(f'{bot.user} has connected to Discord!')
|
|
activity = discord.Game(name="Managing schedules | /help")
|
|
await usk_scheduler.change_presence(activity=activity)
|
|
|
|
|
|
@usk_scheduler.tree.command(name="help", description="Show bot commands and usage")
|
|
async def help_command(interaction: discord.Interaction):
|
|
embed = discord.Embed(
|
|
title="Unshackle Schedule Bot Commands",
|
|
description="Here are the available commands:",
|
|
color=discord.Color.blue()
|
|
)
|
|
embed.add_field(name="/help", value="Show this help message", inline=False)
|
|
embed.add_field(name="/schedule", value="Schedule command", inline=False)
|
|
embed.add_field(name="/get_watchlist", value="Show watchlist", inline=False)
|
|
embed.add_field(name="/add_to_watchlist", value="Add watchlist", inline=False)
|
|
embed.add_field(name="/add_schedule_overwrite", value="Add schedule overwrite", inline=False)
|
|
|
|
await interaction.response.send_message(embed=embed)
|
|
|
|
# Error handling
|
|
@usk_scheduler.tree.error
|
|
async def on_app_command_error(interaction: discord.Interaction, error: app_commands.AppCommandError):
|
|
if isinstance(error, app_commands.CheckFailure):
|
|
embed = discord.Embed(
|
|
title="❌ Permission Denied",
|
|
description="You don't have permission to use this command.",
|
|
color=0xff0000
|
|
)
|
|
if not interaction.response.is_done():
|
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
|
return
|
|
else:
|
|
embed = discord.Embed(
|
|
title="❌ Error",
|
|
description=f"An error occurred: {str(error)}",
|
|
color=0xff0000
|
|
)
|
|
# Get line and file
|
|
console.error("An error occurred")
|
|
channel = usk_scheduler.get_channel(interaction.channel_id)
|
|
|
|
if interaction.response.is_done():
|
|
await interaction.followup.send(embed=embed, ephemeral=True)
|
|
else:
|
|
await channel.send(embed=embed)
|
|
# raise error
|
|
|
|
@usk_scheduler.tree.command(name="schedule", description="Schedule command")
|
|
@app_commands.describe(
|
|
cmd="Command for schedule (e.g., start, check, stop)",
|
|
)
|
|
@app_commands.choices(cmd=[
|
|
app_commands.Choice(name="Start", value="start"),
|
|
app_commands.Choice(name="Check", value="check"),
|
|
app_commands.Choice(name="Stop", value="stop"),
|
|
])
|
|
async def schedule_command(
|
|
interaction: discord.Interaction,
|
|
cmd: str,
|
|
|
|
):
|
|
if cmd == "start":
|
|
|
|
# await interaction.response.send_message("Starting the schedule...")
|
|
# Here you would start your scheduling logic
|
|
|
|
embed = discord.Embed(
|
|
title="Schedule Starting",
|
|
description="The schedule is starting now. Please wait...",
|
|
color=discord.Color.green()
|
|
)
|
|
await interaction.response.send_message(embed=embed)
|
|
|
|
await usk_scheduler.set_today_schedule(interaction)
|
|
|
|
console.log("Schedule started successfully.")
|
|
|
|
|
|
embed = discord.Embed(
|
|
title="Scheduled Jobs",
|
|
description="Here are the currently scheduled jobs:",
|
|
color=discord.Color.blue()
|
|
)
|
|
jobs = usk_scheduler.scheduler.get_jobs()
|
|
for job in jobs:
|
|
if job:
|
|
embed.add_field(
|
|
name=job.id,
|
|
value=f"Next run time: {job.next_run_time.strftime('%Y-%m-%d %H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
await asyncio.sleep(1)
|
|
await interaction.followup.send(embed=embed)
|
|
|
|
|
|
|
|
elif cmd == "check":
|
|
# Here you would check the current schedule
|
|
embed = discord.Embed(
|
|
title="Today's Schedule",
|
|
description="Here is the current schedule for today:",
|
|
color=discord.Color.blue()
|
|
)
|
|
# schedule = bot.sonarr.get_today_schedule()
|
|
queue=usk_scheduler.db.get_today_queue()
|
|
# print(queue)
|
|
# exit()
|
|
if queue:
|
|
for item in queue:
|
|
embed.add_field(
|
|
name=f"{item['title']} (S{item['season']:02}E{item['episode']:02}) - {item['status']}",
|
|
value=f"Air Date: {datetime.fromtimestamp(item['start_timestamp']).strftime('%Y-%m-%d %H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
else:
|
|
embed.add_field(name="No Queue", value="There are no queued episodes for today.", inline=False)
|
|
|
|
jobs = usk_scheduler.scheduler.get_jobs()
|
|
|
|
if jobs:
|
|
job_list = "\n".join([f"{job.id} - {job.next_run_time}" for job in jobs])
|
|
embed.add_field(name="Scheduled Jobs", value=job_list, inline=False)
|
|
else:
|
|
embed.add_field(name="No Scheduled Jobs", value="There are no scheduled jobs at the moment.", inline=False)
|
|
await interaction.response.send_message(embed=embed)
|
|
console.log('Checked the queue successfully.')
|
|
|
|
elif cmd == "stop":
|
|
await interaction.response.send_message("Stopping the schedule...")
|
|
# Here you would stop your scheduling logic
|
|
usk_scheduler.scheduler.shutdown(wait=False)
|
|
await interaction.followup.send("Schedule stopped.")
|
|
console.log('Schedule stopped successfully.')
|
|
|
|
@usk_scheduler.tree.command(name="recheck", description="recheck schedule by weekday")
|
|
@app_commands.describe(
|
|
weekday="Day of the week (0=Monday, 6=Sunday)",
|
|
)
|
|
@app_commands.choices(weekday=[
|
|
app_commands.Choice(name="Monday", value='1'),
|
|
app_commands.Choice(name="Tuesday", value='2'),
|
|
app_commands.Choice(name="Wednesday", value='3'),
|
|
app_commands.Choice(name="Thursday", value='4'),
|
|
app_commands.Choice(name="Friday", value='5'),
|
|
app_commands.Choice(name="Saturday", value='6'),
|
|
app_commands.Choice(name="Sunday", value='7'),
|
|
app_commands.Choice(name="All", value='8'),
|
|
|
|
])
|
|
async def recheck_command(
|
|
interaction: discord.Interaction,
|
|
weekday: str,
|
|
|
|
):
|
|
weekday=int(weekday)
|
|
weekday_name = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "All"][weekday-1]
|
|
await interaction.response.send_message(f"Rechecking schedule for {weekday_name}...")
|
|
# Here you would start your scheduling logic
|
|
await usk_scheduler.recheck_day(weekday,interaction)
|
|
console.log(f"Rechecked the schedule for {weekday_name} successfully.")
|
|
await asyncio.sleep(1)
|
|
await interaction.followup.send(f"Rechecked the schedule for {weekday_name} successfully.")
|
|
|
|
@usk_scheduler.tree.command(name="recheck_title", description="recheck schedule by title")
|
|
@app_commands.describe(
|
|
title="Title of the show"
|
|
)
|
|
async def recheck_title_command(
|
|
interaction: discord.Interaction,
|
|
title: str,
|
|
season: Optional[int] = None,
|
|
episode: Optional[int] = None,
|
|
|
|
):
|
|
await interaction.response.send_message(f"Rechecking schedule for {title}...")
|
|
# Here you would start your scheduling logic
|
|
await usk_scheduler.recheck_Title(title,interaction,season,episode)
|
|
console.log(f"Rechecked the schedule for {title} successfully.")
|
|
await asyncio.sleep(1)
|
|
await interaction.followup.send(f"Rechecked the schedule for {title} successfully.")
|
|
|
|
|
|
@usk_scheduler.tree.command(name="get_watchlist", description="Get watchlist command")
|
|
async def get_watchlist_command(interaction: discord.Interaction):
|
|
watchlist = usk_scheduler.db.get_watchlist()
|
|
if not watchlist:
|
|
await interaction.response.send_message("Your watchlist is empty.")
|
|
return
|
|
|
|
MAX_EMBED_CHARS = 5900 # Stay safely under 6000 char limit
|
|
embeds = []
|
|
current_embed = discord.Embed(
|
|
title="Your Watchlist",
|
|
description="Here are the shows in your watchlist:",
|
|
color=discord.Color.green()
|
|
)
|
|
total_chars = len(current_embed.title) + len(current_embed.description)
|
|
|
|
for show in watchlist:
|
|
field_name = show['Title']
|
|
field_value = (
|
|
f"Service: {show['Service']}\n"
|
|
f"URL: {show['url']}\n"
|
|
f"Quality: {show['quality']}\n"
|
|
f"Codec: {show['codec']}\n"
|
|
f"Range: {show['range']}\n"
|
|
f"Audio lang: {show['audio_lang']}\n"
|
|
f"Subtitle lang: {show['sub_lang']}"
|
|
)
|
|
|
|
# Check if adding this field would exceed the limit
|
|
if total_chars + len(field_name) + len(field_value) > MAX_EMBED_CHARS:
|
|
embeds.append(current_embed)
|
|
current_embed = discord.Embed(color=discord.Color.green())
|
|
total_chars = 0
|
|
|
|
current_embed.add_field(name=field_name, value=field_value, inline=False)
|
|
total_chars += len(field_name) + len(field_value)
|
|
|
|
# Add the last embed
|
|
embeds.append(current_embed)
|
|
|
|
# Send embeds
|
|
for i, embed in enumerate(embeds):
|
|
if i == 0:
|
|
await interaction.response.send_message(embed=embed)
|
|
else:
|
|
await interaction.followup.send(embed=embed)
|
|
|
|
console.log('Fetched watchlist successfully.')
|
|
|
|
@usk_scheduler.tree.command(name="add_to_watchlist", description="Add watchlist command")
|
|
@app_commands.describe(
|
|
id_="ID of the show as Sonarr ID (e.g., 12345)",
|
|
service="Service (e.g., BLBL, TID, MMAX)",
|
|
title="Title of the show",
|
|
url="URL of the show can be ID or URL",
|
|
audio_lang="Audio language (e.g., en, jp)",
|
|
sub_lang="Subtitle language (e.g., en, jp)",
|
|
quality="Quality of the show (e.g., 1080p, 720p)",
|
|
codec="Codec used (e.g., h264, h265)",
|
|
range_="Range of episodes (e.g., SDR,HDR)",
|
|
audio_channel="Audio channel (e.g., 2.0,5.1)",
|
|
season="Season number (e.g., 1, 2)",
|
|
|
|
# for BiliBili
|
|
if_dub="For BiliBili : If the show is dubbed (e.g., True, False)",
|
|
url_org="For BiliBili : URL of the original show (if applicable)",
|
|
|
|
title_lang="For BiliBili : Title language (e.g., en, jp)",
|
|
org_lang="For BiliBili : Original language (e.g., en, jp)",
|
|
|
|
)
|
|
@app_commands.choices(service=[
|
|
app_commands.Choice(name="Amazon Prime", value="AMZN"),
|
|
app_commands.Choice(name="Netflix", value="NF"),
|
|
app_commands.Choice(name="Hotstar", value="HS"),
|
|
app_commands.Choice(name="VIU", value="VIU"),
|
|
app_commands.Choice(name="TrueID", value="TID"),
|
|
app_commands.Choice(name="Mono Max", value="MMAX"),
|
|
app_commands.Choice(name="BiliBili", value="BLBL"),
|
|
app_commands.Choice(name="FutureSkill", value="FSK"),
|
|
app_commands.Choice(name="HBO Max", value="HMAX"),
|
|
app_commands.Choice(name="iQIYI", value="IQ"),
|
|
app_commands.Choice(name="WeTV", value="WTV"),
|
|
app_commands.Choice(name="Crunchyroll", value="CR"),
|
|
app_commands.Choice(name="Laftel", value="LT"),
|
|
])
|
|
@app_commands.choices(if_dub=[
|
|
app_commands.Choice(name="True", value="True"),
|
|
app_commands.Choice(name="False", value="False"),
|
|
|
|
])
|
|
@app_commands.choices(quality=[
|
|
app_commands.Choice(name="2160p", value="2160"),
|
|
app_commands.Choice(name="1440p", value="1440"),
|
|
app_commands.Choice(name="1080p", value="1080"),
|
|
app_commands.Choice(name="720p", value="720"),
|
|
app_commands.Choice(name="480p", value="480"),
|
|
app_commands.Choice(name="Best", value="Best"),
|
|
])
|
|
@app_commands.choices(codec=[
|
|
app_commands.Choice(name="H265", value="265"),
|
|
app_commands.Choice(name="H264", value="264"),
|
|
])
|
|
@app_commands.choices(range_=[
|
|
app_commands.Choice(name="HDR", value="HDR"),
|
|
app_commands.Choice(name="SDR", value="SDR"),
|
|
])
|
|
@app_commands.choices(audio_channel=[
|
|
app_commands.Choice(name="2.0", value="20"),
|
|
app_commands.Choice(name="5.1", value="51"),
|
|
app_commands.Choice(name="Best", value= "Best"),
|
|
])
|
|
async def add_to_watchlist_command(
|
|
interaction: discord.Interaction,
|
|
id_: int,
|
|
service: str,
|
|
title: str,
|
|
url: str,
|
|
|
|
audio_lang: str = "orig,th",
|
|
sub_lang: str = "orig,th,en",
|
|
quality:str = '1080',
|
|
codec: str = '264',
|
|
range_: str = 'SDR',
|
|
audio_channel: str = None,
|
|
|
|
|
|
#for BiliBili
|
|
if_dub: str = "False",
|
|
url_org: str = None,
|
|
season: str = None,
|
|
title_lang: str = None,
|
|
org_lang: str = None,
|
|
|
|
):
|
|
entry = {
|
|
'ID': id_,
|
|
'Service': service,
|
|
'Title': title,
|
|
'url': url,
|
|
'audio_lang': audio_lang,
|
|
'sub_lang': sub_lang,
|
|
'quality': int(quality),
|
|
'codec': int(codec),
|
|
'range': range_,
|
|
'audio_channel': audio_channel,
|
|
|
|
'if_dub': True if if_dub.lower() == "true" else False,
|
|
'url_org': url_org,
|
|
'season': int(season),
|
|
'title_lang': title_lang,
|
|
'org_lang': org_lang
|
|
}
|
|
|
|
usk_scheduler.db.add_watchlist(entry)
|
|
|
|
embed = discord.Embed(
|
|
title="Watchlist Entry Added",
|
|
description=f"Added **{title}** to your watchlist.",
|
|
color=discord.Color.green()
|
|
)
|
|
|
|
await interaction.response.send_message(embed=embed)
|
|
console.log(f'Added {title} to watchlist successfully.')
|
|
|
|
@usk_scheduler.tree.command(name="add_schedule", description="Add schedule command")
|
|
@app_commands.describe(
|
|
title="Title of the show",
|
|
air_time="Air time of the show (format: HHMM, e.g., 2100 for 9 PM)",
|
|
day_of_week="Day of the week (Monday, Sunday or Monday,Sunday)",
|
|
offset="Offset episode (e.g., 0 for no offset, 1 for next episode)",
|
|
)
|
|
# @app_commands.choices(title=[
|
|
# app_commands.Choice(name=f'{t['Title'][:15]} season {t['season']}', value=t['Title'][:20]) for t in sorted(bot.db.get_watchlist(), key=lambda x: x["Title"], reverse=True)
|
|
# ])
|
|
async def add_schedule_command(interaction: discord.Interaction,
|
|
title: str,
|
|
air_time: str,
|
|
day_of_week: str,
|
|
offset: int = 0):
|
|
entry = {
|
|
'title': title,
|
|
'air_time': air_time,
|
|
'day_of_week': day_of_week,
|
|
'offset': offset
|
|
}
|
|
status=usk_scheduler.db.add_overwrite_schedule(entry)
|
|
# console.log(f'Added schedule overwrite for {title} at {air_time} on {day_of_week} with offset {offset}. Status: {status}')
|
|
if status == 'No changes made, entry already exists.':
|
|
console.log(f'Schedule overwrite for {title} at {air_time} on {day_of_week} with offset {offset} already exists.')
|
|
embed = discord.Embed(
|
|
title="Schedule Overwrite Already Exists",
|
|
description=f"An overwrite for **{title}** at **{air_time}** on **{day_of_week}** with offset **{offset}** already exists.",
|
|
color=discord.Color.orange()
|
|
)
|
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
|
return
|
|
elif status == 'Entry added or updated successfully.':
|
|
# If the entry was added or updated successfully, send a confirmation message
|
|
console.log(f'Schedule overwrite for {title} at {air_time} on {day_of_week} with offset {offset} added or updated successfully.')
|
|
embed = discord.Embed(
|
|
title="Schedule Overwrite Added",
|
|
description=f"Added schedule overwrite for **{title}** at **{air_time}** on **{day_of_week}** with offset **{offset}**.",
|
|
color=discord.Color.green()
|
|
)
|
|
await interaction.response.send_message(embed=embed)
|
|
return
|
|
|
|
token = os.getenv("DISCORD_TOKEN")
|
|
if not token:
|
|
print("❌ DISCORD_TOKEN not found in environment variables!")
|
|
print("Make sure you have a .env file with your bot token.")
|
|
else:
|
|
try:
|
|
# bot.usk_scheduler.set_today_schedule() # Initialize the schedule
|
|
usk_scheduler.run(token, log_handler=None)
|
|
except discord.LoginFailure:
|
|
print("❌ Invalid bot token! Please check your DISCORD_TOKEN in the .env file.")
|
|
except Exception as e:
|
|
print(f"❌ An error occurred: {e}")
|
|
|
|
|
|
|