diff --git a/README.md b/README.md
index b210ea6..25f3206 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,15 @@ pip install --no-cache-dir -r requirements.txt -i https://pypi.mirrors.ustc.edu.
```

+# v2.2.0 说明
+
+```shell
+ 1、新增RSS订阅功能。
+ 2、新增RSS订阅后直接发送TR下载,(QB未测试但已集成)。
+ 3、此版本不支持在线升级使用。
+```
+
+
# v2.1.0 说明
```shell
diff --git a/apps/common/sites_sign.py b/apps/common/sites_sign.py
index 2016d56..91dff73 100644
--- a/apps/common/sites_sign.py
+++ b/apps/common/sites_sign.py
@@ -1170,7 +1170,7 @@ def opencd(site_name, site_name_cn, site_url, site_cookie):
logger.info(data_ocr)
#验证码不足6未跳过
- if len(data_ocr) < 6 :
+ if len(data_ocr) != 6 :
continue
data = {'imagehash': imagehash,
@@ -1246,7 +1246,7 @@ def hdsky(site_name, site_name_cn, site_url, site_cookie):
)
try:
- session = requests.session()
+ #session = requests.session()
#验证码签到执行3次验证
for i in range(3):
@@ -1256,7 +1256,7 @@ def hdsky(site_name, site_name_cn, site_url, site_cookie):
#print('i--------->',i)
return False, "%s(%s) 错误:连续3次验证码失败" % (site_name,site_name_cn)
- response = session.post(sign_url, headers=headers, data=data, timeout=10)
+ response = requests.post(sign_url, headers=headers, data=data, timeout=10)
logger.info(response.text)
if response.status_code == 200:
result = json.loads(response.text)
@@ -1264,7 +1264,7 @@ def hdsky(site_name, site_name_cn, site_url, site_cookie):
code = result['code']
#拼接验证码图片
hdsky_image_url = 'https://hdsky.me/image.php?action=regimage&imagehash=' + code
- response = session.get(hdsky_image_url, headers=headers, timeout=10)
+ response = requests.get(hdsky_image_url, headers=headers, timeout=10)
with open(image_code_name, "wb") as fp:
fp.write(response.content)
@@ -1277,14 +1277,14 @@ def hdsky(site_name, site_name_cn, site_url, site_cookie):
logger.info(data_ocr)
#验证码不足6未跳过
- if len(data_ocr) < 6 :
+ if len(data_ocr) != 6 :
continue
data = {'action': 'showup',
'imagehash': code,
'imagestring': data_ocr
}
- response = session.post("https://hdsky.me/showup.php", headers=headers, data=data, timeout=10)
+ response = requests.post("https://hdsky.me/showup.php", headers=headers, data=data, timeout=10)
logger.info(response.text)
try:
result = json.loads(response.text)
diff --git a/apps/common/utils.py b/apps/common/utils.py
index dcc3dc7..7ae89e8 100644
--- a/apps/common/utils.py
+++ b/apps/common/utils.py
@@ -121,8 +121,6 @@ def timesince(dt, since='', default="just now"):
_STRPTIME_LOCK = threading.Lock()
-_GMT_FORMAT = "%a, %d %b %Y %H:%M:%S GMT"
-_ISO8601_FORMAT = "%Y-%m-%dT%H:%M:%S.000Z"
def now_date():
"""当前时间"""
@@ -155,6 +153,7 @@ def http_to_unixtime(time_string):
HTTP Date形如 `Sat, 05 Dec 2015 11:10:29 GMT` 。
"""
+ _GMT_FORMAT = "%a, %d %b %Y %H:%M:%S GMT"
return to_unixtime(time_string, _GMT_FORMAT)
def cst_to_unixtime(time_string):
@@ -166,6 +165,7 @@ def cst_to_unixtime(time_string):
def iso8601_to_unixtime(time_string):
"""把ISO8601时间字符串(形如,2012-02-24T06:07:48.000Z)转换为UNIX时间,精确到秒。"""
+ _ISO8601_FORMAT = "%Y-%m-%dT%H:%M:%S.000Z"
return to_unixtime(time_string, _ISO8601_FORMAT)
def str2datetime(st, s_format='%Y-%m-%d %H:%M:%S'):
@@ -249,10 +249,7 @@ def capacity_convert(size, expect='auto', rate=1000):
return expect_size, expect
def filesizeformat(value, baseMB=False):
- """Format the value like a 'human-readable' file size (i.e. 13 KB,
- 4.1 MB, 102 bytes, etc). Per default decimal prefixes are used (mega,
- giga etc.), if the second parameter is set to `True` the binary
- prefixes are (mebi, gibi).
+ """将字节转换为 1.00KB 1.00Mb 1.00gb
"""
try:
bytes = float(value)
@@ -271,16 +268,16 @@ def filesizeformat(value, baseMB=False):
if bytes < base:
ret = '%d Bytes' % (bytes)
elif bytes < base * base:
- ret = '%d KB' % (bytes / base)
+ ret = '%.2f KB' % (bytes / base)
elif bytes < base * base * base:
- ret = '%d MB' % (bytes / (base * base))
+ ret = '%.2f MB' % (bytes / (base * base))
elif bytes < base * base * base * base:
- if bytes % (base * base * base) == 0:
- ret = '%d GB' % (bytes / (base * base * base))
+ if bytes % (base * base * base) >= 0:
+ ret = '%.2f GB' % (bytes / (base * base * base))
else:
- ret = "%d MB" % (bytes / (base * base))
+ ret = "%.2f MB" % (bytes / (base * base))
else:
- ret = '%.1f TB' % (bytes / (base * base * base * base))
+ ret = '%.2f TB' % (bytes / (base * base * base * base))
return ret
diff --git a/apps/cron/crontabs.py b/apps/cron/crontabs.py
index 23151d1..36618fe 100644
--- a/apps/cron/crontabs.py
+++ b/apps/cron/crontabs.py
@@ -6,12 +6,18 @@ from urllib import parse
import os
import logging
from bs4 import BeautifulSoup
+import feedparser
+from thefuzz import process
+from transmission_rpc import Client
+import qbittorrentapi
-from common.utils import send_email,send_telegram,send_iyuu, send_enwechat
+from common.utils import send_email,send_telegram,send_iyuu, send_enwechat, parseUrl
from common.sites_sign import signIngress
from sites.models import SiteConfig, SiteInfo
from .models import Job, Log
from notify.models import NotifyConfig
+from rss.models import Rule, SeedInfo
+
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
from django_apscheduler.jobstores import DjangoJobStore, register_job
@@ -96,6 +102,9 @@ def my_scheduler(crontab_id=None, crontab_status=None, hour="*", minute="*", job
elif jobtype_id == 1003:
#重签
scheduler.add_job(re_fail_sign, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id])
+ elif jobtype_id == 1002:
+ #RSS订阅
+ scheduler.add_job(rss, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id])
else:
#禁用状态,直接删除任务
@@ -117,6 +126,8 @@ def my_scheduler(crontab_id=None, crontab_status=None, hour="*", minute="*", job
scheduler.add_job(sign, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id])
elif jobtype_id == 1003:
scheduler.add_job(re_fail_sign, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id])
+ elif jobtype_id == 1002:
+ scheduler.add_job(rss, 'cron', hour=hour, minute=minute, id=crontab_id, args=[crontab_id])
return True
@@ -338,4 +349,224 @@ def send_msg(crontab_id = None, send_data = []):
logger.info("-------------enwechat-------------------")
logger.info(msg)
+ return
+
+#==========================================================================================================
+def rss(crontab_id):
+ """
+ 执行订阅
+ 参数:
+ crontab_id:执行任务的ID
+ """
+
+ headers = {
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36',
+ #'cookie': site_cookie,
+ }
+
+ #获取任务ID
+ job_id = Job.objects.get(crontab_id=crontab_id)
+ ormdata_rule = Rule.objects.get(job_id = job_id.id)
+ #订阅地址
+ rss_url = ormdata_rule.config_id.url
+ #站点信息
+ siteinfo_id = ormdata_rule.config_id.siteinfo_id
+ site_name = siteinfo_id.siteconfig_name
+ site_name_cn = siteinfo_id.siteconfig_name_cn
+ #关键字
+ keyword = [x for x in ormdata_rule.keyword.split(',')]
+ #码率
+ rate = ormdata_rule.rate
+
+ logger.info("-------------开始RSS订阅任务%s(%s)-------------------" % (site_name, site_name_cn))
+
+ d = feedparser.parse(rss_url, request_headers=headers)
+ #未获取返回状态
+ if 'status' not in d:
+ logger.error('请求RSS地址失败')
+ return
+
+ #匹配RSS过滤后发送
+ send_data = []
+ if d.status == 200:
+ #entries 电影内容
+ for i in d.entries:
+ #标题 [Movie][Back to 1942 2012 V2 2160p WEB-DL H265 AAC-LeagueWEB][一九四二/温故1942/1942 | 类型: 剧情/历史/战争/灾难 主演: 张国立/张默/徐帆 [国语/中英双语硬字] | *4K* *V2高码*][16.35 GB]
+ seed_name = i.title
+ #种子类型 Movie
+ seed_type = i.tags[0].term
+ #种子页地址 https://lemonhd.org/details_movie.php?id=327311
+ seed_link = i.link
+ #'links': [{'rel': 'alternate', 'type': 'text/html', 'href': 'https://lemonhd.org/details_tv.php?id=328435'},
+ # {'length': '2543569030', 'type': 'application/x-bittorrent', 'href': 'https://lemonhd.org/download.php?id=328435&passkey=c1c6b3d5291bf330ffa9ad2872d52144',
+ # 'rel': 'enclosure'}
+ # ]
+ #种子下载地址
+ seed_download_url = i.links[1].href
+ #种子大小 字节数
+ seed_length = i.links[1].length
+ #发布时间 Wed, 07 Sep 2022 14:27:09 +0800
+ seed_published_time = i.published
+ _TIME_FORMAT = "%a, %d %b %Y %H:%M:%S %z"
+ #将字符串转换成datetime在格式化成需要的 2022-09-07 09:26:22
+ seed_published_time = datetime.datetime.strptime(seed_published_time, _TIME_FORMAT).strftime('%Y-%m-%d %H:%M:%S')
+ #种子ID afe783da83684e92f5ff6a4c42fd11da216b77a2
+ seed_hash_id = i.id
+
+ seedinfo = None
+ #确认无重复,则添加
+ num = SeedInfo.objects.filter(seed_hash_id=seed_hash_id).filter(siteinfo_id=siteinfo_id).count()
+ if num == 0:
+ if keyword[0] == '':
+
+ #未添加关键字则全部加入
+ if rate == 'all':
+ #码率为所有
+ seedinfo = SeedInfo.objects.create(seed_name = seed_name,
+ seed_type = seed_type,
+ seed_details_link = seed_link,
+ seed_donwload_link = seed_download_url,
+ seed_file_size = seed_length,
+ seed_hash_id = seed_hash_id,
+ seed_published_time = seed_published_time,
+ siteinfo_id = siteinfo_id,
+ rule_id = ormdata_rule
+ )
+ else:
+ if rate in seed_name:
+ seedinfo = SeedInfo.objects.create(seed_name = seed_name,
+ seed_type = seed_type,
+ seed_details_link = seed_link,
+ seed_donwload_link = seed_download_url,
+ seed_file_size = seed_length,
+ seed_hash_id = seed_hash_id,
+ seed_published_time = seed_published_time,
+ siteinfo_id = siteinfo_id,
+ rule_id = ormdata_rule
+ )
+ #发送下载器
+ seed_download(seedinfo.id)
+ #将电影名加入发送
+ send_data.append(seed_name)
+ else:
+ #通过匹配关键字添加
+ _name, num=process.extractOne(seed_name, keyword)
+ if num >= 50:
+ #匹配度大于50添加
+ if rate == 'all':
+ #码率为所有
+ seedinfo = SeedInfo.objects.create(seed_name = seed_name,
+ seed_type = seed_type,
+ seed_details_link = seed_link,
+ seed_donwload_link = seed_download_url,
+ seed_file_size = seed_length,
+ seed_hash_id = seed_hash_id,
+ seed_published_time = seed_published_time,
+ siteinfo_id = siteinfo_id,
+ rule_id = ormdata_rule
+ )
+ else:
+ if rate in seed_name:
+ seedinfo = SeedInfo.objects.create(seed_name = seed_name,
+ seed_type = seed_type,
+ seed_details_link = seed_link,
+ seed_donwload_link = seed_download_url,
+ seed_file_size = seed_length,
+ seed_hash_id = seed_hash_id,
+ seed_published_time = seed_published_time,
+ siteinfo_id = siteinfo_id,
+ rule_id = ormdata_rule
+ )
+ #发送下载器
+ seed_download(seedinfo.id)
+ #将电影名加入发送
+ send_data.append(seed_name)
+ #发送通知
+ send_msg(crontab_id,send_data)
+
+ return
+
+def seed_download(seedinfo_id):
+ """
+ 下载种子
+ 参数
+ seedinfo_id rss订阅后存入数据库的id
+ """
+
+ ormdata_seedinfo = SeedInfo.objects.get(id = seedinfo_id)
+ #下载连接
+ seed_donwload_link = ormdata_seedinfo.seed_donwload_link
+ #下载器类型
+ download_type = ormdata_seedinfo.rule_id.tools_id.typed
+ download_username = ormdata_seedinfo.rule_id.tools_id.username
+ download_password = ormdata_seedinfo.rule_id.tools_id.password
+ download_url = ormdata_seedinfo.rule_id.tools_id.url
+ #下载目录
+ download_dirname = ormdata_seedinfo.rule_id.tools_id.dirname
+ #加入下载器后是否立刻下载
+ is_paused = ormdata_seedinfo.rule_id.is_paused
+
+ if download_dirname == "":
+ download_dirname = None
+
+ url_data = parseUrl(download_url)
+
+ #保存加入下载器后返回的ID
+ torrent_id = None
+ if download_type == 'tr':
+ try:
+
+ c = Client(protocol= url_data['protocol'],
+ host=url_data['host'],
+ port=url_data['port'],
+ username=download_username,
+ password=download_password,
+ timeout = 10
+ )
+
+ torrent = c.add_torrent(seed_donwload_link,
+ timeout = 10,
+ download_dir = download_dirname,
+ #paused = is_paused, #立刻下载,需要下载器开启默认下载才有效
+ )
+ #获取种子id
+ torrent_id = torrent.id
+ #如果启动则下载
+ if is_paused:
+ c.start_torrent(torrent_id)
+
+ ormdata_seedinfo.seed_torrent_id = torrent_id
+ ormdata_seedinfo.seed_status = True
+ ormdata_seedinfo.save()
+
+ except Exception as e:
+ print(e)
+
+ elif download_type == 'qb':
+ try:
+
+ c = qbittorrentapi.Client(
+ host=url_data['host'],
+ port=url_data['port'],
+ username=download_username,
+ password=download_password,
+ )
+
+ torrent = c.torrents_add(seed_donwload_link,
+ save_path=download_dirname,
+ #is_paused=is_paused, #立刻下载
+ )
+ #获取种子id
+ torrent_id = torrent.id
+ #如果启动则下载
+ if is_paused:
+ c.start_torrent(torrent_id)
+
+ ormdata_seedinfo.seed_torrent_id = torrent_id
+ ormdata_seedinfo.seed_status = True
+ ormdata_seedinfo.save()
+
+ except Exception as e:
+ print(e)
+
return
\ No newline at end of file
diff --git a/apps/cron/views.py b/apps/cron/views.py
index 7d03159..1ec2659 100644
--- a/apps/cron/views.py
+++ b/apps/cron/views.py
@@ -545,14 +545,14 @@ class SignJobView(LoginRequiredMixin,TemplateView):
name = "签到"
#未配置消息通知不予通过
- if len(notifys) == 0:
- response_data={"code":0,"msg":"请配置消息通知!"}
- return JsonResponse(response_data)
+ #if len(notifys) == 0:
+ #response_data={"code":0,"msg":"请配置消息通知!"}
+ #return JsonResponse(response_data)
data_count = Job.objects.filter(jobtype_id=1000).count()
if data_count == 0:
ormdata = Job.objects.create(name=name,
- crontab_status=crontab_status,
+ crontab_status=int(crontab_status),
hour=hour,
minute=minute,
jobtype_id=jobtype_id,
@@ -563,7 +563,7 @@ class SignJobView(LoginRequiredMixin,TemplateView):
)
else:
ormdata = Job.objects.get(id=_id)
- ormdata.crontab_status = crontab_status
+ ormdata.crontab_status = int(crontab_status)
ormdata.hour = hour
ormdata.minute = minute
ormdata.crontab_time = crontab_time
diff --git a/apps/download/__init__.py b/apps/download/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/apps/download/admin.py b/apps/download/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/apps/download/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/apps/download/apps.py b/apps/download/apps.py
new file mode 100644
index 0000000..c72d845
--- /dev/null
+++ b/apps/download/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class DownloadConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'download'
diff --git a/apps/download/migrations/0001_initial.py b/apps/download/migrations/0001_initial.py
new file mode 100644
index 0000000..1c8c39d
--- /dev/null
+++ b/apps/download/migrations/0001_initial.py
@@ -0,0 +1,26 @@
+# Generated by Django 4.1 on 2022-09-08 14:02
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Tools',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=30, verbose_name='下载器名称')),
+ ('typed', models.CharField(max_length=30, verbose_name='下载器类型tr,qb')),
+ ('url', models.URLField(blank=True, verbose_name='下载器地址')),
+ ('username', models.CharField(max_length=50, verbose_name='下载器用户名')),
+ ('password', models.CharField(max_length=128, verbose_name='下载器密码')),
+ ('dirname', models.CharField(max_length=150, null=True, verbose_name='默认下载目录')),
+ ],
+ ),
+ ]
diff --git a/apps/download/migrations/0002_alter_tools_name.py b/apps/download/migrations/0002_alter_tools_name.py
new file mode 100644
index 0000000..8c3548c
--- /dev/null
+++ b/apps/download/migrations/0002_alter_tools_name.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.1 on 2022-09-08 17:04
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('download', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='tools',
+ name='name',
+ field=models.CharField(max_length=30, unique=True, verbose_name='下载器名称'),
+ ),
+ ]
diff --git a/apps/download/migrations/__init__.py b/apps/download/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/apps/download/models.py b/apps/download/models.py
new file mode 100644
index 0000000..4d7debe
--- /dev/null
+++ b/apps/download/models.py
@@ -0,0 +1,12 @@
+from django.db import models
+
+# Create your models here.
+
+class Tools(models.Model):
+ """下载器"""
+ name = models.CharField('下载器名称', max_length=30, unique=True)
+ typed = models.CharField('下载器类型tr,qb', max_length=30)
+ url = models.URLField('下载器地址', blank=True)
+ username = models.CharField('下载器用户名', max_length=50)
+ password = models.CharField('下载器密码', max_length=128)
+ dirname = models.CharField('默认下载目录', max_length=150, null=True)
\ No newline at end of file
diff --git a/apps/download/templates/download/tools.html b/apps/download/templates/download/tools.html
new file mode 100644
index 0000000..e5e72b6
--- /dev/null
+++ b/apps/download/templates/download/tools.html
@@ -0,0 +1,235 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/download/templates/download/toolsadd.html b/apps/download/templates/download/toolsadd.html
new file mode 100644
index 0000000..3ae615f
--- /dev/null
+++ b/apps/download/templates/download/toolsadd.html
@@ -0,0 +1,112 @@
+
+
+
+
\ No newline at end of file
diff --git a/apps/download/templates/download/toolsedit.html b/apps/download/templates/download/toolsedit.html
new file mode 100644
index 0000000..847bfa0
--- /dev/null
+++ b/apps/download/templates/download/toolsedit.html
@@ -0,0 +1,140 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/download/tests.py b/apps/download/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/apps/download/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/apps/download/urls/__init__.py b/apps/download/urls/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/apps/download/urls/__init__.py
@@ -0,0 +1 @@
+
diff --git a/apps/download/urls/views_urls.py b/apps/download/urls/views_urls.py
new file mode 100644
index 0000000..038e50f
--- /dev/null
+++ b/apps/download/urls/views_urls.py
@@ -0,0 +1,21 @@
+# coding:utf-8
+from django.urls import path
+from .. import views, views_request
+
+app_name = 'download'
+
+urlpatterns = [
+ # Resource asset path
+
+ #下载器配置
+
+ path('tools', views.ToolsListView.as_view()),
+ path('tools/add', views.ToolsAddView.as_view()),
+ path('tools/edit', views.ToolsEditView.as_view()),
+ path('tools/del', views.ToolsDelView.as_view()),
+ path('tools/list', views_request.tools),
+ path('tools/select/list', views_request.select_tools),
+ path('tools/test', views_request.tools_test),
+
+]
+
diff --git a/apps/download/views.py b/apps/download/views.py
new file mode 100644
index 0000000..79f5ebb
--- /dev/null
+++ b/apps/download/views.py
@@ -0,0 +1,165 @@
+from django.shortcuts import render
+from django.views.generic import TemplateView
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.http import JsonResponse
+
+from .models import Tools
+
+# Create your views here.
+
+class ToolsListView(LoginRequiredMixin,TemplateView):
+ """
+ 显示
+ """
+ template_name = 'download/tools.html'
+
+ def get(self, request, *args, **kwargs):
+ """
+
+ """
+ return super(ToolsListView, self).get(request, *args, **kwargs)
+
+ #显示编辑模板
+ def get_context_data(self, **kwargs):
+
+ context = {
+ # 'data': self.ormdata_game
+ }
+ kwargs.update(context)
+ return super(ToolsListView, self).get_context_data(**kwargs)
+
+
+class ToolsAddView(LoginRequiredMixin,TemplateView):
+ """
+ 添加
+ """
+ template_name = 'download/toolsadd.html'
+
+ #显示添加模板
+ def get(self, request, *args, **kwargs):
+ """
+ """
+ return super(ToolsAddView, self).get(request, *args, **kwargs)
+
+ #显示编辑模板
+ def get_context_data(self, **kwargs):
+
+ context = {
+ }
+ kwargs.update(context)
+ return super(ToolsAddView, self).get_context_data(**kwargs)
+
+
+ #数据提交接收方法
+ def post(self, request, *args, **kwargs):
+ """
+ 数据提交
+ """
+ name = request.POST.get("name").strip()
+ url = request.POST.get("url").strip()
+ typed = request.POST.get("typed").strip()
+ username = request.POST.get("username").strip()
+ password = request.POST.get("password").strip()
+ dirname = request.POST.get("dirname").strip()
+
+
+ ormdata = Tools.objects.create(name=name,
+ url=url,
+ typed=typed,
+ username=username,
+ password=password,
+ dirname=dirname
+ )
+
+ ormdata.save()
+
+ response_data={"code":1,"msg":"添加成功"}
+
+
+ return JsonResponse(response_data)
+
+class ToolsEditView(LoginRequiredMixin,TemplateView):
+ """
+ 编辑域名
+ """
+ template_name = 'download/toolsedit.html'
+
+ #显示添加模板
+ def get(self, request, *args, **kwargs):
+ """
+ 得到
+ """
+
+ #记录ID
+ self._id = request.GET.get('id')
+ self.ormdata = Tools.objects.get(id=self._id)
+
+ return super(ToolsEditView, self).get(request, *args, **kwargs)
+
+ #显示编辑模板
+ def get_context_data(self, **kwargs):
+
+ context = {
+ 'id': self._id,
+ 'url': self.ormdata.url,
+ 'name': self.ormdata.name,
+ 'typed': self.ormdata.typed,
+ 'username': self.ormdata.username,
+ 'password': self.ormdata.password,
+ 'dirname': self.ormdata.dirname
+ }
+ kwargs.update(context)
+ return super(ToolsEditView, self).get_context_data(**kwargs)
+
+ #数据提交接收方法
+ def post(self, request, *args, **kwargs):
+ """
+ 数据提交
+ """
+ url = request.POST.get("url").strip()
+ name = request.POST.get("name").strip()
+ typed = request.POST.get("typed").strip()
+ username = request.POST.get("username").strip()
+ password = request.POST.get("password").strip()
+ dirname = request.POST.get("dirname").strip()
+
+ _id = request.POST.get('id')
+
+ ormdata = Tools.objects.get(id=_id)
+
+ ormdata.url = url
+ ormdata.name=name
+ ormdata.typed = typed
+ ormdata.username = username
+ ormdata.password = password
+ ormdata.dirname = dirname
+
+ ormdata.save()
+
+ response_data={"code":1,"msg":"添加成功"}
+
+ return JsonResponse(response_data)
+
+class ToolsDelView(LoginRequiredMixin,TemplateView):
+ """
+ 删除
+ """
+ def post(self, request, *args, **kwargs):
+ """
+ 数据提交
+ """
+
+ #得到批量或者单个要删除的id
+ ids = request.POST.getlist("ids[]")
+ #print("ids====>",ids)
+
+ Tools.objects.filter(id__in=ids).delete()
+
+ #Site.objects.filter(id=i).delete()
+
+ response_data={"code":1,"msg":"操作成功"}
+
+
+ return JsonResponse(response_data)
+
+#==================
\ No newline at end of file
diff --git a/apps/download/views_request.py b/apps/download/views_request.py
new file mode 100644
index 0000000..01dadf6
--- /dev/null
+++ b/apps/download/views_request.py
@@ -0,0 +1,158 @@
+#coding=utf-8
+from django.http import JsonResponse, StreamingHttpResponse,HttpResponse
+from django.db.models import Q
+from django.contrib.auth.decorators import login_required
+from transmission_rpc import Client
+import qbittorrentapi
+
+from .models import Tools
+from common.utils import parseUrl
+
+#直接使用检查是否管理员
+#from django.contrib.auth.decorators import user_passes_test
+#@user_passes_test(lambda u: u.is_superuser)
+
+@login_required
+def tools(request):
+ """
+ 提供相应的数据
+ """
+
+ #得到偏移量
+ pageIndex= int(request.GET.get('page',1))
+ #得到查询个数
+ pageSize = int(request.GET.get('limit',10))
+
+ #搜索字段
+ searchKey = request.GET.get('searchKey','')
+ searchValue = request.GET.get('searchValue','')
+ #去掉空格
+ searchValue = searchValue.strip()
+
+ #得到排序字段
+ sort = request.GET.get('sort','id')
+ #得到排序规则
+ order_by_type = request.GET.get('order','')
+
+ if order_by_type == 'asc':
+ order_by = sort
+ else:
+ order_by = '-' + sort
+
+ data = {}
+ data['code'] = 0
+ data['msg'] = ""
+ data['data'] = []
+
+ if searchValue == '':
+
+ data['count'] = Tools.objects.count()
+ if pageIndex == 1:
+ ormdata = Tools.objects.order_by(order_by)[:pageSize] #offset:limit
+ else:
+ ormdata = Tools.objects.order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
+ else:
+
+ data['count'] = Tools.objects.filter(Q(name__icontains=searchValue)|Q(typed__icontains=searchValue)).count()
+ if pageIndex == 1:
+ ormdata = Tools.objects.filter(Q(name__icontains=searchValue)|Q(typed__icontains=searchValue)).order_by(order_by)[:pageSize] #offset:limit
+ else:
+ ormdata = Tools.objects.filter(Q(name__icontains=searchValue)|Q(typed__icontains=searchValue)).order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
+
+ for i in ormdata:
+
+ data['data'].append({"id":i.id,
+ "name":i.name,
+ "typed":i.typed,
+ "username":i.username,
+ "url":i.url,
+ "password":i.password,
+ "dirname":i.dirname,
+ })
+ #返回json串
+ #return HttpResponse(json.dumps(data,ensure_ascii = False), "application/json")
+ return JsonResponse(data)
+
+#==================
+@login_required
+def tools_test(request):
+ """
+ 测试下载器配置连通性
+ """
+
+ url = request.POST.get("url").strip()
+ typed = request.POST.get("typed").strip()
+ username = request.POST.get("username").strip()
+ password = request.POST.get("password").strip()
+
+ url_data = parseUrl(url)
+
+ if typed == 'tr':
+ try:
+
+ c = Client(protocol= url_data['protocol'],
+ host=url_data['host'],
+ port=url_data['port'],
+ username=username,
+ password=password,
+ timeout = 10
+ )
+
+ response_data={"code":1,"msg": "连接成功" }
+ except:
+ response_data={"code":0,"msg": "连接失败" }
+ elif typed == 'qb':
+
+ c = qbittorrentapi.Client(
+ host=url_data['host'],
+ port=url_data['port'],
+ username=username,
+ password=password,
+ )
+
+ try:
+ c.auth_log_in()
+ response_data={"code":1,"msg": "连接成功" }
+ except:
+ response_data={"code":0,"msg": "连接失败" }
+
+ return JsonResponse(response_data)
+
+#==================
+@login_required
+def select_tools(request):
+ """
+ RSS规则
+ xmSelect
+ """
+
+ data = {}
+ data['code'] = 0
+ data['msg'] = ""
+ data['data'] = []
+
+
+ #得到排序字段
+ sort = request.GET.get('sort','id')
+ #得到排序规则
+ order_by_type = request.GET.get('order','')
+
+ if order_by_type == 'asc':
+ order_by = sort
+ else:
+ order_by = '-' + sort
+
+ #获取所有记录
+ data['count'] = Tools.objects.count()
+
+ ormdata = Tools.objects.order_by(order_by).all()
+
+
+ for i in ormdata:
+
+ data['data'].append({
+ "id":i.id,
+ "name":i.name
+ })
+
+ return JsonResponse(data)
\ No newline at end of file
diff --git a/apps/initdata/initDatas.py b/apps/initdata/initDatas.py
index 8e61001..a62ba39 100644
--- a/apps/initdata/initDatas.py
+++ b/apps/initdata/initDatas.py
@@ -1,16 +1,17 @@
from myauth.models import User
from django.contrib.auth.hashers import make_password
-from sites.models import SiteConfig
+from sites.models import SiteConfig, SiteInfo
from cron.models import JobType
from notify.models import MailType
+from rss.models import FilmCategory, FilmType
def init_datas():
"""
初始化数据库
"""
print('开始初始化用户数据库...')
-
+
if User.objects.count() == 0:
#添加管理员
User.objects.create(name='admin',
@@ -24,7 +25,7 @@ def init_datas():
print('初始化管理员成功.')
else:
print("管理员已经存在,忽略...")
-
+
print('开始初始化站点配置...')
sites_data = [{'name':'hdfans','name_cn':'红豆饭','index_url':'https://hdfans.org','sign_type':'general'},
{'name':'1ptba','name_cn':'壹PT吧','index_url':'https://1ptba.com','sign_type':'general'},
@@ -78,7 +79,7 @@ def init_datas():
{'name':'wintersakura','name_cn':'冬樱','index_url':'https://wintersakura.net','sign_type':'general'},
{'name':'hdpt','name_cn':'明教','index_url':'https://hdpt.xyz','sign_type':'general'},
]
-
+
for site in sites_data:
get_site = SiteConfig.objects.filter(name=site['name']).count()
if get_site == 0:
@@ -91,18 +92,25 @@ def init_datas():
#else:
##更新站点配置
#SiteConfig.objects.filter(name=site['name']).update(sign_type = site['sign_type'])
-
+
#print('站点 [%s] 更新成功' % site['name'])
##print('站点 [%s] 已经存在,忽略...' % site['name'])
-
+
+ print('开始修复站点信息中文名称...')
+ ormdata_siteinfo = SiteInfo.objects.filter(siteconfig_name_cn='')
+ for siteinfo in ormdata_siteinfo:
+ siteconfig_name_cn = list(SiteConfig.objects.filter(name=siteinfo.siteconfig_name).values_list('name_cn',flat=True))
+ SiteInfo.objects.filter(siteconfig_name=siteinfo.siteconfig_name).update(siteconfig_name_cn = siteconfig_name_cn[0])
+
+
print('开始初始化任务类型...')
jobtypes_data = [{'name':'签到','type_id':1000},
{'name':'辅种','type_id':1001},
- {'name':'刷流','type_id':1002},
+ {'name':'RSS订阅','type_id':1002},
{'name':'签到重试','type_id':1003},
]
-
+
for jobtype in jobtypes_data:
get_jobtype = JobType.objects.filter(name=jobtype['name']).count()
if get_jobtype == 0:
@@ -111,14 +119,16 @@ def init_datas():
)
print('添加任务类型 [%s] 成功' % jobtype['name'])
else:
+ #将原刷流更新为RSS订阅
+ JobType.objects.filter(type_id=1002).update(name = 'RSS订阅')
print('任务类型 [%s] 已经存在,忽略...' % jobtype['name'])
-
+
print('开始初始化通知邮箱类型...')
mailtypes_data = [{'name':'QQ邮箱','alias_name':'qq','smtp_server':'smtp.qq.com','smtp_port':465},
- {'name':'新浪邮箱(非vip)','alias_name':'sina','smtp_server':'smtp.sina.com','smtp_port':465},
- {'name':'网易163邮箱','alias_name':'163','smtp_server':'smtp.163.com','smtp_port':465},
+ {'name':'新浪邮箱(非vip)','alias_name':'sina','smtp_server':'smtp.sina.com','smtp_port':465},
+ {'name':'网易163邮箱','alias_name':'163','smtp_server':'smtp.163.com','smtp_port':465},
]
-
+
for mailtype in mailtypes_data:
get_mailtype = MailType.objects.filter(name=mailtype['name']).count()
if get_mailtype == 0:
@@ -130,6 +140,62 @@ def init_datas():
print('添加邮箱类型 [%s] 成功' % mailtype['name'])
else:
print('邮箱类型 [%s] 已经存在,忽略...' % mailtype['name'])
-
+
+ filmcategorys_data = [{'name_en':'Movies','name_cn':'电影'},
+ {'name_en':'TV Series','name_cn':'电视剧'},
+ {'name_en':'Docs','name_cn':'纪录片'},
+ {'name_en':'Animations','name_cn':'动画片'},
+ {'name_en':'TV Shows','name_cn':'综艺'},
+ {'name_en':'Sports','name_cn':'体育'},
+ {'name_en':'MV','name_cn':'音乐视频'},
+ {'name_en':'Music','name_cn':'音乐'},
+ {'name_en':'Others','name_cn':'其他'},
+ ]
+ for film_category in filmcategorys_data:
+ get_film_category = FilmCategory.objects.filter(name_en=film_category['name_en']).count()
+ if get_film_category == 0:
+ FilmCategory.objects.create(name_en = film_category['name_en'],
+ name_cn = film_category['name_cn']
+ )
+ print('添加影视类别 [%s] 成功' % film_category['name_en'])
+ else:
+ print('影视类别 [%s] 已经存在,忽略...' % film_category['name_en'])
+
+ filmtype_data = [{'name':'喜剧'},
+ {'name':'爱情'},
+ {'name':'动作'},
+ {'name':'科幻'},
+ {'name':'动画'},
+ {'name':'悬疑'},
+ {'name':'犯罪'},
+ {'name':'惊悚'},
+ {'name':'冒险'},
+ {'name':'音乐'},
+ {'name':'历史'},
+ {'name':'奇幻'},
+ {'name':'恐怖'},
+ {'name':'战争'},
+ {'name':'传记'},
+ {'name':'歌舞'},
+ {'name':'武侠'},
+ {'name':'情色'},
+ {'name':'灾难'},
+ {'name':'西部'},
+ {'name':'纪录片'},
+ {'name':'短片'},
+ {'name':'真人秀'},
+ {'name':'脱口秀'},
+ {'name':'古装'},
+ {'name':'家庭'},
+ {'name':'剧情'},
+ ]
+
+ for film_type in filmtype_data:
+ get_film_type = FilmType.objects.filter(name=film_type['name']).count()
+ if get_film_type == 0:
+ FilmType.objects.create(name = film_type['name'])
+ print('添加影视类型 [%s] 成功' % film_type['name'])
+ else:
+ print('影视类型 [%s] 已经存在,忽略...' % film_type['name'])
+
print('初始化成功.')
-
\ No newline at end of file
diff --git a/apps/notify/views_request.py b/apps/notify/views_request.py
index 639a79a..bf10ece 100644
--- a/apps/notify/views_request.py
+++ b/apps/notify/views_request.py
@@ -23,37 +23,37 @@ def iyuutest(request):
"""
_id = request.POST.get('id','')
-
- if _id == '':
+ iyuu_key = request.POST.get('iyuu_key').strip()
+ #if _id == '':
- response_data={"code":0,"msg":"请先配置IYUU令牌或刷新页面"}
+ #response_data={"code":0,"msg":"请先配置IYUU令牌或刷新页面"}
+ #else:
+
+ #ormdata = NotifyConfig.objects.get(id=_id)
+ #iyuu_key = ormdata.iyuu_key
+
+
+ user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'
+
+ now = datetime.datetime.now()
+ time = now.strftime("%Y-%m-%d %H:%M:%S")
+ headers = {
+ 'user_agent': user_agent,
+ 'Content-type': 'application/x-www-form-urlencoded'
+ }
+
+ now_time = parse.quote('') + parse.unquote(time) + parse.quote('
')
+ send_txts = parse.quote('[测试]
')
+ api = 'https://iyuu.cn/' + iyuu_key + '.send'
+ sen_url = api + '?text='+ parse.quote('测试提示') + '&desp=' + now_time + send_txts
+ response = requests.get(sen_url, headers=headers ,verify=False)
+
+ response_msg = json.loads(response.text)
+ if response.status_code == 200 and response_msg['errcode'] == 0:
+ response_data={"code":1,"msg":"发送测试成功"}
else:
-
- ormdata = NotifyConfig.objects.get(id=_id)
- iyuu_key = ormdata.iyuu_key
-
-
- user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'
-
- now = datetime.datetime.now()
- time = now.strftime("%Y-%m-%d %H:%M:%S")
- headers = {
- 'user_agent': user_agent,
- 'Content-type': 'application/x-www-form-urlencoded'
- }
-
- now_time = parse.quote('') + parse.unquote(time) + parse.quote('
')
- send_txts = parse.quote('[测试]
')
- api = 'https://iyuu.cn/' + iyuu_key + '.send'
- sen_url = api + '?text='+ parse.quote('测试提示') + '&desp=' + now_time + send_txts
- response = requests.get(sen_url, headers=headers ,verify=False)
-
- response_msg = json.loads(response.text)
- if response.status_code == 200 and response_msg['errcode'] == 0:
- response_data={"code":1,"msg":"发送测试成功"}
- else:
- response_data={"code":0,"msg":"发送测试失败,%s" % response_msg['errmsg'] }
+ response_data={"code":0,"msg":"发送测试失败,%s" % response_msg['errmsg'] }
return JsonResponse(response_data)
diff --git a/apps/rss/__init__.py b/apps/rss/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/apps/rss/admin.py b/apps/rss/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/apps/rss/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/apps/rss/apps.py b/apps/rss/apps.py
new file mode 100644
index 0000000..c81cea6
--- /dev/null
+++ b/apps/rss/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class RSSConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'rss'
diff --git a/apps/rss/migrations/0001_initial.py b/apps/rss/migrations/0001_initial.py
new file mode 100644
index 0000000..487a73a
--- /dev/null
+++ b/apps/rss/migrations/0001_initial.py
@@ -0,0 +1,40 @@
+# Generated by Django 4.1 on 2022-09-08 09:47
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('sites', '0014_alter_siteinfo_siteconfig_name_cn'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='FilmCategory',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name_en', models.CharField(max_length=20, verbose_name='英文名')),
+ ('name_cn', models.CharField(max_length=20, verbose_name='中文名')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='FilmType',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=20, verbose_name='名称')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Config',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('url', models.URLField(blank=True, verbose_name='RSS地址')),
+ ('refresh_time', models.IntegerField(verbose_name='刷新间隔分钟')),
+ ('siteinfo_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='siteinfo', to='sites.siteinfo')),
+ ],
+ ),
+ ]
diff --git a/apps/rss/migrations/0002_rule.py b/apps/rss/migrations/0002_rule.py
new file mode 100644
index 0000000..6a3f0ab
--- /dev/null
+++ b/apps/rss/migrations/0002_rule.py
@@ -0,0 +1,25 @@
+# Generated by Django 4.1 on 2022-09-08 17:04
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('download', '0002_alter_tools_name'),
+ ('rss', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Rule',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=50, verbose_name='规则名称')),
+ ('keyword', models.CharField(max_length=100, null=True, verbose_name='关键字,使用逗号分隔')),
+ ('config_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='config', to='rss.config')),
+ ('tools_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tools', to='download.tools')),
+ ],
+ ),
+ ]
diff --git a/apps/rss/migrations/0003_rule_status_alter_rule_name.py b/apps/rss/migrations/0003_rule_status_alter_rule_name.py
new file mode 100644
index 0000000..ade1a63
--- /dev/null
+++ b/apps/rss/migrations/0003_rule_status_alter_rule_name.py
@@ -0,0 +1,23 @@
+# Generated by Django 4.1 on 2022-09-08 19:09
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rss', '0002_rule'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='rule',
+ name='status',
+ field=models.BooleanField(default=False, verbose_name='状态启用,禁用'),
+ ),
+ migrations.AlterField(
+ model_name='rule',
+ name='name',
+ field=models.CharField(max_length=50, unique=True, verbose_name='规则名称'),
+ ),
+ ]
diff --git a/apps/rss/migrations/0004_remove_config_refresh_time_rule_refresh_time.py b/apps/rss/migrations/0004_remove_config_refresh_time_rule_refresh_time.py
new file mode 100644
index 0000000..ebb0a91
--- /dev/null
+++ b/apps/rss/migrations/0004_remove_config_refresh_time_rule_refresh_time.py
@@ -0,0 +1,22 @@
+# Generated by Django 4.1 on 2022-09-09 13:37
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rss', '0003_rule_status_alter_rule_name'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='config',
+ name='refresh_time',
+ ),
+ migrations.AddField(
+ model_name='rule',
+ name='refresh_time',
+ field=models.IntegerField(default=5, verbose_name='刷新间隔分钟'),
+ ),
+ ]
diff --git a/apps/rss/migrations/0005_rule_crontab_id.py b/apps/rss/migrations/0005_rule_crontab_id.py
new file mode 100644
index 0000000..cd9da28
--- /dev/null
+++ b/apps/rss/migrations/0005_rule_crontab_id.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.1 on 2022-09-09 14:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rss', '0004_remove_config_refresh_time_rule_refresh_time'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='rule',
+ name='crontab_id',
+ field=models.CharField(max_length=64, null=True, verbose_name='执行ID'),
+ ),
+ ]
diff --git a/apps/rss/migrations/0006_remove_rule_crontab_id_rule_job_id.py b/apps/rss/migrations/0006_remove_rule_crontab_id_rule_job_id.py
new file mode 100644
index 0000000..8f65f40
--- /dev/null
+++ b/apps/rss/migrations/0006_remove_rule_crontab_id_rule_job_id.py
@@ -0,0 +1,24 @@
+# Generated by Django 4.1 on 2022-09-09 17:03
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('cron', '0013_alter_job_sites'),
+ ('rss', '0005_rule_crontab_id'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='rule',
+ name='crontab_id',
+ ),
+ migrations.AddField(
+ model_name='rule',
+ name='job_id',
+ field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='job', to='cron.job'),
+ ),
+ ]
diff --git a/apps/rss/migrations/0007_seedinfo.py b/apps/rss/migrations/0007_seedinfo.py
new file mode 100644
index 0000000..d8ddfcc
--- /dev/null
+++ b/apps/rss/migrations/0007_seedinfo.py
@@ -0,0 +1,33 @@
+# Generated by Django 4.0.3 on 2022-09-10 10:36
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('sites', '0014_alter_siteinfo_siteconfig_name_cn'),
+ ('rss', '0006_remove_rule_crontab_id_rule_job_id'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='SeedInfo',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('seed_name', models.CharField(max_length=500, verbose_name='种子名称')),
+ ('seed_type', models.CharField(max_length=50, verbose_name='种子类型')),
+ ('seed_details_link', models.URLField(blank=True, verbose_name='种子详情地址')),
+ ('seed_published_time', models.DateField(verbose_name='发布时间')),
+ ('seed_hash_id', models.CharField(max_length=50, verbose_name='种子hash值')),
+ ('seed_donwload_link', models.URLField(blank=True, verbose_name='种子下载地址')),
+ ('seed_file_size', models.IntegerField(verbose_name='种子文件大小')),
+ ('seed_status', models.BooleanField(default=False, verbose_name='状态:下载,未下载')),
+ ('photos', models.URLField(blank=True, verbose_name='海报')),
+ ('douban_link', models.URLField(blank=True, verbose_name='豆瓣电影地址')),
+ ('imdb_link', models.URLField(blank=True, verbose_name='IMDB电影地址')),
+ ('siteinfo_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.siteinfo')),
+ ],
+ ),
+ ]
diff --git a/apps/rss/migrations/0008_alter_config_url.py b/apps/rss/migrations/0008_alter_config_url.py
new file mode 100644
index 0000000..2d0cc92
--- /dev/null
+++ b/apps/rss/migrations/0008_alter_config_url.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.3 on 2022-09-10 11:10
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rss', '0007_seedinfo'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='config',
+ name='url',
+ field=models.URLField(blank=True, max_length=350, verbose_name='RSS地址'),
+ ),
+ ]
diff --git a/apps/rss/migrations/0009_alter_seedinfo_seed_published_time.py b/apps/rss/migrations/0009_alter_seedinfo_seed_published_time.py
new file mode 100644
index 0000000..750d5c0
--- /dev/null
+++ b/apps/rss/migrations/0009_alter_seedinfo_seed_published_time.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.3 on 2022-09-10 11:26
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rss', '0008_alter_config_url'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='seedinfo',
+ name='seed_published_time',
+ field=models.DateTimeField(verbose_name='发布时间'),
+ ),
+ ]
diff --git a/apps/rss/migrations/0010_alter_seedinfo_seed_file_size.py b/apps/rss/migrations/0010_alter_seedinfo_seed_file_size.py
new file mode 100644
index 0000000..2784dc9
--- /dev/null
+++ b/apps/rss/migrations/0010_alter_seedinfo_seed_file_size.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.3 on 2022-09-10 11:36
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rss', '0009_alter_seedinfo_seed_published_time'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='seedinfo',
+ name='seed_file_size',
+ field=models.BigIntegerField(verbose_name='种子文件大小'),
+ ),
+ ]
diff --git a/apps/rss/migrations/0011_alter_seedinfo_unique_together.py b/apps/rss/migrations/0011_alter_seedinfo_unique_together.py
new file mode 100644
index 0000000..1abb8b8
--- /dev/null
+++ b/apps/rss/migrations/0011_alter_seedinfo_unique_together.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.3 on 2022-09-10 12:20
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('sites', '0014_alter_siteinfo_siteconfig_name_cn'),
+ ('rss', '0010_alter_seedinfo_seed_file_size'),
+ ]
+
+ operations = [
+ migrations.AlterUniqueTogether(
+ name='seedinfo',
+ unique_together={('seed_hash_id', 'siteinfo_id')},
+ ),
+ ]
diff --git a/apps/rss/migrations/0012_seedinfo_rule_id.py b/apps/rss/migrations/0012_seedinfo_rule_id.py
new file mode 100644
index 0000000..88e2509
--- /dev/null
+++ b/apps/rss/migrations/0012_seedinfo_rule_id.py
@@ -0,0 +1,19 @@
+# Generated by Django 4.0.3 on 2022-09-10 15:57
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rss', '0011_alter_seedinfo_unique_together'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='seedinfo',
+ name='rule_id',
+ field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='rss.rule'),
+ ),
+ ]
diff --git a/apps/rss/migrations/0013_seedinfo_seed_torrent_id.py b/apps/rss/migrations/0013_seedinfo_seed_torrent_id.py
new file mode 100644
index 0000000..858b798
--- /dev/null
+++ b/apps/rss/migrations/0013_seedinfo_seed_torrent_id.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.3 on 2022-09-10 16:27
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rss', '0012_seedinfo_rule_id'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='seedinfo',
+ name='seed_torrent_id',
+ field=models.IntegerField(null=True, verbose_name='在下载器的标识ID'),
+ ),
+ ]
diff --git a/apps/rss/migrations/0014_rule_rate.py b/apps/rss/migrations/0014_rule_rate.py
new file mode 100644
index 0000000..b8c526b
--- /dev/null
+++ b/apps/rss/migrations/0014_rule_rate.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.3 on 2022-09-10 20:11
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rss', '0013_seedinfo_seed_torrent_id'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='rule',
+ name='rate',
+ field=models.CharField(max_length=10, null=True, verbose_name='码率:空,1080,2060'),
+ ),
+ ]
diff --git a/apps/rss/migrations/0015_alter_rule_rate.py b/apps/rss/migrations/0015_alter_rule_rate.py
new file mode 100644
index 0000000..09353d4
--- /dev/null
+++ b/apps/rss/migrations/0015_alter_rule_rate.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.3 on 2022-09-10 20:14
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rss', '0014_rule_rate'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='rule',
+ name='rate',
+ field=models.CharField(default='all', max_length=10, verbose_name='码率:all,1080,2060'),
+ ),
+ ]
diff --git a/apps/rss/migrations/0016_rule_is_paused.py b/apps/rss/migrations/0016_rule_is_paused.py
new file mode 100644
index 0000000..df443ad
--- /dev/null
+++ b/apps/rss/migrations/0016_rule_is_paused.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.3 on 2022-09-10 21:54
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rss', '0015_alter_rule_rate'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='rule',
+ name='is_paused',
+ field=models.BooleanField(default=False, verbose_name='是否立刻下载'),
+ ),
+ ]
diff --git a/apps/rss/migrations/__init__.py b/apps/rss/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/apps/rss/models.py b/apps/rss/models.py
new file mode 100644
index 0000000..edbef1e
--- /dev/null
+++ b/apps/rss/models.py
@@ -0,0 +1,74 @@
+from django.db import models
+from sites.models import SiteInfo
+from download.models import Tools
+from cron.models import Job
+# Create your models here.
+
+class FilmCategory(models.Model):
+ """影视类别"""
+ name_en = models.CharField('英文名', max_length=20)
+ name_cn = models.CharField('中文名', max_length=20)
+
+class FilmType(models.Model):
+ """影视类型"""
+ name = models.CharField('名称', max_length=20)
+
+#class FilmActor(models.Model):
+ #"""影视演员"""
+ #name = models.CharField('名称', max_length=50)
+ #name_en = models.CharField('英文名称', max_length=100)
+ #constellation = models.CharField('星座', max_length=10)
+ #gender = models.CharField('性别', max_length=2)
+ #birth = models.DateField('出生日期')
+ #birthplace = models.CharField('出生地', max_length=50)
+ #job = models.CharField('职业', max_length=100)
+ #description = models.TextField('简介')
+ #avatar = models.URLField('头像', blank=True)
+
+class Config(models.Model):
+ """RSS配置"""
+ url = models.URLField('RSS地址', blank=True, max_length=350)
+ #site_name = models.CharField('网站名简称,英文', max_length=50, unique=True)
+ #site_name_cn = models.CharField('网站名简称,中文', max_length=50, unique=True)
+ #on_update 和 on_delete 后面可以跟的词语有四个
+ #1. no action 表示 不做任何操作,
+ #2. set null 表示在外键表中将相应字段设置为null
+ #3. set default 表示设置为默认值
+ #4. cascade 表示级联操作,就是说,如果主键表中被参考字段更新,外键表中也更新,主键表中的记录被删除,外键表中改行也相应删除
+ siteinfo_id = models.ForeignKey(SiteInfo, on_delete=models.CASCADE, related_name='siteinfo')
+
+class Rule(models.Model):
+ """RSS规则"""
+ name = models.CharField('规则名称', max_length=50, unique=True)
+ config_id = models.ForeignKey(Config, on_delete=models.CASCADE, related_name='config')
+ keyword = models.CharField('关键字,使用逗号分隔', max_length=100, null=True)
+ tools_id = models.ForeignKey(Tools, on_delete=models.CASCADE, related_name='tools')
+ status = models.BooleanField("状态启用,禁用",default=False)
+ refresh_time = models.IntegerField('刷新间隔分钟', default=5)
+ rate = models.CharField('码率:all,1080,2060', max_length=10, default='all')
+ is_paused = models.BooleanField("是否立刻下载",default=False)
+
+ job_id = models.ForeignKey(Job, on_delete=models.CASCADE, related_name='job', null=True)
+
+class SeedInfo(models.Model):
+ """种子信息"""
+ seed_name = models.CharField('种子名称', max_length=500)
+ seed_type = models.CharField('种子类型', max_length=50)
+ seed_details_link = models.URLField('种子详情地址', blank=True)
+ seed_published_time = models.DateTimeField('发布时间')
+ seed_hash_id = models.CharField('种子hash值', max_length=50)
+ seed_donwload_link = models.URLField('种子下载地址', blank=True)
+ seed_file_size = models.BigIntegerField('种子文件大小')
+ seed_status = models.BooleanField('状态:下载,未下载', default=False)
+ seed_torrent_id = models.IntegerField("在下载器的标识ID", null=True)
+
+ photos = models.URLField('海报', blank=True)
+ douban_link = models.URLField('豆瓣电影地址', blank=True)
+ imdb_link = models.URLField('IMDB电影地址', blank=True)
+
+ siteinfo_id = models.ForeignKey(SiteInfo, on_delete=models.CASCADE)
+ rule_id = models.ForeignKey(Rule, on_delete=models.CASCADE, null=True)
+
+ class Meta:
+ unique_together=("seed_hash_id", "siteinfo_id")
+
\ No newline at end of file
diff --git a/apps/rss/templates/rss/rssconfig.html b/apps/rss/templates/rss/rssconfig.html
new file mode 100644
index 0000000..21f231c
--- /dev/null
+++ b/apps/rss/templates/rss/rssconfig.html
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/rss/templates/rss/rssconfigadd.html b/apps/rss/templates/rss/rssconfigadd.html
new file mode 100644
index 0000000..c291fe0
--- /dev/null
+++ b/apps/rss/templates/rss/rssconfigadd.html
@@ -0,0 +1,87 @@
+
+
+
+
\ No newline at end of file
diff --git a/apps/rss/templates/rss/rssconfigedit.html b/apps/rss/templates/rss/rssconfigedit.html
new file mode 100644
index 0000000..a285808
--- /dev/null
+++ b/apps/rss/templates/rss/rssconfigedit.html
@@ -0,0 +1,93 @@
+
+
+
+
\ No newline at end of file
diff --git a/apps/rss/templates/rss/rssrule.html b/apps/rss/templates/rss/rssrule.html
new file mode 100644
index 0000000..dca43e3
--- /dev/null
+++ b/apps/rss/templates/rss/rssrule.html
@@ -0,0 +1,241 @@
+
+
+
+
+
+
+
+{% verbatim myblock %}
+
+
+{% endverbatim myblock %}
+
+
\ No newline at end of file
diff --git a/apps/rss/templates/rss/rssruleadd.html b/apps/rss/templates/rss/rssruleadd.html
new file mode 100644
index 0000000..5166190
--- /dev/null
+++ b/apps/rss/templates/rss/rssruleadd.html
@@ -0,0 +1,207 @@
+
+
+
+
\ No newline at end of file
diff --git a/apps/rss/templates/rss/rssruleedit.html b/apps/rss/templates/rss/rssruleedit.html
new file mode 100644
index 0000000..adb3b04
--- /dev/null
+++ b/apps/rss/templates/rss/rssruleedit.html
@@ -0,0 +1,222 @@
+
+
+
+
\ No newline at end of file
diff --git a/apps/rss/templates/rss/rssseedinfo.html b/apps/rss/templates/rss/rssseedinfo.html
new file mode 100644
index 0000000..c293d60
--- /dev/null
+++ b/apps/rss/templates/rss/rssseedinfo.html
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/rss/tests.py b/apps/rss/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/apps/rss/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/apps/rss/urls/__init__.py b/apps/rss/urls/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/apps/rss/urls/__init__.py
@@ -0,0 +1 @@
+
diff --git a/apps/rss/urls/views_urls.py b/apps/rss/urls/views_urls.py
new file mode 100644
index 0000000..5360de3
--- /dev/null
+++ b/apps/rss/urls/views_urls.py
@@ -0,0 +1,32 @@
+# coding:utf-8
+from django.urls import path
+from .. import views, views_request
+
+app_name = 'rss'
+
+urlpatterns = [
+ # Resource asset path
+
+ #RSS配置
+ path('config', views.RssConfigListView.as_view()),
+ path('config/add', views.RssConfigAddView.as_view()),
+ path('config/edit', views.RssConfigEditView.as_view()),
+ path('config/del', views.RssConfigDelView.as_view()),
+ path('config/list', views_request.config),
+ path('config/select/list', views_request.select_rssconfig),
+
+ #RSS规则
+ path('rule', views.RssRuleListView.as_view()),
+ path('rule/add', views.RssRuleAddView.as_view()),
+ path('rule/edit', views.RssRuleEditView.as_view()),
+ path('rule/del', views.RssRuleDelView.as_view()),
+ path('rule/list', views_request.rule),
+ path('rule/checkbox/setstatus', views_request.checkbox_setRuleStatus),
+
+ #RSS种子详情
+ path('seedinfo', views.RssSeedInfoListView.as_view()),
+ path('seedinfo/del', views.RssSeedInfoDelView.as_view()),
+ path('seedinfo/list', views_request.seedinfo),
+ path('seedinfo/donwload', views_request.seed_download),
+]
+
diff --git a/apps/rss/views.py b/apps/rss/views.py
new file mode 100644
index 0000000..a44eb1b
--- /dev/null
+++ b/apps/rss/views.py
@@ -0,0 +1,455 @@
+from django.shortcuts import render
+from django.views.generic import TemplateView
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.http import JsonResponse
+from django.db import transaction
+import uuid
+
+from .models import Config, Rule, SeedInfo
+from sites.models import SiteInfo
+from download.models import Tools
+from cron.crontabs import my_scheduler
+from notify.models import NotifyConfig
+from cron.models import Job
+
+# Create your views here.
+
+class RssConfigListView(LoginRequiredMixin,TemplateView):
+ """
+ 显示
+ """
+ template_name = 'rss/rssconfig.html'
+
+ def get(self, request, *args, **kwargs):
+ """
+
+ """
+ return super(RssConfigListView, self).get(request, *args, **kwargs)
+
+ #显示编辑模板
+ def get_context_data(self, **kwargs):
+
+ context = {
+ # 'data': self.ormdata_game
+ }
+ kwargs.update(context)
+ return super(RssConfigListView, self).get_context_data(**kwargs)
+
+
+class RssConfigAddView(LoginRequiredMixin,TemplateView):
+ """
+ 添加
+ """
+ template_name = 'rss/rssconfigadd.html'
+
+ #显示添加模板
+ def get(self, request, *args, **kwargs):
+ """
+ """
+ return super(RssConfigAddView, self).get(request, *args, **kwargs)
+
+ #显示编辑模板
+ def get_context_data(self, **kwargs):
+
+ context = {
+ }
+ kwargs.update(context)
+ return super(RssConfigAddView, self).get_context_data(**kwargs)
+
+
+ #数据提交接收方法
+ def post(self, request, *args, **kwargs):
+ """
+ 数据提交
+ """
+ siteinfo_id = request.POST.get("siteinfo_id").strip()
+ url = request.POST.get("url").strip()
+
+ ormdata_siteinfo = SiteInfo.objects.get(id=int(siteinfo_id))
+
+ ormdata = Config.objects.create(url=url,
+ siteinfo_id=ormdata_siteinfo
+ )
+
+ ormdata.save()
+
+ response_data={"code":1,"msg":"添加成功"}
+
+
+ return JsonResponse(response_data)
+
+class RssConfigEditView(LoginRequiredMixin,TemplateView):
+ """
+ 编辑域名
+ """
+ template_name = 'rss/rssconfigedit.html'
+
+ #显示添加模板
+ def get(self, request, *args, **kwargs):
+ """
+ 得到
+ """
+
+ #记录ID
+ self._id = request.GET.get('id')
+ self.ormdata = Config.objects.get(id=self._id)
+
+ return super(RssConfigEditView, self).get(request, *args, **kwargs)
+
+ #显示编辑模板
+ def get_context_data(self, **kwargs):
+
+ context = {
+ 'id': self._id,
+ 'url': self.ormdata.url,
+ 'siteinfo_id': self.ormdata.siteinfo_id.id
+ }
+ kwargs.update(context)
+ return super(RssConfigEditView, self).get_context_data(**kwargs)
+
+ #数据提交接收方法
+ def post(self, request, *args, **kwargs):
+ """
+ 数据提交
+ """
+ url = request.POST.get("url").strip()
+ siteinfo_id = request.POST.get("siteinfo_id").strip()
+
+ _id = request.POST.get('id')
+
+ ormdata_siteinfo = SiteInfo.objects.get(id=int(siteinfo_id))
+
+ ormdata = Config.objects.get(id=_id)
+
+ ormdata.url = url
+ ormdata.siteinfo_id=ormdata_siteinfo
+
+ ormdata.save()
+
+ response_data={"code":1,"msg":"添加成功"}
+
+ return JsonResponse(response_data)
+
+class RssConfigDelView(LoginRequiredMixin,TemplateView):
+ """
+ 删除
+ """
+ def post(self, request, *args, **kwargs):
+ """
+ 数据提交
+ """
+
+ #得到批量或者单个要删除的id
+ ids = request.POST.getlist("ids[]")
+ #print("ids====>",ids)
+
+ Config.objects.filter(id__in=ids).delete()
+
+ #Site.objects.filter(id=i).delete()
+
+ response_data={"code":1,"msg":"操作成功"}
+
+
+ return JsonResponse(response_data)
+
+#==================
+class RssRuleListView(LoginRequiredMixin,TemplateView):
+ """
+ 显示
+ """
+ template_name = 'rss/rssrule.html'
+
+ def get(self, request, *args, **kwargs):
+ """
+
+ """
+ return super(RssRuleListView, self).get(request, *args, **kwargs)
+
+ #显示编辑模板
+ def get_context_data(self, **kwargs):
+
+ context = {
+ # 'data': self.ormdata_game
+ }
+ kwargs.update(context)
+ return super(RssRuleListView, self).get_context_data(**kwargs)
+
+
+class RssRuleAddView(LoginRequiredMixin,TemplateView):
+ """
+ 添加
+ """
+ template_name = 'rss/rssruleadd.html'
+
+ #显示添加模板
+ def get(self, request, *args, **kwargs):
+ """
+ """
+ return super(RssRuleAddView, self).get(request, *args, **kwargs)
+
+ #显示编辑模板
+ def get_context_data(self, **kwargs):
+
+ html_notifys = []
+ notify_type = {'iyuu':'IYUU','telegram':'Telegram','email':'邮箱','enwechat':'企业微信'}
+
+ #获取通知配置
+ notifys_count = NotifyConfig.objects.count()
+ if notifys_count == 0:
+ html_notifys.append('请先配置通知')
+ else:
+ for d in NotifyConfig.objects.all():
+ html_notifys.append('')
+
+ context = {
+ 'notifys':"".join(html_notifys),
+ }
+ kwargs.update(context)
+ return super(RssRuleAddView, self).get_context_data(**kwargs)
+
+ #事务回滚
+ @transaction.atomic
+ def post(self, request, *args, **kwargs):
+ """
+ 数据提交
+ """
+ name = request.POST.get("name").strip()
+ config_id = request.POST.get("config_id").strip()
+ keyword = request.POST.get("keyword").strip()
+ tools_id = request.POST.get("tools_id").strip()
+ status = request.POST.get("status")
+ refresh_time = request.POST.get("refresh_time",'')
+ notifys = request.POST.getlist("notifys[]")
+ rate = request.POST.get("rate").strip()
+ is_paused = request.POST.get("rate")
+
+ ormdata_config = Config.objects.get(id=int(config_id))
+ ormdata_tools = Tools.objects.get(id=int(tools_id))
+ #任务ID号
+ crontab_id = str(uuid.uuid1())
+
+ if status == "on":
+ status = 1
+ else:
+ status = 0
+
+ if refresh_time == '':
+ refresh_time = 5
+
+ #创建任务
+ #每几分运行
+ crontab_time = '*/%s * * * *' % refresh_time
+
+ ormdata_job = Job.objects.create(name=name,
+ jobtype_id=1002,
+ crontab_time_type = "minute",
+ crontab_status = status,
+ minute = refresh_time,
+ notifys = ",".join(notifys),
+ crontab_time = crontab_time,
+ crontab_id = crontab_id,
+
+ )
+ ormdata_job.save()
+
+ #创建订阅规则
+ ormdata_rule = Rule.objects.create(name=name,
+ config_id=ormdata_config,
+ tools_id=ormdata_tools,
+ keyword=keyword,
+ status = status,
+ refresh_time = int(refresh_time),
+ job_id = ormdata_job,
+ rate = rate,
+ is_paused = int(is_paused)
+ )
+
+ ormdata_rule.save()
+
+
+ #开始进行订阅操作
+ minute = '*/%s' % refresh_time
+ my_scheduler(crontab_id, status, minute=minute, jobtype_id=1002)
+
+ response_data={"code":1,"msg":"添加成功"}
+
+
+ return JsonResponse(response_data)
+
+class RssRuleEditView(LoginRequiredMixin,TemplateView):
+ """
+ 编辑域名
+ """
+ template_name = 'rss/rssruleedit.html'
+
+ #显示添加模板
+ def get(self, request, *args, **kwargs):
+ """
+ 得到
+ """
+
+ #记录ID
+ self._id = request.GET.get('id')
+ self.ormdata = Rule.objects.get(id=self._id)
+
+ return super(RssRuleEditView, self).get(request, *args, **kwargs)
+
+ #显示编辑模板
+ def get_context_data(self, **kwargs):
+
+ html_notifys = []
+ notify_type = {'iyuu':'IYUU','telegram':'Telegram','email':'邮箱','enwechat':'企业微信'}
+
+ ormdata_job = Job.objects.get(id=self.ormdata.job_id.id)
+
+ for d in NotifyConfig.objects.all():
+ if d.name in ormdata_job.notifys:
+ html_notifys.append('')
+ else:
+ html_notifys.append('')
+
+ context = {
+ 'id': self._id,
+ 'name': self.ormdata.name,
+ 'config_id': self.ormdata.config_id.id,
+ 'tools_id': self.ormdata.tools_id.id,
+ 'keyword': self.ormdata.keyword,
+ 'status': self.ormdata.status,
+ 'refresh_time': self.ormdata.refresh_time,
+ 'notifys':"".join(html_notifys),
+ 'crontab_id': ormdata_job.crontab_id,
+ 'rate': self.ormdata.rate,
+ 'is_paused':self.ormdata.is_paused
+
+ }
+ kwargs.update(context)
+ return super(RssRuleEditView, self).get_context_data(**kwargs)
+
+ #数据提交接收方法
+ def post(self, request, *args, **kwargs):
+ """
+ 数据提交
+ """
+ name = request.POST.get("name").strip()
+ config_id = request.POST.get("config_id").strip()
+ keyword = request.POST.get("keyword").strip()
+ tools_id = request.POST.get("tools_id").strip()
+ status = request.POST.get("status")
+ refresh_time = request.POST.get("refresh_time",'')
+ crontab_id = request.POST.get("crontab_id")
+ rate = request.POST.get("rate")
+ is_paused = request.POST.get("is_paused")
+ notifys = request.POST.getlist("notifys[]")
+
+ _id = request.POST.get('id')
+
+ ormdata_config = Config.objects.get(id=int(config_id))
+ ormdata_tools = Tools.objects.get(id=int(tools_id))
+
+ if status == "on":
+ status = 1
+ else:
+ status = 0
+
+ if refresh_time == '':
+ refresh_time = 5
+
+ ormdata = Rule.objects.get(id=_id)
+
+ ormdata.name = name
+ ormdata.config_id=ormdata_config
+ ormdata.tools_id = ormdata_tools
+ ormdata.keyword = keyword
+ ormdata.status = status
+ ormdata.refresh_time = refresh_time
+ ormdata.rate = rate
+ ormdata.is_paused = int(is_paused)
+
+ ormdata.save()
+
+ crontab_time = '*/%s * * * *' % refresh_time
+ Job.objects.filter(crontab_id=crontab_id).update(notifys=",".join(notifys),
+ crontab_time = crontab_time,
+ minute = refresh_time
+ )
+
+ minute = '*/%s' % refresh_time
+ my_scheduler(crontab_id = crontab_id, crontab_status = status, minute=minute, jobtype_id=1002 )
+
+ response_data={"code":1,"msg":"添加成功"}
+
+ return JsonResponse(response_data)
+
+class RssRuleDelView(LoginRequiredMixin,TemplateView):
+ """
+ 删除
+ """
+ def post(self, request, *args, **kwargs):
+ """
+ 数据提交
+ """
+
+ #得到批量或者单个要删除的id
+ ids = request.POST.getlist("ids[]")
+ #print("ids====>",ids)
+
+ #Rule.objects.filter(id__in=ids).delete()
+
+ for i in ids:
+ _id = Rule.objects.get(id=i)
+ #删除任务
+ Job.objects.filter(id=_id.job_id.id).delete()
+ #删除记录
+ Rule.objects.filter(id=i).delete()
+ #删除计划任务
+ my_scheduler(crontab_id = _id.job_id.crontab_id, action="del")
+
+ response_data={"code":1,"msg":"操作成功"}
+
+
+ return JsonResponse(response_data)
+
+#==================
+class RssSeedInfoListView(LoginRequiredMixin,TemplateView):
+ """
+ 显示
+ """
+ template_name = 'rss/rssseedinfo.html'
+
+ def get(self, request, *args, **kwargs):
+ """
+
+ """
+ return super(RssSeedInfoListView, self).get(request, *args, **kwargs)
+
+ #显示编辑模板
+ def get_context_data(self, **kwargs):
+
+ context = {
+ # 'data': self.ormdata_game
+ }
+ kwargs.update(context)
+ return super(RssSeedInfoListView, self).get_context_data(**kwargs)
+
+
+class RssSeedInfoDelView(LoginRequiredMixin,TemplateView):
+ """
+ 删除
+ """
+ def post(self, request, *args, **kwargs):
+ """
+ 数据提交
+ """
+
+ #得到批量或者单个要删除的id
+ ids = request.POST.getlist("ids[]")
+ #print("ids====>",ids)
+
+ SeedInfo.objects.filter(id__in=ids).delete()
+
+ response_data={"code":1,"msg":"操作成功"}
+
+
+ return JsonResponse(response_data)
+
+#==================
\ No newline at end of file
diff --git a/apps/rss/views_request.py b/apps/rss/views_request.py
new file mode 100644
index 0000000..2fb02ff
--- /dev/null
+++ b/apps/rss/views_request.py
@@ -0,0 +1,339 @@
+#coding=utf-8
+from django.http import JsonResponse, StreamingHttpResponse,HttpResponse
+from django.db.models import Q
+from django.contrib.auth.decorators import login_required
+from transmission_rpc import Client
+import qbittorrentapi
+
+from .models import Config, Rule, SeedInfo
+from cron.crontabs import my_scheduler
+from common.utils import filesizeformat, parseUrl
+
+#直接使用检查是否管理员
+#from django.contrib.auth.decorators import user_passes_test
+#@user_passes_test(lambda u: u.is_superuser)
+
+@login_required
+def config(request):
+ """
+ 提供相应的数据
+ """
+
+ #得到偏移量
+ pageIndex= int(request.GET.get('page',1))
+ #得到查询个数
+ pageSize = int(request.GET.get('limit',10))
+
+ #搜索字段
+ searchKey = request.GET.get('searchKey','')
+ searchValue = request.GET.get('searchValue','')
+ #去掉空格
+ searchValue = searchValue.strip()
+
+ #得到排序字段
+ sort = request.GET.get('sort','id')
+ #得到排序规则
+ order_by_type = request.GET.get('order','')
+
+ if order_by_type == 'asc':
+ order_by = sort
+ else:
+ order_by = '-' + sort
+
+ data = {}
+ data['code'] = 0
+ data['msg'] = ""
+ data['data'] = []
+
+ if searchValue == '':
+
+ data['count'] = Config.objects.count()
+ if pageIndex == 1:
+ ormdata = Config.objects.order_by(order_by)[:pageSize] #offset:limit
+ else:
+ ormdata = Config.objects.order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
+ else:
+
+ data['count'] = Config.objects.filter(Q(name__icontains=searchValue)|Q(name_cn__icontains=searchValue)).count()
+ if pageIndex == 1:
+ ormdata = Config.objects.filter(Q(name__icontains=searchValue)|Q(name_cn__icontains=searchValue)).order_by(order_by)[:pageSize] #offset:limit
+ else:
+ ormdata = Config.objects.filter(Q(name__icontains=searchValue)|Q(name_cn__icontains=searchValue)).order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
+
+ for i in ormdata:
+
+ data['data'].append({"id":i.id,
+ "site_name":i.siteinfo_id.siteconfig_name + '(' + i.siteinfo_id.siteconfig_name_cn + ')',
+ "url":i.url,
+ })
+ #返回json串
+ #return HttpResponse(json.dumps(data,ensure_ascii = False), "application/json")
+ return JsonResponse(data)
+
+#===================================================================================================================
+@login_required
+def rule(request):
+ """
+ 提供相应的数据
+ """
+
+ #得到偏移量
+ pageIndex= int(request.GET.get('page',1))
+ #得到查询个数
+ pageSize = int(request.GET.get('limit',10))
+
+ #搜索字段
+ searchKey = request.GET.get('searchKey','')
+ searchValue = request.GET.get('searchValue','')
+ #去掉空格
+ searchValue = searchValue.strip()
+
+ #得到排序字段
+ sort = request.GET.get('sort','id')
+ #得到排序规则
+ order_by_type = request.GET.get('order','')
+
+ if order_by_type == 'asc':
+ order_by = sort
+ else:
+ order_by = '-' + sort
+
+ data = {}
+ data['code'] = 0
+ data['msg'] = ""
+ data['data'] = []
+
+ if searchValue == '':
+
+ data['count'] = Rule.objects.count()
+ if pageIndex == 1:
+ ormdata = Rule.objects.order_by(order_by)[:pageSize] #offset:limit
+ else:
+ ormdata = Rule.objects.order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
+ else:
+
+ data['count'] = Rule.objects.filter(Q(name__icontains=searchValue)).count()
+ if pageIndex == 1:
+ ormdata = Rule.objects.filter(Q(name__icontains=searchValue)).order_by(order_by)[:pageSize] #offset:limit
+ else:
+ ormdata = Rule.objects.filter(Q(name__icontains=searchValue)).order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
+
+ for i in ormdata:
+
+ data['data'].append({"id":i.id,
+ #"config_id":i.config_id.siteinfo_id.siteconfig_name_cn,
+ "config_id":i.config_id.siteinfo_id.siteconfig_name + '(' + i.config_id.siteinfo_id.siteconfig_name_cn + ')',
+ "tools_id":i.tools_id.name,
+ "name":i.name,
+ "keyword":i.keyword,
+ "status":i.status,
+ "refresh_time":i.refresh_time,
+ "rate":i.rate,
+ "is_paused":i.is_paused
+ })
+ #返回json串
+ #return HttpResponse(json.dumps(data,ensure_ascii = False), "application/json")
+ return JsonResponse(data)
+
+#===================================================================================================================
+@login_required
+def seedinfo(request):
+ """
+ 提供相应的数据
+ """
+
+ #得到偏移量
+ pageIndex= int(request.GET.get('page',1))
+ #得到查询个数
+ pageSize = int(request.GET.get('limit',10))
+
+ #搜索字段
+ searchKey = request.GET.get('searchKey','')
+ searchValue = request.GET.get('searchValue','')
+ #去掉空格
+ searchValue = searchValue.strip()
+
+ #得到排序字段
+ sort = request.GET.get('sort','id')
+ #得到排序规则
+ order_by_type = request.GET.get('order','')
+
+ if order_by_type == 'asc':
+ order_by = sort
+ else:
+ order_by = '-' + sort
+
+ data = {}
+ data['code'] = 0
+ data['msg'] = ""
+ data['data'] = []
+
+ if searchValue == '':
+
+ data['count'] = SeedInfo.objects.count()
+ if pageIndex == 1:
+ ormdata = SeedInfo.objects.order_by(order_by)[:pageSize] #offset:limit
+ else:
+ ormdata = SeedInfo.objects.order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
+ else:
+
+ data['count'] = SeedInfo.objects.filter(Q(seed_name__icontains=searchValue)).count()
+ if pageIndex == 1:
+ ormdata = SeedInfo.objects.filter(Q(seed_name__icontains=searchValue)).order_by(order_by)[:pageSize] #offset:limit
+ else:
+ ormdata = SeedInfo.objects.filter(Q(seed_name__icontains=searchValue)).order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
+
+ for i in ormdata:
+
+ data['data'].append({"id":i.id,
+ "siteinfo_id":i.siteinfo_id.siteconfig_name + '(' + i.siteinfo_id.siteconfig_name_cn + ')',
+ "seed_name":i.seed_name,
+ "seed_type":i.seed_type,
+ "seed_published_time":i.seed_published_time,
+ "seed_file_size":filesizeformat(i.seed_file_size),
+ "seed_status":i.seed_status,
+ "seed_details_link":i.seed_details_link,
+ })
+ #返回json串
+ #return HttpResponse(json.dumps(data,ensure_ascii = False), "application/json")
+ return JsonResponse(data)
+#===================================================================================================================
+@login_required
+def checkbox_setRuleStatus(request):
+ """
+ 设置规则启用,禁用
+ """
+
+ _id = request.GET.get('id')
+ value = request.GET.get('value')
+ tag = request.GET.get('tag')
+
+ ormdata_rule = Rule.objects.get(id=_id)
+
+ if tag == 'status':
+ #修改状态
+ Rule.objects.filter(id=_id).update(status=int(value))
+ if int(value) == 1:
+ #激活任务
+ minute = '*/%s' % ormdata_rule.refresh_time
+ my_scheduler(crontab_id = ormdata_rule.job_id.crontab_id, crontab_status = True, minute=minute, jobtype_id=1002 )
+ else:
+ #禁用任务
+ my_scheduler(crontab_id = ormdata_rule.job_id.crontab_id, action="del" )
+
+ data = {'code':1,'msg':'操作成功'}
+ else:
+ data = {'code':0,'msg':'未知操作'}
+
+ #返回json串
+ #return HttpResponse(json.dumps(data,ensure_ascii = False), "application/json")
+ return JsonResponse(data)
+
+#==================
+@login_required
+def select_rssconfig(request):
+ """
+ RSS订阅
+ xmSelect
+ """
+
+ data = {}
+ data['code'] = 0
+ data['msg'] = ""
+ data['data'] = []
+
+ #获取数据标志 1 返回所有 其它返回未配置站点
+ #flag = request.GET.get('flag', 0)
+
+ #得到排序字段
+ sort = request.GET.get('sort','id')
+ #得到排序规则
+ order_by_type = request.GET.get('order','')
+
+ if order_by_type == 'asc':
+ order_by = sort
+ else:
+ order_by = '-' + sort
+
+ #获取所有记录
+ data['count'] = Config.objects.count()
+
+ ormdata = Config.objects.order_by(order_by).all()
+
+ for i in ormdata:
+ data['data'].append({
+ "id":i.id,
+ "name":i.siteinfo_id.siteconfig_name + "(" + i.siteinfo_id.siteconfig_name_cn + ")"
+ })
+
+ return JsonResponse(data)
+
+
+#==================
+@login_required
+def seed_download(request):
+ """
+ 下载种子
+ """
+ #种子ID
+ seed_id = request.POST.get("id")
+
+ ormdata_seedinfo = SeedInfo.objects.get(id = seed_id)
+ #下载连接
+ seed_donwload_link = ormdata_seedinfo.seed_donwload_link
+ #下载器类型
+ download_type = ormdata_seedinfo.rule_id.tools_id.typed
+ download_username = ormdata_seedinfo.rule_id.tools_id.username
+ download_password = ormdata_seedinfo.rule_id.tools_id.password
+ download_url = ormdata_seedinfo.rule_id.tools_id.url
+ #下载目录
+ download_dirname = ormdata_seedinfo.rule_id.tools_id.dirname
+
+ if download_dirname == "":
+ download_dirname = None
+
+ url_data = parseUrl(download_url)
+
+ if download_type == 'tr':
+ try:
+
+ c = Client(protocol= url_data['protocol'],
+ host=url_data['host'],
+ port=url_data['port'],
+ username=download_username,
+ password=download_password,
+ timeout = 10
+ )
+
+ torrent = c.add_torrent(seed_donwload_link,
+ timeout = 10,
+ download_dir = download_dirname
+
+ )
+ #获取种子id
+ torrent_id = torrent.id
+
+ ormdata_seedinfo.seed_torrent_id = torrent_id
+ ormdata_seedinfo.seed_status = True
+ ormdata_seedinfo.save()
+
+ response_data={"code":1,"msg": "添加成功" }
+ except Exception as e:
+ print(e)
+ response_data={"code":0,"msg": "添加失败" }
+ elif download_type == 'qb':
+
+ c = qbittorrentapi.Client(
+ host=url_data['host'],
+ port=url_data['port'],
+ username=download_username,
+ password=download_password,
+ )
+
+ try:
+ c.auth_log_in()
+ response_data={"code":1,"msg": "添加成功" }
+ except:
+ response_data={"code":0,"msg": "添加失败" }
+
+ return JsonResponse(response_data)
\ No newline at end of file
diff --git a/apps/sites/templates/sites/siteinfoadd.html b/apps/sites/templates/sites/siteinfoadd.html
index 85aac1e..90703ce 100644
--- a/apps/sites/templates/sites/siteinfoadd.html
+++ b/apps/sites/templates/sites/siteinfoadd.html
@@ -61,7 +61,7 @@
/* 获取所有记录类型 */
var loadIndex = layer.load(2);
- admin.req('sites/siteconfigname2siteinfo/list', function (res) {
+ admin.req('sites/siteconfigname/list', function (res) {
layer.close(loadIndex);
if (0 === res.code) {
$.each(res.data, function (index, item) {
diff --git a/apps/sites/templates/sites/siteinfoedit.html b/apps/sites/templates/sites/siteinfoedit.html
index ea6081c..81e5441 100644
--- a/apps/sites/templates/sites/siteinfoedit.html
+++ b/apps/sites/templates/sites/siteinfoedit.html
@@ -60,7 +60,7 @@
/* 获取所有记录类型 */
var loadIndex = layer.load(2);
- admin.req('sites/siteconfigname/list', function (res) {
+ admin.req('sites/siteconfigname/list?flag=1', function (res) {
layer.close(loadIndex);
if (0 === res.code) {
$.each(res.data, function (index, item) {
diff --git a/apps/sites/urls/views_urls.py b/apps/sites/urls/views_urls.py
index a029a99..a27656d 100644
--- a/apps/sites/urls/views_urls.py
+++ b/apps/sites/urls/views_urls.py
@@ -14,7 +14,6 @@ urlpatterns = [
path('siteconfig/del', views.SiteConfigDelView.as_view()),
path('siteconfig/list', views_request.siteconfig),
path('siteconfigname/list', views_request.siteconfigname),
- path('siteconfigname2siteinfo/list', views_request.siteconfigname2siteinfo),
path('siteconfig/export', views_request.siteconfigExport),
path('siteconfig/import', views_request.siteconfigImport),
#站点升级配置
@@ -31,6 +30,7 @@ urlpatterns = [
path('siteinfo/list', views_request.siteinfo),
path('siteinfo/export', views_request.siteinfoExport),
path('siteinfo/import', views_request.siteinfoImport),
+ path('siteinfo/select/list', views_request.select_siteinfo),
]
diff --git a/apps/sites/views.py b/apps/sites/views.py
index a5712d7..bf2cf8f 100644
--- a/apps/sites/views.py
+++ b/apps/sites/views.py
@@ -370,9 +370,12 @@ class SiteInfoAddView(LoginRequiredMixin,TemplateView):
cookie = request.POST.get("cookie").strip()
passkey = request.POST.get("passkey").strip()
+ siteconfig_name_cn = list(SiteConfig.objects.filter(name=siteconfig_name).values_list('name_cn',flat=True))
+
ormdata = SiteInfo.objects.create(siteconfig_name=siteconfig_name,
cookie=cookie,
passkey=passkey,
+ siteconfig_name_cn = siteconfig_name_cn[0]
)
ormdata.save()
@@ -423,12 +426,14 @@ class SiteInfoEditView(LoginRequiredMixin,TemplateView):
_id = request.POST.get('id')
+ siteconfig_name_cn = list(SiteConfig.objects.filter(name=siteconfig_name).values_list('name_cn',flat=True))
+
ormdata = SiteInfo.objects.get(id=_id)
ormdata.siteconfig_name = siteconfig_name
ormdata.cookie = cookie
ormdata.passkey = passkey
-
+ ormdata.siteconfig_name_cn = siteconfig_name_cn[0]
ormdata.save()
diff --git a/apps/sites/views_request.py b/apps/sites/views_request.py
index 84698ad..ab147da 100644
--- a/apps/sites/views_request.py
+++ b/apps/sites/views_request.py
@@ -4,6 +4,7 @@ from django.db.models import Q
from django.contrib.auth.decorators import login_required
from .models import SiteConfig, SiteRank, SiteInfo
+from rss.models import Config
import simplejson as json
import io
from urllib import parse
@@ -178,19 +179,19 @@ def siteinfo(request):
ormdata = SiteInfo.objects.order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
else:
- data['count'] = SiteInfo.objects.filter(Q(siteconfig_name__icontains=searchValue)).count()
+ data['count'] = SiteInfo.objects.filter(Q(siteconfig_name__icontains=searchValue)|Q(siteconfig_name_cn__icontains=searchValue)).count()
if pageIndex == 1:
- ormdata = SiteInfo.objects.filter(Q(siteconfig_name__icontains=searchValue)).order_by(order_by)[:pageSize] #offset:limit
+ ormdata = SiteInfo.objects.filter(Q(siteconfig_name__icontains=searchValue)|Q(siteconfig_name_cn__icontains=searchValue)).order_by(order_by)[:pageSize] #offset:limit
else:
- ormdata = SiteInfo.objects.filter(Q(siteconfig_name__icontains=searchValue)).order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
+ ormdata = SiteInfo.objects.filter(Q(siteconfig_name__icontains=searchValue)|Q(siteconfig_name_cn__icontains=searchValue)).order_by(order_by)[pageSize*(pageIndex-1):pageIndex * pageSize]
for i in ormdata:
- siteconfig_ormdata = SiteConfig.objects.get(name=i.siteconfig_name)
+ #siteconfig_ormdata = SiteConfig.objects.get(name=i.siteconfig_name)
data['data'].append({"id":i.id,
"siteconfig_name":i.siteconfig_name,
- 'siteconfig_name_cn':siteconfig_ormdata.name_cn,
+ 'siteconfig_name_cn':i.siteconfig_name_cn,
"cookie":i.cookie,
"passkey":i.passkey,
})
@@ -392,6 +393,7 @@ def siteinfoImport(request):
return JsonResponse(response_data)
+
#==================
@login_required
def siteconfigname(request):
@@ -405,6 +407,9 @@ def siteconfigname(request):
data['msg'] = ""
data['data'] = []
+ #获取数据标志 1 返回所有 其它返回未配置站点
+ flag = request.GET.get('flag', 0)
+
#得到排序字段
sort = request.GET.get('sort','name')
#得到排序规则
@@ -419,47 +424,12 @@ def siteconfigname(request):
data['count'] = SiteConfig.objects.count()
ormdata = SiteConfig.objects.order_by(order_by).all()
-
-
- for i in ormdata:
-
- data['data'].append({
- "name":i.name,
- "name_en_cn":i.name + "(" + i.name_cn + ")"
- })
-
- return JsonResponse(data)
-
-#==================
-@login_required
-def siteconfigname2siteinfo(request):
- """
- 网站集合,去掉已经创建的站点名称
- xmSelect
- """
-
- data = {}
- data['code'] = 0
- data['msg'] = ""
- data['data'] = []
-
- #得到排序字段
- sort = request.GET.get('sort','name')
- #得到排序规则
- order_by_type = request.GET.get('order','')
- if order_by_type == 'asc':
- order_by = sort
+ if int(flag) == 0:
+ #获取siteinfo中配置的站点名
+ ormdata_siteinfo = list(SiteInfo.objects.values_list('siteconfig_name', flat=True))
else:
- order_by = '-' + sort
-
- #获取所有记录
- data['count'] = SiteConfig.objects.count()
-
- ormdata = SiteConfig.objects.order_by(order_by).all()
-
- #获取siteinfo中配置的站点名
- ormdata_siteinfo = list(SiteInfo.objects.values_list('siteconfig_name', flat=True))
+ ormdata_siteinfo = []
for i in ormdata:
#忽略已经配置的站点
@@ -469,4 +439,52 @@ def siteconfigname2siteinfo(request):
"name_en_cn":i.name + "(" + i.name_cn + ")"
})
+ return JsonResponse(data)
+
+
+#==================
+@login_required
+def select_siteinfo(request):
+ """
+ RSS订阅
+ xmSelect
+ """
+
+ data = {}
+ data['code'] = 0
+ data['msg'] = ""
+ data['data'] = []
+
+ #获取数据标志 1 返回所有 其它返回未配置站点
+ flag = request.GET.get('flag', 0)
+
+ #得到排序字段
+ sort = request.GET.get('sort','id')
+ #得到排序规则
+ order_by_type = request.GET.get('order','')
+
+ if order_by_type == 'asc':
+ order_by = sort
+ else:
+ order_by = '-' + sort
+
+ #获取所有记录
+ data['count'] = SiteInfo.objects.count()
+
+ ormdata = SiteInfo.objects.order_by(order_by).all()
+
+ if int(flag) == 0:
+ #获取RSS配置的站点ID
+ ormdata_config = list(Config.objects.values_list('siteinfo_id', flat=True))
+ else:
+ ormdata_config = []
+
+ for i in ormdata:
+ #只返回未配置rss的站点
+ if i.id not in ormdata_config:
+ data['data'].append({
+ "id":i.id,
+ "name":i.siteconfig_name + "(" + i.siteconfig_name_cn + ")"
+ })
+
return JsonResponse(data)
\ No newline at end of file
diff --git a/paddleocr/captcha_rec_model/inference.pdiparams b/paddleocr/captcha_rec_model/inference.pdiparams
index 53bf535..426efec 100644
Binary files a/paddleocr/captcha_rec_model/inference.pdiparams and b/paddleocr/captcha_rec_model/inference.pdiparams differ
diff --git a/paddleocr/captcha_rec_model/inference.pdmodel b/paddleocr/captcha_rec_model/inference.pdmodel
index 9dadd74..763d147 100644
Binary files a/paddleocr/captcha_rec_model/inference.pdmodel and b/paddleocr/captcha_rec_model/inference.pdmodel differ
diff --git a/requirements.txt b/requirements.txt
index c04f110..27290d8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -17,6 +17,8 @@ thefuzz
#thefuzz[speedup]
#paddlepaddle
paddleocr
+transmission-rpc
+qbittorrent-api
#本地测试使用
#PyMySQL >= 1.0.2
#使用后台运行
diff --git a/static/json/menus.json b/static/json/menus.json
index cc4b18b..2dae95d 100644
--- a/static/json/menus.json
+++ b/static/json/menus.json
@@ -49,6 +49,17 @@
}
]
},
+ {
+ "title": "下载工具管理",
+ "icon": "layui-icon layui-icon-set",
+ "path": "javascript:;",
+ "children": [
+ {
+ "title": "下载器配置",
+ "path": "#/download/tools"
+ }
+ ]
+ },
{
"title": "消息推送配置",
"icon": "layui-icon layui-icon-set",
@@ -72,6 +83,25 @@
}
]
},
+ {
+ "title": "RSS订阅管理",
+ "icon": "layui-icon layui-icon-set",
+ "path": "javascript:;",
+ "children": [
+ {
+ "title": "RSS配置",
+ "path": "#/rss/config"
+ },
+ {
+ "title": "RSS规则",
+ "path": "#/rss/rule"
+ },
+ {
+ "title": "RSS种子详情",
+ "path": "#/rss/seedinfo"
+ }
+ ]
+ },
{
"title": "任务管理",
"icon": "layui-icon layui-icon-set",
diff --git a/static/screenshot/rss.png b/static/screenshot/rss.png
new file mode 100644
index 0000000..1003786
Binary files /dev/null and b/static/screenshot/rss.png differ