Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions autopublisher/autopublisher.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,8 @@

from .dashboard_integration import DashboardIntegration
from .utils import (
get_next_reset_times,
get_owner_timezone,
increment_published_count,
initialize_scheduler,
reset_count,
schedule_resets,
)
from .view import IgnoredNewsChannelsView, StatsView
Expand Down Expand Up @@ -72,17 +69,15 @@ def __init__(self, bot: Red) -> None:
self.config.register_guild(**default_guild)
self.config.register_global(**default_global)
self.scheduler = None
self.bot.loop.create_task(self._initialize_scheduler())

async def _initialize_scheduler(self) -> None:
"""Initialize the scheduler after cog is loaded."""
async def cog_load(self) -> None:
"""Initialize the scheduler when the cog is loaded."""
self.scheduler = await initialize_scheduler(self)
await schedule_resets(self)

def cog_unload(self) -> None:
"""Clean up scheduler on cog unload."""
if self.scheduler and self.scheduler.running:
self.scheduler.remove_all_jobs()
self.scheduler.shutdown()
logger.debug("Scheduler shut down")

Expand Down Expand Up @@ -129,8 +124,22 @@ async def on_message_without_command(self, message: discord.Message) -> None:
await asyncio.sleep(0.5)
await asyncio.wait_for(message.publish(), timeout=60)
await increment_published_count(self.config)
except (discord.HTTPException, discord.Forbidden, asyncio.TimeoutError) as e:
logger.error(f"Failed to publish message in {message.channel.id}: {e}", exc_info=True)
except asyncio.TimeoutError:
logger.error(f"Timed out publishing message in {message.channel.id}")
except discord.Forbidden as e:
logger.error(
f"Missing permissions to publish in {message.channel.id}: {e}", exc_info=True
)
except discord.HTTPException as e:
if e.status == 429:
logger.warning(
f"Rate limited when publishing in {message.channel.id}. "
"Discord limits 10 publishes/hour per channel."
)
else:
logger.error(
f"Failed to publish message in {message.channel.id}: {e}", exc_info=True
)

@commands.guild_only()
@commands.admin_or_permissions(manage_guild=True)
Expand Down Expand Up @@ -283,15 +292,6 @@ async def resetcount(self, ctx: commands.Context) -> None:
await view.wait()
if view.result:
await self.config.clear_all_globals()
# Re-register defaults
await self.config.register_global(
published_count=0,
published_weekly_count=0,
published_monthly_count=0,
published_yearly_count=0,
last_count_time=None,
timezone="UTC",
)
await ctx.send("Counts reset.")
else:
await ctx.send("Reset cancelled.")
3 changes: 2 additions & 1 deletion autopublisher/info.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"tags": [
"news",
"autopublish",
"autopublisher"
"autopublisher",
"Dashboard Integrated"
],
"permissions": [
"manage_messages",
Expand Down
40 changes: 13 additions & 27 deletions autopublisher/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ async def get_owner_timezone(config: Config) -> pytz.timezone:

async def initialize_scheduler(cog: commands.Cog) -> AsyncIOScheduler:
"""Initialize the scheduler."""
scheduler = AsyncIOScheduler()
try:
scheduler = AsyncIOScheduler()
logger.info("Scheduler initialized successfully.")
return scheduler
except Exception as e:
logger.error(f"Failed to initialize scheduler: {e}", exc_info=True)
return scheduler
raise


async def schedule_resets(cog: commands.Cog) -> None:
Expand Down Expand Up @@ -133,9 +134,9 @@ def get_next_reset_times(owner_tz: pytz.timezone) -> tuple[int, int, int]:

# Weekly reset: Next Sunday
days_until_sunday = (6 - now.weekday()) % 7
if days_until_sunday == 0 and now.hour >= 0:
if days_until_sunday == 0:
days_until_sunday = 7
next_weekly = datetime(
next_weekly_naive = datetime(
year=now.year,
month=now.month,
day=now.day,
Expand All @@ -144,35 +145,20 @@ def get_next_reset_times(owner_tz: pytz.timezone) -> tuple[int, int, int]:
second=0,
microsecond=0,
) + timedelta(days=days_until_sunday)
next_weekly = owner_tz.localize(next_weekly)
next_weekly = owner_tz.normalize(owner_tz.localize(next_weekly_naive, is_dst=False))
next_weekly_ts = int(next_weekly.timestamp())

# Monthly reset: First day of next month
next_month = datetime(
year=now.year,
month=now.month,
day=1,
hour=0,
minute=0,
second=0,
microsecond=0,
) + timedelta(days=32)
next_month = next_month.replace(day=1)
next_month = owner_tz.localize(next_month)
if now.month == 12:
next_month_naive = datetime(year=now.year + 1, month=1, day=1)
else:
next_month_naive = datetime(year=now.year, month=now.month + 1, day=1)
next_month = owner_tz.normalize(owner_tz.localize(next_month_naive, is_dst=False))
next_monthly_ts = int(next_month.timestamp())

# Yearly reset: January 1st of next year
next_year = now.year + 1 if now.month > 1 or (now.month == 1 and now.day > 1) else now.year
next_yearly = datetime(
year=next_year,
month=1,
day=1,
hour=0,
minute=0,
second=0,
microsecond=0,
)
next_yearly = owner_tz.localize(next_yearly)
next_yearly_naive = datetime(year=now.year + 1, month=1, day=1)
next_yearly = owner_tz.normalize(owner_tz.localize(next_yearly_naive, is_dst=False))
next_yearly_ts = int(next_yearly.timestamp())

return next_weekly_ts, next_monthly_ts, next_yearly_ts
15 changes: 13 additions & 2 deletions autopublisher/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def __init__(self, cog: commands.Cog) -> None:
channel_types=[discord.ChannelType.news],
placeholder="Select the news channels to ignore.",
min_values=0,
max_values=25,
)
self.select.callback = self.select_callback
self.container.add_item(discord.ui.ActionRow(self.select))
Expand Down Expand Up @@ -128,6 +129,10 @@ async def save_callback(self, interaction: discord.Interaction) -> None:
)

await self.cog.config.guild(self.ctx.guild).ignored_channels.set(new_ignored_channels)
self.select.default_values = [
discord.SelectDefaultValue(type="channel", id=channel.id)
for channel in self.ignored_channels
]
await interaction.response.send_message(
":white_check_mark: Ignored discord news channel(s) saved!", ephemeral=True
)
Expand All @@ -142,11 +147,15 @@ async def unignore_callback(self, interaction: discord.Interaction) -> None:
)

await self.cog.config.guild(self.ctx.guild).ignored_channels.set([])
self.ignored_channels = []
self.select.default_values = []
await interaction.response.send_message(
":white_check_mark: Ignored discord news channel(s) removed!", ephemeral=True
)
self.ignored_channels = []
self.select.default_values = []
try:
await self.message.edit(view=self)
except discord.HTTPException as e:
log.error(f"Failed to update view after unignore: {e}")


class StatsView(discord.ui.LayoutView):
Expand Down Expand Up @@ -241,6 +250,8 @@ async def on_timeout(self) -> None:
"""Handle view timeout."""
self.refresh_button.disabled = True
self.close_button.disabled = True
if self.message is None:
return
try:
await self.message.edit(view=self)
except discord.HTTPException as e:
Expand Down
Loading