Expand Discord download and Jellyfin notifications

This commit is contained in:
Dymas
2026-05-25 19:40:51 +02:00
parent 75262d261d
commit c006fb2d1d
6 changed files with 306 additions and 10 deletions
+129
View File
@@ -531,6 +531,7 @@ class DownloadQueueWorkerFailureTests(unittest.TestCase):
self.assertEqual(send_webhook.call_args.args[1], "download_completed")
self.assertEqual(send_webhook.call_args.args[2]["title"], "Queue Show")
self.assertEqual(send_webhook.call_args.args[2]["category"], "finished")
self.assertEqual(send_webhook.call_args.args[2]["moved_files"], ["/tmp/example/Queue Show - S01E01.mp4"])
class WatchlistRefreshAllTests(unittest.TestCase):
@@ -1320,6 +1321,82 @@ class JellyfinSyncTests(unittest.TestCase):
self.assertTrue(target_file.exists())
self.assertFalse((download_root / "tv" / "Jelly Show").exists())
def test_trigger_jellyfin_sync_for_item_sends_success_notification(self):
self.seed_watchlist_item()
item = APP.WATCHLIST.get("show-jelly-1")
with tempfile.TemporaryDirectory() as temp_root:
download_root = Path(temp_root) / "downloads"
source_file = download_root / "tv" / "Jelly Show" / "Season 01" / "Jelly Show - S01E01.mp4"
source_file.parent.mkdir(parents=True, exist_ok=True)
source_file.write_bytes(b"episode-data")
jellyfin_tv = Path(temp_root) / "jellyfin-tv"
with mock.patch.object(APP, "send_discord_webhook_event") as send_webhook:
result = APP.trigger_jellyfin_sync_for_item(
item,
automatic=True,
config={
"download_dir": str(download_root),
"jellyfin_sync_enabled": True,
"jellyfin_tv_dir": str(jellyfin_tv),
"jellyfin_movie_dir": "",
"discord_webhook_url": "https://discord.example/webhook",
"discord_webhook_events": ["jellyfin_sync_success"],
},
)
self.assertTrue(result["moved"])
send_webhook.assert_called_once()
self.assertEqual(send_webhook.call_args.args[1], "jellyfin_sync_success")
self.assertEqual(send_webhook.call_args.args[2]["title"], "Jelly Show")
self.assertEqual(send_webhook.call_args.args[2]["source"], "automatic")
def test_trigger_jellyfin_sync_for_item_sends_failure_notification(self):
self.seed_watchlist_item()
item = APP.WATCHLIST.get("show-jelly-1")
with mock.patch.object(APP, "send_discord_webhook_event") as send_webhook:
result = APP.trigger_jellyfin_sync_for_item(
item,
automatic=True,
config={
"download_dir": "/tmp/example",
"jellyfin_sync_enabled": True,
"jellyfin_tv_dir": "",
"jellyfin_movie_dir": "",
"discord_webhook_url": "https://discord.example/webhook",
"discord_webhook_events": ["jellyfin_sync_failed"],
},
)
self.assertFalse(result["moved"])
self.assertEqual(result["reason"], "target_missing")
send_webhook.assert_called_once()
self.assertEqual(send_webhook.call_args.args[1], "jellyfin_sync_failed")
self.assertEqual(send_webhook.call_args.args[2]["reason"], "target_missing")
def test_trigger_jellyfin_sync_for_item_skips_already_moved_notification(self):
self.seed_watchlist_item()
item = APP.WATCHLIST.get("show-jelly-1")
with tempfile.TemporaryDirectory() as temp_root:
jellyfin_tv = Path(temp_root) / "jellyfin-tv" / "Jelly Show"
jellyfin_tv.mkdir(parents=True, exist_ok=True)
with mock.patch.object(APP, "send_discord_webhook_event") as send_webhook:
result = APP.trigger_jellyfin_sync_for_item(
item,
automatic=False,
config={
"download_dir": str(Path(temp_root) / "downloads"),
"jellyfin_sync_enabled": True,
"jellyfin_tv_dir": str(Path(temp_root) / "jellyfin-tv"),
"jellyfin_movie_dir": "",
"discord_webhook_url": "https://discord.example/webhook",
"discord_webhook_events": ["jellyfin_sync_failed", "jellyfin_sync_success"],
},
)
self.assertFalse(result["moved"])
self.assertEqual(result["reason"], "already_moved")
send_webhook.assert_not_called()
def test_trigger_jellyfin_sync_for_item_skips_incomplete_series(self):
self.seed_watchlist_item(expected_count=24, downloaded_sub_episodes_json=APP.encode_episode_values([str(index) for index in range(1, 13)]))
item = APP.WATCHLIST.get("show-jelly-1")
@@ -1686,6 +1763,58 @@ class WatchlistAutoRefreshSchedulerTests(unittest.TestCase):
self.assertEqual(send_webhook.call_args_list[1].args[1], "watchlist_refresh_failed")
self.assertEqual(send_webhook.call_args_list[1].args[2]["items"][0]["title"], "Show B")
class DiscordWebhookFormattingTests(unittest.TestCase):
def test_download_completed_webhook_sends_full_file_list_across_embeds(self):
payloads = []
with mock.patch.object(APP.app_support, "_post_discord_webhook", side_effect=lambda url, payload, attachments=None, timeout=10: payloads.append(payload)):
result = APP.app_support.send_discord_webhook_event(
{
"discord_webhook_url": "https://discord.example/webhook",
"discord_webhook_events": ["download_completed"],
},
"download_completed",
{
"title": "Big Download",
"mode": "sub",
"episodes": "1-12",
"category": "finished",
"moved_files": [f"/tmp/downloads/Big Download/File {index:02d}.mp4" for index in range(1, 130)],
},
)
self.assertTrue(result["sent"])
self.assertGreaterEqual(len(payloads), 1)
all_descriptions = "\n".join(
embed.get("description", "")
for payload in payloads
for embed in payload.get("embeds", [])
)
self.assertIn("/tmp/downloads/Big Download/File 01.mp4", all_descriptions)
self.assertIn("/tmp/downloads/Big Download/File 129.mp4", all_descriptions)
def test_jellyfin_success_webhook_includes_moved_files(self):
payloads = []
with mock.patch.object(APP.app_support, "_post_discord_webhook", side_effect=lambda url, payload, attachments=None, timeout=10: payloads.append(payload)):
result = APP.app_support.send_discord_webhook_event(
{
"discord_webhook_url": "https://discord.example/webhook",
"discord_webhook_events": ["jellyfin_sync_success"],
},
"jellyfin_sync_success",
{
"title": "Jelly Show",
"media_type": "tv",
"source": "automatic",
"target": "/srv/jellyfin/Jelly Show",
"moved_files": ["/srv/jellyfin/Jelly Show/Season 01/Jelly Show - S01E01.mp4"],
},
)
self.assertTrue(result["sent"])
self.assertEqual(payloads[0]["content"], "ani-cli-web moved a finished library into Jellyfin.")
self.assertIn("/srv/jellyfin/Jelly Show/Season 01/Jelly Show - S01E01.mp4", payloads[0]["embeds"][1]["description"])
def test_tick_resets_timer_when_schedule_changes(self):
config = {
"watchlist_auto_refresh_enabled": True,