alist_task.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. import configparser
  2. import json
  3. import logging
  4. import os
  5. import shutil
  6. import signal
  7. import threading
  8. import time
  9. import requests
  10. from pyarr import RadarrAPI
  11. from src.models.task_type import TaskType, ActionType
  12. from aria2p import API, Client
  13. class NasToolsClient:
  14. def __init__(self, base_url, api_key=None):
  15. self.base_url = base_url
  16. self.api_key = api_key
  17. self.token = None
  18. # def login(self, username, password):
  19. # """
  20. # 登录以获取Token
  21. # """
  22. # url = f'{self.base_url}/api/v1/user/login'
  23. # data = {'username': username, 'password': password}
  24. # headers = {'Content-Type': 'application/x-www-form-urlencoded'}
  25. # response = requests.post(url, data=data, headers=headers)
  26. # if response.status_code == 200:
  27. # self.token = response.json().get('token')
  28. # return self.token
  29. # else:
  30. # raise Exception("Login failed with status code: " + str(response.status_code))
  31. def login(self, username, password):
  32. """登录并获取令牌"""
  33. url = f'{self.base_url}/api/v1/user/login'
  34. data = {
  35. "username": username,
  36. "password": password
  37. }
  38. headers = {'Content-Type': 'application/x-www-form-urlencoded'}
  39. response = requests.post(url, data=data, headers=headers)
  40. if response.status_code == 200:
  41. self.token = response.json().get("data", {}).get("token")
  42. logging.info(self.token)
  43. logging.info(self.api_key)
  44. return self.token
  45. else:
  46. raise Exception("Failed to login:", response.text)
  47. def get(self, endpoint):
  48. """执行带有令牌的 GET 请求"""
  49. url = f"{self.base_url}{endpoint}"
  50. headers = {
  51. "Authorization": f"Bearer {self.token}" if self.token else f"ApiKey {self.api_key}"
  52. }
  53. response = requests.get(url, headers=headers)
  54. if response.status_code == 200:
  55. return response.json()
  56. else:
  57. raise Exception("Failed to get data:", response.text)
  58. def sync_list(self):
  59. """
  60. 同步目录
  61. """
  62. url = f'{self.base_url}/api/v1/sync/directory/list'
  63. # {"Bearer Auth": {"type": "apiKey", "name": "Authorization", "in": "header"}}
  64. headers = {
  65. 'accept': 'application/json',
  66. 'Content-Type': 'application/x-www-form-urlencoded',
  67. "Authorization": f"{self.token}",
  68. }
  69. logging.info(f"headers: {headers}")
  70. params = {
  71. 'apikey': self.api_key
  72. }
  73. response = requests.post(url, params=params, headers=headers)
  74. logging.info(response.json())
  75. return response.json()
  76. def sync(self, sid):
  77. """
  78. 同步目录 {cmd: "run_directory_sync", data: {sid: []}}
  79. """
  80. url = f'{self.base_url}/api/v1/sync/directory/run'
  81. # {"Bearer Auth": {"type": "apiKey", "name": "Authorization", "in": "header"}}
  82. headers = {
  83. 'accept': 'application/json',
  84. 'Content-Type': 'application/x-www-form-urlencoded',
  85. "Authorization": f"{self.token}",
  86. }
  87. logging.info(f"headers: {headers}")
  88. params = {
  89. 'apikey': self.api_key,
  90. 'sid': sid
  91. }
  92. response = requests.get(url, params=params, headers=headers)
  93. logging.info(response.json())
  94. return response.json()
  95. def run_service(self, service_name):
  96. """
  97. 运行指定的服务
  98. """
  99. url = f'{self.base_url}/api/v1/service/run'
  100. # {"Bearer Auth": {"type": "apiKey", "name": "Authorization", "in": "header"}}
  101. headers = {
  102. 'accept': 'application/json',
  103. 'Content-Type': 'application/x-www-form-urlencoded',
  104. 'security': self.api_key,
  105. "Authorization": f"{self.token}",
  106. }
  107. logging.info(f"headers: {headers}")
  108. payload = {'item': service_name}
  109. response = requests.post(url, data=payload, headers=headers)
  110. logging.info(response.json())
  111. return response.json()
  112. class Aria2API:
  113. def __init__(self, url, secret):
  114. self.aria2_client = Client(url, secret=secret)
  115. self.aria2_api = API(self.aria2_client)
  116. self.is_running = True
  117. self.check_interval = 10
  118. self.monitor_thread = None
  119. def remove(self, download):
  120. return self.aria2_api.remove(download)
  121. def get_downloads(self):
  122. # 返回所有下载信息的列表
  123. return self.aria2_api.get_downloads()
  124. def add_url(self, url, options=None):
  125. """
  126. 将下载链接添加到 Aria2。
  127. :param url: 下载链接
  128. :param options: Aria2下载选项,例如下载目录
  129. """
  130. try:
  131. # 添加下载链接到 Aria2
  132. download = self.aria2_api.add_uris([url], options=options if options else {})
  133. return download
  134. except Exception as e:
  135. print(f"Error adding URL to Aria2: {e}")
  136. return None
  137. def monitor_aria2_and_delete(self):
  138. logging.info('Start remote Aria2 download is_complete monitoring')
  139. while self.is_running:
  140. # 获取 Aria2 当前的下载列表
  141. downloads = self.aria2_api.get_downloads()
  142. for download in downloads:
  143. if download.is_complete:
  144. pass
  145. # movie_name = self.radar_client.get_all_movie_names()
  146. # for file_name in movie_name:
  147. # # logging.info(f"Download completed: {file_name}")
  148. # # 处理每个下载完成的文件
  149. # # 调用方法并获取返回的电影 ID
  150. # movie_id = self.radar_client.find_movie_id_by_filename(file_name)
  151. #
  152. # # 打印结果
  153. # if movie_id is not None:
  154. # print(f"Found movie ID for '{file_name}': {movie_id}")
  155. # else:
  156. # print(f"No movie found for '{file_name}'")
  157. time.sleep(self.check_interval)
  158. def start_monitoring(self):
  159. if not self.is_running:
  160. self.is_running = True
  161. self.monitor_thread = threading.Thread(target=self.monitor_aria2_and_delete)
  162. self.monitor_thread.start()
  163. def stop_monitoring(self):
  164. self.is_running = False
  165. if self.monitor_thread:
  166. self.monitor_thread.join()
  167. def construct_path(base_path, sub_path, file_name):
  168. # 确保路径部分不包含反斜杠
  169. base_path = base_path.replace('\\', '/')
  170. sub_path = sub_path.replace('\\', '/')
  171. file_name = file_name.replace('\\', '/')
  172. # 使用 os.path.join 构建整个路径
  173. return os.path.join(base_path, sub_path, file_name)
  174. class RadarClient:
  175. def __init__(self, url, key):
  176. self.url = url
  177. self.api_key = key
  178. self.client = RadarrAPI(self.url, self.api_key)
  179. def get_all_movies(self):
  180. return self.client.get_movie()
  181. def delete_movie(self, movie_id):
  182. return self.client.del_movie(movie_id, delete_files=True)
  183. def save_movies_to_json(self, file_name='data/movies.json'):
  184. movies = self.get_all_movies()
  185. with open(file_name, 'w') as f:
  186. json.dump(movies, f, indent=4)
  187. print(f"Movies saved to {file_name}")
  188. def get_already_movies(self):
  189. """获取全部已经跟踪已经处理完成的电影"""
  190. already_processed = set() # 用于跟踪已处理的电影
  191. movies = self.get_all_movies()
  192. for movie in movies:
  193. if 'movieFile' in movie and movie['movieFile'] and movie['id'] not in already_processed:
  194. already_processed.add(movie['id'])
  195. return already_processed
  196. def continuous_monitoring(self, check_interval=60, custom_action=None):
  197. """
  198. Continuously monitor movies and perform a custom action if movieFile exists.
  199. check_interval: Time in seconds between checks
  200. custom_action: Function to be called for each downloaded movie
  201. """
  202. already_processed = set() # 用于跟踪已处理的电影
  203. while True:
  204. movies = self.get_all_movies()
  205. for movie in movies:
  206. if 'movieFile' in movie and movie['movieFile'] and movie['id'] not in already_processed:
  207. custom_action(movie)
  208. already_processed.add(movie['id'])
  209. time.sleep(check_interval)
  210. def find_movie_id_by_filename(self, filename):
  211. """根据文件名搜索并返回已完成下载的电影的 ID"""
  212. try:
  213. movies = self.get_all_movies()
  214. for movie in movies:
  215. # 检查电影是否已下载
  216. if 'movieFile' in movie and movie['movieFile']:
  217. movie_file_name = movie['movieFile']['relativePath']
  218. # 检查文件名是否匹配
  219. if filename in movie_file_name:
  220. return movie['id']
  221. return None
  222. except Exception as e:
  223. return None
  224. def get_all_movie_names(self):
  225. """获取所有电影名称的集合"""
  226. movie_names = set()
  227. movies = self.get_all_movies()
  228. for movie in movies:
  229. if 'movieFile' in movie and movie['movieFile']:
  230. movie_file_name = movie['movieFile']['relativePath']
  231. movie_names.add(movie_file_name)
  232. return movie_names
  233. class AlistAPI:
  234. def __init__(self, url, username, password):
  235. self.url = url
  236. self.headers = {
  237. 'UserAgent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
  238. 'Chrome/87.0.4280.88 Safari/537.36',
  239. 'Content-Type': 'application/json'
  240. }
  241. # self.aria2_client = Client(rpc_url, secret=rpc_secret)
  242. # self.aria2_api = API(self.aria2_client)
  243. self.login(username, password)
  244. def login(self, username, password):
  245. data = {
  246. 'username': username,
  247. 'password': password
  248. }
  249. response = requests.post(f'{self.url}/auth/login', data=json.dumps(data), headers=self.headers)
  250. if response.status_code == 200:
  251. token = response.json()
  252. self.headers['Authorization'] = token['data']['token']
  253. else:
  254. raise Exception('Login failed')
  255. def get_directory(self, path="", password="", page=1, per_page=0, refresh=False):
  256. payload = {
  257. "path": path,
  258. "password": password,
  259. "page": page,
  260. "per_page": per_page,
  261. "refresh": refresh
  262. }
  263. response = requests.post(f'{self.url}/fs/dirs', data=json.dumps(payload), headers=self.headers)
  264. return response.json()
  265. def copy_file(self, src_dir, dst_dir, names):
  266. payload = {
  267. "src_dir": src_dir,
  268. "dst_dir": dst_dir,
  269. "names": names
  270. }
  271. response = requests.post(f'{self.url}/fs/copy', data=json.dumps(payload), headers=self.headers)
  272. return response.json()
  273. def get_completed_tasks(self, task_type):
  274. """获取指定任务类型的已完成任务列表"""
  275. if task_type == TaskType.UPLOAD:
  276. api_endpoint = '/admin/task/upload/done'
  277. elif task_type == TaskType.COPY:
  278. api_endpoint = '/admin/task/copy/done'
  279. elif task_type == TaskType.ARIA2_DOWNLOAD:
  280. api_endpoint = '/admin/task/aria2_down/done'
  281. elif task_type == TaskType.ARIA2_TRANSFER:
  282. api_endpoint = '/admin/task/aria2_transfer/done'
  283. elif task_type == TaskType.QBITTORRENT_DOWNLOAD:
  284. api_endpoint = '/admin/task/qbit_down/done'
  285. elif task_type == TaskType.QBITTORRENT_TRANSFER:
  286. api_endpoint = '/admin/task/qbit_transfer/done'
  287. else:
  288. raise ValueError("Invalid task type")
  289. response = requests.get(
  290. f'{self.url}{api_endpoint}',
  291. headers=self.headers
  292. )
  293. return response.json()
  294. def copy_directory(self, src_path, dst_path):
  295. file_list = self.list_directory(src_path)
  296. if not file_list:
  297. return
  298. for file_info in file_list['data']['content']:
  299. if file_info['is_dir']:
  300. new_src_path = src_path + "/" + file_info['name']
  301. new_dst_path = dst_path + "/" + file_info['name']
  302. # new_src_path = os.path.join(src_path, file_info['name'])
  303. # new_dst_path = os.path.join(dst_path, file_info['name'])
  304. print(f"Copying directory: {new_src_path} to {new_dst_path}")
  305. self.copy_directory(new_src_path, new_dst_path)
  306. else:
  307. file_name = file_info['name']
  308. print(f"Copying file: {src_path}/{file_name} to {dst_path}/{file_name}")
  309. # 这里原本是调用 self.copy_file,现在改为仅打印信息
  310. self.copy_file(src_path, dst_path, [file_name])
  311. def list_directory(self, path, password="", page=1, per_page=0, refresh=False):
  312. payload = {
  313. "path": path,
  314. "password": password,
  315. "page": page,
  316. "per_page": per_page,
  317. "refresh": refresh
  318. }
  319. response = requests.post(f'{self.url}/fs/list', data=json.dumps(payload), headers=self.headers)
  320. return response.json()
  321. def get_file_or_directory_info(self, path, password="", page=1, per_page=0, refresh=False):
  322. payload = {
  323. "path": path,
  324. "password": password,
  325. "page": page,
  326. "per_page": per_page,
  327. "refresh": refresh
  328. }
  329. response = requests.post(f"{self.url}/fs/get", data=json.dumps(payload), headers=self.headers)
  330. if response.status_code == 200:
  331. return response.json()
  332. return None
  333. def move_file(self, src_dir, dst_dir, names):
  334. payload = json.dumps({
  335. "src_dir": src_dir,
  336. "dst_dir": dst_dir,
  337. "names": names
  338. })
  339. response = requests.post(f"{self.url}/fs/move", data=payload, headers=self.headers)
  340. return response.json()
  341. def remove_files_or_folders(self, dir_path, names):
  342. """删除指定目录下的文件或文件夹"""
  343. payload = {
  344. "dir": dir_path,
  345. "names": names
  346. }
  347. response = requests.post(
  348. f'{self.url}/fs/remove',
  349. headers=self.headers,
  350. json=payload
  351. )
  352. return response.json()
  353. def remove_empty_directory(self, src_dir):
  354. """删除空文件夹"""
  355. payload = {
  356. "src_dir": src_dir
  357. }
  358. response = requests.post(
  359. f'{self.url}/fs/remove_empty_director',
  360. headers=self.headers,
  361. json=payload
  362. )
  363. return response.json()
  364. def recursive_collect_contents(self,
  365. remote_download_path,
  366. home_download_path,
  367. src_dir=None,
  368. dest_path=None,
  369. current_sub_path=''):
  370. contents = []
  371. file_list = self.list_directory(remote_download_path)
  372. # file_info_json = json.dumps(file_list, indent=4)
  373. # logging.info(f'file_info_json: {file_info_json}')
  374. if file_list['data']['total'] == 0:
  375. return []
  376. for file_info in file_list['data']['content']:
  377. # 拼接完整的远程路径
  378. full_path = os.path.join(remote_download_path, file_info['name']).replace('\\', '/')
  379. # 初始化本地下载路径和复制/移动目的地路径
  380. local_download_path = ''
  381. new_dest_path = ''
  382. new_src_dir = ''
  383. # 根据条件构建本地下载路径和复制/移动目的地路径
  384. if home_download_path is not None:
  385. local_download_path = os.path.join(home_download_path, current_sub_path, file_info['name']).replace(
  386. '\\',
  387. '/')
  388. if dest_path is not None:
  389. new_dest_path = os.path.join(dest_path, current_sub_path).replace('\\', '/')
  390. if src_dir is not None:
  391. new_src_dir = os.path.join(src_dir, current_sub_path).replace('\\', '/')
  392. item = {
  393. 'name': file_info['name'],
  394. 'is_dir': file_info['is_dir'],
  395. 'path': full_path, # 存储完整的远程路径
  396. 'downloads_path': local_download_path,
  397. 'src_dir': new_src_dir,
  398. 'dst_dir': new_dest_path
  399. }
  400. contents.append(item)
  401. if file_info['is_dir']:
  402. # 更新子路径为当前文件夹的路径
  403. new_sub_path = os.path.join(current_sub_path, file_info['name'])
  404. sub_contents = self.recursive_collect_contents(full_path,
  405. home_download_path,
  406. src_dir,
  407. dest_path,
  408. new_sub_path)
  409. contents.extend(sub_contents)
  410. return contents
  411. def copy_files(self, local_json_path, is_debug=False):
  412. """执行拷贝文件"""
  413. # 读取本地 JSON 文件
  414. with open(local_json_path, 'r', encoding='utf-8') as f:
  415. directory_contents = json.load(f)
  416. for item in directory_contents:
  417. if not item['is_dir']:
  418. file_name = item['name']
  419. original_path = item['src_dir'] # 获取原始文件路径
  420. des_path = item['dst_dir'] # 获取原始文件路径
  421. if is_debug:
  422. logging.info(f"Debug mode: Copy {file_name}")
  423. else:
  424. # 复制文件
  425. self.copy_file(original_path, des_path, [file_name])
  426. logging.info(
  427. f"Copied: {file_name} from {original_path} to {des_path}")
  428. def save_directory_contents(self,
  429. remote_download_path,
  430. local_download_path,
  431. scy_copy_path,
  432. des_copy_path,
  433. parent_dir):
  434. """获取远程和本地对应的目录结构,并保存为 JSON 文件"""
  435. # 获取远程目录结构
  436. remote_data = self.recursive_collect_contents(
  437. remote_download_path,
  438. local_download_path
  439. )
  440. remote_json = os.path.join(parent_dir, 'data', 'remote_data.json')
  441. with open(remote_json, 'w', encoding='utf-8') as f:
  442. json.dump(remote_data, f, indent=4)
  443. # # 获取本地目录结构
  444. # home_data = self.home_alist_api.recursive_collect_contents(
  445. # scy_copy_path, des_copy_path, scy_copy_path, des_copy_path
  446. # )
  447. # home_json_path = os.path.join(parent_dir, 'data', self.home_data)
  448. # with open(home_json_path, 'w', encoding='utf-8') as f:
  449. # json.dump(home_data, f, indent=4)
  450. return remote_data
  451. is_running = True
  452. def move_new_files(src_dir, dest_dir, nas_tools_api):
  453. """移动新文件和目录,如果它们在目标目录中不存在"""
  454. if not os.path.exists(dest_dir):
  455. os.makedirs(dest_dir)
  456. for item in os.listdir(src_dir):
  457. src_item = os.path.join(src_dir, item)
  458. dest_item = os.path.join(dest_dir, item)
  459. # 如果是目录
  460. if os.path.isdir(src_item):
  461. # 检查目标目录是否存在
  462. if not os.path.exists(dest_item):
  463. # 直接移动整个目录
  464. shutil.move(src_item, dest_item)
  465. logging.info(f"Moved directory from {src_item} to {dest_item}")
  466. else:
  467. # 如果目标目录已存在,递归处理子目录内容
  468. move_new_files(src_item, dest_item)
  469. elif not item.endswith('.aria2'): # 检查是否为 .aria2 文件
  470. # 如果是文件,且不是 .aria2 文件,则进行移动
  471. if not os.path.exists(dest_item):
  472. shutil.move(src_item, dest_item)
  473. logging.info(f"Moved file from {src_item} to {dest_item}")
  474. # 添加移动完成的提示
  475. logging.info(f"move complete {dest_item} ")
  476. logging.info("Notify nas tools synchronization")
  477. nas_tools_api.login('admin', 'password')
  478. # self.nas_tools_api.run_service('sync')
  479. sjson = nas_tools_api.sync_list()
  480. directory_ids = [sjson['data']['result']['2']['id'], sjson['data']['result']['3']['id']]
  481. for directory_id in directory_ids:
  482. nas_tools_api.sync(directory_id)
  483. logging.info("Completed checking for new files to move.")
  484. else:
  485. logging.info(f"File already exists, skipping: {dest_item}")
  486. def handle_signal(signum, frame):
  487. """处理中断信号,优雅地退出循环"""
  488. global is_running
  489. is_running = False
  490. print("Exiting...")
  491. def has_files_or_directories(directory_path):
  492. """
  493. 检查指定目录下是否存在文件或文件夹。
  494. :param directory_path: 目录的路径
  495. :return: 两个布尔值,第一个表示是否存在文件,第二个表示是否存在文件夹。
  496. """
  497. # 检查路径是否存在
  498. if not os.path.exists(directory_path):
  499. print(f"路径不存在: {directory_path}")
  500. return False, False # 路径不存在时返回两个False
  501. # 获取目录下的所有内容
  502. items = os.listdir(directory_path)
  503. # 检查是否有文件或文件夹
  504. has_files = any(os.path.isfile(os.path.join(directory_path, item)) for item in items)
  505. has_directories = any(os.path.isdir(os.path.join(directory_path, item)) for item in items)
  506. return has_files, has_directories
  507. if __name__ == '__main__':
  508. # 注册信号处理函数
  509. signal.signal(signal.SIGINT, handle_signal)
  510. # 初始化日志和配置
  511. logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
  512. # 获取当前脚本的绝对路径
  513. current_directory = os.path.dirname(os.path.abspath(__file__))
  514. # 获取当前脚本所在目录的上级目录
  515. # parent_directory = os.path.dirname(current_directory)
  516. # 构建 config.ini 文件的路径
  517. config_path = os.path.join(current_directory, 'config', 'config.ini')
  518. # 读取配置文件
  519. config = configparser.ConfigParser()
  520. config.read(config_path)
  521. base_url = config['NSTOOLS']['URL']
  522. api_key = config['NSTOOLS']['API_KEY']
  523. nas_tools_api = NasToolsClient(base_url, api_key)
  524. radar_client = RadarClient(config['RADAR']['URL'],
  525. config['RADAR']['API_KEY'])
  526. aria2_api = Aria2API(config['ARIA2']['RPC_URL'], config['ARIA2']['RPC_SECRET'])
  527. # aria2_api.start_monitoring()
  528. remote_alist_api = AlistAPI(config['REMOTE_ALIST']['API_URL'],
  529. config['REMOTE_ALIST']['USERNAME'],
  530. config['REMOTE_ALIST']['PASSWORD'])
  531. download_path = config['ARIA2']['DESTINATION_PATH']
  532. destination_path = config['ARIA2']['DES_COPY_PATH']
  533. # 获取远程下载目录
  534. remote_alist_download_path = config['REMOTE_ALIST']['DOWNLOAD_PATH']
  535. home_alist_download_path = config['HOME_ALIST']['DOWNLOAD_PATH']
  536. home_scy_alist_copy_path = config['HOME_ALIST']['SCY_COPY_PATH']
  537. home_des_alist_copy_path = config['HOME_ALIST']['DES_COPY_PATH']
  538. # 获取已完成电影的文件名集合
  539. already_movie_names = radar_client.get_all_movie_names()
  540. # 更新当前下载队列集合
  541. current_downloads = {os.path.basename(file.path) for download in aria2_api.get_downloads() for
  542. file in download.files if file.selected}
  543. download_url = None
  544. filename = None
  545. while is_running:
  546. # 获取远程目录结构
  547. remote_json_path = remote_alist_api.save_directory_contents(
  548. remote_alist_download_path,
  549. home_alist_download_path,
  550. home_scy_alist_copy_path,
  551. home_des_alist_copy_path,
  552. current_directory)
  553. for home_item in remote_json_path:
  554. # 如果当前下载集合中已经包含了这个文件名,跳过这次循环
  555. if home_item['name'] in current_downloads:
  556. continue
  557. if not home_item['is_dir']:
  558. cent_data = remote_alist_api.get_file_or_directory_info(home_item['path'])
  559. if cent_data:
  560. logging.info(f"name {home_item['name']}")
  561. download_url = aria2_api.add_url(cent_data['data']['raw_url'])
  562. logging.info(f"Started to download {cent_data['data']['raw_url']}")
  563. current_downloads.add(home_item['name'])
  564. else:
  565. logging.info("File not found")
  566. if download_url is not None:
  567. # 检查下载是否完成
  568. while not download_url.is_complete:
  569. download_url.update() # 更新下载状态
  570. print("下载中...")
  571. time.sleep(10) # 等待10秒再次检查
  572. # 下载完成后移动文件
  573. if download_url.is_complete:
  574. print("下载完成")
  575. for file in download_url.files:
  576. filePath = file.path
  577. print(filePath)
  578. filename = os.path.basename(file.path)
  579. print(filename)
  580. already_movie_names = radar_client.get_all_movie_names()
  581. for movie_name in already_movie_names:
  582. movie_id = radar_client.find_movie_id_by_filename(movie_name)
  583. if movie_id:
  584. radar_client.delete_movie(movie_id)
  585. files_exist, directories_exist = has_files_or_directories(download_path)
  586. if files_exist or directories_exist:
  587. move_new_files(download_path, destination_path + "/movie", nas_tools_api)
  588. print("移动文件完成")
  589. else:
  590. print("没有文件或者目录")
  591. time.sleep(10) # 模拟任务执行
  592. # aria2_api.stop_monitoring()
  593. # print("停止监控")