aa-rss-to-discord 2.4.0__py3-none-any.whl → 2.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. aa_rss_to_discord/__init__.py +1 -1
  2. aa_rss_to_discord/locale/cs_CZ/LC_MESSAGES/django.po +1 -1
  3. aa_rss_to_discord/locale/de/LC_MESSAGES/django.po +1 -1
  4. aa_rss_to_discord/locale/django.pot +2 -2
  5. aa_rss_to_discord/locale/es/LC_MESSAGES/django.mo +0 -0
  6. aa_rss_to_discord/locale/es/LC_MESSAGES/django.po +7 -5
  7. aa_rss_to_discord/locale/fr_FR/LC_MESSAGES/django.po +1 -1
  8. aa_rss_to_discord/locale/it_IT/LC_MESSAGES/django.po +1 -1
  9. aa_rss_to_discord/locale/ja/LC_MESSAGES/django.po +1 -1
  10. aa_rss_to_discord/locale/ko_KR/LC_MESSAGES/django.po +1 -1
  11. aa_rss_to_discord/locale/nl_NL/LC_MESSAGES/django.mo +0 -0
  12. aa_rss_to_discord/locale/nl_NL/LC_MESSAGES/django.po +6 -7
  13. aa_rss_to_discord/locale/pl_PL/LC_MESSAGES/django.po +1 -1
  14. aa_rss_to_discord/locale/ru/LC_MESSAGES/django.po +1 -1
  15. aa_rss_to_discord/locale/sk/LC_MESSAGES/django.po +1 -1
  16. aa_rss_to_discord/locale/uk/LC_MESSAGES/django.mo +0 -0
  17. aa_rss_to_discord/locale/uk/LC_MESSAGES/django.po +6 -5
  18. aa_rss_to_discord/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  19. aa_rss_to_discord/locale/zh_Hans/LC_MESSAGES/django.po +11 -12
  20. aa_rss_to_discord/tasks.py +81 -58
  21. aa_rss_to_discord/tests/test_tasks.py +165 -105
  22. {aa_rss_to_discord-2.4.0.dist-info → aa_rss_to_discord-2.5.1.dist-info}/METADATA +4 -4
  23. {aa_rss_to_discord-2.4.0.dist-info → aa_rss_to_discord-2.5.1.dist-info}/RECORD +25 -25
  24. {aa_rss_to_discord-2.4.0.dist-info → aa_rss_to_discord-2.5.1.dist-info}/WHEEL +0 -0
  25. {aa_rss_to_discord-2.4.0.dist-info → aa_rss_to_discord-2.5.1.dist-info}/licenses/LICENSE +0 -0
@@ -5,6 +5,6 @@ App init
5
5
  # Django
6
6
  from django.utils.translation import gettext_lazy as _
7
7
 
8
- __version__ = "2.4.0"
8
+ __version__ = "2.5.1"
9
9
  __title__ = "RSS to Discord"
10
10
  __title_translated__ = _("RSS to Discord")
@@ -7,7 +7,7 @@ msgid ""
7
7
  msgstr ""
8
8
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
9
9
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
10
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
10
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
11
11
  "PO-Revision-Date: 2024-05-10 14:10+0000\n"
12
12
  "Last-Translator: Anonymous <noreply@weblate.org>\n"
13
13
  "Language-Team: Czech <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/cs/>\n"
@@ -6,7 +6,7 @@ msgid ""
6
6
  msgstr ""
7
7
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
8
8
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
9
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
9
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
10
10
  "PO-Revision-Date: 2025-04-25 14:24+0000\n"
11
11
  "Last-Translator: Peter Pfeufer <info@ppfeufer.de>\n"
12
12
  "Language-Team: German <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/de/>\n"
@@ -6,9 +6,9 @@
6
6
  #, fuzzy
7
7
  msgid ""
8
8
  msgstr ""
9
- "Project-Id-Version: AA RSS to Discord 2.4.0\n"
9
+ "Project-Id-Version: AA RSS to Discord 2.5.1\n"
10
10
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
11
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
11
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
12
12
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -2,24 +2,26 @@
2
2
  # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
4
  # Zigor Fernandez Moreno <sietehierros@gmail.com>, 2023, 2024.
5
+ # Ivan <isangar2000@gmail.com>, 2025.
5
6
  msgid ""
6
7
  msgstr ""
7
8
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
8
9
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
9
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
10
- "PO-Revision-Date: 2024-05-10 14:10+0000\n"
11
- "Last-Translator: Zigor Fernandez Moreno <sietehierros@gmail.com>\n"
10
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
11
+ "PO-Revision-Date: 2025-12-18 23:47+0000\n"
12
+ "Last-Translator: Ivan <isangar2000@gmail.com>\n"
12
13
  "Language-Team: Spanish <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/es/>\n"
13
14
  "Language: es\n"
14
15
  "MIME-Version: 1.0\n"
15
16
  "Content-Type: text/plain; charset=UTF-8\n"
16
17
  "Content-Transfer-Encoding: 8bit\n"
17
18
  "Plural-Forms: nplurals=2; plural=n != 1;\n"
18
- "X-Generator: Weblate 5.5.3\n"
19
+ "X-Generator: Weblate 5.14.3\n"
19
20
 
20
21
  #: aa_rss_to_discord/__init__.py:10
22
+ #, fuzzy
21
23
  msgid "RSS to Discord"
22
- msgstr ""
24
+ msgstr "RSS ir discord"
23
25
 
24
26
  #: aa_rss_to_discord/models.py:44
25
27
  msgid "RSS Feed"
@@ -9,7 +9,7 @@ msgid ""
9
9
  msgstr ""
10
10
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
11
11
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
12
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
12
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
13
13
  "PO-Revision-Date: 2025-08-03 04:24+0000\n"
14
14
  "Last-Translator: The “Devcutter” Guy <mick162534@gmail.com>\n"
15
15
  "Language-Team: French <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/fr/>\n"
@@ -7,7 +7,7 @@ msgid ""
7
7
  msgstr ""
8
8
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
9
9
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
10
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
10
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
11
11
  "PO-Revision-Date: 2024-05-10 14:10+0000\n"
12
12
  "Last-Translator: Anonymous <noreply@weblate.org>\n"
13
13
  "Language-Team: Italian <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/it/>\n"
@@ -6,7 +6,7 @@ msgid ""
6
6
  msgstr ""
7
7
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
8
8
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
9
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
9
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
10
10
  "PO-Revision-Date: 2024-08-05 10:10+0000\n"
