alroyso 10 місяців тому
батько
коміт
8b1ea7661b

+ 1 - 1
.idea/misc.xml

@@ -3,5 +3,5 @@
   <component name="Black">
     <option name="sdkName" value="Python 3.11 (pythonProject)" />
   </component>
-  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (pythonProject)" project-jdk-type="Python SDK" />
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (autodownload)" project-jdk-type="Python SDK" />
 </project>

+ 1 - 1
.idea/pythonProject.iml

@@ -4,7 +4,7 @@
     <content url="file://$MODULE_DIR$">
       <excludeFolder url="file://$MODULE_DIR$/.venv" />
     </content>
-    <orderEntry type="inheritedJdk" />
+    <orderEntry type="jdk" jdkName="Python 3.10 (autodownload)" jdkType="Python SDK" />
     <orderEntry type="sourceFolder" forTests="false" />
   </component>
 </module>

+ 61 - 48
.idea/workspace.xml

@@ -5,30 +5,24 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="e3b9eb38-ee4f-4b25-9417-dca75aa02bfe" name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/.idea/inspectionProfiles/Project_Default.xml" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/.idea/inspectionProfiles/profiles_settings.xml" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/.idea/modules.xml" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/.idea/pythonProject.iml" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/__init__.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/alist.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/api_clients.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/aria2.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/api/nas_tools.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/app.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/config/__init__.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/config/config.ini" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/config/config_manager.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/main.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/pikpak.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/services/__init__.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/services/download_manager.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/services/download_service.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/services/nas_sync_service.py" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/templates/files.html" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/templates/index.html" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/app/__init__.py" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/app/routes.py" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/app/service_manager.py" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/data/download.txt" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/database/__init__.py" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/database/database.py" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/models/__init__.py" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/models/models.py" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/scripts/load_movies.py" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/.idea/pythonProject.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/pythonProject.iml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/api/alist.py" beforeDir="false" afterPath="$PROJECT_DIR$/api/alist.py" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/app.py" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/main.py" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/services/download_manager.py" beforeDir="false" afterPath="$PROJECT_DIR$/services/download_manager.py" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/services/download_service.py" beforeDir="false" afterPath="$PROJECT_DIR$/services/download_service.py" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/templates/files.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/files.html" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -38,8 +32,8 @@
   <component name="FileTemplateManagerImpl">
     <option name="RECENT_TEMPLATES">
       <list>
-        <option value="Python Script" />
         <option value="HTML File" />
+        <option value="Python Script" />
       </list>
     </option>
   </component>
@@ -62,32 +56,37 @@
   "keyToString": {
     "DefaultHtmlFileTemplate": "HTML File",
     "Python.app.executor": "Debug",
+    "Python.load_movies.executor": "Debug",
     "Python.main.executor": "Debug",
     "Python.pikpak.executor": "Debug",
     "RunOnceActivity.OpenProjectViewOnStart": "true",
     "RunOnceActivity.ShowReadmeOnStart": "true",
     "git-widget-placeholder": "master",
-    "last_opened_file_path": "/Users/cauto/Desktop/work/python_work/alist_task/pythonProject/config",
+    "last_opened_file_path": "/Users/cauto/Desktop/work/python_work/autodownload/models",
     "node.js.detected.package.eslint": "true",
     "node.js.detected.package.tslint": "true",
     "node.js.selected.package.eslint": "(autodetect)",
     "node.js.selected.package.tslint": "(autodetect)",
     "nodejs_package_manager_path": "npm",
+    "settings.editor.selected.configurable": "preferences.pluginManager",
     "vue.rearranger.settings.migration": "true"
   }
 }]]></component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
+      <recent name="$PROJECT_DIR$/models" />
       <recent name="$PROJECT_DIR$/config" />
       <recent name="$PROJECT_DIR$/services" />
     </key>
     <key name="MoveFile.RECENT_KEYS">
+      <recent name="$PROJECT_DIR$/app" />
+      <recent name="$PROJECT_DIR$/models" />
       <recent name="$PROJECT_DIR$/services" />
+      <recent name="$PROJECT_DIR$/data" />
       <recent name="$PROJECT_DIR$/config" />
-      <recent name="$PROJECT_DIR$/api" />
     </key>
   </component>
-  <component name="RunManager" selected="Python.app">
+  <component name="RunManager" selected="Python.main">
     <configuration name="app" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
       <module name="pythonProject" />
       <option name="ENV_FILES" value="" />
@@ -102,7 +101,30 @@
       <option name="ADD_CONTENT_ROOTS" value="true" />
       <option name="ADD_SOURCE_ROOTS" value="true" />
       <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
