Refactor update osxmetadata (#804)
* Updated osxmetadata to use v1.0.0 * Added README_DEV * fix for missing detected_text xattr * fix for missing detected_text xattr
This commit is contained in:
@@ -262,10 +262,9 @@ EXTENDED_ATTRIBUTE_NAMES = [
|
||||
"description",
|
||||
"findercomment",
|
||||
"headline",
|
||||
"keywords",
|
||||
"participants",
|
||||
"projects",
|
||||
"rating",
|
||||
"starrating",
|
||||
"subject",
|
||||
"title",
|
||||
"version",
|
||||
|
||||
@@ -11,10 +11,16 @@ import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from typing import Iterable, List, Tuple
|
||||
from typing import Iterable, List, Optional, Tuple
|
||||
|
||||
import click
|
||||
import osxmetadata
|
||||
from osxmetadata import (
|
||||
MDITEM_ATTRIBUTE_DATA,
|
||||
MDITEM_ATTRIBUTE_SHORT_NAMES,
|
||||
OSXMetaData,
|
||||
Tag,
|
||||
)
|
||||
from osxmetadata.constants import _TAGS_NAMES
|
||||
|
||||
import osxphotos
|
||||
from osxphotos._constants import (
|
||||
@@ -86,7 +92,7 @@ from .common import (
|
||||
from .help import ExportCommand, get_help_msg
|
||||
from .list import _list_libraries
|
||||
from .param_types import ExportDBType, FunctionCall, TemplateString
|
||||
from .report_writer import report_writer_factory, ReportWriterNoOp
|
||||
from .report_writer import ReportWriterNoOp, report_writer_factory
|
||||
from .rich_progress import rich_progress
|
||||
from .verbose import get_verbose_console, time_stamp, verbose_print
|
||||
|
||||
@@ -2683,9 +2689,9 @@ def write_finder_tags(
|
||||
]
|
||||
tags.extend(rendered_tags)
|
||||
|
||||
tags = [osxmetadata.Tag(tag) for tag in set(tags)]
|
||||
tags = [Tag(tag, 0) for tag in set(tags)]
|
||||
for f in files:
|
||||
md = osxmetadata.OSXMetaData(f)
|
||||
md = OSXMetaData(f)
|
||||
if sorted(md.tags) != sorted(tags):
|
||||
verbose_(f"Writing Finder tags to {f}")
|
||||
md.tags = tags
|
||||
@@ -2747,24 +2753,24 @@ def write_extended_attributes(
|
||||
written = set()
|
||||
skipped = set()
|
||||
for f in files:
|
||||
md = osxmetadata.OSXMetaData(f)
|
||||
md = OSXMetaData(f)
|
||||
for attr, value in attributes.items():
|
||||
islist = osxmetadata.ATTRIBUTES[attr].list
|
||||
attr_type = get_metadata_attribute_type(attr) or "str"
|
||||
if value:
|
||||
value = ", ".join(value) if not islist else sorted(value)
|
||||
file_value = md.get_attribute(attr)
|
||||
value = sorted(list(value)) if attr_type == "list" else ", ".join(value)
|
||||
file_value = md.get(attr)
|
||||
|
||||
if file_value and islist:
|
||||
if file_value and attr_type == "lists":
|
||||
file_value = sorted(file_value)
|
||||
|
||||
if (not file_value and not value) or file_value == value:
|
||||
# if both not set or both equal, nothing to do
|
||||
# get_attribute returns None if not set and value will be [] if not set so can't directly compare
|
||||
# get returns None if not set and value will be [] if not set so can't directly compare
|
||||
verbose_(f"Skipping extended attribute {attr} for {f}: nothing to do")
|
||||
skipped.add(f)
|
||||
else:
|
||||
verbose_(f"Writing extended attribute {attr} to {f}")
|
||||
md.set_attribute(attr, value)
|
||||
md.set(attr, value)
|
||||
written.add(f)
|
||||
|
||||
return list(written), [f for f in skipped if f not in written]
|
||||
@@ -2841,3 +2847,23 @@ def render_and_validate_report(report: str, exiftool_path: str, export_dir: str)
|
||||
sys.exit(1)
|
||||
|
||||
return report
|
||||
|
||||
|
||||
def get_metadata_attribute_type(attr: str) -> Optional[str]:
|
||||
"""Get the type of a metadata attribute
|
||||
|
||||
Args:
|
||||
attr: attribute name
|
||||
|
||||
Returns:
|
||||
type of attribute as string or None if type is not known
|
||||
"""
|
||||
if attr in MDITEM_ATTRIBUTE_SHORT_NAMES:
|
||||
attr = MDITEM_ATTRIBUTE_SHORT_NAMES[attr]
|
||||
return (
|
||||
"list"
|
||||
if attr in _TAGS_NAMES
|
||||
else MDITEM_ATTRIBUTE_DATA[attr]["python_type"]
|
||||
if attr in MDITEM_ATTRIBUTE_DATA
|
||||
else None
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import re
|
||||
import typing as t
|
||||
|
||||
import click
|
||||
import osxmetadata
|
||||
from osxmetadata import MDITEM_ATTRIBUTE_DATA, MDITEM_ATTRIBUTE_SHORT_NAMES
|
||||
from rich.console import Console
|
||||
from rich.markdown import Markdown
|
||||
|
||||
@@ -256,34 +256,46 @@ class ExportCommand(click.Command):
|
||||
formatter.write_text(
|
||||
"""
|
||||
Some options (currently '--finder-tag-template', '--finder-tag-keywords', '-xattr-template') write
|
||||
additional metadata to extended attributes in the file. These options will only work
|
||||
if the destination filesystem supports extended attributes (most do).
|
||||
additional metadata accessible by Spotlight to facilitate searching.
|
||||
For example, --finder-tag-keyword writes all keywords (including any specified by '--keyword-template'
|
||||
or other options) to Finder tags that are searchable in Spotlight using the syntax: 'tag:tagname'.
|
||||
For example, if you have images with keyword "Travel" then using '--finder-tag-keywords' you could quickly
|
||||
find those images in the Finder by typing 'tag:Travel' in the Spotlight search bar.
|
||||
Finder tags are written to the 'com.apple.metadata:_kMDItemUserTags' extended attribute.
|
||||
Unlike EXIF metadata, extended attributes do not modify the actual file. Most cloud storage services
|
||||
do not synch extended attributes. Dropbox does sync them and any changes to a file's extended attributes
|
||||
Unlike EXIF metadata, extended attributes do not modify the actual file;
|
||||
the metadata is written to extended attributes associated with the file and the Spotlight metadata database.
|
||||
Most cloud storage services do not synch extended attributes.
|
||||
Dropbox does sync them and any changes to a file's extended attributes
|
||||
will cause Dropbox to re-sync the files.
|
||||
|
||||
The following attributes may be used with '--xattr-template':
|
||||
|
||||
"""
|
||||
)
|
||||
|
||||
# build help text from all the attribute names
|
||||
# passed to click.HelpFormatter.write_dl for formatting
|
||||
attr_tuples = [
|
||||
(
|
||||
rich_text("[bold]Attribute[/bold]", width=formatter.width),
|
||||
rich_text("[bold]Description[/bold]", width=formatter.width),
|
||||
),
|
||||
*[
|
||||
(
|
||||
attr,
|
||||
f"{osxmetadata.ATTRIBUTES[attr].help} ({osxmetadata.ATTRIBUTES[attr].constant})",
|
||||
)
|
||||
for attr in EXTENDED_ATTRIBUTE_NAMES
|
||||
],
|
||||
)
|
||||
]
|
||||
for attr_key in sorted(EXTENDED_ATTRIBUTE_NAMES):
|
||||
# get short and long name
|
||||
attr = MDITEM_ATTRIBUTE_SHORT_NAMES[attr_key]
|
||||
short_name = MDITEM_ATTRIBUTE_DATA[attr]["short_name"]
|
||||
long_name = MDITEM_ATTRIBUTE_DATA[attr]["name"]
|
||||
constant = MDITEM_ATTRIBUTE_DATA[attr]["xattr_constant"]
|
||||
|
||||
# get help text
|
||||
description = MDITEM_ATTRIBUTE_DATA[attr]["description"]
|
||||
type_ = MDITEM_ATTRIBUTE_DATA[attr]["help_type"]
|
||||
attr_help = f"{long_name}; {constant}; {description}; {type_}"
|
||||
|
||||
# add to list
|
||||
attr_tuples.append((short_name, attr_help))
|
||||
|
||||
formatter.write_dl(attr_tuples)
|
||||
formatter.write("\n")
|
||||
formatter.write_text(
|
||||
|
||||
@@ -1440,11 +1440,29 @@ class PhotoInfo:
|
||||
return []
|
||||
|
||||
md = OSXMetaData(path)
|
||||
detected_text = md.get_attribute("osxphotos_detected_text")
|
||||
try:
|
||||
|
||||
def decoder(val):
|
||||
"""Decode value from JSON"""
|
||||
return json.loads(val.decode("utf-8"))
|
||||
|
||||
detected_text = md.get_xattr(
|
||||
"osxphotos.metadata:detected_text", decode=decoder
|
||||
)
|
||||
except KeyError:
|
||||
detected_text = None
|
||||
if detected_text is None:
|
||||
orientation = self.orientation or None
|
||||
detected_text = detect_text(path, orientation)
|
||||
md.set_attribute("osxphotos_detected_text", detected_text)
|
||||
|
||||
def encoder(obj):
|
||||
"""Encode value as JSON"""
|
||||
val = json.dumps(obj)
|
||||
return val.encode("utf-8")
|
||||
|
||||
md.set_xattr(
|
||||
"osxphotos.metadata:detected_text", detected_text, encode=encoder
|
||||
)
|
||||
return detected_text
|
||||
|
||||
@property
|
||||
|
||||
Reference in New Issue
Block a user