diff options
-rw-r--r-- | .gitignore | 112 | ||||
-rw-r--r-- | afeedprocessor/afeedparser.py | 59 | ||||
-rw-r--r-- | afeedprocessor/afeedprocessor.py | 96 | ||||
-rw-r--r-- | afeedprocessor/anitemprocessor.py | 47 | ||||
-rw-r--r-- | example.py | 32 | ||||
-rw-r--r-- | license.txt | 661 | ||||
-rw-r--r-- | readme.md | 45 |
7 files changed, 1052 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c0fa452 --- /dev/null +++ b/.gitignore | |||
@@ -0,0 +1,112 @@ | |||
1 | # Created by .ignore support plugin (hsz.mobi) | ||
2 | |||
3 | ### Python template | ||
4 | # Byte-compiled / optimized / DLL files | ||
5 | __pycache__/ | ||
6 | *.py[cod] | ||
7 | *$py.class | ||
8 | |||
9 | # C extensions | ||
10 | *.so | ||
11 | |||
12 | # Distribution / packaging | ||
13 | .Python | ||
14 | env/ | ||
15 | build/ | ||
16 | develop-eggs/ | ||
17 | dist/ | ||
18 | downloads/ | ||
19 | eggs/ | ||
20 | .eggs/ | ||
21 | lib/ | ||
22 | lib64/ | ||
23 | parts/ | ||
24 | sdist/ | ||
25 | var/ | ||
26 | *.egg-info/ | ||
27 | .installed.cfg | ||
28 | *.egg | ||
29 | |||
30 | # PyInstaller | ||
31 | # Usually these files are written by a python script from a template | ||
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
33 | *.manifest | ||
34 | *.spec | ||
35 | |||
36 | # Installer logs | ||
37 | pip-log.txt | ||
38 | pip-delete-this-directory.txt | ||
39 | |||
40 | # Unit test / coverage reports | ||
41 | htmlcov/ | ||
42 | .tox/ | ||
43 | .coverage | ||
44 | .coverage.* | ||
45 | .cache | ||
46 | nosetests.xml | ||
47 | coverage.xml | ||
48 | *,cover | ||
49 | |||
50 | # Translations | ||
51 | *.mo | ||
52 | *.pot | ||
53 | |||
54 | # Django stuff: | ||
55 | *.log | ||
56 | |||
57 | # Sphinx documentation | ||
58 | docs/_build/ | ||
59 | |||
60 | # PyBuilder | ||
61 | target/ | ||
62 | |||
63 | |||
64 | ### JetBrains template | ||
65 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion | ||
66 | |||
67 | *.iml | ||
68 | |||
69 | ## Directory-based project format: | ||
70 | .idea/ | ||
71 | # if you remove the above rule, at least ignore the following: | ||
72 | |||
73 | # User-specific stuff: | ||
74 | # .idea/workspace.xml | ||
75 | # .idea/tasks.xml | ||
76 | # .idea/dictionaries | ||
77 | |||
78 | # Sensitive or high-churn files: | ||
79 | # .idea/dataSources.ids | ||
80 | # .idea/dataSources.xml | ||
81 | # .idea/sqlDataSources.xml | ||
82 | # .idea/dynamic.xml | ||
83 | # .idea/uiDesigner.xml | ||
84 | |||
85 | # Gradle: | ||
86 | # .idea/gradle.xml | ||
87 | # .idea/libraries | ||
88 | |||
89 | # Mongo Explorer plugin: | ||
90 | # .idea/mongoSettings.xml | ||
91 | |||
92 | ## File-based project format: | ||
93 | *.ipr | ||
94 | *.iws | ||
95 | |||
96 | ## Plugin-specific files: | ||
97 | |||
98 | # IntelliJ | ||
99 | /out/ | ||
100 | |||
101 | # mpeltonen/sbt-idea plugin | ||
102 | .idea_modules/ | ||
103 | |||
104 | # JIRA plugin | ||
105 | atlassian-ide-plugin.xml | ||
106 | |||
107 | # Crashlytics plugin (for Android Studio and IntelliJ) | ||
108 | com_crashlytics_export_strings.xml | ||
109 | crashlytics.properties | ||
110 | crashlytics-build.properties | ||
111 | |||
112 | |||
diff --git a/afeedprocessor/afeedparser.py b/afeedprocessor/afeedparser.py new file mode 100644 index 0000000..0c23187 --- /dev/null +++ b/afeedprocessor/afeedparser.py | |||
@@ -0,0 +1,59 @@ | |||
1 | import feedparser | ||
2 | import PyRSS2Gen | ||
3 | import datetime | ||
4 | |||
5 | |||
6 | class FeedParser: | ||
7 | @staticmethod | ||
8 | def date_tuple_to_datetime(date_tuple): | ||
9 | return datetime.datetime(*(date_tuple[:5])) if date_tuple else None | ||
10 | |||
11 | @staticmethod | ||
12 | def get_first(lst): | ||
13 | return lst[0] if lst and len(lst) > 0 else None | ||
14 | |||
15 | def get_rss_item_for_entry(self, entry): | ||
16 | return PyRSS2Gen.RSSItem( | ||
17 | title=entry.get('title'), | ||
18 | link=entry.get('link'), | ||
19 | description=entry.get('description'), | ||
20 | author=entry.get('author'), | ||
21 | categories=entry.get('tags'), | ||
22 | comments=entry.get('comments'), | ||
23 | enclosure=self.get_first(entry.get('enclosures')), | ||
24 | guid=entry.get('id'), | ||
25 | pubDate=self.date_tuple_to_datetime(entry.get('published_parsed')), | ||
26 | source=entry.get('source'), | ||
27 | ) | ||
28 | |||
29 | def get_rss2_from_feed(self, feed, entries): | ||
30 | return PyRSS2Gen.RSS2( | ||
31 | title=feed.get('title'), | ||
32 | link=feed.get('link'), | ||
33 | description=feed.get('subtitle'), | ||
34 | |||
35 | language=feed.get('language'), | ||
36 | copyright=feed.get('rights'), | ||
37 | managingEditor=feed.get('contributors'), | ||
38 | webMaster=feed.get('publisher'), | ||
39 | pubDate=self.date_tuple_to_datetime(feed.get('published_parsed')), | ||
40 | lastBuildDate=self.date_tuple_to_datetime(feed.get('updated_parsed')), | ||
41 | |||
42 | categories=feed.get('tags'), | ||
43 | generator=feed.get('generator'), | ||
44 | docs=feed.get('docs'), | ||
45 | cloud=feed.get('cloud'), | ||
46 | ttl=feed.get('ttl'), | ||
47 | |||
48 | image=feed.get('image'), | ||
49 | rating=None, | ||
50 | textInput=feed.get('textinput'), | ||
51 | skipHours=None, | ||
52 | skipDays=None, | ||
53 | |||
54 | items=[self.get_rss_item_for_entry(entry) for entry in entries], | ||
55 | ) | ||
56 | |||
57 | def parse(self, feed): | ||
58 | parsed_feed = feedparser.parse(feed) | ||
59 | return self.get_rss2_from_feed(parsed_feed.feed, parsed_feed.entries) | ||
diff --git a/afeedprocessor/afeedprocessor.py b/afeedprocessor/afeedprocessor.py new file mode 100644 index 0000000..e3663ee --- /dev/null +++ b/afeedprocessor/afeedprocessor.py | |||
@@ -0,0 +1,96 @@ | |||
1 | import PyRSS2Gen | ||
2 | |||
3 | from afeedprocessor.anitemprocessor import ItemProcessor | ||
4 | |||
5 | |||
6 | class FeedProcessor: | ||
7 | def __init__(self, item_processor: ItemProcessor=None): | ||
8 | if item_processor is None: | ||
9 | self.item_processor = ItemProcessor() | ||
10 | else: | ||
11 | self.item_processor = item_processor | ||
12 | |||
13 | def get_title(self, title, feed): | ||
14 | return title | ||
15 | |||
16 | def get_link(self, link, feed): | ||
17 | return link | ||
18 | |||
19 | def get_description(self, description, feed): | ||
20 | return description | ||
21 | |||
22 | def get_language(self, language, feed): | ||
23 | return language | ||
24 | |||
25 | def get_copyright(self, copyright, feed): | ||
26 | return copyright | ||
27 | |||
28 | def get_managing_editor(self, managing_editor, feed): | ||
29 | return managing_editor | ||
30 | |||
31 | def get_web_master(self, web_master, feed): | ||
32 | return web_master | ||
33 | |||
34 | def get_pub_date(self, pub_date, feed): | ||
35 | return pub_date | ||
36 | |||
37 | def get_last_build_date(self, last_build_date, feed): | ||
38 | return last_build_date | ||
39 | |||
40 | def get_categories(self, categories, feed): | ||
41 | return categories | ||
42 | |||
43 | def get_generator(self, generator, feed): | ||
44 | return generator | ||
45 | |||
46 | def get_docs(self, docs, feed): | ||
47 | return docs | ||
48 | |||
49 | def get_cloud(self, cloud, feed): | ||
50 | return cloud | ||
51 | |||
52 | def get_ttl(self, ttl, feed): | ||
53 | return ttl | ||
54 | |||
55 | def get_image(self, image, feed): | ||
56 | return image | ||
57 | |||
58 | def get_rating(self, rating, feed): | ||
59 | return rating | ||
60 | |||
61 | def get_text_input(self, text_input, feed): | ||
62 | return text_input | ||
63 | |||
64 | def get_skip_hours(self, skip_hours, feed): | ||
65 | return skip_hours | ||
66 | |||
67 | def get_skip_days(self, skip_days, feed): | ||
68 | return skip_days | ||
69 | |||
70 | def get_items(self, items, feed): | ||
71 | return [self.item_processor.process(item) for item in items] | ||
72 | |||
73 | def process(self, feed: PyRSS2Gen.RSS2): | ||