|
@@ -0,0 +1,360 @@
|
|
|
+"""RemoteDownloadSerivce 类"""
|
|
|
+"""主要实现功能"""
|
|
|
+"""通过读取radarr服务器上的api 获取已经完成的电影"""
|
|
|
+"""并通过alist api 获取到对应到文件到下载地址 """
|
|
|
+"""并送到本地 airai2 下载"""
|
|
|
+
|
|
|
+"""相关配置"""
|
|
|
+# [COMMON]
|
|
|
+# LOG_LEVEL = INFO
|
|
|
+# TIMEOUT = 3600
|
|
|
+# CHECK_INTERVAL = 10
|
|
|
+# REMOTE_DATA=remote.json
|
|
|
+# HOME_DATA=home.json
|
|
|
+#
|
|
|
+# [ARIA2]
|
|
|
+# RPC_URL = http://192.168.88.29
|
|
|
+# RPC_SECRET = 123456
|
|
|
+# DESTINATION_PATH = /home/downloads
|
|
|
+# DES_COPY_PATH = /home/video/sync
|
|
|
+#
|
|
|
+# [HOME_ALIST]
|
|
|
+# API_URL = http://192.168.88.29:5244/api
|
|
|
+# WEB_URL = http://192.168.88.29
|
|
|
+# CLIENT_ID = 4e34854d5d7390ef7801
|
|
|
+# USERNAME = admin
|
|
|
+# PASSWORD = nokidc123@#
|
|
|
+# DOWNLOAD_PATH = /downloads/movie
|
|
|
+# SCY_COPY_PATH = /downloads/movie
|
|
|
+# DES_COPY_PATH = /media/sync/movie
|
|
|
+#
|
|
|
+# [REMOTE_ALIST]
|
|
|
+# API_URL = http://box.szfa.xyz:5244/api
|
|
|
+# WEB_URL = http://box.szfa.xyz:5244
|
|
|
+# CLIENT_ID = 4e34854d5d7390ef7801
|
|
|
+# USERNAME = admin
|
|
|
+# PASSWORD = nokidc123@#
|
|
|
+# DOWNLOAD_PATH = /data/media/moive
|
|
|
+#
|
|
|
+# [RADAR]
|
|
|
+# URL = http://box.szfa.xyz:7878
|
|
|
+# API_KEY = bd45569f422a4c159600964b7b85a0bd
|
|
|
+
|
|
|
+
|
|
|
+"""这里需要修改一下"""
|
|
|
+
|
|
|
+
|
|
|
+# def process_downloads(self):
|
|
|
+# completed_movies = self.radar_client.get_already_movies()
|
|
|
+# for movie in completed_movies:
|
|
|
+# file_path = self.get_remote_file_path(movie)
|
|
|
+# if file_path:
|
|
|
+# self.send_to_aria2(file_path)
|
|
|
+"""这里radar_client 只能获取到数量,用来循环"""
|
|
|
+"""电影到下载地址,应该是 远程 apist 提供到,所以需要遍历了 远程路径"""
|
|
|
+# self.remote_download_path = config['REMOTE_ALIST']['DOWNLOAD_PATH']
|
|
|
+"""alist api 的实现"""
|
|
|
+# import json
|
|
|
+# import logging
|
|
|
+# import os
|
|
|
+# import requests
|
|
|
+# from src.models.task_type import TaskType, ActionType
|
|
|
+#
|
|
|
+
|
|
|
+# def construct_path(base_path, sub_path, file_name):
|
|
|
+# # 确保路径部分不包含反斜杠
|
|
|
+# base_path = base_path.replace('\\', '/')
|
|
|
+# sub_path = sub_path.replace('\\', '/')
|
|
|
+# file_name = file_name.replace('\\', '/')
|
|
|
+#
|
|
|
+# # 使用 os.path.join 构建整个路径
|
|
|
+# return os.path.join(base_path, sub_path, file_name)
|
|
|
+#
|
|
|
+#
|
|
|
+# class AlistAPI:
|
|
|
+# def __init__(self, url, username, password):
|
|
|
+# self.url = url
|
|
|
+# self.headers = {
|
|
|
+# 'UserAgent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
|
|
+# 'Chrome/87.0.4280.88 Safari/537.36',
|
|
|
+# 'Content-Type': 'application/json'
|
|
|
+# }
|
|
|
+# # self.aria2_client = Client(rpc_url, secret=rpc_secret)
|
|
|
+# # self.aria2_api = API(self.aria2_client)
|
|
|
+# self.login(username, password)
|
|
|
+#
|
|
|
+# def login(self, username, password):
|
|
|
+# data = {
|
|
|
+# 'username': username,
|
|
|
+# 'password': password
|
|
|
+# }
|
|
|
+# response = requests.post(f'{self.url}/auth/login', data=json.dumps(data), headers=self.headers)
|
|
|
+# if response.status_code == 200:
|
|
|
+# token = response.json()
|
|
|
+# self.headers['Authorization'] = token['data']['token']
|
|
|
+# else:
|
|
|
+# raise Exception('Login failed')
|
|
|
+#
|
|
|
+# def get_directory(self, path="", password="", page=1, per_page=0, refresh=False):
|
|
|
+# payload = {
|
|
|
+# "path": path,
|
|
|
+# "password": password,
|
|
|
+# "page": page,
|
|
|
+# "per_page": per_page,
|
|
|
+# "refresh": refresh
|
|
|
+# }
|
|
|
+# response = requests.post(f'{self.url}/fs/dirs', data=json.dumps(payload), headers=self.headers)
|
|
|
+# return response.json()
|
|
|
+#
|
|
|
+# def copy_file(self, src_dir, dst_dir, names):
|
|
|
+# payload = {
|
|
|
+# "src_dir": src_dir,
|
|
|
+# "dst_dir": dst_dir,
|
|
|
+# "names": names
|
|
|
+# }
|
|
|
+# response = requests.post(f'{self.url}/fs/copy', data=json.dumps(payload), headers=self.headers)
|
|
|
+# return response.json()
|
|
|
+#
|
|
|
+# def get_completed_tasks(self, task_type):
|
|
|
+# """获取指定任务类型的已完成任务列表"""
|
|
|
+# if task_type == TaskType.UPLOAD:
|
|
|
+# api_endpoint = '/admin/task/upload/done'
|
|
|
+# elif task_type == TaskType.COPY:
|
|
|
+# api_endpoint = '/admin/task/copy/done'
|
|
|
+# elif task_type == TaskType.ARIA2_DOWNLOAD:
|
|
|
+# api_endpoint = '/admin/task/aria2_down/done'
|
|
|
+# elif task_type == TaskType.ARIA2_TRANSFER:
|
|
|
+# api_endpoint = '/admin/task/aria2_transfer/done'
|
|
|
+# elif task_type == TaskType.QBITTORRENT_DOWNLOAD:
|
|
|
+# api_endpoint = '/admin/task/qbit_down/done'
|
|
|
+# elif task_type == TaskType.QBITTORRENT_TRANSFER:
|
|
|
+# api_endpoint = '/admin/task/qbit_transfer/done'
|
|
|
+# else:
|
|
|
+# raise ValueError("Invalid task type")
|
|
|
+#
|
|
|
+# response = requests.get(
|
|
|
+# f'{self.url}{api_endpoint}',
|
|
|
+# headers=self.headers
|
|
|
+# )
|
|
|
+# return response.json()
|
|
|
+#
|
|
|
+# def copy_directory(self, src_path, dst_path):
|
|
|
+# file_list = self.list_directory(src_path)
|
|
|
+# if not file_list:
|
|
|
+# return
|
|
|
+# for file_info in file_list['data']['content']:
|
|
|
+# if file_info['is_dir']:
|
|
|
+# new_src_path = src_path + "/" + file_info['name']
|
|
|
+# new_dst_path = dst_path + "/" + file_info['name']
|
|
|
+# # new_src_path = os.path.join(src_path, file_info['name'])
|
|
|
+# # new_dst_path = os.path.join(dst_path, file_info['name'])
|
|
|
+# print(f"Copying directory: {new_src_path} to {new_dst_path}")
|
|
|
+# self.copy_directory(new_src_path, new_dst_path)
|
|
|
+# else:
|
|
|
+# file_name = file_info['name']
|
|
|
+# print(f"Copying file: {src_path}/{file_name} to {dst_path}/{file_name}")
|
|
|
+# # 这里原本是调用 self.copy_file,现在改为仅打印信息
|
|
|
+# self.copy_file(src_path, dst_path, [file_name])
|
|
|
+#
|
|
|
+# def list_directory(self, path, password="", page=1, per_page=0, refresh=False):
|
|
|
+# payload = {
|
|
|
+# "path": path,
|
|
|
+# "password": password,
|
|
|
+# "page": page,
|
|
|
+# "per_page": per_page,
|
|
|
+# "refresh": refresh
|
|
|
+# }
|
|
|
+# response = requests.post(f'{self.url}/fs/list', data=json.dumps(payload), headers=self.headers)
|
|
|
+# return response.json()
|
|
|
+#
|
|
|
+# def get_file_or_directory_info(self, path, password="", page=1, per_page=0, refresh=False):
|
|
|
+# payload = {
|
|
|
+# "path": path,
|
|
|
+# "password": password,
|
|
|
+# "page": page,
|
|
|
+# "per_page": per_page,
|
|
|
+# "refresh": refresh
|
|
|
+# }
|
|
|
+# response = requests.post(f"{self.url}/fs/get", data=json.dumps(payload), headers=self.headers)
|
|
|
+# if response.status_code == 200:
|
|
|
+# return response.json()
|
|
|
+# return None
|
|
|
+#
|
|
|
+# def move_file(self, src_dir, dst_dir, names):
|
|
|
+# payload = json.dumps({
|
|
|
+# "src_dir": src_dir,
|
|
|
+# "dst_dir": dst_dir,
|
|
|
+# "names": names
|
|
|
+# })
|
|
|
+# response = requests.post(f"{self.url}/fs/move", data=payload, headers=self.headers)
|
|
|
+# return response.json()
|
|
|
+#
|
|
|
+# def remove_files_or_folders(self, dir_path, names):
|
|
|
+# """删除指定目录下的文件或文件夹"""
|
|
|
+# payload = {
|
|
|
+# "dir": dir_path,
|
|
|
+# "names": names
|
|
|
+# }
|
|
|
+# response = requests.post(
|
|
|
+# f'{self.url}/fs/remove',
|
|
|
+# headers=self.headers,
|
|
|
+# json=payload
|
|
|
+# )
|
|
|
+# return response.json()
|
|
|
+#
|
|
|
+# def remove_empty_directory(self, src_dir):
|
|
|
+# """删除空文件夹"""
|
|
|
+# payload = {
|
|
|
+# "src_dir": src_dir
|
|
|
+# }
|
|
|
+# response = requests.post(
|
|
|
+# f'{self.url}/fs/remove_empty_director',
|
|
|
+# headers=self.headers,
|
|
|
+# json=payload
|
|
|
+# )
|
|
|
+# return response.json()
|
|
|
+#
|
|
|
+# def recursive_collect_contents(self,
|
|
|
+# remote_download_path,
|
|
|
+# home_download_path,
|
|
|
+# src_dir,
|
|
|
+# dest_path,
|
|
|
+# current_sub_path=''):
|
|
|
+# contents = []
|
|
|
+# file_list = self.list_directory(remote_download_path)
|
|
|
+# for file_info in file_list['data']['content']:
|
|
|
+# # 拼接完整的远程路径
|
|
|
+# full_path = os.path.join(remote_download_path, file_info['name']).replace('\\', '/')
|
|
|
+#
|
|
|
+# # 初始化本地下载路径和复制/移动目的地路径
|
|
|
+# local_download_path = ''
|
|
|
+# new_dest_path = ''
|
|
|
+# new_src_dir = ''
|
|
|
+# # 根据条件构建本地下载路径和复制/移动目的地路径
|
|
|
+# if home_download_path is not None:
|
|
|
+# local_download_path = os.path.join(home_download_path, current_sub_path, file_info['name']).replace(
|
|
|
+# '\\',
|
|
|
+# '/')
|
|
|
+# if dest_path is not None:
|
|
|
+# new_dest_path = os.path.join(dest_path, current_sub_path).replace('\\', '/')
|
|
|
+#
|
|
|
+# if src_dir is not None:
|
|
|
+# new_src_dir = os.path.join(src_dir, current_sub_path).replace('\\', '/')
|
|
|
+#
|
|
|
+# item = {
|
|
|
+# 'name': file_info['name'],
|
|
|
+# 'is_dir': file_info['is_dir'],
|
|
|
+# 'path': full_path, # 存储完整的远程路径
|
|
|
+# 'downloads_path': local_download_path,
|
|
|
+# 'src_dir': new_src_dir,
|
|
|
+# 'dst_dir': new_dest_path
|
|
|
+# }
|
|
|
+# contents.append(item)
|
|
|
+#
|
|
|
+# if file_info['is_dir']:
|
|
|
+# # 更新子路径为当前文件夹的路径
|
|
|
+# new_sub_path = os.path.join(current_sub_path, file_info['name'])
|
|
|
+# sub_contents = self.recursive_collect_contents(full_path,
|
|
|
+# home_download_path,
|
|
|
+# src_dir,
|
|
|
+# dest_path,
|
|
|
+# new_sub_path)
|
|
|
+# contents.extend(sub_contents)
|
|
|
+#
|
|
|
+# return contents
|
|
|
+#
|
|
|
+# def copy_files(self, local_json_path, is_debug=False):
|
|
|
+# """执行拷贝文件"""
|
|
|
+# # 读取本地 JSON 文件
|
|
|
+# with open(local_json_path, 'r', encoding='utf-8') as f:
|
|
|
+# directory_contents = json.load(f)
|
|
|
+#
|
|
|
+# for item in directory_contents:
|
|
|
+#
|
|
|
+# if not item['is_dir']:
|
|
|
+# file_name = item['name']
|
|
|
+# original_path = item['src_dir'] # 获取原始文件路径
|
|
|
+# des_path = item['dst_dir'] # 获取原始文件路径
|
|
|
+#
|
|
|
+# if is_debug:
|
|
|
+# logging.info(f"Debug mode: Copy {file_name}")
|
|
|
+# else:
|
|
|
+# # 复制文件
|
|
|
+# self.copy_file(original_path, des_path, [file_name])
|
|
|
+# logging.info(
|
|
|
+# f"Copied: {file_name} from {original_path} to {des_path}")
|
|
|
+
|
|
|
+"""这个函数已经是实现了,遍历"""
|
|
|
+# recursive_collect_contents
|
|
|
+"""结果是"""
|
|
|
+# [
|
|
|
+# {
|
|
|
+# "name": "Alien Covenant (2017)",
|
|
|
+# "is_dir": true,
|
|
|
+# "path": "/data/media/moive/Alien Covenant (2017)",
|
|
|
+# "downloads_path": "/mnt/data1/downloads/movie/Alien Covenant (2017)",
|
|
|
+# "scy_path": "",
|
|
|
+# "copy_des_path": ""
|
|
|
+# },
|
|
|
+# {
|
|
|
+# "name": "Alien Covenant (2017) Bluray-1080p Proper.mp4",
|
|
|
+# "is_dir": false,
|
|
|
+# "path": "/data/media/moive/Alien Covenant (2017)/Alien Covenant (2017) Bluray-1080p Proper.mp4",
|
|
|
+# "downloads_path": "/mnt/data1/downloads/movie/Alien Covenant (2017)/Alien Covenant (2017) Bluray-1080p Proper.mp4",
|
|
|
+# "scy_path": "",
|
|
|
+# "copy_des_path": ""
|
|
|
+# },
|
|
|
+# ]
|
|
|
+
|
|
|
+
|
|
|
+"""你说的我了解,我增加一个"""
|
|
|
+import time
|
|
|
+
|
|
|
+from pyarr import RadarrAPI
|
|
|
+import json
|
|
|
+
|
|
|
+
|
|
|
+class RadarClient:
|
|
|
+ def __init__(self, url, key):
|
|
|
+ self.url = url
|
|
|
+ self.api_key = key
|
|
|
+ self.client = RadarrAPI(self.url, self.api_key)
|
|
|
+
|
|
|
+ def get_all_movies(self):
|
|
|
+ return self.client.get_movie()
|
|
|
+
|
|
|
+ def delete_movie(self, movie_id):
|
|
|
+ return self.client.del_movie(movie_id)
|
|
|
+
|
|
|
+ def save_movies_to_json(self, file_name='data/movies.json'):
|
|
|
+ movies = self.get_all_movies()
|
|
|
+ with open(file_name, 'w') as f:
|
|
|
+ json.dump(movies, f, indent=4)
|
|
|
+ print(f"Movies saved to {file_name}")
|
|
|
+
|
|
|
+ def get_already_movies(self):
|
|
|
+ """获取全部已经跟踪已经处理完成的电影"""
|
|
|
+ already_processed = set() # 用于跟踪已处理的电影
|
|
|
+ movies = self.get_all_movies()
|
|
|
+ for movie in movies:
|
|
|
+ if 'movieFile' in movie and movie['movieFile'] and movie['id'] not in already_processed:
|
|
|
+ already_processed.add(movie['id'])
|
|
|
+ return already_processed
|
|
|
+
|
|
|
+ def continuous_monitoring(self, check_interval=60, custom_action=None):
|
|
|
+ """
|
|
|
+ Continuously monitor movies and perform a custom action if movieFile exists.
|
|
|
+ check_interval: Time in seconds between checks
|
|
|
+ custom_action: Function to be called for each downloaded movie
|
|
|
+ """
|
|
|
+ already_processed = set() # 用于跟踪已处理的电影
|
|
|
+ while True:
|
|
|
+ movies = self.get_all_movies()
|
|
|
+ for movie in movies:
|
|
|
+ if 'movieFile' in movie and movie['movieFile'] and movie['id'] not in already_processed:
|
|
|
+ custom_action(movie)
|
|
|
+ already_processed.add(movie['id'])
|
|
|
+ time.sleep(check_interval)
|
|
|
+#### 是为了更好的检测远程服务器是不是下载完成了,不然没有下载完成的,开始下载这不符合我的预期
|
|
|
+
|
|
|
+# 你应该没有明白的需要,我需要获取处理完的电影,然后通过调用远程alist api获取到所有到电影的地址,然后下载,那么我RemoteDownloadService 给我一个解决方案
|