django-rss-filter 0.1.0__tar.gz
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.
- django_rss_filter-0.1.0/.github/workflows/tests.yml +20 -0
- django_rss_filter-0.1.0/.gitignore +9 -0
- django_rss_filter-0.1.0/LICENSE +21 -0
- django_rss_filter-0.1.0/PKG-INFO +69 -0
- django_rss_filter-0.1.0/README.md +51 -0
- django_rss_filter-0.1.0/example/.python-version +1 -0
- django_rss_filter-0.1.0/example/config/__init__.py +0 -0
- django_rss_filter-0.1.0/example/config/asgi.py +16 -0
- django_rss_filter-0.1.0/example/config/settings.py +124 -0
- django_rss_filter-0.1.0/example/config/urls.py +24 -0
- django_rss_filter-0.1.0/example/config/wsgi.py +16 -0
- django_rss_filter-0.1.0/example/manage.py +23 -0
- django_rss_filter-0.1.0/example/pyproject.toml +17 -0
- django_rss_filter-0.1.0/example/uv.lock +292 -0
- django_rss_filter-0.1.0/pyproject.toml +55 -0
- django_rss_filter-0.1.0/rssfilter/__init__.py +0 -0
- django_rss_filter-0.1.0/rssfilter/admin.py +23 -0
- django_rss_filter-0.1.0/rssfilter/migrations/0001_initial.py +36 -0
- django_rss_filter-0.1.0/rssfilter/migrations/__init__.py +0 -0
- django_rss_filter-0.1.0/rssfilter/models.py +67 -0
- django_rss_filter-0.1.0/rssfilter/settings.py +3 -0
- django_rss_filter-0.1.0/rssfilter/urls.py +7 -0
- django_rss_filter-0.1.0/rssfilter/utils.py +46 -0
- django_rss_filter-0.1.0/rssfilter/views.py +9 -0
- django_rss_filter-0.1.0/tests/__init__.py +0 -0
- django_rss_filter-0.1.0/tests/settings.py +12 -0
- django_rss_filter-0.1.0/tests/test_utils.py +76 -0
- django_rss_filter-0.1.0/uv.lock +657 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Unit tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["*"]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: ["*"]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
max-parallel: 4
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v3
|
|
17
|
+
- uses: astral-sh/setup-uv@v3
|
|
18
|
+
- run: uv python install
|
|
19
|
+
- run: uv sync --group dev
|
|
20
|
+
- run: uv run pytest
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Loopwerk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-rss-filter
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Filter public RSS feeds, remove articles that contain certain keywords or categories.
|
|
5
|
+
Project-URL: Homepage, https://github.com/loopwerk/django-rss-filter/issues
|
|
6
|
+
Project-URL: Repository, https://github.com/loopwerk/django-rss-filter.git
|
|
7
|
+
Project-URL: Issues, https://github.com/loopwerk/django-rss-filter/issues
|
|
8
|
+
Author-email: Kevin Renskers <kevin@loopwerk.io>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: atom,django,feed,filter,mute,rss
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Requires-Dist: django>=3.2.0
|
|
14
|
+
Requires-Dist: fastfeedparser>=0.3.7
|
|
15
|
+
Requires-Dist: feedgen>=1.0.0
|
|
16
|
+
Requires-Dist: httpx>=0.28.1
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# django-rss-filter
|
|
20
|
+
|
|
21
|
+
This is a Django app that creates filtered RSS feeds. It does this by filtering exsiting RSS feeds, removing articles that match filtered words and/or filtered categories. It's what powers https://www.rssfilter.com.
|
|
22
|
+
|
|
23
|
+
It comes with one view that returns the filtered feed XML, as well as Django Admin configuration to make it possible and easy to self-host your own instance of django-rss-filter. It does not come with views to create or edit filtered feeds; this can be done using the Django Admin.
|
|
24
|
+
|
|
25
|
+
## Getting started
|
|
26
|
+
|
|
27
|
+
All instructions use [uv](https://docs.astral.sh/uv/), but should work just as well with pip or Poetry for example.
|
|
28
|
+
|
|
29
|
+
In an existing Django project:
|
|
30
|
+
|
|
31
|
+
1. Install: `uv add django-rss-filter`
|
|
32
|
+
2. Add `rssfilter` to `INSTALLED_APPS`
|
|
33
|
+
3. `uv run ./manage.py migrate`
|
|
34
|
+
4. Include the URL config: `path("", include("rssfilter.urls"))`
|
|
35
|
+
|
|
36
|
+
If you don't have a Django project yet, these are the steps to get started:
|
|
37
|
+
|
|
38
|
+
1. `uv init my-django-project`
|
|
39
|
+
2. `cd my-django-project`
|
|
40
|
+
3. `uv add django`
|
|
41
|
+
4. `uv run django-admin startproject my_django_app .`
|
|
42
|
+
5. `uv run ./manage.py migrate`
|
|
43
|
+
6. `uv run ./manage.py createsuperuser`
|
|
44
|
+
7. `uv run ./manage.py runserver`
|
|
45
|
+
|
|
46
|
+
This will get you up and running with a working Admin site at http://127.0.0.1:8000/admin/.
|
|
47
|
+
|
|
48
|
+
Then follow the first four steps to add django-rss-filter to your Django project.
|
|
49
|
+
|
|
50
|
+
## Example project
|
|
51
|
+
|
|
52
|
+
There's an example Django project using django-rss-filter under `example/`.
|
|
53
|
+
|
|
54
|
+
1. `cd example`
|
|
55
|
+
2. `uv run ./manage.py migrate`
|
|
56
|
+
3. `uv run ./manage.py createsuperuser`
|
|
57
|
+
4. `uv run ./manage.py runserver`
|
|
58
|
+
|
|
59
|
+
You can then go to http://127.0.0.1:8000/admin/ to create a feed, which you can then access at http://127.0.0.1:8000/[feed_uuid]/.
|
|
60
|
+
|
|
61
|
+
## Settings
|
|
62
|
+
|
|
63
|
+
There is one setting that can be configured: `RSS_FILTER_CACHE_SECONDS`. The default value is 300 (5 minutes).
|
|
64
|
+
|
|
65
|
+
This setting controls how long a feed will be cached before it's fetched, filtered, and stored again.
|
|
66
|
+
|
|
67
|
+
## Tests
|
|
68
|
+
|
|
69
|
+
Unit tests can be run with `uv run pytest`.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# django-rss-filter
|
|
2
|
+
|
|
3
|
+
This is a Django app that creates filtered RSS feeds. It does this by filtering exsiting RSS feeds, removing articles that match filtered words and/or filtered categories. It's what powers https://www.rssfilter.com.
|
|
4
|
+
|
|
5
|
+
It comes with one view that returns the filtered feed XML, as well as Django Admin configuration to make it possible and easy to self-host your own instance of django-rss-filter. It does not come with views to create or edit filtered feeds; this can be done using the Django Admin.
|
|
6
|
+
|
|
7
|
+
## Getting started
|
|
8
|
+
|
|
9
|
+
All instructions use [uv](https://docs.astral.sh/uv/), but should work just as well with pip or Poetry for example.
|
|
10
|
+
|
|
11
|
+
In an existing Django project:
|
|
12
|
+
|
|
13
|
+
1. Install: `uv add django-rss-filter`
|
|
14
|
+
2. Add `rssfilter` to `INSTALLED_APPS`
|
|
15
|
+
3. `uv run ./manage.py migrate`
|
|
16
|
+
4. Include the URL config: `path("", include("rssfilter.urls"))`
|
|
17
|
+
|
|
18
|
+
If you don't have a Django project yet, these are the steps to get started:
|
|
19
|
+
|
|
20
|
+
1. `uv init my-django-project`
|
|
21
|
+
2. `cd my-django-project`
|
|
22
|
+
3. `uv add django`
|
|
23
|
+
4. `uv run django-admin startproject my_django_app .`
|
|
24
|
+
5. `uv run ./manage.py migrate`
|
|
25
|
+
6. `uv run ./manage.py createsuperuser`
|
|
26
|
+
7. `uv run ./manage.py runserver`
|
|
27
|
+
|
|
28
|
+
This will get you up and running with a working Admin site at http://127.0.0.1:8000/admin/.
|
|
29
|
+
|
|
30
|
+
Then follow the first four steps to add django-rss-filter to your Django project.
|
|
31
|
+
|
|
32
|
+
## Example project
|
|
33
|
+
|
|
34
|
+
There's an example Django project using django-rss-filter under `example/`.
|
|
35
|
+
|
|
36
|
+
1. `cd example`
|
|
37
|
+
2. `uv run ./manage.py migrate`
|
|
38
|
+
3. `uv run ./manage.py createsuperuser`
|
|
39
|
+
4. `uv run ./manage.py runserver`
|
|
40
|
+
|
|
41
|
+
You can then go to http://127.0.0.1:8000/admin/ to create a feed, which you can then access at http://127.0.0.1:8000/[feed_uuid]/.
|
|
42
|
+
|
|
43
|
+
## Settings
|
|
44
|
+
|
|
45
|
+
There is one setting that can be configured: `RSS_FILTER_CACHE_SECONDS`. The default value is 300 (5 minutes).
|
|
46
|
+
|
|
47
|
+
This setting controls how long a feed will be cached before it's fetched, filtered, and stored again.
|
|
48
|
+
|
|
49
|
+
## Tests
|
|
50
|
+
|
|
51
|
+
Unit tests can be run with `uv run pytest`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ASGI config for config project.
|
|
3
|
+
|
|
4
|
+
It exposes the ASGI callable as a module-level variable named ``application``.
|
|
5
|
+
|
|
6
|
+
For more information on this file, see
|
|
7
|
+
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
from django.core.asgi import get_asgi_application
|
|
13
|
+
|
|
14
|
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
|
|
15
|
+
|
|
16
|
+
application = get_asgi_application()
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Django settings for config project.
|
|
3
|
+
|
|
4
|
+
Generated by 'django-admin startproject' using Django 5.1.7.
|
|
5
|
+
|
|
6
|
+
For more information on this file, see
|
|
7
|
+
https://docs.djangoproject.com/en/5.1/topics/settings/
|
|
8
|
+
|
|
9
|
+
For the full list of settings and their values, see
|
|
10
|
+
https://docs.djangoproject.com/en/5.1/ref/settings/
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
|
16
|
+
BASE_DIR = Path(__file__).resolve().parent.parent
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Quick-start development settings - unsuitable for production
|
|
20
|
+
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
|
|
21
|
+
|
|
22
|
+
# SECURITY WARNING: keep the secret key used in production secret!
|
|
23
|
+
SECRET_KEY = "django-insecure-26+#r2)29f3+2-%_%5_9=4&-h-b#2e0wa7@xj8q($c(92r)-_x"
|
|
24
|
+
|
|
25
|
+
# SECURITY WARNING: don't run with debug turned on in production!
|
|
26
|
+
DEBUG = True
|
|
27
|
+
|
|
28
|
+
ALLOWED_HOSTS = []
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Application definition
|
|
32
|
+
|
|
33
|
+
INSTALLED_APPS = [
|
|
34
|
+
"django.contrib.admin",
|
|
35
|
+
"django.contrib.auth",
|
|
36
|
+
"django.contrib.contenttypes",
|
|
37
|
+
"django.contrib.sessions",
|
|
38
|
+
"django.contrib.messages",
|
|
39
|
+
"django.contrib.staticfiles",
|
|
40
|
+
"rssfilter",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
MIDDLEWARE = [
|
|
44
|
+
"django.middleware.security.SecurityMiddleware",
|
|
45
|
+
"django.contrib.sessions.middleware.SessionMiddleware",
|
|
46
|
+
"django.middleware.common.CommonMiddleware",
|
|
47
|
+
"django.middleware.csrf.CsrfViewMiddleware",
|
|
48
|
+
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
|
49
|
+
"django.contrib.messages.middleware.MessageMiddleware",
|
|
50
|
+
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
ROOT_URLCONF = "config.urls"
|
|
54
|
+
|
|
55
|
+
TEMPLATES = [
|
|
56
|
+
{
|
|
57
|
+
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
|
58
|
+
"DIRS": [],
|
|
59
|
+
"APP_DIRS": True,
|
|
60
|
+
"OPTIONS": {
|
|
61
|
+
"context_processors": [
|
|
62
|
+
"django.template.context_processors.debug",
|
|
63
|
+
"django.template.context_processors.request",
|
|
64
|
+
"django.contrib.auth.context_processors.auth",
|
|
65
|
+
"django.contrib.messages.context_processors.messages",
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
WSGI_APPLICATION = "config.wsgi.application"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# Database
|
|
75
|
+
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
|
|
76
|
+
|
|
77
|
+
DATABASES = {
|
|
78
|
+
"default": {
|
|
79
|
+
"ENGINE": "django.db.backends.sqlite3",
|
|
80
|
+
"NAME": BASE_DIR / "db.sqlite3",
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# Password validation
|
|
86
|
+
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
|
|
87
|
+
|
|
88
|
+
AUTH_PASSWORD_VALIDATORS = [
|
|
89
|
+
{
|
|
90
|
+
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
|
100
|
+
},
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# Internationalization
|
|
105
|
+
# https://docs.djangoproject.com/en/5.1/topics/i18n/
|
|
106
|
+
|
|
107
|
+
LANGUAGE_CODE = "en-us"
|
|
108
|
+
|
|
109
|
+
TIME_ZONE = "UTC"
|
|
110
|
+
|
|
111
|
+
USE_I18N = True
|
|
112
|
+
|
|
113
|
+
USE_TZ = True
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# Static files (CSS, JavaScript, Images)
|
|
117
|
+
# https://docs.djangoproject.com/en/5.1/howto/static-files/
|
|
118
|
+
|
|
119
|
+
STATIC_URL = "static/"
|
|
120
|
+
|
|
121
|
+
# Default primary key field type
|
|
122
|
+
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
|
|
123
|
+
|
|
124
|
+
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
URL configuration for config project.
|
|
3
|
+
|
|
4
|
+
The `urlpatterns` list routes URLs to views. For more information please see:
|
|
5
|
+
https://docs.djangoproject.com/en/5.1/topics/http/urls/
|
|
6
|
+
Examples:
|
|
7
|
+
Function views
|
|
8
|
+
1. Add an import: from my_app import views
|
|
9
|
+
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
|
10
|
+
Class-based views
|
|
11
|
+
1. Add an import: from other_app.views import Home
|
|
12
|
+
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
|
13
|
+
Including another URLconf
|
|
14
|
+
1. Import the include() function: from django.urls import include, path
|
|
15
|
+
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from django.contrib import admin
|
|
19
|
+
from django.urls import include, path
|
|
20
|
+
|
|
21
|
+
urlpatterns = [
|
|
22
|
+
path("", include("rssfilter.urls")),
|
|
23
|
+
path("admin/", admin.site.urls),
|
|
24
|
+
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
WSGI config for config project.
|
|
3
|
+
|
|
4
|
+
It exposes the WSGI callable as a module-level variable named ``application``.
|
|
5
|
+
|
|
6
|
+
For more information on this file, see
|
|
7
|
+
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
from django.core.wsgi import get_wsgi_application
|
|
13
|
+
|
|
14
|
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
|
|
15
|
+
|
|
16
|
+
application = get_wsgi_application()
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Django's command-line utility for administrative tasks."""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main():
|
|
9
|
+
"""Run administrative tasks."""
|
|
10
|
+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
|
11
|
+
try:
|
|
12
|
+
from django.core.management import execute_from_command_line
|
|
13
|
+
except ImportError as exc:
|
|
14
|
+
raise ImportError(
|
|
15
|
+
"Couldn't import Django. Are you sure it's installed and "
|
|
16
|
+
"available on your PYTHONPATH environment variable? Did you "
|
|
17
|
+
"forget to activate a virtual environment?"
|
|
18
|
+
) from exc
|
|
19
|
+
execute_from_command_line(sys.argv)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if __name__ == "__main__":
|
|
23
|
+
main()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "django-rss-filter-example"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A simple Django project using django-rss-filter"
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "Kevin Renskers", email = "kevin@loopwerk.io"},
|
|
7
|
+
]
|
|
8
|
+
license = "MIT"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.13"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"django>=5.1.7",
|
|
13
|
+
"django-rss-filter",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[tool.uv.sources]
|
|
17
|
+
django-rss-filter = { path = "../", editable = true }
|