-      <option name="SCRIPT_NAME" value="$PROJECT_DIR$/app.py" />
+      <option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/app.py" />
+      <option name="PARAMETERS" value="" />
+      <option name="SHOW_COMMAND_LINE" value="false" />
+      <option name="EMULATE_TERMINAL" value="false" />
+      <option name="MODULE_MODE" value="false" />
+      <option name="REDIRECT_INPUT" value="false" />
+      <option name="INPUT_FILE" value="" />
+      <method v="2" />
+    </configuration>
+    <configuration name="load_movies" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
+      <module name="pythonProject" />
+      <option name="ENV_FILES" value="" />
+      <option name="INTERPRETER_OPTIONS" value="" />
+      <option name="PARENT_ENVS" value="true" />
+      <envs>
+        <env name="PYTHONUNBUFFERED" value="1" />
+      </envs>
+      <option name="SDK_HOME" value="" />
+      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/scripts" />
+      <option name="IS_MODULE_SDK" value="true" />
+      <option name="ADD_CONTENT_ROOTS" value="true" />
+      <option name="ADD_SOURCE_ROOTS" value="true" />
+      <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
+      <option name="SCRIPT_NAME" value="$PROJECT_DIR$/scripts/load_movies.py" />
       <option name="PARAMETERS" value="" />
       <option name="SHOW_COMMAND_LINE" value="false" />
       <option name="EMULATE_TERMINAL" value="false" />
@@ -159,6 +181,7 @@
     </configuration>
     <recent_temporary>
       <list>
+        <item itemvalue="Python.load_movies" />
         <item itemvalue="Python.app" />
         <item itemvalue="Python.pikpak" />
       </list>
@@ -167,7 +190,8 @@
   <component name="SharedIndexes">
     <attachedChunks>
       <set>
-        <option value="bundled-python-sdk-5a2391486177-2887949eec09-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-233.13763.11" />
+        <option value="bundled-js-predefined-1d06a55b98c1-74d2a5396914-JavaScript-PY-241.14494.241" />
+        <option value="bundled-python-sdk-0509580d9d50-28c9f5db9ffe-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-241.14494.241" />
       </set>
     </attachedChunks>
   </component>
@@ -182,31 +206,20 @@
       <workItem from="1713279929305" duration="6625000" />
       <workItem from="1713360335152" duration="1834000" />
       <workItem from="1714757043688" duration="3901000" />
+      <workItem from="1714799916042" duration="212000" />
+      <workItem from="1714800139279" duration="11538000" />
     </task>
     <servers />
   </component>
   <component name="TypeScriptGeneratedFilesManager">
     <option name="version" value="3" />
   </component>
-  <component name="XDebuggerManager">
-    <breakpoint-manager>
-      <breakpoints>
-        <line-breakpoint enabled="true" suspend="THREAD" type="python-line">
-          <url>file://$PROJECT_DIR$/api/alist.py</url>
-          <line>177</line>
-          <option name="timeStamp" value="6" />
-        </line-breakpoint>
-        <line-breakpoint enabled="true" suspend="THREAD" type="python-line">
-          <url>file://$PROJECT_DIR$/api/alist.py</url>
-          <line>180</line>
-          <option name="timeStamp" value="7" />
-        </line-breakpoint>
-      </breakpoints>
-    </breakpoint-manager>
-  </component>
   <component name="com.intellij.coverage.CoverageDataManagerImpl">
-    <SUITE FILE_PATH="coverage/pythonProject$pikpak.coverage" NAME="pikpak Coverage Results" MODIFIED="1713361137219" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
-    <SUITE FILE_PATH="coverage/pythonProject$app.coverage" NAME="app Coverage Results" MODIFIED="1714760950945" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
     <SUITE FILE_PATH="coverage/pythonProject$main.coverage" NAME="main Coverage Results" MODIFIED="1713282932589" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
+    <SUITE FILE_PATH="coverage/pythonProject$app.coverage" NAME="app Coverage Results" MODIFIED="1714760950945" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
+    <SUITE FILE_PATH="coverage/autodownload$main.coverage" NAME="main 覆盖结果" MODIFIED="1714819948245" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
+    <SUITE FILE_PATH="coverage/pythonProject$pikpak.coverage" NAME="pikpak Coverage Results" MODIFIED="1713361137219" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
+    <SUITE FILE_PATH="coverage/autodownload$app.coverage" NAME="app 覆盖结果" MODIFIED="1714813632611" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
+    <SUITE FILE_PATH="coverage/autodownload$load_movies.coverage" NAME="load_movies 覆盖结果" MODIFIED="1714819865901" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/scripts" />
   </component>
 </project>

