ASMRManager 2.9.0__tar.gz → 2.9.2__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.
Files changed (81) hide show
  1. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/PKG-INFO +3 -3
  2. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/README.md +2 -2
  3. asmrmanager-2.9.2/asmrmanager/_version.py +1 -0
  4. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/core.py +9 -4
  5. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/dl.py +4 -2
  6. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/file.py +44 -9
  7. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/main.py +3 -0
  8. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/sql.py +15 -3
  9. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/utils.py +5 -3
  10. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/which.py +3 -3
  11. asmrmanager-2.9.2/asmrmanager/common/__init__.py +11 -0
  12. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/common/fileconverter.py +4 -2
  13. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/common/output.py +1 -1
  14. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/config.py +6 -1
  15. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/resources/config.example.toml +10 -1
  16. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/lrcplayer/player/pygameplayer.py +1 -1
  17. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/spider/downloader.py +5 -3
  18. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/spider/interface.py +4 -2
  19. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/pyproject.toml +1 -1
  20. asmrmanager-2.9.0/asmrmanager/_version.py +0 -1
  21. asmrmanager-2.9.0/asmrmanager/common/__init__.py +0 -1
  22. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/LICENSE +0 -0
  23. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/__init__.py +0 -0
  24. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/__main__.py +0 -0
  25. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/hold.py +0 -0
  26. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/info.py +0 -0
  27. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/pl.py +0 -0
  28. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/play.py +0 -0
  29. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/query.py +0 -0
  30. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/review.py +0 -0
  31. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/view.py +0 -0
  32. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/cli/vote.py +0 -0
  33. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/common/browse_params.py +0 -0
  34. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/common/download_params.py +0 -0
  35. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/common/parse_filter.py +0 -0
  36. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/common/rj_parse.py +0 -0
  37. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/common/select.py +0 -0
  38. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/common/subtitle.py +0 -0
  39. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/common/types.py +0 -0
  40. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/common/vtt2lrc.py +0 -0
  41. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/__init__.py +0 -0
  42. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/__pycache__/database.d.er +0 -0
  43. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/__pycache__/engine.d.er +0 -0
  44. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/__pycache__/q_func.d.er +0 -0
  45. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/database.py +0 -0
  46. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/engine.py +0 -0
  47. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/manage.py +0 -0
  48. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/orm_type.py +0 -0
  49. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/q_func.py +0 -0
  50. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/utils/__init__.py +0 -0
  51. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/utils/add2db.py +0 -0
  52. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/database/utils/uuid_sqlite.py +0 -0
  53. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/__init__.py +0 -0
  54. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/appdirs_.py +0 -0
  55. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/exceptions.py +0 -0
  56. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/file_zipper.py +0 -0
  57. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/manager.py +0 -0
  58. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/resources/akarin.jpg +0 -0
  59. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/resources/sqls.example/circle_name.sql +0 -0
  60. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/resources/sqls.example/score.sql +0 -0
  61. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/resources/sqls.example/search.sql +0 -0
  62. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/resources/sqls.example/tags.sql +0 -0
  63. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/resources/sqls.example/test.sql +0 -0
  64. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/resources/sqls.example/vas.sql +0 -0
  65. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/filemanager/utils.py +0 -0
  66. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/logger/__init__.py +0 -0
  67. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/lrcplayer/__init__.py +0 -0
  68. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/lrcplayer/lrcparse.py +0 -0
  69. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/lrcplayer/main.css +0 -0
  70. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/lrcplayer/main.py +0 -0
  71. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/lrcplayer/player/base.py +0 -0
  72. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/lrcplayer/player/mpdplayer.py +0 -0
  73. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/lrcplayer/player/sdplayer.py +0 -0
  74. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/spider/__init__.py +0 -0
  75. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/spider/asmrapi.py +0 -0
  76. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/spider/playlist.py +0 -0
  77. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/spider/tag.py +0 -0
  78. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/spider/utils/IDMHelper.py +0 -0
  79. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/spider/utils/aria2_downloader.py +0 -0
  80. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/spider/utils/concurrency.py +0 -0
  81. {asmrmanager-2.9.0 → asmrmanager-2.9.2}/asmrmanager/spider/utils/retry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ASMRManager