11
11
  "Last-Translator: Anata_no_Usiro <yt23542354m@gmail.com>\n"
12
12
  "Language-Team: Japanese <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/ja/>\n"
@@ -7,7 +7,7 @@ msgid ""
7
7
  msgstr ""
8
8
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
9
9
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
10
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
10
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
11
11
  "PO-Revision-Date: 2024-05-10 14:10+0000\n"
12
12
  "Last-Translator: Hue Radient <seataoji@gmail.com>\n"
13
13
  "Language-Team: Korean <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/ko/>\n"
@@ -1,26 +1,25 @@
1
1
  # SOME DESCRIPTIVE TITLE.
2
2
  # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
- # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
4
+ # Peter Pfeufer <info@ppfeufer.de>, 2026.
6
5
  msgid ""
7
6
  msgstr ""
8
7
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
9
8
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
10
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
11
- "PO-Revision-Date: 2024-05-10 14:10+0000\n"
12
- "Last-Translator: Anonymous <noreply@weblate.org>\n"
9
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
10
+ "PO-Revision-Date: 2026-02-01 14:23+0000\n"
11
+ "Last-Translator: Peter Pfeufer <info@ppfeufer.de>\n"
13
12
  "Language-Team: Dutch <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/nl/>\n"
14
13
  "Language: nl_NL\n"
15
14
  "MIME-Version: 1.0\n"
16
15
  "Content-Type: text/plain; charset=UTF-8\n"
17
16
  "Content-Transfer-Encoding: 8bit\n"
18
17
  "Plural-Forms: nplurals=2; plural=n != 1;\n"
19
- "X-Generator: Weblate 5.5.3\n"
18
+ "X-Generator: Weblate 5.15.2\n"
20
19
 
21
20
  #: aa_rss_to_discord/__init__.py:10
22
21
  msgid "RSS to Discord"
23
- msgstr ""
22
+ msgstr "RSS naar Discord"
24
23
 
25
24
  #: aa_rss_to_discord/models.py:44
26
25
  msgid "RSS Feed"
@@ -7,7 +7,7 @@ msgid ""
7
7
  msgstr ""
8
8
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
9
9
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
10
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
10
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
11
11
  "PO-Revision-Date: 2024-05-10 14:10+0000\n"
12
12
  "Last-Translator: Anonymous <noreply@weblate.org>\n"
13
13
  "Language-Team: Polish <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/pl/>\n"
@@ -7,7 +7,7 @@ msgid ""
7
7
  msgstr ""
8
8
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
9
9
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
10
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
10
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
11
11
  "PO-Revision-Date: 2024-05-10 14:10+0000\n"
12
12
  "Last-Translator: Dromiel <dimhry@yandex.ru>\n"
13
13
  "Language-Team: Russian <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/ru/>\n"
@@ -7,7 +7,7 @@ msgid ""
7
7
  msgstr ""
8
8
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
9
9
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
10
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
10
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
11
11
  "PO-Revision-Date: 2024-05-10 14:10+0000\n"
12
12
  "Last-Translator: Anonymous <noreply@weblate.org>\n"
13
13
  "Language-Team: Slovak <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/sk/>\n"
@@ -3,20 +3,21 @@
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
4
  # Peter Pfeufer <info@ppfeufer.de>, 2023, 2024.
5
5
  # s0k0l -_- <salarysalo@gmail.com>, 2025.
6
+ # Варрус <horowiserus@gmail.com>, 2025.
6
7
  msgid ""
7
8
  msgstr ""
8
9
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
9
10
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
10
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
11
- "PO-Revision-Date: 2025-08-27 20:43+0000\n"
12
- "Last-Translator: s0k0l -_- <salarysalo@gmail.com>\n"
11
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
12
+ "PO-Revision-Date: 2025-12-15 14:17+0000\n"
13
+ "Last-Translator: Варрус <horowiserus@gmail.com>\n"
13
14
  "Language-Team: Ukrainian <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/uk/>\n"
14
15
  "Language: uk\n"
15
16
  "MIME-Version: 1.0\n"
16
17
  "Content-Type: text/plain; charset=UTF-8\n"
17
18
  "Content-Transfer-Encoding: 8bit\n"
18
19
  "Plural-Forms: nplurals=4; plural=n==1 ? 3 : (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
19
- "X-Generator: Weblate 5.13\n"
20
+ "X-Generator: Weblate 5.14.3\n"
20
21
 
21
22
  #: aa_rss_to_discord/__init__.py:10
22
23
  msgid "RSS to Discord"
@@ -24,7 +25,7 @@ msgstr "RSS до Діскорду"
24
25
 
25
26
  #: aa_rss_to_discord/models.py:44
26
27
  msgid "RSS Feed"
27
- msgstr "RSS-фід"
28
+ msgstr "RSS-стрічка"
28
29
 
29
30
  #: aa_rss_to_discord/models.py:45
30
31
  msgid "RSS Feeds"
@@ -1,39 +1,38 @@
1
1
  # SOME DESCRIPTIVE TITLE.
2
2
  # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
- # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
4
+ # AKA Patrick <hsc844766246@gmail.com>, 2025.
6
5
  msgid ""
7
6
  msgstr ""
8
7
  "Project-Id-Version: AA RSS to Discord 2.2.0\n"
9
8
  "Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-rss-to-discord/issues\n"
10
- "POT-Creation-Date: 2025-12-02 08:06+0100\n"
11
- "PO-Revision-Date: 2024-05-10 14:10+0000\n"
12
- "Last-Translator: Anonymous <noreply@weblate.org>\n"
13
- "Language-Team: Chinese (Simplified) <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/zh_Hans/>\n"
9
+ "POT-Creation-Date: 2026-02-03 14:28+0100\n"
10
+ "PO-Revision-Date: 2025-12-08 09:17+0000\n"
11
+ "Last-Translator: AKA Patrick <hsc844766246@gmail.com>\n"
12
+ "Language-Team: Chinese (Simplified Han script) <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-rss-to-discord/zh_Hans/>\n"
14
13
  "Language: zh_Hans\n"
15
14
  "MIME-Version: 1.0\n"
16
15
  "Content-Type: text/plain; charset=UTF-8\n"
17
16
  "Content-Transfer-Encoding: 8bit\n"
18
17
  "Plural-Forms: nplurals=1; plural=0;\n"
19
- "X-Generator: Weblate 5.5.3\n"
18
+ "X-Generator: Weblate 5.14.3\n"
20
19
 