+ 1 - 0
api/alist.py

@@ -266,6 +266,7 @@ class AlistAPI:
             remote_download_path,
             local_download_path
         )
+
         remote_json = os.path.join(parent_dir, 'data', 'remote_data.json')
         with open(remote_json, 'w', encoding='utf-8') as f:
             json.dump(remote_data, f, indent=4)

+ 0 - 58
app.py

@@ -1,58 +0,0 @@
-# app.py
-import logging
-import os
-
-from flask import Flask, render_template, request, redirect, url_for
-from config.config_manager import ConfigManager
-from api.api_clients import APIManager
-from services.download_manager import DownloadManager
-from services.download_service import DownloadService
-from services.nas_sync_service import NasSyncService
-
-app = Flask(__name__)
-# 获取当前脚本的绝对路径
-current_directory = os.path.dirname(os.path.abspath(__file__))
-# 构建 config.ini 文件的路径
-config_path = os.path.join(current_directory, 'config', 'config.ini')
-config = ConfigManager(config_path)
-api_manager = APIManager(config)
-
-download_manager = DownloadManager(config.get_value('ARIA2', 'DOCKER_DOWNLOAD_PATH'))
-download_service = DownloadService(api_manager, download_manager)
-nas_sync_service = NasSyncService(api_manager.nas_tools_api)
-
-
-@app.before_request
-def ensure_api_login():
-    api_manager.login_apis()
-
-
-@app.route('/files')
-def files():
-    file_list = download_service.fetch_directory_contents()
-    return render_template('files.html', file_list=file_list)
-
-
-@app.route('/download/<path:filepath>')
-def download(filepath):
-    # 这里添加触发下载的逻辑
-    return redirect(url_for('files'))
-
-
-@app.route('/', methods=['GET', 'POST'])
-def index():
-    message = ""
-    if request.method == 'POST':
-        if request.form.get('action') == 'sync':
-            nas_sync_service.sync_directories()
-            message = "Directories are being synchronized."
-        elif request.form.get('action') == 'download':
-            download_urls = download_service.fetch_and_download()
-            message = f"Downloading: {len(download_urls)} files."
-        return render_template('index.html', message=message)
-    return render_template('index.html')
-
-
-if __name__ == '__main__':
-    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
-    app.run(debug=True, port=5000)

+ 21 - 0
app/__init__.py

@@ -0,0 +1,21 @@
+# app/__init__.py
+from flask import Flask
+from database.database import init_db
+
+
+from .service_manager import ServiceManager
+import os
+# 获取当前文件(__file__)的路径,然后找到 'instance' 文件夹
+base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+print(f"根目录{base_dir}")
+# 指定模板文件夹的路径
+template_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'templates'))
+app = Flask(__name__, template_folder=template_dir)
+init_db(app)  # 确保传入 Flask 应用实例
+
+# 导入所有数据库模型
+from models.models import DownloadedFile
+# 使用 ServiceManager 来管理所有服务和配置
+service_manager = ServiceManager(app)
+
+from app import routes

+ 30 - 0
app/routes.py

@@ -0,0 +1,30 @@
+# app/routes.py
+from flask import render_template, redirect, url_for, request
+from app import app, service_manager
+
+
+@app.route('/files')
+def files():
+    service_manager.api_manager.login_apis()
+    file_list = service_manager.download_service.fetch_directory_contents()
+    return render_template('files.html', file_list=file_list)
+
+
+@app.route('/download/<path:filepath>')
+def download(filepath):
+    # 添加下载逻辑
+    return redirect(url_for('files'))
+
+
+@app.route('/', methods=['GET', 'POST'])
+def index():
+    message = ""
+    if request.method == 'POST':
+        if request.form.get('action') == 'sync':
+            service_manager.nas_sync_service.sync_directories()
+            message = "Directories are being synchronized."
+        elif request.form.get('action') == 'download':
+            download_urls = service_manager.download_service.fetch_and_download()
+            message = f"Downloading: {len(download_urls)} files."
+        return render_template('index.html', message=message)
+    return render_template('index.html')

+ 26 - 0
app/service_manager.py