3
- Version: 2.9.0
3
+ Version: 2.9.2
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>
@@ -216,8 +216,8 @@ asmr dl get 300015443 # 本项目存储VJ与BJ所使用的ID("3" + 8位VJ号
216
216
  检查下载目录下文件是否下载完全(默认会计算hash并向服务器验证,较为耗时。可使用 --offline 跳过)
217
217
 
218
218
  ```shell
219
- asmr file check
220
- asmr file check --list | xargs asmr dl get --force --replace # 重新下载所有不完整的文件,以bash shell为例
219
+ asmr file check --all
220
+ asmr file check --all --list | xargs asmr dl get --force --replace # 重新下载所有不完整的文件,以bash shell为例
221
221
  ```
222
222
 
223
223
  将下载的文件转移到存储目录(STORAGE_PATH),并执行相应文件格式转换(详情见config.toml的before_store字段)
@@ -167,8 +167,8 @@ asmr dl get 300015443 # 本项目存储VJ与BJ所使用的ID("3" + 8位VJ号
167
167
  检查下载目录下文件是否下载完全(默认会计算hash并向服务器验证,较为耗时。可使用 --offline 跳过)
168
168
 
169
169
  ```shell
170
- asmr file check
171
- asmr file check --list | xargs asmr dl get --force --replace # 重新下载所有不完整的文件,以bash shell为例
170
+ asmr file check --all
171
+ asmr file check --all --list | xargs asmr dl get --force --replace # 重新下载所有不完整的文件,以bash shell为例
172
172
  ```
173
173
 
174
174
  将下载的文件转移到存储目录(STORAGE_PATH),并执行相应文件格式转换(详情见config.toml的before_store字段)
@@ -0,0 +1 @@
1
+ __version__ = "2.9.2"
@@ -93,6 +93,7 @@ def create_downloader_and_database(
93
93
  aria2_config=config.aria2_config,
94
94
  limit=config.api_max_concurrent_requests,
95
95
  fetch_cover=config.fetch_cover,
96
+ tagger=config.default_tagger,
96
97
  ),
97
98
  db,
98
99
  )
@@ -437,7 +438,9 @@ def multi_rj_argument(convert: Literal[False, "local", "remote"] = False):
437
438
  SEPARATOR = ":"
438
439
 
439
440
 
440
- def interval_preprocess_cb(ctx: click.Context, opt: click.Parameter, val: str):
441
+ def interval_preprocess_cb(
442
+ _ctx: click.Context, _opt: click.Parameter, val: str
443
+ ):
441
444
  """
442
445
  input must be numeric or None,
443
446
  and it returns a float/int/str/None value tuple
@@ -470,9 +473,11 @@ def time_interval_preprocess_cb(
470
473
  ):
471
474
  return tuple(
472
475
  map(
473
- lambda x: str(x) + "m"
474
- if (x is not None) and (not isinstance(x, str))
475
- else x,
476
+ lambda x: (
477
+ str(x) + "m"
478
+ if (x is not None) and (not isinstance(x, str))
479
+ else x
480
+ ),
476
481
  interval_preprocess_cb(ctx, opt, val),
477
482
  )
478
483
  )
@@ -283,8 +283,10 @@ def search(
283
283
  spider.search(
284
284
  " ".join(
285
285
  map(
286
- lambda t: (t := t.strip())
287
- and ("-" + t[1:] if t.startswith("!") else t),
286
+ lambda t: (
287
+ (t := t.strip())
288
+ and ("-" + t[1:] if t.startswith("!") else t)
289
+ ),
288
290
  keywords,
289
291
  )
290
292
  ),
@@ -153,12 +153,21 @@ def recover(source_id: LocalSourceID, regex: str, ignore_filter: bool):
153
153
  show_default=True,
154
154
  help="check files before storing",
155
155
  )
156
+ @click.option(
157
+ "--on-error",
158
+ "-e",
159
+ type=click.Choice(["abort", "skip"], case_sensitive=False),
160
+ default="abort",
161
+ show_default=True,
162
+ help="what to do when a check failed",
163
+ )
156
164
  def store(
157
165
  source_ids: List[LocalSourceID],
158
166
  no_convert: bool,
159
167
  replace: bool,
160
168
  all_: bool,
161
169
  check: Literal["none", "offline", "online"],
170
+ on_error: Literal["abort", "skip"],
162
171
  ):
163
172
  """
