Skip to content

Commit 2676132

Browse files
authored
feat: import from opml (#96)
1 parent 7313e2e commit 2676132

File tree

5 files changed

+91
-1
lines changed

5 files changed

+91
-1
lines changed

core/admin.py

+17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from django.contrib.auth.models import User, Group
55
from django.utils.html import format_html
66
from django.utils.translation import gettext_lazy as _
7+
from django.urls import path, reverse
78

89
from .models import O_Feed, T_Feed
910
from .custom_admin_site import core_admin_site
@@ -19,6 +20,7 @@
1920
)
2021
from .tasks import update_original_feed, update_translated_feed
2122
from utils.modelAdmin_utils import valid_icon
23+
from .views import import_opml
2224

2325

2426
class O_FeedAdmin(admin.ModelAdmin):
@@ -40,6 +42,21 @@ class O_FeedAdmin(admin.ModelAdmin):
4042
actions = [o_feed_force_update, o_feed_export_as_opml, o_feed_batch_modify]
4143
list_per_page = 20
4244

45+
def get_urls(self):
46+
urls = super().get_urls()
47+
custom_urls = [
48+
path('import_opml/', self.admin_site.admin_view(import_opml), name='core_o_feed_import_opml'),
49+
]
50+
return custom_urls + urls
51+
52+
def changelist_view(self, request, extra_context=None):
53+
extra_context = extra_context or {}
54+
extra_context['import_opml_button'] = format_html(
55+
'<a class="button" href="{}">导入OPML</a>',
56+
reverse('admin:core_o_feed_import_opml')
57+
)
58+
return super().changelist_view(request, extra_context=extra_context)
59+
4360
def save_formset(self, request, form, formset, change):
4461
instances = formset.save(commit=False)
4562
for instance in instances:

core/urls.py

+1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
path("category/<str:category>/", views.category, name="category"),
1313
path("json/<str:feed_sid>", views.rss_json, name="json"),
1414
path("json/<str:feed_sid>/", views.rss_json, name="json"),
15+
path('core/o_feed/import_opml/', views.import_opml, name='import_opml'),
1516
re_path(r"(?P<feed_sid>[^/]+)/?$", views.rss, name="rss"),
1617
]

core/views.py

+31
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,40 @@
88
from django.views.decorators.cache import cache_page
99
from django.views.decorators.http import condition
1010
from .models import T_Feed, O_Feed
11+
from django.shortcuts import redirect
12+
from django.contrib import messages
13+
from django.core.files.uploadedfile import InMemoryUploadedFile
14+
from opyml import OPML
15+
from django.utils.translation import gettext_lazy as _
1116

1217
from utils.feed_action import merge_all_atom, check_file_path
1318

19+
def import_opml(request):
20+
if request.method == 'POST':
21+
opml_file = request.FILES.get('opml_file')
22+
if opml_file and isinstance(opml_file, InMemoryUploadedFile):
23+
try:
24+
opml_content = opml_file.read().decode('utf-8')
25+
opml = OPML.from_xml(opml_content)
26+
27+
for outline in opml.body.outlines:
28+
category = outline.text
29+
#category, _ = Category.objects.get_or_create(name=category_name)
30+
31+
for feed in outline.outlines:
32+
O_Feed.objects.create(
33+
name=feed.title or feed.text,
34+
feed_url=feed.xml_url,
35+
category=category
36+
)
37+
38+
messages.success(request, _("OPML file imported successfully."))
39+
except Exception as e:
40+
messages.error(request, _("Error importing OPML file: {}").format(str(e)))
41+
else:
42+
messages.error(request, _("Please upload a valid OPML file."))
43+
44+
return redirect('admin:core_o_feed_changelist')
1445

1546
def get_modified(request, feed_sid):
1647
try:

templates/admin/base_site.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
<div id="footer" style="text-align: center;">
6868
<a href="https://rsstranslator.com" title="RSS Translator">RSS Translator</a> ·
6969
<a href="https://afdian.com/a/versun" title="Donate">Donate</a> ·
70-
Version: <span data-version="2024.8.21">2024.8.21</span>
70+
Version: <span data-version="2024.8.30">2024.8.30</span>
7171
<svg id="update-button" class="svg-icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" onclick="checkUpdate()">
7272
<title>Check Updates</title>
7373
<path d="M783.568 328C724.571 241.095 624.953 184 512 184c-181.15 0-328 146.85-328 328h-72c0-220.914 179.086-400 400-400 135.738 0 255.685 67.611 328 170.994V128c0-8.837 7.163-16 16-16h48a8 8 0 0 1 8 8v248c0 17.673-14.327 32-32 32H632a8 8 0 0 1-8-8v-48c0-8.837 7.163-16 16-16h143.568zM240.432 696C299.429 782.905 399.047 840 512 840c181.15 0 328-146.85 328-328h72c0 220.914-179.086 400-400 400-135.738 0-255.685-67.611-328-170.994V896c0 8.837-7.163 16-16 16h-48a8 8 0 0 1-8-8V656c0-17.673 14.327-32 32-32h248a8 8 0 0 1 8 8v48c0 8.837-7.163 16-16 16H240.432z"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{% extends "admin/change_list.html" %}
2+
{% load i18n admin_urls %}
3+
4+
{% block object-tools-items %}
5+
{{ block.super }}
6+
<li>
7+
{{ import_opml_button }}
8+
</li>
9+
{% endblock %}
10+
11+
{% block content %}
12+
<div id="import-opml-modal" class="modal" style="display: none;">
13+
<div class="modal-content">
14+
<h2>{% trans "Import OPML" %}</h2>
15+
<form method="post" action="{% url 'admin:core_o_feed_import_opml' %}" enctype="multipart/form-data">
16+
{% csrf_token %}
17+
<input type="file" name="opml_file" accept=".opml,.xml">
18+
<input type="submit" value="{% trans 'Import' %}">
19+
</form>
20+
</div>
21+
22+
</div>
23+
{{ block.super }}
24+
<script>
25+
document.addEventListener('DOMContentLoaded', function() {
26+
var importButton = document.querySelector('a[href="{% url 'admin:core_o_feed_import_opml' %}"]');
27+
var modal = document.getElementById('import-opml-modal');
28+
29+
importButton.addEventListener('click', function(e) {
30+
e.preventDefault();
31+
modal.style.display = 'block';
32+
});
33+
34+
window.onclick = function(event) {
35+
if (event.target == modal) {
36+
modal.style.display = "none";
37+
}
38+
}
39+
});
40+
</script>
41+
{% endblock %}

0 commit comments

Comments
 (0)