diff --git a/docs/library/index.md b/docs/library/index.md index 0b7d6718b..42e77af34 100644 --- a/docs/library/index.md +++ b/docs/library/index.md @@ -86,20 +86,21 @@ Audio thumbnails will default to embedded cover art (if any) andfallback to gene Preview support for office documents or well-known project file formats varies by the format and whether or not embedded thumbnails are available to be read from. OpenDocument-based files are typically supported. -| Filetype | Extensions | Preview Type | -| ----------------------------- | --------------------- | -------------------------------------------------------------------------- | -| Blender | `.blend`, `.blend<#>` | Embedded thumbnail :material-alert-circle:{ title="If available in file" } | -| Keynote (Apple iWork) | `.key` | Embedded thumbnail | -| Krita[^3] | `.kra`, `.krz` | Embedded thumbnail :material-alert-circle:{ title="If available in file" } | -| MuseScore | `.mscz` | Embedded thumbnail :material-alert-circle:{ title="If available in file" } | -| Numbers (Apple iWork) | `.numbers` | Embedded thumbnail | -| OpenDocument Presentation | `.odp`, `.fodp` | Embedded thumbnail | -| OpenDocument Spreadsheet | `.ods`, `.fods` | Embedded thumbnail | -| OpenDocument Text | `.odt`, `.fodt` | Embedded thumbnail | -| Pages (Apple iWork) | `.pages` | Embedded thumbnail | -| PDF | `.pdf` | First page render | -| Photoshop | `.psd` | Flattened image render | -| PowerPoint (Microsoft Office) | `.pptx`, `.ppt` | Embedded thumbnail :material-alert-circle:{ title="If available in file" } | +| Filetype | Extensions | Preview Type | +| ------------------------------------ | --------------------- | -------------------------------------------------------------------------- | +| Blender | `.blend`, `.blend<#>` | Embedded thumbnail :material-alert-circle:{ title="If available in file" } | +| Keynote (Apple iWork) | `.key` | Embedded thumbnail | +| Krita[^3] | `.kra`, `.krz` | Embedded thumbnail :material-alert-circle:{ title="If available in file" } | +| Mdipack (FireAlpaca, Medibang Paint) | `.mdp` | Embedded thumbnail | +| MuseScore | `.mscz` | Embedded thumbnail :material-alert-circle:{ title="If available in file" } | +| Numbers (Apple iWork) | `.numbers` | Embedded thumbnail | +| OpenDocument Presentation | `.odp`, `.fodp` | Embedded thumbnail | +| OpenDocument Spreadsheet | `.ods`, `.fods` | Embedded thumbnail | +| OpenDocument Text | `.odt`, `.fodt` | Embedded thumbnail | +| Pages (Apple iWork) | `.pages` | Embedded thumbnail | +| PDF | `.pdf` | First page render | +| Photoshop | `.psd` | Flattened image render | +| PowerPoint (Microsoft Office) | `.pptx`, `.ppt` | Embedded thumbnail :material-alert-circle:{ title="If available in file" } | ### :material-book: eBooks diff --git a/src/tagstudio/core/media_types.py b/src/tagstudio/core/media_types.py index 8659c389d..4988b7980 100644 --- a/src/tagstudio/core/media_types.py +++ b/src/tagstudio/core/media_types.py @@ -46,6 +46,7 @@ class MediaType(str, Enum): INSTALLER = "installer" IWORK = "iwork" MATERIAL = "material" + MDIPACK = "mdipack" MODEL = "model" OPEN_DOCUMENT = "open_document" PACKAGE = "package" @@ -335,6 +336,7 @@ class MediaCategories: _INSTALLER_SET: set[str] = {".appx", ".msi", ".msix"} _IWORK_SET: set[str] = {".key", ".pages", ".numbers"} _MATERIAL_SET: set[str] = {".mtl"} + _MDIPACK_SET: set[str] = {".mdp"} _MODEL_SET: set[str] = {".3ds", ".fbx", ".obj", ".stl"} _OPEN_DOCUMENT_SET: set[str] = { ".fodg", @@ -536,6 +538,12 @@ class MediaCategories: is_iana=False, name="material", ) + MDIPACK_TYPES = MediaCategory( + media_type=MediaType.MDIPACK, + extensions=_MDIPACK_SET, + is_iana=False, + name="mdipack", + ) MODEL_TYPES = MediaCategory( media_type=MediaType.MODEL, extensions=_MODEL_SET, @@ -640,6 +648,7 @@ class MediaCategories: INSTALLER_TYPES, IWORK_TYPES, MATERIAL_TYPES, + MDIPACK_TYPES, MODEL_TYPES, OPEN_DOCUMENT_TYPES, PACKAGE_TYPES, diff --git a/src/tagstudio/qt/previews/renderer.py b/src/tagstudio/qt/previews/renderer.py index f47d534ac..eb8c18939 100644 --- a/src/tagstudio/qt/previews/renderer.py +++ b/src/tagstudio/qt/previews/renderer.py @@ -7,9 +7,11 @@ import hashlib import math import os +import struct import tarfile import xml.etree.ElementTree as ET import zipfile +import zlib from copy import deepcopy from io import BytesIO from pathlib import Path @@ -1378,6 +1380,48 @@ def _video_thumb(filepath: Path) -> Image.Image | None: logger.error("Couldn't render thumbnail", filepath=filepath, error=type(e).__name__) return im + @staticmethod + def _mdp_thumb(filepath: Path) -> Image.Image | None: + """Extract the thumbnail from a .mdp file. + + Args: + filepath (Path): The path of the .mdp file. + + Returns: + Image: The embedded thumbnail. + """ + im: Image.Image | None = None + try: + with open(filepath, "rb") as f: + magic = struct.unpack("<7sx", f.read(8))[0] + if magic != b"mdipack": + return im + + bin_header = struct.unpack("