21
20
  #: aa_rss_to_discord/__init__.py:10
22
21
  msgid "RSS to Discord"
23
- msgstr ""
22
+ msgstr "链接Discord的Rss"
24
23
 
25
24
  #: aa_rss_to_discord/models.py:44
26
25
  msgid "RSS Feed"
27
- msgstr ""
26
+ msgstr "RSS源"
28
27
 
29
28
  #: aa_rss_to_discord/models.py:45
30
29
  msgid "RSS Feeds"
31
- msgstr ""
30
+ msgstr "RSS源"
32
31
 
33
32
  #: aa_rss_to_discord/models.py:72
34
33
  msgid "Last Item"
35
- msgstr ""
34
+ msgstr "最后一项"
36
35
 
37
36
  #: aa_rss_to_discord/models.py:73
38
37
  msgid "Last Items"
39
- msgstr ""
38
+ msgstr "最后几项"
@@ -8,7 +8,7 @@ import re
8
8
  # Third Party
9
9
  import feedparser
10
10
  from aadiscordbot.tasks import send_message
11
- from celery import shared_task
11
+ from celery import group, shared_task
12
12
 
13
13
  # Alliance Auth
14
14
  from allianceauth.services.hooks import get_extension_logger
@@ -23,15 +23,15 @@ from aa_rss_to_discord.providers import AppLogger
23
23
  logger = AppLogger(get_extension_logger(__name__), __title__)
24
24
 
25
25
 
26
- def remove_emoji(string):
26
+ def remove_emoji(string: str) -> str:
27
27
  """
28
28
  Removing these dumb as fuck emojis from the title string.
29
29
  Like honestly, who in the hell needs that shit?
30
30
 
31
- :param string:
32
- :type string:
33
- :return:
34
- :rtype:
31
+ :param string: Input string
32
+ :type string: str
33
+ :return: String without emojis
34
+ :rtype: str
35
35
  """
36
36
 
