mirror of
https://github.com/Cp0204/quark-auto-save.git
synced 2026-01-12 15:20:44 +08:00
commit
0e458e934e
@ -11,6 +11,7 @@
|
||||
- **WebUI**:对整个 WebUI 进行了重塑,增加了更多实用功能,如文件选择和预览界面的排序功能、资源搜索的过滤功能、TMDB 和豆瓣搜索功能、页面视图切换功能、账号设置功能等等。
|
||||
- **查重逻辑**:支持优先通过历史转存记录查重,对于有转存记录的文件,即使删除网盘文件,也不会重复转存。
|
||||
- **Aria2**:支持成功添加 Aria2 下载任务后自动删除夸克网盘内对应的文件,清理网盘空间。
|
||||
- **文件整理**:支持浏览和管理多个夸克账号的网盘文件,支持批量重命名(支持应用完整的命名、过滤规则和撤销重命名等操作)、删除文件等操作。
|
||||
|
||||
本项目修改后的版本为个人需求定制版,目的是满足我自己的使用需求,某些(我不用的)功能可能会因为修改而出现 BUG,不一定会被修复。若你要使用本项目,请知晓本人不是程序员,我无法保证本项目的稳定性,如果你在使用过程中发现了 BUG,可以在 Issues 中提交,但不保证每个 BUG 都能被修复,请谨慎使用,风险自担。
|
||||
|
||||
@ -39,6 +40,7 @@
|
||||
- [x] 转存后文件名整理(正则命名、**顺序命名**、**剧集命名**)
|
||||
- [x] 可选忽略文件后缀
|
||||
- [x] **数据库记录所有转存历史(支持查看、查询和删除记录)**
|
||||
- [x] **文件整理(支持浏览和管理多个夸克账号的网盘文件)**
|
||||
|
||||
- 任务管理
|
||||
- [x] 支持多组任务
|
||||
@ -54,7 +56,7 @@
|
||||
- 其它
|
||||
- [x] 每日签到领空间 <sup>[?](https://github.com/x1ao4/quark-auto-save-x/wiki/使用技巧集锦#每日签到领空间)</sup>
|
||||
- [x] 支持多个通知推送渠道 <sup>[?](https://github.com/x1ao4/quark-auto-save-x/wiki/通知推送服务配置)</sup>
|
||||
- [x] 支持多账号(多账号签到,仅首账号转存)
|
||||
- [x] 支持多账号(多账号签到、**文件管理**,仅首账号转存)
|
||||
- [x] 支持网盘文件下载、strm 文件生成等功能 <sup>[?](https://github.com/x1ao4/quark-auto-save-x/wiki/插件配置)</sup>
|
||||
|
||||
## 部署
|
||||
|
||||
906
app/run.py
906
app/run.py
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,7 @@ class RecordDB:
|
||||
os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
|
||||
|
||||
# 创建数据库连接
|
||||
self.conn = sqlite3.connect(self.db_path)
|
||||
self.conn = sqlite3.connect(self.db_path, check_same_thread=False)
|
||||
cursor = self.conn.cursor()
|
||||
|
||||
# 创建表,如果不存在
|
||||
@ -49,13 +49,14 @@ class RecordDB:
|
||||
self.conn.close()
|
||||
|
||||
def add_record(self, task_name, original_name, renamed_to, file_size, modify_date,
|
||||
duration="", resolution="", file_id="", file_type="", save_path=""):
|
||||
duration="", resolution="", file_id="", file_type="", save_path="", transfer_time=None):
|
||||
"""添加一条转存记录"""
|
||||
cursor = self.conn.cursor()
|
||||
now_ms = int(time.time() * 1000) if transfer_time is None else transfer_time
|
||||
cursor.execute(
|
||||
"INSERT INTO transfer_records (transfer_time, task_name, original_name, renamed_to, file_size, "
|
||||
"duration, resolution, modify_date, file_id, file_type, save_path) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(int(time.time()), task_name, original_name, renamed_to, file_size,
|
||||
(now_ms, task_name, original_name, renamed_to, file_size,
|
||||
duration, resolution, modify_date, file_id, file_type, save_path)
|
||||
)
|
||||
self.conn.commit()
|
||||
@ -123,7 +124,7 @@ class RecordDB:
|
||||
return 0
|
||||
|
||||
def get_records(self, page=1, page_size=20, sort_by="transfer_time", order="desc",
|
||||
task_name_filter="", keyword_filter=""):
|
||||
task_name_filter="", keyword_filter="", exclude_task_names=None):
|
||||
"""获取转存记录列表,支持分页、排序和筛选
|
||||
|
||||
Args:
|
||||
@ -133,6 +134,7 @@ class RecordDB:
|
||||
order: 排序方向(asc/desc)
|
||||
task_name_filter: 任务名称筛选条件(精确匹配)
|
||||
keyword_filter: 关键字筛选条件(模糊匹配任务名)
|
||||
exclude_task_names: 需要排除的任务名称列表
|
||||
"""
|
||||
cursor = self.conn.cursor()
|
||||
offset = (page - 1) * page_size
|
||||
@ -159,6 +161,10 @@ class RecordDB:
|
||||
params.append(f"%{keyword_filter}%")
|
||||
params.append(f"%{keyword_filter}%")
|
||||
|
||||
if exclude_task_names:
|
||||
where_clauses.append("task_name NOT IN ({})".format(",".join(["?" for _ in exclude_task_names])))
|
||||
params.extend(exclude_task_names)
|
||||
|
||||
where_clause = " AND ".join(where_clauses)
|
||||
where_sql = f"WHERE {where_clause}" if where_clause else ""
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
155
app/static/js/sort_file_by_name.js
Normal file
155
app/static/js/sort_file_by_name.js
Normal file
@ -0,0 +1,155 @@
|
||||
// 与后端 quark_auto_save.py 的 sort_file_by_name 完全一致的排序逻辑
|
||||
// 用于前端文件列表排序
|
||||
|
||||
function chineseToArabic(chinese) {
|
||||
// 简单实现,支持一到一万
|
||||
const cnNums = {
|
||||
'零': 0, '一': 1, '二': 2, '两': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9,
|
||||
'十': 10, '百': 100, '千': 1000, '万': 10000
|
||||
};
|
||||
let result = 0, unit = 1, num = 0;
|
||||
for (let i = chinese.length - 1; i >= 0; i--) {
|
||||
const char = chinese[i];
|
||||
if (cnNums[char] >= 10) {
|
||||
unit = cnNums[char];
|
||||
if (unit === 10 && (i === 0 || cnNums[chinese[i - 1]] === undefined)) {
|
||||
num = 1;
|
||||
}
|
||||
} else if (cnNums[char] !== undefined) {
|
||||
num = cnNums[char];
|
||||
result += num * unit;
|
||||
}
|
||||
}
|
||||
return result || null;
|
||||
}
|
||||
|
||||
function sortFileByName(file) {
|
||||
// 兼容 dict 或字符串
|
||||
let filename = typeof file === 'object' ? (file.file_name || '') : file;
|
||||
let update_time = typeof file === 'object' ? (file.updated_at || 0) : 0;
|
||||
let file_name_without_ext = filename.replace(/\.[^/.]+$/, '');
|
||||
let date_value = Infinity, episode_value = Infinity, segment_value = 0;
|
||||
|
||||
// 1. 日期提取
|
||||
let match;
|
||||
// YYYY-MM-DD
|
||||
match = filename.match(/((?:19|20)\d{2})[-./\s](\d{1,2})[-./\s](\d{1,2})/);
|
||||
if (match) {
|
||||
date_value = parseInt(match[1]) * 10000 + parseInt(match[2]) * 100 + parseInt(match[3]);
|
||||
}
|
||||
// YY-MM-DD
|
||||
if (date_value === Infinity) {
|
||||
match = filename.match(/((?:19|20)?\d{2})[-./\s](\d{1,2})[-./\s](\d{1,2})/);
|
||||
if (match && match[1].length === 2) {
|
||||
let year = parseInt('20' + match[1]);
|
||||
date_value = year * 10000 + parseInt(match[2]) * 100 + parseInt(match[3]);
|
||||
}
|
||||
}
|
||||
// YYYYMMDD
|
||||
if (date_value === Infinity) {
|
||||
match = filename.match(/((?:19|20)\d{2})(\d{2})(\d{2})/);
|
||||
if (match) {
|
||||
date_value = parseInt(match[1]) * 10000 + parseInt(match[2]) * 100 + parseInt(match[3]);
|
||||
}
|
||||
}
|
||||
// YYMMDD
|
||||
if (date_value === Infinity) {
|
||||
match = filename.match(/(?<!\d)(\d{2})(\d{2})(\d{2})(?!\d)/);
|
||||
if (match) {
|
||||
let month = parseInt(match[2]), day = parseInt(match[3]);
|
||||
if (1 <= month && month <= 12 && 1 <= day && day <= 31) {
|
||||
let year = parseInt('20' + match[1]);
|
||||
date_value = year * 10000 + month * 100 + day;
|
||||
}
|
||||
}
|
||||
}
|
||||
// MM/DD/YYYY
|
||||
if (date_value === Infinity) {
|
||||
match = filename.match(/(\d{1,2})[-./\s](\d{1,2})[-./\s]((?:19|20)\d{2})/);
|
||||
if (match) {
|
||||
let month = parseInt(match[1]), day = parseInt(match[2]), year = parseInt(match[3]);
|
||||
if (month > 12) [month, day] = [day, month];
|
||||
date_value = year * 10000 + month * 100 + day;
|
||||
}
|
||||
}
|
||||
// MM-DD
|
||||
if (date_value === Infinity) {
|
||||
match = filename.match(/(?<!\d)(\d{1,2})[-./\s](\d{1,2})(?!\d)/);
|
||||
if (match) {
|
||||
let month = parseInt(match[1]), day = parseInt(match[2]);
|
||||
if (month > 12) [month, day] = [day, month];
|
||||
date_value = 20000000 + month * 100 + day;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 期数/集数
|
||||
// 第X期/集/话
|
||||
match = filename.match(/第(\d+)[期集话]/);
|
||||
if (match) episode_value = parseInt(match[1]);
|
||||
// 第[中文数字]期/集/话
|
||||
if (episode_value === Infinity) {
|
||||
match = filename.match(/第([一二三四五六七八九十百千万零两]+)[期集话]/);
|
||||
if (match) {
|
||||
let arabic = chineseToArabic(match[1]);
|
||||
if (arabic !== null) episode_value = arabic;
|
||||
}
|
||||
}
|
||||
// X集/期/话
|
||||
if (episode_value === Infinity) {
|
||||
match = filename.match(/(\d+)[期集话]/);
|
||||
if (match) episode_value = parseInt(match[1]);
|
||||
}
|
||||
// [中文数字]集/期/话
|
||||
if (episode_value === Infinity) {
|
||||
match = filename.match(/([一二三四五六七八九十百千万零两]+)[期集话]/);
|
||||
if (match) {
|
||||
let arabic = chineseToArabic(match[1]);
|
||||
if (arabic !== null) episode_value = arabic;
|
||||
}
|
||||
}
|
||||
// S01E01
|
||||
if (episode_value === Infinity) {
|
||||
match = filename.match(/[Ss](\d+)[Ee](\d+)/);
|
||||
if (match) episode_value = parseInt(match[2]);
|
||||
}
|
||||
// E01/EP01
|
||||
if (episode_value === Infinity) {
|
||||
match = filename.match(/[Ee][Pp]?(\d+)/);
|
||||
if (match) episode_value = parseInt(match[1]);
|
||||
}
|
||||
// 1x01
|
||||
if (episode_value === Infinity) {
|
||||
match = filename.match(/(\d+)[Xx](\d+)/);
|
||||
if (match) episode_value = parseInt(match[2]);
|
||||
}
|
||||
// [数字]或【数字】
|
||||
if (episode_value === Infinity) {
|
||||
match = filename.match(/\[(\d+)\]|【(\d+)】/);
|
||||
if (match) episode_value = parseInt(match[1] || match[2]);
|
||||
}
|
||||
// 纯数字文件名
|
||||
if (episode_value === Infinity) {
|
||||
if (/^\d+$/.test(file_name_without_ext)) {
|
||||
episode_value = parseInt(file_name_without_ext);
|
||||
} else {
|
||||
match = filename.match(/(\d+)/);
|
||||
if (match) episode_value = parseInt(match[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 上中下
|
||||
if (/[上][集期话部篇]?|[集期话部篇]上/.test(filename)) segment_value = 1;
|
||||
else if (/[中][集期话部篇]?|[集期话部篇]中/.test(filename)) segment_value = 2;
|
||||
else if (/[下][集期话部篇]?|[集期话部篇]下/.test(filename)) segment_value = 3;
|
||||
|
||||
return [date_value, episode_value, segment_value, update_time];
|
||||
}
|
||||
|
||||
// 用法:
|
||||
// arr.sort((a, b) => {
|
||||
// const ka = sortFileByName(a), kb = sortFileByName(b);
|
||||
// for (let i = 0; i < ka.length; ++i) {
|
||||
// if (ka[i] !== kb[i]) return ka[i] > kb[i] ? 1 : -1;
|
||||
// }
|
||||
// return 0;
|
||||
// });
|
||||
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,9 @@ class Alist:
|
||||
# 缓存参数
|
||||
storage_mount_path = None
|
||||
quark_root_dir = None
|
||||
# 多账号支持
|
||||
storage_mount_paths = []
|
||||
quark_root_dirs = []
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""初始化AList插件"""
|
||||
@ -28,8 +31,17 @@ class Alist:
|
||||
if key in kwargs:
|
||||
setattr(self, key, kwargs[key])
|
||||
else:
|
||||
print(f"{self.plugin_name} 模块缺少必要参数: {key}")
|
||||
|
||||
pass # 不显示缺少参数的提示
|
||||
|
||||
# 处理多账号配置:支持数组形式的storage_id
|
||||
if isinstance(self.storage_id, list):
|
||||
self.storage_ids = self.storage_id
|
||||
# 为了向后兼容,使用第一个ID作为默认值
|
||||
self.storage_id = self.storage_ids[0] if self.storage_ids else ""
|
||||
else:
|
||||
# 单一配置转换为数组格式
|
||||
self.storage_ids = [self.storage_id] if self.storage_id else []
|
||||
|
||||
# 检查基本配置
|
||||
if not self.url or not self.token or not self.storage_id:
|
||||
return
|
||||
@ -43,27 +55,56 @@ class Alist:
|
||||
|
||||
# 验证AList连接
|
||||
if self.get_info():
|
||||
# 解析存储ID
|
||||
success, result = self.storage_id_to_path(self.storage_id)
|
||||
if success:
|
||||
self.storage_mount_path, self.quark_root_dir = result
|
||||
|
||||
# 确保路径格式正确
|
||||
if self.quark_root_dir != "/":
|
||||
if not self.quark_root_dir.startswith("/"):
|
||||
self.quark_root_dir = f"/{self.quark_root_dir}"
|
||||
self.quark_root_dir = self.quark_root_dir.rstrip("/")
|
||||
|
||||
if not self.storage_mount_path.startswith("/"):
|
||||
self.storage_mount_path = f"/{self.storage_mount_path}"
|
||||
self.storage_mount_path = self.storage_mount_path.rstrip("/")
|
||||
|
||||
# 解析所有存储ID
|
||||
for i, storage_id in enumerate(self.storage_ids):
|
||||
success, result = self.storage_id_to_path(storage_id)
|
||||
if success:
|
||||
mount_path, root_dir = result
|
||||
|
||||
# 确保路径格式正确
|
||||
if root_dir != "/":
|
||||
if not root_dir.startswith("/"):
|
||||
root_dir = f"/{root_dir}"
|
||||
root_dir = root_dir.rstrip("/")
|
||||
|
||||
if not mount_path.startswith("/"):
|
||||
mount_path = f"/{mount_path}"
|
||||
mount_path = mount_path.rstrip("/")
|
||||
|
||||
self.storage_mount_paths.append(mount_path)
|
||||
self.quark_root_dirs.append(root_dir)
|
||||
|
||||
if i == 0:
|
||||
# 设置默认值(向后兼容)
|
||||
self.storage_mount_path = mount_path
|
||||
self.quark_root_dir = root_dir
|
||||
|
||||
|
||||
else:
|
||||
print(f"AList 刷新: 存储ID [{i}] {storage_id} 解析失败")
|
||||
# 添加空值保持索引对应
|
||||
self.storage_mount_paths.append("")
|
||||
self.quark_root_dirs.append("")
|
||||
|
||||
# 只要有一个存储ID解析成功就激活插件
|
||||
if any(self.storage_mount_paths):
|
||||
self.is_active = True
|
||||
else:
|
||||
print(f"AList 刷新: 存储信息解析失败")
|
||||
print(f"AList 刷新: 所有存储ID解析失败")
|
||||
else:
|
||||
print(f"AList 刷新: 服务器连接失败")
|
||||
|
||||
def get_storage_config(self, account_index=0):
|
||||
"""根据账号索引获取对应的存储配置"""
|
||||
if account_index < len(self.storage_mount_paths) and account_index < len(self.quark_root_dirs):
|
||||
return self.storage_mount_paths[account_index], self.quark_root_dirs[account_index]
|
||||
else:
|
||||
# 如果索引超出范围,使用第一个配置作为默认值
|
||||
if self.storage_mount_paths and self.quark_root_dirs:
|
||||
return self.storage_mount_paths[0], self.quark_root_dirs[0]
|
||||
else:
|
||||
return "", ""
|
||||
|
||||
def run(self, task, **kwargs):
|
||||
"""
|
||||
插件主入口,当有新文件保存时触发刷新AList目录
|
||||
|
||||
@ -46,12 +46,10 @@ class Alist_strm_gen:
|
||||
missing_configs.append(key)
|
||||
|
||||
if missing_configs:
|
||||
print(f"{self.plugin_name} 模块缺少必要参数: {', '.join(missing_configs)}")
|
||||
return
|
||||
|
||||
return # 不显示缺少参数的提示
|
||||
|
||||
if not self.url or not self.token or not self.storage_id:
|
||||
print(f"{self.plugin_name} 模块配置不完整,请检查配置")
|
||||
return
|
||||
return # 不显示配置不完整的提示
|
||||
|
||||
# 检查 strm_save_dir 是否存在
|
||||
if not os.path.exists(self.strm_save_dir):
|
||||
|
||||
@ -18,11 +18,29 @@ class Plex:
|
||||
if key in kwargs:
|
||||
setattr(self, key, kwargs[key])
|
||||
else:
|
||||
print(f"{self.__class__.__name__} 模块缺少必要参数: {key}")
|
||||
pass # 不显示缺少参数的提示
|
||||
|
||||
# 处理多账号配置:支持数组形式的quark_root_path
|
||||
if isinstance(self.quark_root_path, list):
|
||||
self.quark_root_paths = self.quark_root_path
|
||||
# 为了向后兼容,使用第一个路径作为默认值
|
||||
self.quark_root_path = self.quark_root_paths[0] if self.quark_root_paths else ""
|
||||
else:
|
||||
# 单一配置转换为数组格式
|
||||
self.quark_root_paths = [self.quark_root_path] if self.quark_root_path else []
|
||||
|
||||
if self.url and self.token and self.quark_root_path:
|
||||
if self.get_info():
|
||||
self.is_active = True
|
||||
|
||||
def get_quark_root_path(self, account_index=0):
|
||||
"""根据账号索引获取对应的quark_root_path"""
|
||||
if account_index < len(self.quark_root_paths):
|
||||
return self.quark_root_paths[account_index]
|
||||
else:
|
||||
# 如果索引超出范围,使用第一个路径作为默认值
|
||||
return self.quark_root_paths[0] if self.quark_root_paths else ""
|
||||
|
||||
def run(self, task, **kwargs):
|
||||
if task.get("savepath"):
|
||||
# 检查是否已缓存库信息
|
||||
@ -59,10 +77,8 @@ class Plex:
|
||||
try:
|
||||
for library in self._libraries:
|
||||
for location in library.get("Location", []):
|
||||
if (
|
||||
os.path.commonpath([folder_path, location["path"]])
|
||||
== location["path"]
|
||||
):
|
||||
location_path = location.get("path", "")
|
||||
if folder_path.startswith(location_path):
|
||||
refresh_url = f"{self.url}/library/sections/{library['key']}/refresh?path={folder_path}"
|
||||
refresh_response = requests.get(refresh_url, headers=headers)
|
||||
if refresh_response.status_code == 200:
|
||||
|
||||
@ -229,6 +229,9 @@ def extract_episode_number(filename, episode_patterns=None, config_data=None):
|
||||
Returns:
|
||||
int: 提取到的剧集号,如果无法提取则返回None
|
||||
"""
|
||||
# 首先去除文件扩展名
|
||||
file_name_without_ext = os.path.splitext(filename)[0]
|
||||
|
||||
# 预处理:排除文件名中可能是日期的部分,避免误识别
|
||||
date_patterns = [
|
||||
# YYYY-MM-DD 或 YYYY.MM.DD 或 YYYY/MM/DD 或 YYYY MM DD格式(四位年份)
|
||||
@ -245,10 +248,10 @@ def extract_episode_number(filename, episode_patterns=None, config_data=None):
|
||||
r'(?<!\d)(\d{1,2})[-./\s](\d{1,2})(?!\d)',
|
||||
]
|
||||
|
||||
# 从文件名中移除日期部分,创建一个不含日期的文件名副本用于提取剧集号
|
||||
filename_without_dates = filename
|
||||
# 从不含扩展名的文件名中移除日期部分
|
||||
filename_without_dates = file_name_without_ext
|
||||
for pattern in date_patterns:
|
||||
matches = re.finditer(pattern, filename)
|
||||
matches = re.finditer(pattern, filename_without_dates)
|
||||
for match in matches:
|
||||
# 检查匹配的内容是否确实是日期
|
||||
date_str = match.group(0)
|
||||
@ -369,13 +372,9 @@ def extract_episode_number(filename, episode_patterns=None, config_data=None):
|
||||
except:
|
||||
continue
|
||||
|
||||
# 如果从不含日期的文件名中没有找到剧集号,尝试从原始文件名中提取
|
||||
# 这是为了兼容某些特殊情况,但要检查提取的数字不是日期
|
||||
file_name_without_ext = os.path.splitext(filename)[0]
|
||||
|
||||
# 如果文件名是纯数字,且不是日期格式,则可能是剧集号
|
||||
if file_name_without_ext.isdigit() and not is_date_format(file_name_without_ext):
|
||||
return int(file_name_without_ext)
|
||||
if filename_without_dates.isdigit() and not is_date_format(filename_without_dates):
|
||||
return int(filename_without_dates)
|
||||
|
||||
# 最后尝试提取任何数字,但要排除日期可能性
|
||||
num_match = re.search(r'(\d+)', filename_without_dates)
|
||||
@ -933,6 +932,9 @@ class Quark:
|
||||
def ls_dir(self, pdir_fid, **kwargs):
|
||||
file_list = []
|
||||
page = 1
|
||||
# 优化:增加每页大小,减少API调用次数
|
||||
page_size = kwargs.get("page_size", 200) # 从50增加到200
|
||||
|
||||
while True:
|
||||
url = f"{self.BASE_URL}/1/clouddrive/file/sort"
|
||||
querystring = {
|
||||
@ -941,7 +943,7 @@ class Quark:
|
||||
"uc_param_str": "",
|
||||
"pdir_fid": pdir_fid,
|
||||
"_page": page,
|
||||
"_size": "50",
|
||||
"_size": str(page_size),
|
||||
"_fetch_total": "1",
|
||||
"_fetch_sub_dirs": "0",
|
||||
"_sort": "file_type:asc,updated_at:desc",
|
||||
@ -959,6 +961,48 @@ class Quark:
|
||||
break
|
||||
return file_list
|
||||
|
||||
def get_paths(self, folder_id):
|
||||
"""
|
||||
获取指定文件夹ID的完整路径信息
|
||||
|
||||
Args:
|
||||
folder_id: 文件夹ID
|
||||
|
||||
Returns:
|
||||
list: 路径信息列表,每个元素包含fid和name
|
||||
"""
|
||||
if folder_id == "0" or folder_id == 0:
|
||||
return []
|
||||
|
||||
url = f"{self.BASE_URL}/1/clouddrive/file/sort"
|
||||
querystring = {
|
||||
"pr": "ucpro",
|
||||
"fr": "pc",
|
||||
"uc_param_str": "",
|
||||
"pdir_fid": folder_id,
|
||||
"_page": 1,
|
||||
"_size": "50",
|
||||
"_fetch_total": "1",
|
||||
"_fetch_sub_dirs": "0",
|
||||
"_sort": "file_type:asc,updated_at:desc",
|
||||
"_fetch_full_path": 1,
|
||||
}
|
||||
|
||||
try:
|
||||
response = self._send_request("GET", url, params=querystring).json()
|
||||
if response["code"] == 0 and "full_path" in response["data"]:
|
||||
paths = []
|
||||
for item in response["data"]["full_path"]:
|
||||
paths.append({
|
||||
"fid": item["fid"],
|
||||
"name": item["file_name"]
|
||||
})
|
||||
return paths
|
||||
except Exception as e:
|
||||
print(f"获取文件夹路径出错: {str(e)}")
|
||||
|
||||
return []
|
||||
|
||||
def save_file(self, fid_list, fid_token_list, to_pdir_fid, pwd_id, stoken):
|
||||
url = f"{self.BASE_URL}/1/clouddrive/share/sharepage/save"
|
||||
querystring = {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user