ASMRManager 2.2.1__tar.gz → 2.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/PKG-INFO +6 -5
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/README.md +5 -4
- asmrmanager-2.2.3/asmrmanager/_version.py +1 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/dl.py +17 -3
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/file.py +52 -16
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/common/fileconverter.py +6 -4
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/common/vtt2lrc.py +3 -3
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/config.py +2 -1
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/manager.py +25 -18
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/config.example.toml +20 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/pyproject.toml +1 -1
- asmrmanager-2.2.1/asmrmanager/_version.py +0 -1
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/LICENSE +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/__init__.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/__main__.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/core.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/hold.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/info.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/main.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/pl.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/play.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/query.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/review.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/sql.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/utils.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/view.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/cli/which.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/common/__init__.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/common/browse_params.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/common/download_params.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/common/output.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/common/parse_filter.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/common/rj_parse.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/common/select.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/common/types.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/database/__init__.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/database/database.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/database/engine.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/database/manage.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/database/orm_type.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/database/q_func.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/database/utils/__init__.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/database/utils/add2db.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/database/utils/uuid_sqlite.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/__init__.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/appdirs_.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/exceptions.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/file_zipper.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/sqls.example/circle_name.sql +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/sqls.example/score.sql +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/sqls.example/search.sql +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/sqls.example/tags.sql +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/sqls.example/test.sql +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/sqls.example/vas.sql +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/utils.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/logger/__init__.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/lrcplayer/__init__.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/lrcplayer/lrcparse.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/lrcplayer/main.css +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/lrcplayer/main.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/lrcplayer/player/base.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/lrcplayer/player/mpdplayer.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/lrcplayer/player/pygameplayer.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/spider/__init__.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/spider/asmrapi.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/spider/downloader.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/spider/interface.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/spider/playlist.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/spider/utils/IDMHelper.py +0 -0
- {asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/spider/utils/aria2_downloader.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ASMRManager
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.3
|
|
4
4
|
Summary: download, manage and play the voices on asmr.one
|
|
5
5
|
Keywords: asmr,downloader,music,player,manager,cli,tui,commandline,terminal
|
|
6
6
|
Author-Email: SLQY <sqiyel@gmail.com>
|
|
@@ -48,8 +48,9 @@ Description-Content-Type: text/markdown
|
|
|
48
48
|
|
|
49
49
|
### 下载
|
|
50
50
|
|
|
51
|
-
支持网站所支持的所有索引方式(关键词,标签,会社,价格,声优,日期,年龄分级等等)
|
|
51
|
+
支持网站所支持的所有索引方式(关键词,标签,会社,价格,声优,日期,年龄分级等等)以及排序方式。
|
|
52
52
|
目前仅支持调用 IDM 或 aria2 下载。
|
|
53
|
+
支持根据根据文件名对下载的文件进行过滤,以及对音频文件的格式转换。
|
|
53
54
|
|
|
54
55
|
```
|
|
55
56
|
> asmr dl search --help
|
|
@@ -124,8 +125,6 @@ Options:
|
|
|
124
125
|
|
|
125
126
|
## 使用方法
|
|
126
127
|
|
|
127
|
-
<!-- **注意**:由于网站最近更新了针对BJ和VJ的支持,本项目进行了很大的重构,2.0.0 版本暂并不保证稳定运行,如果没有对BJ和VJ的需求,可以考虑继续使用1代的最后一个版本`pip install ASMRManager[依赖]==1.9.1` -->
|
|
128
|
-
|
|
129
128
|
本工具支持 `python >= 3.10`, 安装方法如下:
|
|
130
129
|
|
|
131
130
|
```shell
|
|
@@ -158,9 +157,11 @@ pip install ASMRManager[依赖]
|
|
|
158
157
|
常用的命令有:
|
|
159
158
|
- `dl search` 搜索并下载。
|
|
160
159
|
- `info` 搜索某个 RJID 的具体信息
|
|
160
|
+
- `file check` 检查下载目录下的文件是否按照规则被正确下载
|
|
161
|
+
- `file store` 将下载文件转移到存储目录(STORAGE_PATH),并执行相应文件格式转换(详情见config.toml的before_store字段)
|
|
161
162
|
- `view` 将选择文件并移动到 VIEW_PATH
|
|
162
|
-
- `review` 为某个作品评分并评论(本地)
|
|
163
163
|
- `pl add` 将某个音声添加到用户的云端播放列表(配合 `pl create` 使用)
|
|
164
|
+
- `review` 为某个作品评分并评论(本地)
|
|
164
165
|
|
|
165
166
|
> 使用命令时,如果不输入 RJID ,将会自动使用上一次命令的RJID。
|
|
166
167
|
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
### 下载
|
|
8
8
|
|
|
9
|
-
支持网站所支持的所有索引方式(关键词,标签,会社,价格,声优,日期,年龄分级等等)
|
|
9
|
+
支持网站所支持的所有索引方式(关键词,标签,会社,价格,声优,日期,年龄分级等等)以及排序方式。
|
|
10
10
|
目前仅支持调用 IDM 或 aria2 下载。
|
|
11
|
+
支持根据根据文件名对下载的文件进行过滤,以及对音频文件的格式转换。
|
|
11
12
|
|
|
12
13
|
```
|
|
13
14
|
> asmr dl search --help
|
|
@@ -82,8 +83,6 @@ Options:
|
|
|
82
83
|
|
|
83
84
|
## 使用方法
|
|
84
85
|
|
|
85
|
-
<!-- **注意**:由于网站最近更新了针对BJ和VJ的支持,本项目进行了很大的重构,2.0.0 版本暂并不保证稳定运行,如果没有对BJ和VJ的需求,可以考虑继续使用1代的最后一个版本`pip install ASMRManager[依赖]==1.9.1` -->
|
|
86
|
-
|
|
87
86
|
本工具支持 `python >= 3.10`, 安装方法如下:
|
|
88
87
|
|
|
89
88
|
```shell
|
|
@@ -116,9 +115,11 @@ pip install ASMRManager[依赖]
|
|
|
116
115
|
常用的命令有:
|
|
117
116
|
- `dl search` 搜索并下载。
|
|
118
117
|
- `info` 搜索某个 RJID 的具体信息
|
|
118
|
+
- `file check` 检查下载目录下的文件是否按照规则被正确下载
|
|
119
|
+
- `file store` 将下载文件转移到存储目录(STORAGE_PATH),并执行相应文件格式转换(详情见config.toml的before_store字段)
|
|
119
120
|
- `view` 将选择文件并移动到 VIEW_PATH
|
|
120
|
-
- `review` 为某个作品评分并评论(本地)
|
|
121
121
|
- `pl add` 将某个音声添加到用户的云端播放列表(配合 `pl create` 使用)
|
|
122
|
+
- `review` 为某个作品评分并评论(本地)
|
|
122
123
|
|
|
123
124
|
> 使用命令时,如果不输入 RJID ,将会自动使用上一次命令的RJID。
|
|
124
125
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.2.3"
|
|
@@ -93,7 +93,11 @@ def check(source_ids: List[LocalSourceID]):
|
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
@click.command()
|
|
96
|
-
@click.argument(
|
|
96
|
+
@click.argument(
|
|
97
|
+
"keywords",
|
|
98
|
+
type=str,
|
|
99
|
+
nargs=-1,
|
|
100
|
+
)
|
|
97
101
|
@click.option(
|
|
98
102
|
"--tags", "-t", type=str, multiple=True, help="tags to include[multiple]"
|
|
99
103
|
)
|
|
@@ -163,7 +167,7 @@ def check(source_ids: List[LocalSourceID]):
|
|
|
163
167
|
@browse_param_options
|
|
164
168
|
@download_param_options
|
|
165
169
|
def search(
|
|
166
|
-
|
|
170
|
+
keywords: Tuple[str],
|
|
167
171
|
tags: Tuple[str],
|
|
168
172
|
vas: Tuple[str],
|
|
169
173
|
circle: str | None,
|
|
@@ -182,6 +186,10 @@ def search(
|
|
|
182
186
|
"""
|
|
183
187
|
search and download ASMR
|
|
184
188
|
|
|
189
|
+
The keywords argument is used to filter the title of an ASMR.
|
|
190
|
+
Specially, you can pass a keyword starts with `!`
|
|
191
|
+
to exclude this word, eg: `!中文版`
|
|
192
|
+
|
|
185
193
|
the [multiple] options means you can add multiple same option such as:
|
|
186
194
|
|
|
187
195
|
--tags tag1 --tags tag2 --no-tags tag3
|
|
@@ -198,7 +206,13 @@ def search(
|
|
|
198
206
|
)
|
|
199
207
|
spider.run(
|
|
200
208
|
spider.search(
|
|
201
|
-
|
|
209
|
+
" ".join(
|
|
210
|
+
map(
|
|
211
|
+
lambda t: (t := t.strip())
|
|
212
|
+
and ('-' + t[1:] if t.startswith("!") else t),
|
|
213
|
+
keywords,
|
|
214
|
+
)
|
|
215
|
+
),
|
|
202
216
|
tags=tags,
|
|
203
217
|
vas=vas,
|
|
204
218
|
circle=circle,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import List, Tuple
|
|
3
|
+
from typing import List, Tuple, Literal
|
|
4
4
|
|
|
5
5
|
import click
|
|
6
6
|
|
|
7
|
+
from asmrmanager.config import config
|
|
7
8
|
from asmrmanager.cli.core import (
|
|
8
9
|
create_database,
|
|
9
10
|
fm,
|
|
@@ -39,9 +40,9 @@ def del_(source_id: LocalSourceID):
|
|
|
39
40
|
|
|
40
41
|
folders = folder_chooser_multiple(
|
|
41
42
|
rj_path,
|
|
42
|
-
lambda p: any(
|
|
43
|
-
|
|
44
|
-
),
|
|
43
|
+
lambda p: any([
|
|
44
|
+
i.suffix != ".info" for i in p.iterdir() if not i.is_dir()
|
|
45
|
+
]),
|
|
45
46
|
)
|
|
46
47
|
|
|
47
48
|
for folder in folders:
|
|
@@ -136,6 +137,40 @@ def store(source_ids: List[LocalSourceID], replace: bool, all_: bool):
|
|
|
136
137
|
store the downloaded files to the storage
|
|
137
138
|
"""
|
|
138
139
|
|
|
140
|
+
def before_store_hook(path: Path):
|
|
141
|
+
from asmrmanager.common.fileconverter import (
|
|
142
|
+
convert_audio_format,
|
|
143
|
+
convert_vtt2lrc,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
def convert(
|
|
147
|
+
file: Path, to: Literal["mp3", "flac", "m4a", "wav", "lrc"]
|
|
148
|
+
):
|
|
149
|
+
if to == "lrc":
|
|
150
|
+
assert file.suffix.lower() == ".vtt"
|
|
151
|
+
logger.debug(f"converting {file} to lrc")
|
|
152
|
+
convert_vtt2lrc(file)
|
|
153
|
+
else:
|
|
154
|
+
logger.debug(f"converting {file} to {to}")
|
|
155
|
+
convert_audio_format(file, to)
|
|
156
|
+
|
|
157
|
+
assert file.with_suffix(f".{to}").exists()
|
|
158
|
+
file.unlink()
|
|
159
|
+
|
|
160
|
+
def convert_all(from_: str, to: Literal["mp3", "flac", "m4a", "wav", "lrc"]):
|
|
161
|
+
for file in path.rglob(f"*.{from_}", case_sensitive=False):
|
|
162
|
+
convert(file, to)
|
|
163
|
+
|
|
164
|
+
code = config.before_store
|
|
165
|
+
logger.debug("executing before_store_hook code: %s", code)
|
|
166
|
+
if not code.strip():
|
|
167
|
+
return
|
|
168
|
+
|
|
169
|
+
exec(code, {"path": path, "convert": convert, "convert_all": convert_all})
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
139
174
|
db = create_database()
|
|
140
175
|
try:
|
|
141
176
|
if all_:
|
|
@@ -146,12 +181,12 @@ def store(source_ids: List[LocalSourceID], replace: bool, all_: bool):
|
|
|
146
181
|
)
|
|
147
182
|
if res is None or res is False:
|
|
148
183
|
return
|
|
149
|
-
fm.store_all(replace=replace)
|
|
184
|
+
fm.store_all(replace=replace, hook=before_store_hook)
|
|
150
185
|
id_to_store = fm.list_("download")
|
|
151
186
|
|
|
152
187
|
else:
|
|
153
188
|
for rj_id in source_ids:
|
|
154
|
-
fm.store(rj_id, replace=replace)
|
|
189
|
+
fm.store(rj_id, replace=replace, hook=before_store_hook)
|
|
155
190
|
id_to_store = source_ids
|
|
156
191
|
|
|
157
192
|
for id_ in id_to_store:
|
|
@@ -162,10 +197,11 @@ def store(source_ids: List[LocalSourceID], replace: bool, all_: bool):
|
|
|
162
197
|
)
|
|
163
198
|
continue
|
|
164
199
|
res.stored = True
|
|
165
|
-
db.commit()
|
|
166
200
|
logger.info("succesfully stored all files")
|
|
167
201
|
except DstItemAlreadyExistsException as e:
|
|
168
202
|
logger.error("storing terminated for %s", e)
|
|
203
|
+
finally:
|
|
204
|
+
db.commit()
|
|
169
205
|
|
|
170
206
|
|
|
171
207
|
@click.command()
|
|
@@ -182,12 +218,12 @@ def diff(source_id: LocalSourceID):
|
|
|
182
218
|
|
|
183
219
|
local_files = fm.get_all_files(source_id)
|
|
184
220
|
|
|
185
|
-
remote_files_should_down = set(
|
|
186
|
-
|
|
187
|
-
)
|
|
188
|
-
remote_files_filterd = set(
|
|
189
|
-
|
|
190
|
-
)
|
|
221
|
+
remote_files_should_down = set([
|
|
222
|
+
Path(i["path"]) for i in recovers if i["should_download"]
|
|
223
|
+
])
|
|
224
|
+
remote_files_filterd = set([
|
|
225
|
+
Path(i["path"]) for i in recovers if not i["should_download"]
|
|
226
|
+
])
|
|
191
227
|
filtered_but_downloaded = remote_files_filterd & local_files
|
|
192
228
|
should_download_but_missing = remote_files_should_down - local_files
|
|
193
229
|
added_new_files = (
|
|
@@ -252,9 +288,9 @@ def check(list_: bool):
|
|
|
252
288
|
continue
|
|
253
289
|
|
|
254
290
|
local_files = fm.get_all_files(source_id)
|
|
255
|
-
remote_files_should_down = set(
|
|
256
|
-
|
|
257
|
-
)
|
|
291
|
+
remote_files_should_down = set([
|
|
292
|
+
Path(i["path"]) for i in recovers if i["should_download"]
|
|
293
|
+
])
|
|
258
294
|
should_download_but_missing = remote_files_should_down - local_files
|
|
259
295
|
if len(should_download_but_missing):
|
|
260
296
|
logger.error(
|
|
@@ -13,7 +13,7 @@ def convert_vtt2lrc(vtt_path: Path):
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def convert_audio_format(
|
|
16
|
-
audio_path: Path, dst: Literal["mp3", "flac", "wav"] = "mp3"
|
|
16
|
+
audio_path: Path, dst: Literal["mp3", "flac","m4a", "wav"] = "mp3"
|
|
17
17
|
):
|
|
18
18
|
from subprocess import run
|
|
19
19
|
|
|
@@ -23,13 +23,15 @@ def convert_audio_format(
|
|
|
23
23
|
" add it to your path"
|
|
24
24
|
)
|
|
25
25
|
|
|
26
|
-
match dst:
|
|
26
|
+
match dst.lower():
|
|
27
27
|
case "mp3":
|
|
28
|
-
convert_args = ["mp3", "-ab", "
|
|
28
|
+
convert_args = ["mp3", "-ab", "320k"]
|
|
29
29
|
case "flac":
|
|
30
|
-
convert_args = ["flac"]
|
|
30
|
+
convert_args = ["flac", '-compression_level', '5']
|
|
31
31
|
case "wav":
|
|
32
32
|
convert_args = ["pcm_s16le"]
|
|
33
|
+
case "m4a":
|
|
34
|
+
convert_args = ["aac", '-ab', '320k']
|
|
33
35
|
case _:
|
|
34
36
|
assert False
|
|
35
37
|
|
|
@@ -16,7 +16,7 @@ def format_time(time):
|
|
|
16
16
|
DEFAULT_THRESHOLD = timedelta(seconds=2)
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def vtt2lrc(
|
|
19
|
+
def vtt2lrc(vtt_path: Path, header=True, threshold=DEFAULT_THRESHOLD):
|
|
20
20
|
lrc = ""
|
|
21
21
|
|
|
22
22
|
if header:
|
|
@@ -24,6 +24,7 @@ def vtt2lrc(vtt, header=True, threshold=DEFAULT_THRESHOLD):
|
|
|
24
24
|
|
|
25
25
|
last_end = parse_time("23:59:59.99") # Insanely big value
|
|
26
26
|
|
|
27
|
+
vtt = vtt_path.read_text(encoding="utf-8")
|
|
27
28
|
for chunk in vtt.split("\n\n")[1:]:
|
|
28
29
|
if not chunk:
|
|
29
30
|
continue
|
|
@@ -53,8 +54,7 @@ def vtt2lrc(vtt, header=True, threshold=DEFAULT_THRESHOLD):
|
|
|
53
54
|
"vtt", type=click.Path(exists=True, dir_okay=False, path_type=Path)
|
|
54
55
|
)
|
|
55
56
|
def main(vtt: Path):
|
|
56
|
-
|
|
57
|
-
lrc = vtt2lrc(content)
|
|
57
|
+
lrc = vtt2lrc(vtt)
|
|
58
58
|
with open(
|
|
59
59
|
vtt.with_suffix("").with_suffix(".lrc"), "w", encoding="utf-8"
|
|
60
60
|
) as f:
|
|
@@ -23,7 +23,7 @@ class Config:
|
|
|
23
23
|
playlist_aliases: Dict[str, str]
|
|
24
24
|
player: Literal["mpd", "pygame"]
|
|
25
25
|
mpd_config: "MPDConfig"
|
|
26
|
-
|
|
26
|
+
before_store: str = ""
|
|
27
27
|
|
|
28
28
|
@dataclass
|
|
29
29
|
class Filter:
|
|
@@ -89,4 +89,5 @@ config = Config(
|
|
|
89
89
|
playlist_aliases=_config.get("playlist_aliases", {}),
|
|
90
90
|
player=_config.get("player", "pygame"),
|
|
91
91
|
mpd_config=MPDConfig(**_config.get("mpd_config", {})),
|
|
92
|
+
before_store=_config.get("before_store", ""),
|
|
92
93
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import shutil
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import Iterable, List, Literal, NamedTuple, Set, Tuple
|
|
4
|
+
from typing import Callable, Iterable, List, Literal, NamedTuple, Set, Tuple
|
|
5
5
|
|
|
6
6
|
import toml
|
|
7
7
|
|
|
@@ -124,7 +124,12 @@ class FileManager:
|
|
|
124
124
|
def could_store(self):
|
|
125
125
|
return self.storage_path_exists and self.download_path_exists
|
|
126
126
|
|
|
127
|
-
def store(
|
|
127
|
+
def store(
|
|
128
|
+
self,
|
|
129
|
+
source_id: LocalSourceID,
|
|
130
|
+
replace=True,
|
|
131
|
+
hook: Callable[[Path], None] | None = None,
|
|
132
|
+
):
|
|
128
133
|
"""sync download path and storage path"""
|
|
129
134
|
# TODO 换用fcp实现?
|
|
130
135
|
assert self.could_store()
|
|
@@ -133,6 +138,10 @@ class FileManager:
|
|
|
133
138
|
logger.warning(f"item {rj_name} does not exists, skip it")
|
|
134
139
|
return
|
|
135
140
|
|
|
141
|
+
if hook is not None:
|
|
142
|
+
logger.info(f'Execute hook function for: {rj_name}')
|
|
143
|
+
hook(self.download_path / rj_name)
|
|
144
|
+
|
|
136
145
|
# if os.path.exists(self.storage_path / rj_name):
|
|
137
146
|
# if not exists_ok:
|
|
138
147
|
# logger.error(f"the item {rj_name} to store already exists!")
|
|
@@ -189,13 +198,15 @@ class FileManager:
|
|
|
189
198
|
# )
|
|
190
199
|
# exit(-1)
|
|
191
200
|
|
|
192
|
-
def store_all(
|
|
201
|
+
def store_all(
|
|
202
|
+
self, replace=True, hook: Callable[[Path], None] | None = None
|
|
203
|
+
):
|
|
193
204
|
for file in os.listdir(self.download_path):
|
|
194
205
|
source_id = source_name2id(SourceName(file))
|
|
195
206
|
if source_id is None:
|
|
196
207
|
logger.warning(f"Ignore invalid file {file} in download path")
|
|
197
208
|
continue
|
|
198
|
-
self.store(source_id, replace=replace)
|
|
209
|
+
self.store(source_id, replace=replace, hook=hook)
|
|
199
210
|
|
|
200
211
|
def could_view(self):
|
|
201
212
|
"""
|
|
@@ -374,20 +385,16 @@ class FileManager:
|
|
|
374
385
|
def get_all_files(self, source_id: LocalSourceID) -> Set[Path]:
|
|
375
386
|
"""get all files of source ID both in download and storage path"""
|
|
376
387
|
source_name = id2source_name(source_id)
|
|
377
|
-
l1 = set(
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
for i in (self.storage_path / source_name).rglob("*")
|
|
388
|
-
if not i.is_dir()
|
|
389
|
-
]
|
|
390
|
-
)
|
|
388
|
+
l1 = set([
|
|
389
|
+
i.relative_to(self.download_path / source_name)
|
|
390
|
+
for i in (self.download_path / source_name).rglob("*")
|
|
391
|
+
if not i.is_dir()
|
|
392
|
+
])
|
|
393
|
+
l2 = set([
|
|
394
|
+
i.relative_to(self.storage_path / source_name)
|
|
395
|
+
for i in (self.storage_path / source_name).rglob("*")
|
|
396
|
+
if not i.is_dir()
|
|
397
|
+
])
|
|
391
398
|
return l1 | l2
|
|
392
399
|
|
|
393
400
|
@classmethod
|
{asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/config.example.toml
RENAMED
|
@@ -36,6 +36,26 @@ download_method = "idm"
|
|
|
36
36
|
# 若使用mpd请确保已安装mpd依赖并配置好mpd_config
|
|
37
37
|
player = 'pygame'
|
|
38
38
|
|
|
39
|
+
# asmr file store 前执行的脚本,若不需要可直接删除或留空,
|
|
40
|
+
# 使用 Python 语法编写,运行时动态执行,并提供以下全局资源以供调用:
|
|
41
|
+
|
|
42
|
+
# - path: pathlib.Path 音声的存储路径,download_path的子目录
|
|
43
|
+
|
|
44
|
+
# - convert(file: pathlib.Path, to: Literal['mp3', 'wav', 'flac', 'm4a', 'lrc'])
|
|
45
|
+
# 将单个文件转化为目标格式,mp3与m4a默认采用320k码率,flac默认使用压缩等级为5
|
|
46
|
+
# 若使用to='lrc',请确保原文件为vtt格式。
|
|
47
|
+
|
|
48
|
+
# - convert_all(from_: Literal['mp3', 'wav', 'flac', 'm4a', 'vtt'], to: Literal['mp3', 'wav', 'flac', 'm4a', 'lrc'])
|
|
49
|
+
# 将path 下的所有<from_>类型的文件转化为<to>类型,
|
|
50
|
+
# 对convert函数的封装,其余细节与convert无异。
|
|
51
|
+
|
|
52
|
+
before_store = '''
|
|
53
|
+
convert_all('vtt', 'lrc')
|
|
54
|
+
convert_all('wav', 'mp3')
|
|
55
|
+
convert_all('flac', 'mp3')
|
|
56
|
+
''''
|
|
57
|
+
|
|
58
|
+
|
|
39
59
|
# 如使用aria2请配置此项,否则请忽略
|
|
40
60
|
# 如果是在本地使用aria2,运行`aria2c --enable-rpc`,以下保持默认即可
|
|
41
61
|
# 如果使用motrix,且没有更改过默认端口,请将端口(port)改为16800
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.2.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/sqls.example/score.sql
RENAMED
|
File without changes
|
{asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/sqls.example/search.sql
RENAMED
|
File without changes
|
{asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/sqls.example/tags.sql
RENAMED
|
File without changes
|
{asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/sqls.example/test.sql
RENAMED
|
File without changes
|
{asmrmanager-2.2.1 → asmrmanager-2.2.3}/asmrmanager/filemanager/resources/sqls.example/vas.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|