37
37
  emoji_pattern = re.compile(
@@ -64,68 +64,91 @@ def remove_emoji(string):
64
64
  @shared_task(**{"base": QueueOnce})
65
65
  def fetch_rss() -> None:
66
66
  """
67
- Fetch RSS feeds and post new entries to Discord channels.
67
+ Fetch all enabled RSS feeds and dispatch processing tasks.
68
68
 
69
- :return:
70
- :rtype:
69
+ :return: None
70
+ :rtype: None
71
71
  """
72
72
 
73
73
  rss_feeds = RssFeeds.objects.select_enabled()
74
-
75
74
  if not rss_feeds:
76
75
  logger.debug("No RSS feeds found to parse.")
76
+ return
77
77
 
78
+ feed_ids = [f.id for f in rss_feeds]
79
+ if not feed_ids:
80
+ logger.debug("No RSS feed ids to dispatch.")
78
81
  return
79
82
 
80
- for rss_feed in rss_feeds:
81
- logger.info(f'Fetching RSS Feed "{rss_feed.name}"')
82
- feed = feedparser.parse(rss_feed.url, agent=USER_AGENT)
83
-
84
- try:
85
- latest_entry = feed.entries[0]
86
- feed_entry_title = remove_emoji(latest_entry.get("title", "No title"))
87
- feed_entry_link = latest_entry.get("link")
88
- feed_entry_time = latest_entry.get("published", latest_entry.updated)
89
- feed_entry_guid = latest_entry.get("id")
90
- except (AttributeError, IndexError) as exc:
91
- logger.debug(f'Error processing feed "{rss_feed.name}": {exc}')
92
-
93
- continue
94
-
95
- try:
96
- last_item = LastItem.objects.get(rss_feed=rss_feed)
97
- is_duplicate = (
98
- last_item.rss_item_time == feed_entry_time
99
- and last_item.rss_item_title == feed_entry_title
100
- and last_item.rss_item_link == feed_entry_link
101
- and last_item.rss_item_guid == feed_entry_guid
102
- )
103
-
104
- if is_duplicate:
105
- logger.debug(
106
- f'News item "{feed_entry_title}" for RSS Feed "{rss_feed.name}" '
107
- "has already been posted to your Discord"
108
- )
109
-
110
- continue
111
- except LastItem.DoesNotExist:
112
- logger.debug("This seems to be a completely new RSS feed.")
113
-
114
- logger.info(
115
- f"New entry found, posting to Discord channel {rss_feed.discord_channel}"
116
- )
83
+ group(_process_feed.s(fid) for fid in feed_ids).apply_async()
84
+
85
+
86
+ @shared_task
87
+ def _process_feed(rss_feed_id: int) -> None:
88
+ """
89
+ Process a single RSS feed by fetching its latest entry and posting to Discord if it's new.
90
+
91
+ :param rss_feed_id: ID of the RSS feed to process
92
+ :type rss_feed_id: int
93
+ :return: None
94
+ :rtype: None
95
+ """
117
96
 
118
- LastItem.objects.update_or_create(
119
- rss_feed=rss_feed,
120
- defaults={
121
- "rss_item_time": feed_entry_time,
122
- "rss_item_title": feed_entry_title,
123
- "rss_item_link": feed_entry_link,
124
- "rss_item_guid": feed_entry_guid,
125
- },
97
+ try:
98
+ rss_feed = RssFeeds.objects.select_related("discord_channel").get(
99
+ id=rss_feed_id
126
100
  )
101
+ except RssFeeds.DoesNotExist:
102
+ logger.debug("RSS feed %s not found", rss_feed_id)
103
+ return
104
+
105
+ logger.info(f'Fetching RSS Feed "{rss_feed.name}"')
106
+ feed = feedparser.parse(rss_feed.url, agent=USER_AGENT)
127
107
 
128
- send_message(
129
- channel_id=rss_feed.discord_channel.channel,
130
- message=f"**{rss_feed.name}**\n{feed_entry_link}",
108
+ latest_entry = next(iter(getattr(feed, "entries", [])), None)
109
+ if not latest_entry:
110
+ logger.debug(f'No entries found for feed "{rss_feed.name}".')
111
+ return
112
+
113
+ feed_entry_title = remove_emoji(latest_entry.get("title", "No title"))
114
+ feed_entry_link = latest_entry.get("link")
115
+ feed_entry_time = latest_entry.get("published", latest_entry.get("updated"))
116
+ feed_entry_guid = latest_entry.get("id")
117
+
118
+ last_item = LastItem.objects.filter(rss_feed=rss_feed).first()
119
+ if last_item and (
120
+ last_item.rss_item_time,
121
+ last_item.rss_item_title,
122
+ last_item.rss_item_link,
123
+ last_item.rss_item_guid,
124
+ ) == (feed_entry_time, feed_entry_title, feed_entry_link, feed_entry_guid):
125
+ logger.debug(
126
+ 'News item "%s" for RSS Feed "%s" has already been posted to your Discord',
127
+ feed_entry_title,
128
+ rss_feed.name,
131
129
  )
130
+ return
131
+
132
+ if not last_item:
133
+ logger.debug("This seems to be a completely new RSS feed: %s", rss_feed.name)
134
+
135
+ logger.info(
136
+ 'New entry found for RSS feed "%s", posting to Discord channel %s',
137
+ rss_feed.name,
138
+ rss_feed.discord_channel,
139
+ )
140
+
141
+ LastItem.objects.update_or_create(
142
+ rss_feed=rss_feed,
143
+ defaults={
144
+ "rss_item_time": feed_entry_time,
145
+ "rss_item_title": feed_entry_title,
146
+ "rss_item_link": feed_entry_link,
147
+ "rss_item_guid": feed_entry_guid,
148
+ },
149
+ )
150
+
151
+ send_message(
152
+ channel_id=rss_feed.discord_channel.channel,
153
+ message=f"**{rss_feed.name}**\n{feed_entry_link}",
154
+ )
@@ -3,22 +3,24 @@ Test cases for the fetch_rss task
3
3
  """
4
4
 
5
5
  # Standard Library
6
+ from types import SimpleNamespace
6
7
  from unittest.mock import MagicMock, patch
7
8
 
8
9
  # AA RSS to Discord
9
- from aa_rss_to_discord.models import LastItem
10
- from aa_rss_to_discord.tasks import fetch_rss
10
+ from aa_rss_to_discord.constants import USER_AGENT
11
+ from aa_rss_to_discord.models import RssFeeds
12
+ from aa_rss_to_discord.tasks import _process_feed, fetch_rss
11
13
  from aa_rss_to_discord.tests import BaseTestCase
12
14
 
13
15
 
14
16
  class TestFetchRss(BaseTestCase):
15
17
  """
16
- Test fetch_rss task
18
+ Test cases for the fetch_rss task
17
19
  """
18
20
 
19
- def test_logs_warning_if_no_rss_feeds_found(self):
21
+ def test_fetch_rss_logs_message_when_no_rss_feeds_found(self):
20
22
  """
21
- Test that a warning is logged if no RSS feeds are found.
23
+ Test that fetch_rss logs a message when no RSS feeds are found.
22
24
 
23
25
  :return:
24
26
  :rtype:
@@ -26,151 +28,209 @@ class TestFetchRss(BaseTestCase):
26
28
 
27
29
  with (
28
30
  patch(
29
- "aa_rss_to_discord.tasks.RssFeeds.objects.select_enabled",
30
- return_value=[],
31
- ),
32
- patch("aa_rss_to_discord.tasks.logger.debug") as mock_debug,
31
+ "aa_rss_to_discord.tasks.RssFeeds.objects.select_enabled"
32
+ ) as mock_select_enabled,
33
+ patch("aa_rss_to_discord.tasks.logger.debug") as mock_logger_debug,
33
34
  ):
35
+ mock_select_enabled.return_value = []
36
+
34
37
  fetch_rss()
35
- mock_debug.assert_called_once_with("No RSS feeds found to parse.")
36
38
 
37
- def test_processes_valid_rss_feed_entry(self):
39
+ mock_logger_debug.assert_called_once_with("No RSS feeds found to parse.")
40
+
41
+ def test_fetch_rss_dispatches_tasks_for_enabled_feeds(self):
38
42
  """
39
- Test that a valid RSS feed entry is processed and sent to Discord.
43
+ Test that fetch_rss dispatches tasks for enabled RSS feeds.
40
44
 
41
45
  :return:
42
46
  :rtype:
43
47
  """
44
48
 
45
- discord_channel = MagicMock()
46
- discord_channel.channel = 12345
47
-
48
- rss_feed = MagicMock()
49
- rss_feed.name = "Valid Feed"
50
- rss_feed.url = "http://example.com/rss"
51
- rss_feed.discord_channel = discord_channel
52
-
53
- # Use a MagicMock that acts like feedparser entry with both dict and attribute access
54
- feed_entry = MagicMock()
55
- feed_entry.get = lambda key, default=None: {
56
- "title": "Valid Entry",
57
- "link": "http://example.com/valid-entry",
58
- "published": "2023-10-01T12:00:00Z",
59
- "id": "entry-1",
60
- }.get(key, default)
61
- feed_entry.updated = (
62
- "2023-10-01T12:00:00Z" # Fallback if 'published' is missing
63
- )
64
-
65
- parsed_feed = MagicMock()
66
- parsed_feed.entries = [feed_entry]
67
-
68
49
  with (
69
50
  patch(
70
- "aa_rss_to_discord.tasks.RssFeeds.objects.select_enabled",
71
- return_value=[rss_feed],
72
- ),
73
- patch(
74
- "aa_rss_to_discord.tasks.feedparser.parse",
75
- return_value=parsed_feed,
76
- ),
51
+ "aa_rss_to_discord.tasks.RssFeeds.objects.select_enabled"
52
+ ) as mock_select_enabled,
53
+ patch("aa_rss_to_discord.tasks.group") as mock_group,
54
+ ):
55
+ mock_rss_feed_1 = MagicMock(id=1)
56
+ mock_rss_feed_2 = MagicMock(id=2)
57
+ mock_select_enabled.return_value = [mock_rss_feed_1, mock_rss_feed_2]
58
+
59
+ fetch_rss()
60
+
61
+ mock_group.assert_called_once()
62
+ mock_group.return_value.apply_async.assert_called_once()
63
+ dispatched_tasks = mock_group.call_args[0][0]
64
+ dispatched_list = list(dispatched_tasks)
65
+ self.assertEqual(len(dispatched_list), 2)
66
+ self.assertEqual(dispatched_list[0].args[0], 1)
67
+ self.assertEqual(dispatched_list[1].args[0], 2)
68
+
69
+ def test_handles_empty_rss_feed_ids_gracefully(self):
70
+ """
71
+ Test that fetch_rss handles an empty list of RSS feed IDs gracefully.
72
+
73
+ :return:
74
+ :rtype:
75
+ """
76
+
77
+ with (
77
78
  patch(
78
- "aa_rss_to_discord.tasks.LastItem.objects.get",
79
- side_effect=LastItem.DoesNotExist,
80
- ),
79
+ "aa_rss_to_discord.tasks.RssFeeds.objects.select_enabled"
80
+ ) as mock_select_enabled,
81
+ patch("aa_rss_to_discord.tasks.group") as mock_group,
82
+ patch("aa_rss_to_discord.tasks.logger.debug") as mock_logger_debug,
83
+ ):
84
+ mock_select_enabled.return_value = iter([])
85
+
86
+ fetch_rss()
87
+
88
+ mock_group.assert_not_called()
89
+ mock_logger_debug.assert_called_once_with("No RSS feed ids to dispatch.")
90
+
91
+
92
+ class TestHelperProcessRssFeed(BaseTestCase):
93
+ """
94
+ Test cases for the _process_feed task
95
+ """
96
+
97
+ def test_handles_missing_rss_feed_gracefully(self):
98
+ """
99
+ Test that _process_feed handles a missing RSS feed gracefully.
100
+
101
+ :return:
102
+ :rtype:
103
+ """
104
+
105
+ with patch(
106
+ "aa_rss_to_discord.tasks.RssFeeds.objects.select_related"
107
+ ) as mock_select_related:
108
+ mock_select_related.return_value.get.side_effect = RssFeeds.DoesNotExist
109
+
110
+ _process_feed(1)
111
+
112
+ mock_select_related.return_value.get.assert_called_once_with(id=1)
113
+
114
+ def test_logs_and_skips_when_no_entries_in_feed(self):
115
+ """
116
+ Test that _process_feed logs and skips processing when no entries are found in the feed.
117
+
118
+ :return:
119
+ :rtype:
120
+ """
121
+
122
+ with (
81
123
  patch(
82
- "aa_rss_to_discord.tasks.LastItem.objects.update_or_create",
83
- ),
124
+ "aa_rss_to_discord.tasks.RssFeeds.objects.select_related"
125
+ ) as mock_select_related,
84
126
  patch(
85
- "aa_rss_to_discord.tasks.send_message",
86
- ) as mock_send_message,
127
+ "aa_rss_to_discord.tasks.feedparser.parse", return_value={}
128
+ ) as mock_parse,
87
129
  ):