@@ -0,0 +1,26 @@
+import os
+from config.config_manager import ConfigManager
+from api.api_clients import APIManager
+from services.download_service import DownloadService
+from services.nas_sync_service import NasSyncService
+
+
+class ServiceManager:
+    def __init__(self, app):
+        self.app = app
+        self.config = self.init_config()
+        # 获取 app 文件夹的父目录
+        base_directory = os.path.dirname(self.app.root_path)
+        self.api_manager = APIManager(self.config)
+        self.download_service = DownloadService(self.api_manager, base_directory)
+        self.nas_sync_service = NasSyncService(self.api_manager.nas_tools_api)
+
+    def init_config(self):
+        # 获取 app 文件夹的父目录
+        base_directory = os.path.dirname(self.app.root_path)
+        # 构建到 config.ini 文件的完整路径
+        config_path = os.path.join(base_directory, 'config', 'config.ini')
+        return ConfigManager(config_path)
+
+    def login(self):
+        self.api_manager.login_apis()

+ 41 - 0
data/download.txt

@@ -0,0 +1,41 @@
+复仇者联盟 (2012) Bluray-1080p Proper.mkv
+复仇者联盟2:奥创纪元 (2015) Bluray-1080p.mkv
+复仇者联盟3:无限战争 (2018) Bluray-1080p.mkv
+复仇者联盟4:终局之战 (2019) Remux-2160p.mkv
+新蝙蝠侠 (2022) Bluray-1080p Proper.mkv
+独立日 (1996) Bluray-1080p.mkv
+独立日2:卷土重来 (2016) Bluray-1080p.mkv
+美国队长 (2011) Bluray-1080p Proper.mp4
+美国队长2 (2014) Bluray-1080p Proper.mp4
+美国队长3 (2016) Bluray-1080p Proper.mp4
+蝙蝠侠:侠影之谜 (2005) Bluray-1080p.mkv
+蝙蝠侠:黑暗骑士 (2008) Bluray-1080p Proper.mkv
+蝙蝠侠:黑暗骑士崛起 (2012) Bluray-1080p.mkv
+钢铁侠 (2008) Bluray-1080p Proper.mkv
+钢铁侠2 (2010) Bluray-1080p Proper.mkv
+钢铁侠3 (2013) Bluray-1080p Proper.mp4
+蚁人 (2015) Bluray-1080p.mkv
+蚁人2:黄蜂女现身 (2018) Bluray-1080p.mp4
+蚁人与黄蜂女:量子狂潮 (2023) Bluray-1080p.mp4
+钢铁侠3 (2013) Bluray-1080p Proper.mp4
+变形金刚 (2007) Bluray-1080p Proper.mkv
+蚁人 (2015) Bluray-1080p.mkv
+生化危机4:战神再生 (2010) Bluray-2160p.mkv
+生化危机6:终章 (2016) Bluray-2160p.mkv
+鹿鼎记2:神龙教 (1992) Bluray-1080p.mkv
+变形金刚2 (2009) Bluray-2160p.mkv
+生化危机5:惩罚 (2012) Bluray-2160p.mkv
+鹿鼎记 (1992) Bluray-1080p.mkv
+异形 (1979) Bluray-1080p Proper.mkv
+异形:契约 (2017) Remux-2160p Proper.mkv
+正义联盟 (2017) Bluray-2160p.mkv
+奇异博士2:疯狂多元宇宙 (2022) Bluray-1080p.mkv
+康斯坦丁 (2005) Bluray-2160p.mkv
+异形魔怪 (1990) Remux-1080p.mkv
+新木乃伊 (2017) Bluray-1080p.mkv
+正义联盟:无限地球危机(上) (2024) Remux-2160p.mkv
+环太平洋 (2013) Remux-2160p.mkv
+环太平洋:雷霆再起 (2018) Remux-1080p.mkv
+黑客帝国 (1999) Remux-2160p.mkv
+正义联盟:无限地球危机(中) (2024) WEBDL-2160p.mkv
+蝙蝠侠大战超人:正义黎明 (2016) Remux-2160p.mkv

+ 0 - 0
database/__init__.py


+ 16 - 0
database/database.py

@@ -0,0 +1,16 @@
+# database.py
+import os
+
+from flask_sqlalchemy import SQLAlchemy
+
+db = SQLAlchemy()
+
+
+def init_db(app):
+    base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+    database_path = os.path.join(base_dir, 'instance', 'downloads.db')
+    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + database_path
+    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
+    db.init_app(app)  # 使用 init_app 来绑定 app 和 db
+    with app.app_context():
+        db.create_all()

+ 0 - 0
models/__init__.py


+ 12 - 0
models/models.py

@@ -0,0 +1,12 @@
+# models.py
+from database.database import db
+
+
+class DownloadedFile(db.Model):
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(db.String(255), unique=True, nullable=False)
+    path = db.Column(db.String(255), nullable=True)  # 允许 NULL 值
+    downloaded = db.Column(db.Boolean, default=False, nullable=False)
+
+    def __repr__(self):
+        return f'<DownloadedFile {self.name}>'

