mirror of
https://github.com/Cp0204/quark-auto-save.git
synced 2026-01-12 23:30:44 +08:00
增加拼音排序支持,修复文件夹无法进行大小排序的问题
This commit is contained in:
parent
28d68f1f71
commit
8933311072
14
app/run.py
14
app/run.py
@ -40,6 +40,14 @@ from quark_auto_save import Config, format_bytes
|
|||||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
from quark_auto_save import extract_episode_number, sort_file_by_name, chinese_to_arabic, is_date_format
|
from quark_auto_save import extract_episode_number, sort_file_by_name, chinese_to_arabic, is_date_format
|
||||||
|
|
||||||
|
# 导入拼音排序工具
|
||||||
|
try:
|
||||||
|
from utils.pinyin_sort import get_filename_pinyin_sort_key
|
||||||
|
except ImportError:
|
||||||
|
# 如果导入失败,使用简单的小写排序作为备用
|
||||||
|
def get_filename_pinyin_sort_key(filename):
|
||||||
|
return filename.lower()
|
||||||
|
|
||||||
# 导入数据库模块
|
# 导入数据库模块
|
||||||
try:
|
try:
|
||||||
# 先尝试相对导入
|
# 先尝试相对导入
|
||||||
@ -1581,9 +1589,11 @@ def get_file_list():
|
|||||||
# 优化排序:使用更高效的排序方法
|
# 优化排序:使用更高效的排序方法
|
||||||
def get_sort_key(file_item):
|
def get_sort_key(file_item):
|
||||||
if sort_by == "file_name":
|
if sort_by == "file_name":
|
||||||
return file_item["file_name"].lower()
|
# 使用拼音排序
|
||||||
|
return get_filename_pinyin_sort_key(file_item["file_name"])
|
||||||
elif sort_by == "file_size":
|
elif sort_by == "file_size":
|
||||||
return file_item["size"] if not file_item["dir"] else 0
|
# 文件夹按项目数量排序,文件按大小排序
|
||||||
|
return file_item.get("include_items", 0) if file_item["dir"] else file_item["size"]
|
||||||
else: # updated_at
|
else: # updated_at
|
||||||
return file_item["updated_at"]
|
return file_item["updated_at"]
|
||||||
|
|
||||||
|
|||||||
@ -174,9 +174,34 @@ class RecordDB:
|
|||||||
total_records = cursor.fetchone()[0]
|
total_records = cursor.fetchone()[0]
|
||||||
|
|
||||||
# 获取分页数据
|
# 获取分页数据
|
||||||
query_sql = f"SELECT * FROM transfer_records {where_sql} ORDER BY {sort_by} {order_direction} LIMIT ? OFFSET ?"
|
if sort_by in ["task_name", "original_name", "renamed_to"]:
|
||||||
cursor.execute(query_sql, params + [page_size, offset])
|
# 对于需要拼音排序的字段,先获取所有数据然后在Python中进行拼音排序
|
||||||
records = cursor.fetchall()
|
query_sql = f"SELECT * FROM transfer_records {where_sql}"
|
||||||
|
cursor.execute(query_sql, params)
|
||||||
|
all_records = cursor.fetchall()
|
||||||
|
|
||||||
|
# 使用拼音排序
|
||||||
|
from utils.pinyin_sort import get_filename_pinyin_sort_key
|
||||||
|
|
||||||
|
# 根据排序字段选择对应的索引
|
||||||
|
field_index_map = {
|
||||||
|
"task_name": 2, # task_name字段索引
|
||||||
|
"original_name": 3, # original_name字段索引
|
||||||
|
"renamed_to": 4 # renamed_to字段索引
|
||||||
|
}
|
||||||
|
field_index = field_index_map[sort_by]
|
||||||
|
|
||||||
|
sorted_records = sorted(all_records, key=lambda x: get_filename_pinyin_sort_key(x[field_index]), reverse=(order_direction == "DESC"))
|
||||||
|
|
||||||
|
# 手动分页
|
||||||
|
start_idx = offset
|
||||||
|
end_idx = offset + page_size
|
||||||
|
records = sorted_records[start_idx:end_idx]
|
||||||
|
else:
|
||||||
|
# 其他字段使用SQL排序
|
||||||
|
query_sql = f"SELECT * FROM transfer_records {where_sql} ORDER BY {sort_by} {order_direction} LIMIT ? OFFSET ?"
|
||||||
|
cursor.execute(query_sql, params + [page_size, offset])
|
||||||
|
records = cursor.fetchall()
|
||||||
|
|
||||||
# 将结果转换为字典列表
|
# 将结果转换为字典列表
|
||||||
columns = [col[0] for col in cursor.description]
|
columns = [col[0] for col in cursor.description]
|
||||||
|
|||||||
1
app/static/js/pinyin-pro.min.js
vendored
Executable file
1
app/static/js/pinyin-pro.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
@ -17,6 +17,7 @@
|
|||||||
<script src="./static/js/axios.min.js"></script>
|
<script src="./static/js/axios.min.js"></script>
|
||||||
<script src="./static/js/v-jsoneditor.min.js"></script>
|
<script src="./static/js/v-jsoneditor.min.js"></script>
|
||||||
<script src="./static/js/sort_file_by_name.js"></script>
|
<script src="./static/js/sort_file_by_name.js"></script>
|
||||||
|
<script src="./static/js/pinyin-pro.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// 添加检测文本溢出的自定义指令
|
// 添加检测文本溢出的自定义指令
|
||||||
Vue.directive('check-overflow', {
|
Vue.directive('check-overflow', {
|
||||||
@ -1700,7 +1701,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return [...taskNames].sort();
|
return this.sortTaskNamesByPinyin([...taskNames]);
|
||||||
},
|
},
|
||||||
taskNames() {
|
taskNames() {
|
||||||
// 从任务列表中提取唯一的任务名称
|
// 从任务列表中提取唯一的任务名称
|
||||||
@ -1715,7 +1716,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return [...taskNames].sort();
|
return this.sortTaskNamesByPinyin([...taskNames]);
|
||||||
},
|
},
|
||||||
totalPages() {
|
totalPages() {
|
||||||
// 直接使用后端返回的total_pages
|
// 直接使用后端返回的total_pages
|
||||||
@ -1953,6 +1954,14 @@
|
|||||||
document.removeEventListener('click', this.handleOutsideClick);
|
document.removeEventListener('click', this.handleOutsideClick);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 拼音排序辅助函数
|
||||||
|
sortTaskNamesByPinyin(taskNames) {
|
||||||
|
return taskNames.sort((a, b) => {
|
||||||
|
const aKey = pinyinPro.pinyin(a, { toneType: 'none', type: 'string' }).toLowerCase();
|
||||||
|
const bKey = pinyinPro.pinyin(b, { toneType: 'none', type: 'string' }).toLowerCase();
|
||||||
|
return aKey > bKey ? 1 : -1;
|
||||||
|
});
|
||||||
|
},
|
||||||
// 添加格式化分享链接警告信息的方法
|
// 添加格式化分享链接警告信息的方法
|
||||||
formatShareUrlBanMessage(message) {
|
formatShareUrlBanMessage(message) {
|
||||||
if (!message) return message;
|
if (!message) return message;
|
||||||
@ -3705,7 +3714,7 @@
|
|||||||
}
|
}
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
if (response.data.success && response.data.data.all_task_names) {
|
if (response.data.success && response.data.data.all_task_names) {
|
||||||
this.allTaskNames = response.data.data.all_task_names.sort();
|
this.allTaskNames = this.sortTaskNamesByPinyin(response.data.data.all_task_names);
|
||||||
} else {
|
} else {
|
||||||
// 如果API失败,回退到从当前页记录中提取任务名称
|
// 如果API失败,回退到从当前页记录中提取任务名称
|
||||||
if (this.history.records && this.history.records.length > 0) {
|
if (this.history.records && this.history.records.length > 0) {
|
||||||
@ -3715,7 +3724,7 @@
|
|||||||
taskNames.add(record.task_name);
|
taskNames.add(record.task_name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.allTaskNames = [...taskNames].sort();
|
this.allTaskNames = this.sortTaskNamesByPinyin([...taskNames]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@ -3727,7 +3736,7 @@
|
|||||||
taskNames.add(record.task_name);
|
taskNames.add(record.task_name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.allTaskNames = [...taskNames].sort();
|
this.allTaskNames = this.sortTaskNamesByPinyin([...taskNames]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -3859,8 +3868,9 @@
|
|||||||
// 文件夹始终在前
|
// 文件夹始终在前
|
||||||
if (a.dir && !b.dir) return -1;
|
if (a.dir && !b.dir) return -1;
|
||||||
if (!a.dir && b.dir) return 1;
|
if (!a.dir && b.dir) return 1;
|
||||||
let aValue = a.file_name.toLowerCase();
|
// 使用拼音排序
|
||||||
let bValue = b.file_name.toLowerCase();
|
let aValue = pinyinPro.pinyin(a.file_name, { toneType: 'none', type: 'string' }).toLowerCase();
|
||||||
|
let bValue = pinyinPro.pinyin(b.file_name, { toneType: 'none', type: 'string' }).toLowerCase();
|
||||||
if (this.fileSelect.sortOrder === 'asc') {
|
if (this.fileSelect.sortOrder === 'asc') {
|
||||||
return aValue > bValue ? 1 : -1;
|
return aValue > bValue ? 1 : -1;
|
||||||
} else {
|
} else {
|
||||||
@ -3887,9 +3897,9 @@
|
|||||||
aValue = a.episode_number;
|
aValue = a.episode_number;
|
||||||
bValue = b.episode_number;
|
bValue = b.episode_number;
|
||||||
} else {
|
} else {
|
||||||
// 否则使用重命名后的文件名进行字符串排序
|
// 否则使用重命名后的文件名进行拼音排序
|
||||||
aValue = (a.file_name_re || '').toLowerCase();
|
aValue = pinyinPro.pinyin(a.file_name_re || '', { toneType: 'none', type: 'string' }).toLowerCase();
|
||||||
bValue = (b.file_name_re || '').toLowerCase();
|
bValue = pinyinPro.pinyin(b.file_name_re || '', { toneType: 'none', type: 'string' }).toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.fileSelect.sortOrder === 'asc') {
|
if (this.fileSelect.sortOrder === 'asc') {
|
||||||
@ -3934,8 +3944,9 @@
|
|||||||
if (a.dir && !b.dir) return -1;
|
if (a.dir && !b.dir) return -1;
|
||||||
if (!a.dir && b.dir) return 1;
|
if (!a.dir && b.dir) return 1;
|
||||||
|
|
||||||
let aValue = a.dir ? 0 : (a.size || 0);
|
// 文件夹按项目数量排序,文件按大小排序
|
||||||
let bValue = b.dir ? 0 : (b.size || 0);
|
let aValue = a.dir ? (a.include_items || 0) : (a.size || 0);
|
||||||
|
let bValue = b.dir ? (b.include_items || 0) : (b.size || 0);
|
||||||
if (this.fileSelect.sortOrder === 'asc') {
|
if (this.fileSelect.sortOrder === 'asc') {
|
||||||
return aValue > bValue ? 1 : -1;
|
return aValue > bValue ? 1 : -1;
|
||||||
} else {
|
} else {
|
||||||
@ -3958,8 +3969,9 @@
|
|||||||
if (field === 'file_name') {
|
if (field === 'file_name') {
|
||||||
if (a.dir && !b.dir) return -1;
|
if (a.dir && !b.dir) return -1;
|
||||||
if (!a.dir && b.dir) return 1;
|
if (!a.dir && b.dir) return 1;
|
||||||
let aValue = a.file_name.toLowerCase();
|
// 使用拼音排序
|
||||||
let bValue = b.file_name.toLowerCase();
|
let aValue = pinyinPro.pinyin(a.file_name, { toneType: 'none', type: 'string' }).toLowerCase();
|
||||||
|
let bValue = pinyinPro.pinyin(b.file_name, { toneType: 'none', type: 'string' }).toLowerCase();
|
||||||
if (order === 'asc') {
|
if (order === 'asc') {
|
||||||
return aValue > bValue ? 1 : -1;
|
return aValue > bValue ? 1 : -1;
|
||||||
} else {
|
} else {
|
||||||
@ -3986,9 +3998,9 @@
|
|||||||
aValue = a.episode_number;
|
aValue = a.episode_number;
|
||||||
bValue = b.episode_number;
|
bValue = b.episode_number;
|
||||||
} else {
|
} else {
|
||||||
// 否则使用重命名后的文件名进行字符串排序
|
// 否则使用重命名后的文件名进行拼音排序
|
||||||
aValue = (a.file_name_re || '').toLowerCase();
|
aValue = pinyinPro.pinyin(a.file_name_re || '', { toneType: 'none', type: 'string' }).toLowerCase();
|
||||||
bValue = (b.file_name_re || '').toLowerCase();
|
bValue = pinyinPro.pinyin(b.file_name_re || '', { toneType: 'none', type: 'string' }).toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (order === 'asc') {
|
if (order === 'asc') {
|
||||||
@ -4033,8 +4045,9 @@
|
|||||||
if (a.dir && !b.dir) return -1;
|
if (a.dir && !b.dir) return -1;
|
||||||
if (!a.dir && b.dir) return 1;
|
if (!a.dir && b.dir) return 1;
|
||||||
|
|
||||||
let aValue = a.dir ? 0 : (a.size || 0);
|
// 文件夹按项目数量排序,文件按大小排序
|
||||||
let bValue = b.dir ? 0 : (b.size || 0);
|
let aValue = a.dir ? (a.include_items || 0) : (a.size || 0);
|
||||||
|
let bValue = b.dir ? (b.include_items || 0) : (b.size || 0);
|
||||||
if (order === 'asc') {
|
if (order === 'asc') {
|
||||||
return aValue > bValue ? 1 : -1;
|
return aValue > bValue ? 1 : -1;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
89
app/utils/pinyin_sort.py
Normal file
89
app/utils/pinyin_sort.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
拼音排序工具模块
|
||||||
|
用于将中文字符串转换为拼音后进行排序
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
from pypinyin import lazy_pinyin, Style
|
||||||
|
PYPINYIN_AVAILABLE = True
|
||||||
|
except ImportError:
|
||||||
|
PYPINYIN_AVAILABLE = False
|
||||||
|
print("Warning: pypinyin not available, falling back to simple string sort")
|
||||||
|
|
||||||
|
def to_pinyin_for_sort(text):
|
||||||
|
"""
|
||||||
|
将字符串转换为拼音用于排序
|
||||||
|
保留非中文字符,只转换中文字符为拼音
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): 要转换的字符串
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 转换后的拼音字符串,用于排序比较
|
||||||
|
"""
|
||||||
|
if not text:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
if PYPINYIN_AVAILABLE:
|
||||||
|
# 使用pypinyin库进行转换
|
||||||
|
# Style.NORMAL: 普通风格,不带声调
|
||||||
|
# errors='default': 保留无法转换的字符
|
||||||
|
pinyin_list = lazy_pinyin(text, style=Style.NORMAL, errors='default')
|
||||||
|
return ''.join(pinyin_list).lower()
|
||||||
|
else:
|
||||||
|
# 如果pypinyin不可用,直接返回小写字符串
|
||||||
|
return text.lower()
|
||||||
|
|
||||||
|
def pinyin_compare(a, b):
|
||||||
|
"""
|
||||||
|
拼音排序比较函数
|
||||||
|
|
||||||
|
Args:
|
||||||
|
a (str): 第一个字符串
|
||||||
|
b (str): 第二个字符串
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: 比较结果 (-1, 0, 1)
|
||||||
|
"""
|
||||||
|
pinyin_a = to_pinyin_for_sort(a)
|
||||||
|
pinyin_b = to_pinyin_for_sort(b)
|
||||||
|
|
||||||
|
if pinyin_a < pinyin_b:
|
||||||
|
return -1
|
||||||
|
elif pinyin_a > pinyin_b:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_filename_pinyin_sort_key(filename):
|
||||||
|
"""
|
||||||
|
为文件名生成拼音排序键
|
||||||
|
保持完整内容,只将汉字转换为拼音
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename (str): 文件名
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 用于排序的拼音字符串
|
||||||
|
"""
|
||||||
|
return to_pinyin_for_sort(filename)
|
||||||
|
|
||||||
|
def pinyin_sort_files(files, key_func=None, reverse=False):
|
||||||
|
"""
|
||||||
|
使用拼音排序对文件列表进行排序
|
||||||
|
|
||||||
|
Args:
|
||||||
|
files (list): 文件列表
|
||||||
|
key_func (callable): 从文件对象中提取文件名的函数,默认为None(假设files是字符串列表)
|
||||||
|
reverse (bool): 是否逆序排序
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: 排序后的文件列表
|
||||||
|
"""
|
||||||
|
if key_func is None:
|
||||||
|
# 假设files是字符串列表
|
||||||
|
return sorted(files, key=to_pinyin_for_sort, reverse=reverse)
|
||||||
|
else:
|
||||||
|
# 使用key_func提取文件名后进行拼音排序
|
||||||
|
return sorted(files, key=lambda x: to_pinyin_for_sort(key_func(x)), reverse=reverse)
|
||||||
@ -8,6 +8,7 @@ import time
|
|||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
try:
|
try:
|
||||||
from quark_auto_save import sort_file_by_name
|
from quark_auto_save import sort_file_by_name
|
||||||
|
from app.utils.pinyin_sort import get_filename_pinyin_sort_key
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# 如果无法导入,提供一个简单的排序函数作为替代
|
# 如果无法导入,提供一个简单的排序函数作为替代
|
||||||
def sort_file_by_name(file):
|
def sort_file_by_name(file):
|
||||||
@ -15,8 +16,21 @@ except ImportError:
|
|||||||
filename = file.get("file_name", "")
|
filename = file.get("file_name", "")
|
||||||
else:
|
else:
|
||||||
filename = file
|
filename = file
|
||||||
# 简单排序,主要通过文件名进行
|
# 简单排序,主要通过文件名进行(使用拼音排序)
|
||||||
return filename
|
try:
|
||||||
|
from pypinyin import lazy_pinyin, Style
|
||||||
|
pinyin_list = lazy_pinyin(filename, style=Style.NORMAL, errors='ignore')
|
||||||
|
return ''.join(pinyin_list).lower()
|
||||||
|
except ImportError:
|
||||||
|
return filename.lower()
|
||||||
|
|
||||||
|
def get_filename_pinyin_sort_key(filename):
|
||||||
|
try:
|
||||||
|
from pypinyin import lazy_pinyin, Style
|
||||||
|
pinyin_list = lazy_pinyin(filename, style=Style.NORMAL, errors='ignore')
|
||||||
|
return ''.join(pinyin_list).lower()
|
||||||
|
except ImportError:
|
||||||
|
return filename.lower()
|
||||||
|
|
||||||
|
|
||||||
class Aria2:
|
class Aria2:
|
||||||
|
|||||||
@ -2,3 +2,4 @@ flask
|
|||||||
apscheduler
|
apscheduler
|
||||||
requests
|
requests
|
||||||
treelib
|
treelib
|
||||||
|
pypinyin
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user