88
- fetch_rss()
130
+ mock_rss_feed = MagicMock(url="http://example.com", name="No Entries Feed")
131
+ mock_select_related.return_value.get.return_value = mock_rss_feed
132
+
133
+ _process_feed(1)
89
134
 
90
- mock_send_message.assert_called_once()
91
- call_args = mock_send_message.call_args
92
- self.assertEqual(call_args.kwargs.get("channel_id"), 12345)
93
- message = call_args.kwargs.get("message", "")
94
- self.assertIn("http://example.com/valid-entry", message)
95
- self.assertIn("Valid Feed", message)
135
+ mock_parse.assert_called_once_with(mock_rss_feed.url, agent=USER_AGENT)
96
136
 
97
- def test_skips_duplicate_rss_feed_entry(self):
137
+ def test_posts_new_entry_to_discord(self):
98
138
  """
99
- Test that a duplicate RSS feed entry is skipped.
139
+ Test that _process_feed posts a new entry to Discord when it's not a duplicate.
100
140
 
101
141
  :return:
102
142
  :rtype:
103
143
  """
104
144
 
105
- rss_feed = MagicMock()
106
- rss_feed.name = "Duplicate Feed"
107
- rss_feed.url = "http://example.com/rss"
108
-
109
- # Create feed entry that supports both dict-style and attribute access
110
- feed_entry = MagicMock()
111
- feed_entry.get = lambda key, default=None: {
112
- "title": "Duplicate Entry",
113
- "link": "http://example.com/duplicate-entry",
114
- "published": "2023-10-01T12:00:00Z",
115
- "id": "entry-1",
116
- }.get(key, default)
117
- feed_entry.updated = "2023-10-01T12:00:00Z"
118
-
119
- last_item = MagicMock(
120
- rss_item_time="2023-10-01T12:00:00Z",
121
- rss_item_title="Duplicate Entry",
122
- rss_item_link="http://example.com/duplicate-entry",
123
- rss_item_guid="entry-1",
124
- )
145
+ entry = {"title": "New Entry", "link": "http://example.com", "id": "123"}
125
146
 
126
147
  with (
127
148
  patch(
128
- "aa_rss_to_discord.tasks.RssFeeds.objects.select_enabled",
129
- return_value=[rss_feed],
130
- ),
149
+ "aa_rss_to_discord.tasks.RssFeeds.objects.select_related"
150
+ ) as mock_select_related,
131
151
  patch(
132
152
  "aa_rss_to_discord.tasks.feedparser.parse",
133
- return_value=MagicMock(entries=[feed_entry]),
134
- ),
153
+ return_value=SimpleNamespace(entries=[entry]),
154
+ ) as mock_parse,
155
+ patch("aa_rss_to_discord.tasks.LastItem.objects.filter") as mock_filter,
135
156
  patch(
136
- "aa_rss_to_discord.tasks.LastItem.objects.get",
137
- return_value=last_item,
138
- ),
139
- patch("aa_rss_to_discord.tasks.logger.debug") as mock_debug,
157
+ "aa_rss_to_discord.tasks.LastItem.objects.update_or_create"
158
+ ) as mock_update_or_create,
140
159
  patch("aa_rss_to_discord.tasks.send_message") as mock_send_message,
141
160
  ):
142
- fetch_rss()
161
+ mock_rss_feed = MagicMock(
162
+ discord_channel=MagicMock(channel=12345),
163
+ name="Test Feed",
164
+ url="http://example.com",
165
+ )
166
+ mock_select_related.return_value.get.return_value = mock_rss_feed
167
+ mock_filter.return_value.first.return_value = None
168
+ mock_update_or_create.return_value = (MagicMock(), True)
143
169
 