+ 28 - 0
scripts/load_movies.py

@@ -0,0 +1,28 @@
+# scripts/load_movies.py
+import os
+from app import app
+from database.database import db
+from models.models import DownloadedFile
+
+
+def add_movies_from_file(file_path):
+    with open(file_path, 'r', encoding='utf-8') as file:
+        movies = file.readlines()
+
+    with app.app_context():
+
+        for movie in movies:
+            movie = movie.strip()
+            if not DownloadedFile.query.filter_by(name=movie).first():
+                new_movie = DownloadedFile(name=movie, downloaded=False)
+                db.session.add(new_movie)
+        db.session.commit()
+
+
+if __name__ == '__main__':
+    # Assume the path to the movie file
+
+    base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+    database_path = os.path.join(base_dir, 'data', 'download.txt')
+    file_path = database_path
+    add_movies_from_file(file_path)

+ 14 - 14
services/download_manager.py

@@ -1,19 +1,19 @@
 # download_manager.py
-import os
 
 
 class DownloadManager:
-    def __init__(self, download_data_path):
-        self.download_data_path = download_data_path
+    @staticmethod
+    def is_downloaded(name):
+        from models.models import DownloadedFile, db
+        # 查询数据库以检查文件是否已下载
+        file_record = DownloadedFile.query.filter_by(name=name).first()
+        return file_record is not None and file_record.downloaded
 
-    def is_downloaded(self, fileName):
-        if not os.path.exists(self.download_data_path):
-            return False
-        with open(self.download_data_path, 'r', encoding='utf-8') as file:
-            downloaded_files = file.readlines()
-        downloaded_files = [line.strip() for line in downloaded_files]
-        return fileName in downloaded_files
-
-    def record_download(self, filename):
-        with open(self.download_data_path, 'a', encoding='utf-8') as file:
-            file.write(filename + "\n")
+    @staticmethod
+    def record_download(name, path):
+        from models.models import DownloadedFile, db
+        # 记录文件下载到数据库
+        if not DownloadManager.is_downloaded(name):
+            new_file = DownloadedFile(name=name, path=path, downloaded=True)
+            db.session.add(new_file)
+            db.session.commit()

+ 12 - 6
services/download_service.py

@@ -2,11 +2,14 @@
 import os
 import time
 
+from services.download_manager import DownloadManager
+
 
 class DownloadService:
-    def __init__(self, api_manager, download_manager):
+    def __init__(self, api_manager, parent_dir: str):
+        self.parent_dir = parent_dir
         self.api_manager = api_manager
-        self.download_manager = download_manager
+        self.download_manager = DownloadManager()
 
     def fetch_directory_contents(self):
 
@@ -15,9 +18,12 @@ class DownloadService:
             self.api_manager.config.get_value('HOME_ALIST', 'DOWNLOAD_PATH'),
             self.api_manager.config.get_value('HOME_ALIST', 'SCY_COPY_PATH'),
             self.api_manager.config.get_value('HOME_ALIST', 'DES_COPY_PATH'),
-            os.path.dirname(os.path.abspath(__file__))
-        )
-        return remote_json_path  # 假设这返回的是文件和文件夹列表
+            self.parent_dir)
+
+        # 检查每个文件是否已下载,并添加下载状态信息
+        for item in remote_json_path:
+            item['is_downloaded'] = self.download_manager.is_downloaded(item['name'])
+        return remote_json_path
 
     def fetch_and_download(self):
 
@@ -26,7 +32,7 @@ class DownloadService:
             self.api_manager.config.get_value('HOME_ALIST', 'DOWNLOAD_PATH'),
             self.api_manager.config.get_value('HOME_ALIST', 'SCY_COPY_PATH'),
             self.api_manager.config.get_value('HOME_ALIST', 'DES_COPY_PATH'),
-            os.path.dirname(os.path.abspath(__file__))
+            self.parent_dir
         )
         download_url = []
         for home_item in remote_json_path:

+ 6 - 3
templates/files.html

@@ -14,12 +14,15 @@
         </tr>
         {% for file in file_list %}
         <tr>
-            <td>{{ file.name }}</td>
+            <td>{{ file['name'] }}</td>
             <td>
-                <!-- 假设每个文件有唯一的路径或标识符 -->
-                <form action="{{ url_for('download', filepath=file.path) }}" method="post">
+                {% if file['is_downloaded'] %}
+                <button disabled>已下载</button>
+                {% else %}
+                <form action="{{ url_for('download', filepath=file['path']) }}" method="post">
                     <button type="submit">下载</button>
                 </form>
+                {% endif %}
             </td>
         </tr>
         {% endfor %}