From 892a803f26044a6635bbad3c46d4288c8e2ae3cc Mon Sep 17 00:00:00 2001 From: Jacob Chapman <7908073+chapmanjacobd@users.noreply.github.com> Date: Fri, 5 Jan 2024 12:06:12 -0600 Subject: [PATCH] 2.3.005 --- .github/README.md | 2 +- pdm.lock | 6 +++--- xklb/__init__.py | 2 +- xklb/fs_extract.py | 27 ++++++++++++++++++--------- xklb/media/av.py | 9 +++++++-- xklb/media/media_check.py | 10 +++++++++- 6 files changed, 39 insertions(+), 17 deletions(-) diff --git a/.github/README.md b/.github/README.md index 2057aae7..56da2b02 100644 --- a/.github/README.md +++ b/.github/README.md @@ -95,7 +95,7 @@ To stop playing press Ctrl+C in either the terminal or mpv
List all subcommands $ library - xk media library subcommands (v2.3.004) + xk media library subcommands (v2.3.005) Create database subcommands: ╭───────────────┬────────────────────────────────────────────────────╮ diff --git a/pdm.lock b/pdm.lock index e688e900..77569db8 100644 --- a/pdm.lock +++ b/pdm.lock @@ -823,7 +823,7 @@ files = [ [[package]] name = "geopandas" -version = "0.14.1" +version = "0.14.2" requires_python = ">=3.9" summary = "Geographic pandas extensions" dependencies = [ @@ -834,8 +834,8 @@ dependencies = [ "shapely>=1.8.0", ] files = [ - {file = "geopandas-0.14.1-py3-none-any.whl", hash = "sha256:ed5a7cae7874bfc3238fb05e0501cc1760e1b7b11e5b76ecad29da644ca305da"}, - {file = "geopandas-0.14.1.tar.gz", hash = "sha256:4853ff89ecb6d1cfc43e7b3671092c8160e8a46a3dd7368f25906283314e42bb"}, + {file = "geopandas-0.14.2-py3-none-any.whl", hash = "sha256:0efa61235a68862c1c6be89fc3707cdeba67667d5676bb19e24f3c57a8c2f723"}, + {file = "geopandas-0.14.2.tar.gz", hash = "sha256:6e71d57b8376f9fdc9f1c3aa3170e7e420e91778de854f51013ae66fd371ccdb"}, ] [[package]] diff --git a/xklb/__init__.py b/xklb/__init__.py index 5c83166d..31faac64 100644 --- a/xklb/__init__.py +++ b/xklb/__init__.py @@ -1 +1 @@ -__version__ = "2.3.004" +__version__ = "2.3.005" diff --git a/xklb/fs_extract.py b/xklb/fs_extract.py index f7922872..137ae361 100644 --- a/xklb/fs_extract.py +++ b/xklb/fs_extract.py @@ -62,6 +62,7 @@ def parse_args(action, usage) -> argparse.Namespace: ) parser.set_defaults(profile=DBType.video) parser.add_argument("--scan-all-files", "-a", action="store_true", help=argparse.SUPPRESS) + parser.add_argument("--ext", action=arg_utils.ArgparseList) parser.add_argument( "--io-multiplier", @@ -117,7 +118,7 @@ def parse_args(action, usage) -> argparse.Namespace: args = parser.parse_args() if args.move: - args.move = Path(args.move).expanduser().resolve() + args.move = str(Path(args.move).expanduser().resolve()) args.gap = nums.float_from_percent(args.gap) if args.delete_corrupt: @@ -171,10 +172,6 @@ def extract_metadata(mp_args, path) -> Optional[Dict[str, int]]: "time_deleted": 0, } - if mp_args.hash: - # TODO: it would be better if this was saved to and checked against an external global file - media["hash"] = sample_hash.sample_hash_file(path) - if mp_args.profile in (DBType.audio, DBType.video): media = av.munge_av_tags(mp_args, media, path) if media is None: @@ -192,8 +189,12 @@ def extract_metadata(mp_args, path) -> Optional[Dict[str, int]]: else: log.debug(f"{timer()-start} {path}") - if mp_args.move: - dest_path = bytes(mp_args.move / Path(path).relative_to(mp_args.playlist_path)) + if getattr(mp_args, "hash", False): + # TODO: it would be better if this was saved to and checked against an external global file + media["hash"] = sample_hash.sample_hash_file(path) + + if getattr(mp_args, "move", False): + dest_path = bytes(Path(mp_args.move) / Path(path).relative_to(mp_args.playlist_path)) dest_path = path_utils.clean_path(dest_path) file_utils.rename_move_file(path, dest_path) media["path"] = dest_path @@ -271,7 +272,9 @@ def find_new_files(args, path) -> List[str]: if path.is_file(): scanned_set = set(str(path)) else: - if args.scan_all_files: + if args.ext: + scanned_set = file_utils.rglob(path, args.ext)[0] + elif args.scan_all_files: scanned_set = file_utils.rglob(path)[0] elif args.profile == DBType.filesystem: scanned_set = set.union(*file_utils.rglob(path)) @@ -362,7 +365,13 @@ def scan_path(args, path_str: str) -> int: info = { "extractor_key": "Local", - "extractor_config": objects.filter_namespace(args, ["ocr", "speech_recognition", "scan_subtitles"]), + "extractor_config": objects.dict_filter_bool( + { + k: v + for k, v in args.__dict__.items() + if k not in ["db", "database", "verbose", "extra_playlist_data", "force", "paths"] + } + ), "time_deleted": 0, } args.playlist_id = db_playlists.add(args, str(path), info, check_subpath=True) diff --git a/xklb/media/av.py b/xklb/media/av.py index 7e7689f3..52b6b49c 100644 --- a/xklb/media/av.py +++ b/xklb/media/av.py @@ -154,8 +154,13 @@ def munge_av_tags(args, media, path) -> Optional[dict]: raise if media_check.corruption_threshold_exceeded(args.delete_corrupt, corruption, duration): - log.info("Deleting %s corruption %.1f%% exceeded threshold %s", path, corruption, args.delete_corrupt) - file_utils.trash(path) + threshold_str = ( + strings.safe_percent(args.delete_corrupt) + if 0 < args.delete_corrupt < 1 + else (args.delete_corrupt + "s") + ) + log.warning("Deleting %s corruption %.1f%% exceeded threshold %s", path, corruption * 100, threshold_str) + file_utils.trash(path) # file is not open, checked during initial probe return None tags = format_.pop("tags", None) diff --git a/xklb/media/media_check.py b/xklb/media/media_check.py index 973462f7..e663319d 100644 --- a/xklb/media/media_check.py +++ b/xklb/media/media_check.py @@ -126,7 +126,7 @@ def decode_full_scan(path, audio_scan=False, frames="frames", threads=5): data = json.loads(output)["streams"][0] r_frame_rate = fractions.Fraction(data["r_frame_rate"]) - nb_frames = int(data[f"nb_read_{frames}"]) + nb_frames = int(data.get(f"nb_read_{frames}") or 0) metadata_duration = ffprobe.duration or 0 actual_duration = nb_frames * r_frame_rate.denominator / r_frame_rate.numerator @@ -199,4 +199,12 @@ def media_check() -> None: raise else: if corruption_threshold_exceeded(args.delete_corrupt, corruption, processes.FFProbe(path).duration): + threshold_str = ( + strings.safe_percent(args.delete_corrupt) + if 0 < args.delete_corrupt < 1 + else (args.delete_corrupt + "s") + ) + log.warning( + "Deleting %s corruption %.1f%% exceeded threshold %s", path, corruption * 100, threshold_str + ) file_utils.trash(path)