144
- mock_send_message.assert_not_called()
145
- mock_debug.assert_any_call(
146
- 'News item "Duplicate Entry" for RSS Feed "Duplicate Feed" has already been posted to your Discord'
170
+ _process_feed(1)
171
+
172
+ mock_parse.assert_called_once_with(mock_rss_feed.url, agent=USER_AGENT)
173
+ mock_update_or_create.assert_called_once()
174
+ self.assertTrue(
175
+ mock_send_message.called,
176
+ f"send_message not called. calls: {mock_send_message.call_args_list}",
147
177
  )
148
178
 
149
- def test_skips_rss_feed_with_no_entries(self):
179
+ call_args, call_kwargs = mock_send_message.call_args
180
+ called_channel = (
181
+ call_kwargs.get("channel_id")
182
+ if "channel_id" in call_kwargs
183
+ else (call_args[0] if len(call_args) > 0 else None)
184
+ )
185
+ called_message = (
186
+ call_kwargs.get("message")
187
+ if "message" in call_kwargs
188
+ else (
189
+ call_args[1]
190
+ if len(call_args) > 1
191
+ else (call_args[0] if len(call_args) == 1 else None)
192
+ )
193
+ )
194
+
195
+ self.assertEqual(called_channel, 12345)
196
+ self.assertIsNotNone(called_message)
197
+ self.assertIn(mock_rss_feed.url, called_message)
198
+
199
+ def test_skips_posting_duplicate_entry(self):
150
200
  """
151
- Test that an RSS feed with no entries is skipped.
201
+ Test that _process_feed skips posting a duplicate entry to Discord.
152
202
 
153
203
  :return:
154
204
  :rtype:
155
205
  """
156
206
 
157
- rss_feed = MagicMock()
158
- rss_feed.name = "Empty Feed"
159
- rss_feed.url = "http://example.com/rss"
207
+ entry = {"title": "Duplicate Entry", "link": "http://example.com", "id": "123"}
160
208
 
161
209
  with (
162
210
  patch(
163
- "aa_rss_to_discord.tasks.RssFeeds.objects.select_enabled",
164
- return_value=[rss_feed],
165
- ),
211
+ "aa_rss_to_discord.tasks.RssFeeds.objects.select_related"
212
+ ) as mock_select_related,
166
213
  patch(
167
214
  "aa_rss_to_discord.tasks.feedparser.parse",
168
- return_value=MagicMock(entries=[]),
215
+ return_value=SimpleNamespace(entries=[entry]),
169
216
  ),
170
- patch("aa_rss_to_discord.tasks.logger.debug") as mock_debug,
217
+ patch("aa_rss_to_discord.tasks.LastItem.objects.filter") as mock_filter,
218
+ patch("aa_rss_to_discord.tasks.send_message") as mock_send_message,
171
219
  ):
