mirror of
https://github.com/JoeanAmier/XHS-Downloader.git
synced 2025-12-26 04:48:05 +08:00
feat: 支持按作者归档保存作品文件
BREAKING CHANGE: 新增配置文件参数:account_archive Closes #226 Closes #229
This commit is contained in:
parent
ea63059dbf
commit
c2fa98bb51
11
README.md
11
README.md
@ -214,6 +214,7 @@ async def example():
|
|||||||
"""通过代码设置参数,适合二次开发"""
|
"""通过代码设置参数,适合二次开发"""
|
||||||
# 示例链接
|
# 示例链接
|
||||||
demo_link = "https://www.xiaohongshu.com/explore/XXX?xsec_token=XXX"
|
demo_link = "https://www.xiaohongshu.com/explore/XXX?xsec_token=XXX"
|
||||||
|
|
||||||
# 实例对象
|
# 实例对象
|
||||||
work_path = "D:\\" # 作品数据/文件保存根路径,默认值:项目根路径
|
work_path = "D:\\" # 作品数据/文件保存根路径,默认值:项目根路径
|
||||||
folder_name = "Download" # 作品文件储存文件夹名称(自动创建),默认值:Download
|
folder_name = "Download" # 作品文件储存文件夹名称(自动创建),默认值:Download
|
||||||
@ -232,9 +233,12 @@ async def example():
|
|||||||
live_download = False # 图文动图文件下载开关
|
live_download = False # 图文动图文件下载开关
|
||||||
download_record = True # 是否记录下载成功的作品 ID
|
download_record = True # 是否记录下载成功的作品 ID
|
||||||
language = "zh_CN" # 设置程序提示语言
|
language = "zh_CN" # 设置程序提示语言
|
||||||
|
account_archive = True # 是否将每个作者的作品存至单独的文件夹
|
||||||
read_cookie = None # 读取浏览器 Cookie,支持设置浏览器名称(字符串)或者浏览器序号(整数),设置为 None 代表不读取
|
read_cookie = None # 读取浏览器 Cookie,支持设置浏览器名称(字符串)或者浏览器序号(整数),设置为 None 代表不读取
|
||||||
|
|
||||||
# async with XHS() as xhs:
|
# async with XHS() as xhs:
|
||||||
# pass # 使用默认参数
|
# pass # 使用默认参数
|
||||||
|
|
||||||
async with XHS(
|
async with XHS(
|
||||||
work_path=work_path,
|
work_path=work_path,
|
||||||
folder_name=folder_name,
|
folder_name=folder_name,
|
||||||
@ -254,6 +258,7 @@ async def example():
|
|||||||
download_record=download_record,
|
download_record=download_record,
|
||||||
language=language,
|
language=language,
|
||||||
read_cookie=read_cookie,
|
read_cookie=read_cookie,
|
||||||
|
account_archive=account_archive,
|
||||||
) as xhs: # 使用自定义参数
|
) as xhs: # 使用自定义参数
|
||||||
download = True # 是否下载作品文件,默认值:False
|
download = True # 是否下载作品文件,默认值:False
|
||||||
# 返回作品详细信息,包括下载地址
|
# 返回作品详细信息,包括下载地址
|
||||||
@ -376,6 +381,12 @@ async def example():
|
|||||||
<td align="center">true</td>
|
<td align="center">true</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td align="center">account_archive</td>
|
||||||
|
<td align="center">bool</td>
|
||||||
|
<td align="center">是否将每个作者的作品储存至单独的文件夹;文件夹名称为作者昵称或者作者 ID</td>
|
||||||
|
<td align="center">false</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td align="center">language</td>
|
<td align="center">language</td>
|
||||||
<td align="center">str</td>
|
<td align="center">str</td>
|
||||||
<td align="center">设置程序语言,目前支持:<code>zh_CN</code>、<code>en_US</code></td>
|
<td align="center">设置程序语言,目前支持:<code>zh_CN</code>、<code>en_US</code></td>
|
||||||
|
|||||||
11
README_EN.md
11
README_EN.md
@ -218,6 +218,7 @@ async def example():
|
|||||||
"""通过代码设置参数,适合二次开发"""
|
"""通过代码设置参数,适合二次开发"""
|
||||||
# 示例链接
|
# 示例链接
|
||||||
demo_link = "https://www.xiaohongshu.com/explore/XXX?xsec_token=XXX"
|
demo_link = "https://www.xiaohongshu.com/explore/XXX?xsec_token=XXX"
|
||||||
|
|
||||||
# 实例对象
|
# 实例对象
|
||||||
work_path = "D:\\" # 作品数据/文件保存根路径,默认值:项目根路径
|
work_path = "D:\\" # 作品数据/文件保存根路径,默认值:项目根路径
|
||||||
folder_name = "Download" # 作品文件储存文件夹名称(自动创建),默认值:Download
|
folder_name = "Download" # 作品文件储存文件夹名称(自动创建),默认值:Download
|
||||||
@ -236,9 +237,12 @@ async def example():
|
|||||||
live_download = False # 图文动图文件下载开关
|
live_download = False # 图文动图文件下载开关
|
||||||
download_record = True # 是否记录下载成功的作品 ID
|
download_record = True # 是否记录下载成功的作品 ID
|
||||||
language = "zh_CN" # 设置程序提示语言
|
language = "zh_CN" # 设置程序提示语言
|
||||||
|
account_archive = True # 是否将每个作者的作品存至单独的文件夹
|
||||||
read_cookie = None # 读取浏览器 Cookie,支持设置浏览器名称(字符串)或者浏览器序号(整数),设置为 None 代表不读取
|
read_cookie = None # 读取浏览器 Cookie,支持设置浏览器名称(字符串)或者浏览器序号(整数),设置为 None 代表不读取
|
||||||
|
|
||||||
# async with XHS() as xhs:
|
# async with XHS() as xhs:
|
||||||
# pass # 使用默认参数
|
# pass # 使用默认参数
|
||||||
|
|
||||||
async with XHS(
|
async with XHS(
|
||||||
work_path=work_path,
|
work_path=work_path,
|
||||||
folder_name=folder_name,
|
folder_name=folder_name,
|
||||||
@ -258,6 +262,7 @@ async def example():
|
|||||||
download_record=download_record,
|
download_record=download_record,
|
||||||
language=language,
|
language=language,
|
||||||
read_cookie=read_cookie,
|
read_cookie=read_cookie,
|
||||||
|
account_archive=account_archive,
|
||||||
) as xhs: # 使用自定义参数
|
) as xhs: # 使用自定义参数
|
||||||
download = True # 是否下载作品文件,默认值:False
|
download = True # 是否下载作品文件,默认值:False
|
||||||
# 返回作品详细信息,包括下载地址
|
# 返回作品详细信息,包括下载地址
|
||||||
@ -380,6 +385,12 @@ async def example():
|
|||||||
<td align="center">true</td>
|
<td align="center">true</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td align="center">account_archive</td>
|
||||||
|
<td align="center">bool</td>
|
||||||
|
<td align="center">Whether to save each author's works into a separate folder; the folder name will be the author's nickname or author ID</td>
|
||||||
|
<td align="center">false</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td align="center">language</td>
|
<td align="center">language</td>
|
||||||
<td align="center">str</td>
|
<td align="center">str</td>
|
||||||
<td align="center">Set program language. Currently supported: <code>zh_CN</code>, <code>en_US</code></td>
|
<td align="center">Set program language. Currently supported: <code>zh_CN</code>, <code>en_US</code></td>
|
||||||
|
|||||||
52
example.py
52
example.py
@ -28,30 +28,32 @@ async def example():
|
|||||||
live_download = False # 图文动图文件下载开关
|
live_download = False # 图文动图文件下载开关
|
||||||
download_record = True # 是否记录下载成功的作品 ID
|
download_record = True # 是否记录下载成功的作品 ID
|
||||||
language = "zh_CN" # 设置程序提示语言
|
language = "zh_CN" # 设置程序提示语言
|
||||||
|
account_archive = True # 是否将每个作者的作品存至单独的文件夹
|
||||||
read_cookie = None # 读取浏览器 Cookie,支持设置浏览器名称(字符串)或者浏览器序号(整数),设置为 None 代表不读取
|
read_cookie = None # 读取浏览器 Cookie,支持设置浏览器名称(字符串)或者浏览器序号(整数),设置为 None 代表不读取
|
||||||
|
|
||||||
# async with XHS() as xhs:
|
# async with XHS() as xhs:
|
||||||
# pass # 使用默认参数
|
# pass # 使用默认参数
|
||||||
|
|
||||||
async with XHS(
|
async with XHS(
|
||||||
work_path=work_path,
|
work_path=work_path,
|
||||||
folder_name=folder_name,
|
folder_name=folder_name,
|
||||||
name_format=name_format,
|
name_format=name_format,
|
||||||
user_agent=user_agent,
|
user_agent=user_agent,
|
||||||
cookie=cookie,
|
cookie=cookie,
|
||||||
proxy=proxy,
|
proxy=proxy,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
chunk=chunk,
|
chunk=chunk,
|
||||||
max_retry=max_retry,
|
max_retry=max_retry,
|
||||||
record_data=record_data,
|
record_data=record_data,
|
||||||
image_format=image_format,
|
image_format=image_format,
|
||||||
folder_mode=folder_mode,
|
folder_mode=folder_mode,
|
||||||
image_download=image_download,
|
image_download=image_download,
|
||||||
video_download=video_download,
|
video_download=video_download,
|
||||||
live_download=live_download,
|
live_download=live_download,
|
||||||
download_record=download_record,
|
download_record=download_record,
|
||||||
language=language,
|
language=language,
|
||||||
read_cookie=read_cookie,
|
read_cookie=read_cookie,
|
||||||
|
account_archive=account_archive,
|
||||||
) as xhs: # 使用自定义参数
|
) as xhs: # 使用自定义参数
|
||||||
download = True # 是否下载作品文件,默认值:False
|
download = True # 是否下载作品文件,默认值:False
|
||||||
# 返回作品详细信息,包括下载地址
|
# 返回作品详细信息,包括下载地址
|
||||||
@ -62,13 +64,13 @@ async def example():
|
|||||||
async def test():
|
async def test():
|
||||||
url = ""
|
url = ""
|
||||||
async with XHS(
|
async with XHS(
|
||||||
download_record=False,
|
download_record=False,
|
||||||
# image_format="PNG",
|
# image_format="PNG",
|
||||||
# image_format="WEBP",
|
# image_format="WEBP",
|
||||||
# image_format="JPEG",
|
# image_format="JPEG",
|
||||||
# image_format="HEIC",
|
# image_format="HEIC",
|
||||||
# image_format="AVIF",
|
# image_format="AVIF",
|
||||||
# image_format="AUTO",
|
# image_format="AUTO",
|
||||||
) as xhs:
|
) as xhs:
|
||||||
print(
|
print(
|
||||||
await xhs.extract(
|
await xhs.extract(
|
||||||
|
|||||||
@ -24,8 +24,8 @@ class Setting(Screen):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
data: dict,
|
data: dict,
|
||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.data = data
|
self.data = data
|
||||||
@ -129,7 +129,7 @@ class Setting(Screen):
|
|||||||
value=self.data["record_data"],
|
value=self.data["record_data"],
|
||||||
),
|
),
|
||||||
Checkbox(
|
Checkbox(
|
||||||
_("作品文件夹归档模式"),
|
_("作品归档保存模式"),
|
||||||
id="folder_mode",
|
id="folder_mode",
|
||||||
value=self.data["folder_mode"],
|
value=self.data["folder_mode"],
|
||||||
),
|
),
|
||||||
@ -157,6 +157,11 @@ class Setting(Screen):
|
|||||||
id="download_record",
|
id="download_record",
|
||||||
value=self.data["download_record"],
|
value=self.data["download_record"],
|
||||||
),
|
),
|
||||||
|
Checkbox(
|
||||||
|
_("作者归档保存模式"),
|
||||||
|
id="account_archive",
|
||||||
|
value=self.data["account_archive"],
|
||||||
|
),
|
||||||
classes="horizontal-layout",
|
classes="horizontal-layout",
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
@ -229,6 +234,7 @@ class Setting(Screen):
|
|||||||
"video_download": self.query_one("#video_download").value,
|
"video_download": self.query_one("#video_download").value,
|
||||||
"live_download": self.query_one("#live_download").value,
|
"live_download": self.query_one("#live_download").value,
|
||||||
"download_record": self.query_one("#download_record").value,
|
"download_record": self.query_one("#download_record").value,
|
||||||
|
"account_archive": self.query_one("#account_archive").value,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -100,6 +100,7 @@ class XHS:
|
|||||||
live_download=False,
|
live_download=False,
|
||||||
folder_mode=False,
|
folder_mode=False,
|
||||||
download_record=True,
|
download_record=True,
|
||||||
|
account_archive=False,
|
||||||
language="zh_CN",
|
language="zh_CN",
|
||||||
read_cookie: int | str = None,
|
read_cookie: int | str = None,
|
||||||
_print: bool = True,
|
_print: bool = True,
|
||||||
@ -125,6 +126,7 @@ class XHS:
|
|||||||
live_download,
|
live_download,
|
||||||
download_record,
|
download_record,
|
||||||
folder_mode,
|
folder_mode,
|
||||||
|
account_archive,
|
||||||
_print,
|
_print,
|
||||||
)
|
)
|
||||||
self.html = Html(self.manager)
|
self.html = Html(self.manager)
|
||||||
@ -170,6 +172,7 @@ class XHS:
|
|||||||
u,
|
u,
|
||||||
container["动图地址"],
|
container["动图地址"],
|
||||||
index,
|
index,
|
||||||
|
self.CLEANER.filter_name(container["作者昵称"]) or container["作者ID"],
|
||||||
name,
|
name,
|
||||||
container["作品类型"],
|
container["作品类型"],
|
||||||
log,
|
log,
|
||||||
|
|||||||
@ -63,23 +63,25 @@ class Download:
|
|||||||
self.image_download = manager.image_download
|
self.image_download = manager.image_download
|
||||||
self.video_download = manager.video_download
|
self.video_download = manager.video_download
|
||||||
self.live_download = manager.live_download
|
self.live_download = manager.live_download
|
||||||
|
self.account_archive = manager.account_archive
|
||||||
|
|
||||||
async def run(
|
async def run(
|
||||||
self,
|
self,
|
||||||
urls: list,
|
urls: list,
|
||||||
lives: list,
|
lives: list,
|
||||||
index: list | tuple | None,
|
index: list | tuple | None,
|
||||||
name: str,
|
nickname: str,
|
||||||
|
filename: str,
|
||||||
type_: str,
|
type_: str,
|
||||||
log,
|
log,
|
||||||
bar,
|
bar,
|
||||||
) -> tuple[Path, list[Any]]:
|
) -> tuple[Path, list[Any]]:
|
||||||
path = self.__generate_path(name)
|
path = self.__generate_path(nickname, filename)
|
||||||
if type_ == _("视频"):
|
if type_ == _("视频"):
|
||||||
tasks = self.__ready_download_video(
|
tasks = self.__ready_download_video(
|
||||||
urls,
|
urls,
|
||||||
path,
|
path,
|
||||||
name,
|
filename,
|
||||||
log,
|
log,
|
||||||
)
|
)
|
||||||
elif type_ == _("图文"):
|
elif type_ == _("图文"):
|
||||||
@ -88,7 +90,7 @@ class Download:
|
|||||||
lives,
|
lives,
|
||||||
index,
|
index,
|
||||||
path,
|
path,
|
||||||
name,
|
filename,
|
||||||
log,
|
log,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -107,8 +109,13 @@ class Download:
|
|||||||
tasks = await gather(*tasks)
|
tasks = await gather(*tasks)
|
||||||
return path, tasks
|
return path, tasks
|
||||||
|
|
||||||
def __generate_path(self, name: str):
|
def __generate_path(self, nickname:str, filename: str):
|
||||||
path = self.manager.archive(self.folder, name, self.folder_mode)
|
if self.account_archive:
|
||||||
|
folder = self.folder.joinpath(nickname)
|
||||||
|
folder.mkdir(exist_ok=True)
|
||||||
|
else:
|
||||||
|
folder = self.folder
|
||||||
|
path = self.manager.archive(folder, filename, self.folder_mode)
|
||||||
path.mkdir(exist_ok=True)
|
path.mkdir(exist_ok=True)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|||||||
@ -65,6 +65,7 @@ class Manager:
|
|||||||
live_download: bool,
|
live_download: bool,
|
||||||
download_record: bool,
|
download_record: bool,
|
||||||
folder_mode: bool,
|
folder_mode: bool,
|
||||||
|
account_archive:bool,
|
||||||
_print: bool,
|
_print: bool,
|
||||||
):
|
):
|
||||||
self.root = root
|
self.root = root
|
||||||
@ -115,6 +116,7 @@ class Manager:
|
|||||||
self.image_download = self.check_bool(image_download, True)
|
self.image_download = self.check_bool(image_download, True)
|
||||||
self.video_download = self.check_bool(video_download, True)
|
self.video_download = self.check_bool(video_download, True)
|
||||||
self.live_download = self.check_bool(live_download, True)
|
self.live_download = self.check_bool(live_download, True)
|
||||||
|
self.account_archive = self.check_bool(account_archive, False)
|
||||||
|
|
||||||
def __check_path(self, path: str) -> Path:
|
def __check_path(self, path: str) -> Path:
|
||||||
if not path:
|
if not path:
|
||||||
|
|||||||
@ -27,6 +27,7 @@ class Settings:
|
|||||||
"live_download": False,
|
"live_download": False,
|
||||||
"folder_mode": False,
|
"folder_mode": False,
|
||||||
"download_record": True,
|
"download_record": True,
|
||||||
|
"account_archive": False,
|
||||||
"language": "zh_CN",
|
"language": "zh_CN",
|
||||||
}
|
}
|
||||||
encode = "UTF-8-SIG" if system() == "Windows" else "UTF-8"
|
encode = "UTF-8-SIG" if system() == "Windows" else "UTF-8"
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
**项目更新内容:**
|
**项目更新内容:**
|
||||||
|
|
||||||
1. 增加对 `JPEG` 和 `HEIC` 图片格式的支持
|
1. 增加对 `JPEG` 和 `HEIC` 图片格式的支持
|
||||||
2. 优化 `headers` 处理逻辑
|
2. 支持按作者归档保存作品文件
|
||||||
3. 支持 `SOCKS` 代理
|
3. 优化 `headers` 处理逻辑
|
||||||
|
4. 支持 `SOCKS` 代理
|
||||||
|
|
||||||
|
**注意:**
|
||||||
|
|
||||||
|
<p><strong>配置文件新增参数 <code>account_archive</code>,旧版本更新需要手动添加配置内容:<code>"account_archive": false</code>;或者直接删除旧版配置文件后再运行程序!</strong></p>
|
||||||
|
|
||||||
*****
|
*****
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user