164
173
  store the downloaded files to the storage
@@ -204,8 +213,9 @@ def store(
204
213
  else:
205
214
  src_paths = list(
206
215
  filter(
207
- lambda p: not p.is_dir()
208
- and p.suffix.lower() != f".{to}",
216
+ lambda p: (
217
+ not p.is_dir() and p.suffix.lower() != f".{to}"
218
+ ),
209
219
  path.rglob(f"*.{from_}", case_sensitive=False),
210
220
  )
211
221
  )
@@ -269,7 +279,12 @@ def store(
269
279
  )
270
280
  if not success:
271
281
  logger.error("Stop storing due to check failed")
272
- return
282
+ if on_error == "abort":
283
+ return
284
+ elif on_error == "skip":
285
+ continue
286
+ else:
287
+ assert False
273
288
  fm.store(id_, replace=replace, hook=hook)
274
289
 
275
290
  res = db.check_exists(id_)
@@ -353,15 +368,21 @@ def verify_voices(source_id: LocalSourceID, offline: bool) -> bool:
353
368
  logger.error(f"failed to load recover for id {source_id}")
354
369
  return False
355
370
 
356
- # local_files = fm.get_all_files(source_id)
371
+ local_files = fm.get_all_files(source_id)
372
+ for p in local_files:
373
+ if p.suffix == ".aria2":
374
+ logger.error(f"Aria2 control file found: {p}")
375
+ return False
357
376
  remote_files_should_down = set(
358
377
  [Path(i["path"]) for i in recovers if i["should_download"]]
359
378
  )
360
379
  # should_download_but_missing = remote_files_should_down - local_files
361
380
  should_download_but_missing = set(
362
381
  filter(
363
- lambda p: not any(
364
- fm.check_exists(f"{id2source_name(source_id)}/{str(p)}")
382
+ lambda p: (
383
+ not any(
384
+ fm.check_exists(f"{id2source_name(source_id)}/{str(p)}")
385
+ )
365
386
  ),
366
387
  remote_files_should_down,
367
388
  )
@@ -375,6 +396,7 @@ def verify_voices(source_id: LocalSourceID, offline: bool) -> bool:
375
396
 
376
397
  if offline:
377
398
  return True
399
+ logger.info(f"Start hash verification: {source_id}")
378
400
 
379
401
  remote_files_should_down_list = [
380
402
  Path(i["path"]) for i in recovers if i["should_download"]
@@ -454,12 +476,25 @@ def verify_voices(source_id: LocalSourceID, offline: bool) -> bool:
454
476
  show_default=True,
455
477
  help="only list source id (pipe it to `dl get --force` to redownload them)",
456
478
  )
457
- def check(list_: bool, offline: bool):
479
+ @click.option(
480
+ "--all",
481
+ "-a",
482
+ "all_",
483
+ is_flag=True,
484
+ default=False,
485
+ show_default=True,
486
+ help="check all files in download path",
487
+ )
488
+ @multi_rj_argument(convert="local")
489
+ def check(
490
+ source_ids: list[LocalSourceID], list_: bool, offline: bool, all_: bool
491
+ ):
458
492
  """
459
493
  check for download path for files to be downloaded correctly without missing or fail.
460
494
  """
461
- # TODO: check hash with xxhash3
462
- source_ids = fm.list_("download")
495
+ if all_:
496
+ source_ids = list(fm.list_("download"))
497
+
463
498
  for source_id in source_ids:
464
499
  success = verify_voices(source_id, offline)
465
500
  if not success and list_:
@@ -46,12 +46,15 @@ try:
46
46
  import importlib.util
47
47
 
48
48
  if importlib.util.find_spec("trogon"):
49
+
49
50
  @click.command("tui", help="Open Textual TUI.")
50
51
  @click.pass_context
51
52
  def tui(ctx: click.Context):
52
53
  from trogon import Trogon # type: ignore
54
+
53
55
  if ctx.parent is not None:
54
56
  Trogon(ctx.parent.command, click_context=ctx).run()
57
+
55
58
  main.add_command(tui)
56
59
  except ImportError:
57
60
  pass
@@ -25,8 +25,20 @@ class SQLName(click.ParamType):
25
25
 
26
26
  @click.command()
27
27
  @click.argument("sql_name", type=SQLName())
28
- @click.option("--edit", '-e', is_flag=True, default=False, help="whether to open an editor")
29
- @click.option("--raw", '-r', is_flag=True, default=False, help="output sql results as json")
28
+ @click.option(
29
+ "--edit",
30
+ "-e",
31
+ is_flag=True,
32
+ default=False,
33
+ help="whether to open an editor",
34
+ )
35
+ @click.option(
36
+ "--raw",
37
+ "-r",
38
+ is_flag=True,
39
+ default=False,
40
+ help="output sql results as json",
41
+ )
30
42
  @click.option(
31
43
  "--save/--no-save",
32
44
  "-s/-ns",
@@ -55,7 +67,7 @@ def sql(sql_name: str, save: bool, edit: bool, raw: bool):
55
67
  temp_file_path.write_text(
56
68
  sql_path.read_text(encoding="utf8"), encoding="utf8"
57
69
  )
58
- if edit:
70
+ if edit:
59
71
  run(f'{config.editor} "{temp_file_path}"', shell=True)
60
72
  # db_path = temp_file_path.with_name('data.db')
61
73
  # print(db_path, temp_file_path)
@@ -73,9 +73,11 @@ def convert(
73
73
 
74
74
  src_paths = list(
75
75
  filter(
76
- lambda p: not p.is_dir()
77
- and p.suffix.lower() in [".flac", ".wav", ".m4a"]
78
- and p.suffix.lower() != f".{mode}",
76
+ lambda p: (
77
+ not p.is_dir()
78
+ and p.suffix.lower() in [".flac", ".wav", ".m4a"]
79
+ and p.suffix.lower() != f".{mode}"
80
+ ),
79
81
  path.rglob("*.*"),
80
82
  )
81
83
  )
@@ -1,4 +1,4 @@
1
- import os
1
+ import subprocess
2
2
 
3
3
  import click
4
4
 
@@ -22,9 +22,9 @@ def which(source_id: LocalSourceID, show: bool):
22
22
  import sys
23
23
 
24
24
  if sys.platform == "win32":
25
- os.system(f'explorer.exe "{path}"')
25
+ subprocess.Popen(["explorer.exe", path], start_new_session=True)
26
26
  elif sys.platform.startswith("linux"):
27
- os.system(f'xdg-open "{path}"')
27
+ subprocess.Popen(["xdg-open", path], start_new_session=True)
28
28
  else:
29
29
  logger.error(
30
30
  "option --show is for windows and XDG based linux desktop environment only, if you are using other platform, using"
@@ -0,0 +1,11 @@
1
+ MUSIC_SUFFIXES = (
2
+ ".mp3",
3
+ ".wav",
4
+ ".m4a",
5
+ ".flac",
6
+ ".wma",
7
+ ".mp4",
8
+ ".mkv",
9
+ ".avi",
10
+ ".wmv", # some works only have video files, such as RJ265135"
11
+ )
@@ -96,6 +96,7 @@ class AudioConverter:
96
96
  ):
97
97
  self.tasks_total = len(src)
98
98
  self.tasks_done = 0
99
+ self.update_total_progress()
99
100
 
100
101
  match dst.lower():
101
102
  case "mp3":
@@ -122,8 +123,9 @@ class AudioConverter:
122
123
  x, x.with_suffix(f".{dst}"), convert_args
123
124
  ),
124
125
  filter(
125
- lambda p: not p.is_dir()
126
- and p.suffix.lower() != f".{dst}",
126
+ lambda p: (
127
+ not p.is_dir() and p.suffix.lower() != f".{dst}"
128
+ ),
127
129
  src,
128
130
  ),
129
131
  )
@@ -64,7 +64,7 @@ def print_table(
64
64
  rows,
65
65
  raw=False,
66
66
  image_paths: list[str] | None = None,
67
- image_size=(8, 3),
67
+ image_size=(16, 6),
68
68
  ):
69
69
  if raw or not support_image():
70
70
  _print_table(titles, rows, raw)
@@ -19,6 +19,7 @@ class Config:
19
19
  download_path: str
20
20
  storage_path: str
21
21
  view_path: str
22
+ default_tagger: Literal["tag", "tagw"]
22
23
  tag_strategy: Literal["common_only", "accept_all", "except_rejected"] | str
23
24
  tag_filter: List[str]
24
25
  fetch_cover: bool
@@ -30,7 +31,7 @@ class Config:
30
31
  aria2_config: "Aria2Config"
31
32
  subtitle_config: "SubtitleConfig"
32
33
  playlist_aliases: Dict[str, str]
33
- player: Literal["mpd", "pygame"]
34
+ player: Literal["mpd", "pygame", "sounddevice"]
34
35
  mpd_config: "MPDConfig"
35
36
  before_store: str = ""
36
37
 
@@ -101,6 +102,7 @@ config = Config(
101
102
  download_path=_config["download_path"],
102
103
  storage_path=_config["storage_path"],
103
104
  view_path=_config["view_path"],
105
+ default_tagger=_config.get("default_tagger", "tag"),
104
106
  tag_strategy=_config.get("tag_strategy", "common_only"),
105
107
  tag_filter=_config["tag_filter"],
106
108
  fetch_cover=_config.get("fetch_cover", False),
@@ -127,4 +129,7 @@ if env_concurrency_limit := os.getenv("ASMR_CONCURRENCY_LIMIT"):
127
129
  if os.getenv("ASMR_DISABLE_COVER") == "1":
128
130
  config.display_cover = False
129
131
 
132
+ if (__tagger := os.getenv("ASMR_DEFAULT_TAGGER")) in ("tag", "tagw"):
133
+ config.default_tagger = __tagger
134
+
130
135
  logger.debug(f"Config loaded: {config}")
@@ -37,6 +37,13 @@ storage_path = "~/Music/asmr"
37
37
  # 如不使用 view 方法可以设为空
38
38
  view_path = "~/Desktop/asmr"
39
39
 
40
+ # [可选]
41
+ # 默认标签搜索策略,可选值为 tag 或 tagw
42
+ # 默认 tag 将排除用户添加的低愿力标签
43
+ # 如果你希望搜索它们可以使用 tagw
44
+ # 详见:https://t.me/asmr_one_chan/79
45
+ default_tagger = "tag"
46
+
40
47
  # [高级]
41
48
  # 标签接受策略,具体说明参考官方频道:https://t.me/asmr_one_chan/73
42
49
  # 可选项有:
@@ -56,6 +63,8 @@ view_path = "~/Desktop/asmr"
56
63
  # 因此,如果你特别讨厌某个标签,那么对于包含该标签的作品,即使票数并不多,也可以考虑接受该标签,这样在下一步的tag_filter中就可以过滤掉这个作品。
57
64
  # 例如下面的设置,将对于特定的标签只需分数大于2即考虑接受,而一般标签需要分数大于5:
58
65
  # tag_strategy = "common_only or (voteRank >= 5 or (tag['name'] in ['tagname1', 'tagname2'] and voteRank >= 2))"
66
+ #
67
+ # 请注意当default_tagger = "tag" 时,将不会搜到低愿力标签,即voteStatus != 0
59
68
 
60
69
  # 默认会过滤除普通标签外的所有标签
61
70
  tag_strategy = "common_only"
@@ -83,7 +92,7 @@ display_cover = false
83
92
  editor = "code --wait"
84
93
 
85
94
  # [可选]
86
- # 下载所用的工具,可选则idm或aria2,请注意需安装对应的依赖项
95
+ # 下载所用的工具,可选择idm或aria2,请注意需安装对应的依赖项
87
96
  download_method = "idm"
88
97
 
89
98
  # [高级]
@@ -5,7 +5,7 @@ from .base import BasePlayer, Music
5
5
 
6
6
  try:
7
7
  with contextlib.redirect_stdout(None):
8
- from pygame import mixer
8
+ from pygame import mixer # type: ignore
9
9
  except ImportError:
10
10
  raise ImportError(
11
11
  "pygame is not installed, please install asmrmanager with pygame"
@@ -149,8 +149,10 @@ class ASMRDownloadAPI(ASMRAPI):
149
149
  )
150
150
  if any(
151
151
  map(
152
- lambda f: 1 <= f.download_order <= download_order
153
- and f.path.suffix.lower() in MUSIC_SUFFIXES,
152
+ lambda f: (
153
+ 1 <= f.download_order <= download_order
154
+ and f.path.suffix.lower() in MUSIC_SUFFIXES
155
+ ),
154
156
  file_list_with_order,
155
157
  )
156
158
  ):
@@ -215,7 +217,7 @@ class ASMRDownloadAPI(ASMRAPI):
215
217
  logger.debug("final file list: %s", file_list)
216
218
 
217
219
  self.create_recover_file(file_list, voice_path)
218
- if self.fetch_cover:
220
+ if self.fetch_cover and all(f.path != 'cover.jpg' for f in file_list):
219
221
  await self.download_cover(voice_id, voice_path)
220
222
  await self.create_dir_and_download(file_list)
221
223
 
@@ -97,6 +97,7 @@ class ASMRDownloadManager(AsyncManager):
97
97
  aria2_config: Aria2Config | None = None,
98
98
  limit: int = 4,
99
99
  fetch_cover: bool = False,
100
+ tagger: Literal["tag", "tagw"] = "tag",
100
101
  ):
101
102
  self.downloader = ASMRDownloadAPI(
102
103
  name=name,
@@ -112,6 +113,7 @@ class ASMRDownloadManager(AsyncManager):
112
113
  )
113
114
  super().__init__(self.downloader)
114
115
  self.id_should_download = id_should_download or (lambda _: True)
116
+ self.tagger = tagger
115
117
 
116
118
  async def get(self, ids: List[RemoteSourceID]):
117
119
  tasks = []
@@ -152,8 +154,8 @@ class ASMRDownloadManager(AsyncManager):
152
154
 
153
155
  filters = []
154
156
 
155
- filters += [f"$tag:{t}$" for t in tags]
156
- filters += [f"$-tag:{nt}$" for nt in no_tags]
157
+ filters += [f"${self.tagger}:{t}$" for t in tags]
158
+ filters += [f"$-{self.tagger}:{nt}$" for nt in no_tags]
157
159
 
158
160
  filters += [f"$va:{va}$" for va in vas]
159
161
  filters += [f"$-va:{nva}$" for nva in no_vas]
@@ -33,7 +33,7 @@ dependencies = [
33
33
  ]
34
34
  requires-python = ">=3.12"
35
35
  readme = "README.md"
36
- version = "2.9.0"
36
+ version = "2.9.2"
37
37
 
38
38
  [project.license]
39
39
  text = "MIT"
@@ -1 +0,0 @@
1
- __version__ = "2.9.0"
@@ -1 +0,0 @@
1
- MUSIC_SUFFIXES = (".mp3", ".wav", ".m4a", ".flac")
File without changes