172
- fetch_rss()
173
-
174
- mock_debug.assert_any_call(
175
- 'Error processing feed "Empty Feed": list index out of range'
220
+ mock_rss_feed = MagicMock(
221
+ discord_channel=MagicMock(channel=12345),
222
+ name="Dup Feed",
223
+ url="http://example.com",
176
224
  )
225
+ mock_select_related.return_value.get.return_value = mock_rss_feed
226
+ mock_existing = MagicMock(
227
+ rss_item_time=None,
228
+ rss_item_title="Duplicate Entry",
229
+ rss_item_link="http://example.com",
230
+ rss_item_guid="123",
231
+ )
232
+ mock_filter.return_value.first.return_value = mock_existing
233
+
234
+ _process_feed(1)
235
+
236
+ mock_send_message.assert_not_called()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aa-rss-to-discord
3
- Version: 2.4.0
3
+ Version: 2.5.1
4
4
  Summary: Alliance Auth module to post news from RSS feeds to your Discord
5
5
  Project-URL: Changelog, https://github.com/ppfeufer/aa-rss-to-discord/blob/master/CHANGELOG.md
6
6
  Project-URL: Codecov, https://codecov.io/gh/ppfeufer/aa-rss-to-discord
@@ -705,7 +705,7 @@ Requires-Python: <3.14,>=3.10
705
705
  Requires-Dist: allianceauth-discordbot>=3.0.5
706
706
  Requires-Dist: allianceauth<5,>=4.3.1
707
707
  Requires-Dist: feedparser
708
- Requires-Dist: py-cord>=2.7.0rc2; python_version == '3.13'
708
+ Requires-Dist: py-cord>=2.7.0rc2; python_version >= '3.13'
709
709
  Provides-Extra: tests-allianceauth-latest
710
710
  Requires-Dist: coverage; extra == 'tests-allianceauth-latest'
711
711
  Requires-Dist: django-webtest; extra == 'tests-allianceauth-latest'
@@ -773,7 +773,7 @@ Make sure you're in the virtual environment (venv) of your Alliance Auth
773
773
  installation Then install the latest release directly from PyPi.
774
774
 
775
775
  ```shell
776
- pip install aa-rss-to-discord==2.4.0
776
+ pip install aa-rss-to-discord==2.5.1
777
777
  ```
778
778
 
779
779
  ### Step 2: Configure Alliance Auth<a name="step-2-configure-alliance-auth"></a>
@@ -828,7 +828,7 @@ To update your existing installation of Alliance Auth RSS to Discord, first enab
828
828
  virtual environment (venv) of your Alliance Auth installation.
829
829
 
830
830
  ```bash
831
- pip install aa-rss-to-discord==2.4.0
831
+ pip install aa-rss-to-discord==2.5.1
832
832
 
833
833
  python manage.py migrate
834
834
  ```
@@ -1,4 +1,4 @@
1
- aa_rss_to_discord/__init__.py,sha256=tshvB4Ib8of9KNQB_JuWVhJ7TJ0nePhojMS47YIbaT0,177
1
+ aa_rss_to_discord/__init__.py,sha256=YswLHVdtoDhl1NRaog-epkIsP2cju4CeLwdT-mkgv_8,177
2
2
  aa_rss_to_discord/admin.py,sha256=bbvD0w0vFgD4kR4riWIwpOWpb9t8R6BI7ofYqTZbjDw,440
3
3
  aa_rss_to_discord/apps.py,sha256=jtIy1uXn92yURf7QG7TxzLniSbOAL41OzqjCLxTwMbA,458
4
4
  aa_rss_to_discord/auth_hooks.py,sha256=k5mLzQR1NwtA5MCedLzPyULEhv4ylwqvFpTPZ62eWJ0,273
@@ -6,36 +6,36 @@ aa_rss_to_discord/constants.py,sha256=SD5aSlRanXsE07tV5q4PxVJXH0Xgivr8DjfNgyTDaq
6
6
  aa_rss_to_discord/managers.py,sha256=oERpP9OXZNg3_SJCKiMZrt7aa_NGxKswZntfgYkpRdA,307
7
7
  aa_rss_to_discord/models.py,sha256=G-_LjShFDQFcbcg3nuR5mwjBl4zmANsgF8PIrokJOdU,1781
8
8
  aa_rss_to_discord/providers.py,sha256=AwZ4QgWg_LNQsWjwHCurAFBHEFwTXGEDGUP6xTKxGJc,1029
9
- aa_rss_to_discord/tasks.py,sha256=4L-vdX1570nyVp1NBl6yJ13a9hW2aT_ABK1YY_8y9Ss,3807
9
+ aa_rss_to_discord/tasks.py,sha256=8-XzCVqWqc3bDE7Msf68ahsID2P5db6TSl1TTvVB0DQ,4360
10
10
  aa_rss_to_discord/discordbot/cogs/__init__.py,sha256=3u3OJfO3Xh1GightCaX0lhbUbP7Lq2c1nY4Tg1FsrZo,27
11
11
  aa_rss_to_discord/discordbot/cogs/rss.py,sha256=aPov4y-ckTwzXdXfKtA5WZZKwy7myOlW2xyK5yWGhy4,8174
12
- aa_rss_to_discord/locale/django.pot,sha256=4uKpgRNE82d-SXtbOIxfkhJ0yE_Yo146_XoneZPQNDQ,962
12
+ aa_rss_to_discord/locale/django.pot,sha256=T_-mgd2Bp83MncjxpfbDCAdBq7msgfAPWo39X2p_ch0,962
13
13
  aa_rss_to_discord/locale/cs_CZ/LC_MESSAGES/django.mo,sha256=e5Bcjwg3sIKgDgHKifbl2DcH0atHMSygiZwgvKEaifs,565
14
- aa_rss_to_discord/locale/cs_CZ/LC_MESSAGES/django.po,sha256=zeffaDdZEfeeIWiUetKO_Ft7muDgkHtMdVxecVC5yQQ,1187
14
+ aa_rss_to_discord/locale/cs_CZ/LC_MESSAGES/django.po,sha256=poz7c0BlMoSQnmhGD7GMXe3yV9pudXG7Zd_ghVzmzk0,1187
15
15
  aa_rss_to_discord/locale/de/LC_MESSAGES/django.mo,sha256=NGLMzDZwRKCvQH_RtK9wm6UXKWHLuipasTLnjaosbRE,717
16
- aa_rss_to_discord/locale/de/LC_MESSAGES/django.po,sha256=Y1mynnUEi0AgHUQZUKVNSQL0EquILhK3RYPBnQkqz9g,1183
17
- aa_rss_to_discord/locale/es/LC_MESSAGES/django.mo,sha256=BNXYj-j0OPYFuLpm0uJS_b28tdtbs1BOMYp_HCWcoC8,664
18
- aa_rss_to_discord/locale/es/LC_MESSAGES/django.po,sha256=XVZ6DPLize4AS-LRH5ayMsXuY4txIHe7IBwHpib0EPU,1196
16
+ aa_rss_to_discord/locale/de/LC_MESSAGES/django.po,sha256=Q4g4HIWgZ03oETrK3VRrAx4PrQHmroFX_2tfnamv2gE,1183
17
+ aa_rss_to_discord/locale/es/LC_MESSAGES/django.mo,sha256=VqcFVQKAN-xQqvtysBccVIbDGedac6l-qxgx-751R0c,665
18
+ aa_rss_to_discord/locale/es/LC_MESSAGES/django.po,sha256=Z0p4vChihfkSjcbHDbioWPEcAlhM0BKxOq2a_hf1q3o,1239
19
19
  aa_rss_to_discord/locale/fr_FR/LC_MESSAGES/django.mo,sha256=zwgaGEqI-UlHpc9q1irjc4xDxZJZBheixtIWz-43q1U,721
20
- aa_rss_to_discord/locale/fr_FR/LC_MESSAGES/django.po,sha256=XmpegMaCzAX5_y1YQzFbwPM6FpcoWFiK0ZjuGeA1s5A,1337
20
+ aa_rss_to_discord/locale/fr_FR/LC_MESSAGES/django.po,sha256=4fBgDFBeqNLf1L4yRLJgYFwqZ1JL4RBu2VwiuuKQVnU,1337
21
21
  aa_rss_to_discord/locale/it_IT/LC_MESSAGES/django.mo,sha256=jyxuImpxL3PnEGxbqzYoLvrE014f-wPENwh0LMuWviM,487
22
- aa_rss_to_discord/locale/it_IT/LC_MESSAGES/django.po,sha256=z4pSagMW-mF7R9XxQQNPKfMbKW7g-0y9Qh8oByNgWZk,1107
22
+ aa_rss_to_discord/locale/it_IT/LC_MESSAGES/django.po,sha256=tjqpq5fZyxZMNJjpHsFSC0cbxBaCmH7RUjIr0HkwSLQ,1107
23
23
  aa_rss_to_discord/locale/ja/LC_MESSAGES/django.mo,sha256=dzafm9mmWwOeYbuJWyMmxTKxqdBu7ptUXdhXllkSoY4,770
24
- aa_rss_to_discord/locale/ja/LC_MESSAGES/django.po,sha256=zdH0HWBf8QcZl_t7Nuc5-QB0OqVDFLeypouFYh3c_Uk,1229
24
+ aa_rss_to_discord/locale/ja/LC_MESSAGES/django.po,sha256=wCV8JkLNhoe59SWRKby8jn6Yw-WrerrMgEgP4imP_zk,1229
25
25
  aa_rss_to_discord/locale/ko_KR/LC_MESSAGES/django.mo,sha256=1IW9bwgVPrzDl_0crEO0UMaPF4jP3SyTUrZeRjalzCk,738
26
- aa_rss_to_discord/locale/ko_KR/LC_MESSAGES/django.po,sha256=AWBaC8P8bCMgZ7NYF2fRBLhDvAk9Qc7W9YMWbMfZpmI,1239
27
- aa_rss_to_discord/locale/nl_NL/LC_MESSAGES/django.mo,sha256=JLv2IW5Kp2wqE7MqNn9P9blZ_I-Jp0CIWiHsadYgFUU,483
28
- aa_rss_to_discord/locale/nl_NL/LC_MESSAGES/django.po,sha256=ClrnrkigalQgcw1UT8pDjtrxyWR8psEChhU4YXtTyIk,1105
26
+ aa_rss_to_discord/locale/ko_KR/LC_MESSAGES/django.po,sha256=A6FtSJpWP7MRxS21J5rEpqVT_n1g2grmvAr4LDmcH94,1239
27
+ aa_rss_to_discord/locale/nl_NL/LC_MESSAGES/django.mo,sha256=v7rZwxQu_IeiPCsTvDaHbWaIFc12Qwy_0gm_yuR5PBg,540
28
+ aa_rss_to_discord/locale/nl_NL/LC_MESSAGES/django.po,sha256=Veig2Vb78SqYKZycTTiP3aHEcWim5TeO49zZWojM82Y,1125
29
29
  aa_rss_to_discord/locale/pl_PL/LC_MESSAGES/django.mo,sha256=2ugIqkNNVUGxIgfxUjU8SCIBJvSCn6vGzAV9Xnqiyag,543
30
- aa_rss_to_discord/locale/pl_PL/LC_MESSAGES/django.po,sha256=yIUIUBx_eDd_qT4zWCOd_VjDPKf9xxrGH-Pv0GQqkrc,1164
30
+ aa_rss_to_discord/locale/pl_PL/LC_MESSAGES/django.po,sha256=k1XGfy3x9Sc472AwR0gGLqWavcpO9CxWG5YVw-8qpiA,1164
31
31
  aa_rss_to_discord/locale/ru/LC_MESSAGES/django.mo,sha256=BzuRJnMwz-rpbr8rc_K755H-sstix0LsOpb7lSbkRuo,865
32
- aa_rss_to_discord/locale/ru/LC_MESSAGES/django.po,sha256=CNH5PJAu9dFOgtgOttRhpHDgxvKIQx39P2mgIftCemw,1351
32
+ aa_rss_to_discord/locale/ru/LC_MESSAGES/django.po,sha256=3bIO2b9h7QhptMP7whS_3cIn9h0ashlmVo3uxsA-3jQ,1351
33
33
  aa_rss_to_discord/locale/sk/LC_MESSAGES/django.mo,sha256=WPcDxnOaK_bCNIPoZQRxryi5F97g2RNn0Zuh9us90U0,562
34
- aa_rss_to_discord/locale/sk/LC_MESSAGES/django.po,sha256=I2P3KN-Q0-EyywmQ_aO54i4zcQ5RGVeri0Dbtr4lLCc,1180
35
- aa_rss_to_discord/locale/uk/LC_MESSAGES/django.mo,sha256=5DL6DnJ0kP7s9PbVr92PAeVQf-cGMSQibbnoJmZJHG8,858
36
- aa_rss_to_discord/locale/uk/LC_MESSAGES/django.po,sha256=VUl9mZPHBA6kTyLhWO0pw9lmOozXPgaZ-EAbZwQhHlo,1352
37
- aa_rss_to_discord/locale/zh_Hans/LC_MESSAGES/django.mo,sha256=DaODnWQcYUSgtxUaPmZoEG6IQ190DS3WzCh6uNvhHh8,518
38
- aa_rss_to_discord/locale/zh_Hans/LC_MESSAGES/django.po,sha256=7OkKDvfLIkZWOBi98fyPNVTlHXw_Kch8VIYzZejAQQs,1122
34
+ aa_rss_to_discord/locale/sk/LC_MESSAGES/django.po,sha256=VzCl1E3bPedpwVQiNYD7XXW9ZppU_PrIdmh3emnAAQ0,1180
35
+ aa_rss_to_discord/locale/uk/LC_MESSAGES/django.mo,sha256=lkMHhhk6cARn69ekx4BfYukLBm6y8-V6OaryZ2FQFP8,868
36
+ aa_rss_to_discord/locale/uk/LC_MESSAGES/django.po,sha256=YWV_4WkPc-SRYn8iYwWJw-_0K0Fajad-7Gi-GJUz38M,1412
37
+ aa_rss_to_discord/locale/zh_Hans/LC_MESSAGES/django.mo,sha256=kFA6fZgb6fIbeSwnGhKHVqyV9eOxC0MMYi6DWBC2xII,768
38
+ aa_rss_to_discord/locale/zh_Hans/LC_MESSAGES/django.po,sha256=bcz-mMFltPuXqlT6mJMZ1gP793W1zZ_0M5pa98UF6rU,1200
39
39
  aa_rss_to_discord/migrations/0001_initial.py,sha256=TD8ZmWLleWEw1G3PlQh3HBU4pRXxwIfp_LMQj4IyTDE,2764
40
40
  aa_rss_to_discord/migrations/0002_enable_disable_rss_feeds.py,sha256=apLeuxILrxvTntSc1bixfcDqpgt49VscyT6inLKU9k8,396
41
41
  aa_rss_to_discord/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -44,8 +44,8 @@ aa_rss_to_discord/tests/test_auth_hooks.py,sha256=DZLEdVO9E82GEqPMv6_JOgSLPjU_Dr
44
44
  aa_rss_to_discord/tests/test_managers.py,sha256=Ar4Mc4z1k0701jjAWKTqe9BzxBjX-32KIdT4VgXfJ_s,1023
45
45
  aa_rss_to_discord/tests/test_models.py,sha256=XtqGVZQbbtyDktYlHYsKFrLb3qB-UpU7wIpA6gXsKL8,4823
46
46
  aa_rss_to_discord/tests/test_providers.py,sha256=ZF1zV3-_yFWwruiR_g2yB-RRy_t5W0WPbaF7guFRXF8,2677
47
- aa_rss_to_discord/tests/test_tasks.py,sha256=tJykTvZ4FHTkZP0J6MUA5Me-0NP-mK_uPqNNrGWuv2Y,5584
48
- aa_rss_to_discord-2.4.0.dist-info/METADATA,sha256=k40M2wasM80fl20MBe1DQeqKO4GPv_naRfZ2QixZ9Ow,50408
49
- aa_rss_to_discord-2.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
50
- aa_rss_to_discord-2.4.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
51
- aa_rss_to_discord-2.4.0.dist-info/RECORD,,
47
+ aa_rss_to_discord/tests/test_tasks.py,sha256=lSoeqGulKiRFT3Hyrlg1svv7RqiBD3DSfC8vOGRVqhs,7969
48
+ aa_rss_to_discord-2.5.1.dist-info/METADATA,sha256=O9TvLjw0jY9YOF13Jq-VHqqzGFpZ87TUuje-6X9WMqs,50408
49
+ aa_rss_to_discord-2.5.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
50
+ aa_rss_to_discord-2.5.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
51
+ aa_rss_to_discord-2.5.1.dist-info/RECORD,,