Compare commits

..

6 Commits

Author SHA1 Message Date
Travis Abendshien fdcb3ce65f ci(tests): remove macOS pytest runner 2026-07-08 22:46:39 -07:00
Travis Abendshien e3b73fa4d4 ci: enforce single quotes in github yaml files 2026-07-08 22:40:09 -07:00
Travis Abendshien 3b6980db6e docs: update location of tagstudio.spec 2026-07-08 15:10:09 -07:00
Travis Abendshien 99170e1c8b ci: remove symlinked CHANGELONG.md from build_docs.yml paths 2026-07-08 15:08:54 -07:00
Xarvex be8d96976b feat(ci)!: rework workflows and build processes
All Python setups route through one local action, and checks are much
more conditional. There is more to be done, but this is a significant
improvement in processing time and redundancy.

As well, nightly builds are made (though not made as GitHub releases..
yet).
2026-07-07 17:48:18 -05:00
Xarvex 91d2147598 chore(ci): move spec-file into scripts 2026-07-07 17:48:15 -05:00
11 changed files with 82 additions and 131 deletions
+4 -6
View File
@@ -8,13 +8,12 @@ on:
paths: &on_paths
- .github/actions/setup-python/action.yml
- .github/workflows/checks_python.yml
- src/**.json
- tests/**
- .editorconfig
- pyproject.toml
- pyrightconfig.json
- pytest.ini
- uv.lock
- '**.py'
- '**.pyi'
push:
paths: *on_paths
workflow_dispatch:
@@ -51,13 +50,12 @@ jobs:
- pyproject.toml
- uv.lock
- '**.py'
- '**.pyi'
pyright:
- .github/actions/setup-python/action.yml
- pyrightconfig.json
pytest:
- .github/actions/setup-python/action.yml
- src/**.json
- tests/**
- pytest.ini
ruff:
- .editorconfig
+4 -3
View File
@@ -3,10 +3,11 @@
# TagStudio: A User-Focused Photo & File Management System
[![Downloads](https://img.shields.io/github/downloads/TagStudioDev/TagStudio/total.svg)](https://github.com/TagStudioDev/TagStudio/releases)
[![Downloads](https://img.shields.io/github/downloads/TagStudioDev/TagStudio/total.svg?maxAge=2592001)](https://github.com/TagStudioDev/TagStudio/releases)
[![Translations](https://hosted.weblate.org/widget/tagstudio/strings/svg-badge.svg)](https://hosted.weblate.org/projects/tagstudio/strings/)
[![REUSE Status](https://api.reuse.software/badge/github.com/TagStudioDev/TagStudio)](https://api.reuse.software/info/github.com/TagStudioDev/TagStudio)
[![Python Checks](https://github.com/TagStudioDev/TagStudio/actions/workflows/checks_python.yml/badge.svg)](https://github.com/TagStudioDev/TagStudio/actions/workflows/checks_python.yml)
[![PyTest](https://github.com/TagStudioDev/TagStudio/actions/workflows/pytest.yaml/badge.svg)](https://github.com/TagStudioDev/TagStudio/actions/workflows/pytest.yaml)
[![MyPy](https://github.com/TagStudioDev/TagStudio/actions/workflows/mypy.yaml/badge.svg)](https://github.com/TagStudioDev/TagStudio/actions/workflows/mypy.yaml)
[![Ruff](https://github.com/TagStudioDev/TagStudio/actions/workflows/ruff.yaml/badge.svg)](https://github.com/TagStudioDev/TagStudio/actions/workflows/ruff.yaml)
<p align="center">
<img width="60%" src="src/tagstudio/resources/qt/images/tagstudio_logo-text_color.png">
+2 -8
View File
@@ -9,11 +9,7 @@ toc_depth: 2
# :material-script-text: Changelog
## 9.6.1 <small>July 9th, 2026</small>
### Added
- feat(ui): render .pxd thumbnails by @Sola-ris in #1430
## 9.6.1 <small>July 6th, 2026</small>
### Changed
@@ -34,15 +30,13 @@ toc_depth: 2
#### Internal Changes
- fix(nix): add pyright to devshell by @Computerdores in #1415
- fix(deps): replace optional dependencies with dependency groups by @Xarvex in #1435
- feat(ci)!: complete workflows revamp by @Xarvex in #1437
#### Translations
- **French** updated by @kitsumed
- **Hungarian** updated by @smileyhead
- **Russian** updated by @romandobra
- **Spanish** updated by @JCC1998, @2004milenadiaz-source
- **Spanish** updated by @JCC1998
---
+23 -20
View File
@@ -1,12 +1,12 @@
---
title: Installing
title: Installation
icon: material/download
---
<!-- SPDX-FileCopyrightText: (c) TagStudio Contributors -->
<!-- SPDX-License-Identifier: GPL-3.0-only -->
# :material-download: Installing
# :material-download: Installation
TagStudio provides executable [releases](https://github.com/TagStudioDev/TagStudio/releases) as well as full access to its [source code](https://github.com/TagStudioDev/TagStudio) under the [GPLv3](https://github.com/TagStudioDev/TagStudio/blob/main/LICENSE) license.
@@ -17,8 +17,8 @@ To download executable builds of TagStudio, visit the [Releases](https://github.
TagStudio has builds for :fontawesome-brands-windows: **Windows**, :fontawesome-brands-apple: **macOS** _(Apple Silicon & Intel)_, and :material-penguin: **Linux**. We also offer portable releases for Windows and Linux which are self-contained and easier to move around.
<!-- prettier-ignore -->
!!! info "Optional Dependencies"
You may need to install [optional third-party dependencies](#optional-dependencies) such as [FFmpeg](https://ffmpeg.org/download.html) to use the full feature set of TagStudio.
!!! info "Third-Party Dependencies"
You may need to install [third-party dependencies](#third-party-dependencies) such as [FFmpeg](https://ffmpeg.org/download.html) to use the full feature set of TagStudio.
<!-- prettier-ignore -->
!!! warning ":fontawesome-brands-apple: macOS "Privacy & Security" Popup"
@@ -82,19 +82,6 @@ Some external dependencies are required for TagStudio to execute. Below is a tab
| [qt-multimedia](https://repology.org/project/qt) | required |
| [qt-wayland](https://repology.org/project/qt) | Wayland support |
<!-- prettier-ignore -->
!!! bug "Missing Linux Dependency Example"
An error message such as the following indicates that you're missing the `libxcb-cursor` or `xcb-util-cursor` library, depending on your distro:
```
qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin.
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "/tmp/_MEIayuTiW/cv2/qt/plugins" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: vnc, wayland-egl, offscreen, wayland, linuxfb, minimalegl, eglfs, minimal, vkkhrdisplay, xcb.
Aborted (core dumped)
```
### :material-nix: Nix(OS)
For [Nix(OS)](https://nixos.org/), the TagStudio repository includes a [flake](https://wiki.nixos.org/wiki/Flakes) that provides some outputs such as a development shell and package.
@@ -225,9 +212,7 @@ Finally, `inputs` can be used in a module to add the package to your packages li
Don't forget to rebuild!
## Optional Dependencies
Some TagStudio functionality such as multimedia thumbnails and playback, RAR archive thumbnails, and improved directory scanning performance will require installing optional third-party dependencies. Depending on your system, you may already have one or more of these installed. To check
## Third-Party Dependencies
<!-- prettier-ignore -->
!!! tip
@@ -257,3 +242,21 @@ To generate thumbnails for RAR-based files (like `.cbr`) you'll need an extracto
### ripgrep
A recommended tool to improve the performance of directory scanning is [`ripgrep`](https://github.com/BurntSushi/ripgrep), a Rust-based directory walker that natively integrates with our [`.ts_ignore`](ignore.md) (`.gitignore`-style) pattern matching system for excluding files and directories. Ripgrep is already pre-installed on some Linux distributions and also available from several package managers.
## Common Error Messages
### Could not load the Qt platform plugin "xcb"
If you get an error message like this one:
```
qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin.
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "/tmp/_MEIayuTiW/cv2/qt/plugins" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: vnc, wayland-egl, offscreen, wayland, linuxfb, minimalegl, eglfs, minimal, vkkhrdisplay, xcb.
Aborted (core dumped)
```
Make sure you installed `libxcb-cursor` or `xcb-util-cursor`.
+3 -3
View File
@@ -196,8 +196,8 @@ Migration from the legacy JSON format is provided via a walkthrough when opening
#### Version 202
| Added in Commit | Introduced in Release | Format |
| ---------------------------------------- | ----------------------------------------------------------------------- | ------ |
| 95e2fe7b4449951c385e35a2e13f0c1925f1f98e | [v9.6.1](https://github.com/TagStudioDev/TagStudio/releases/tag/v9.6.1) | SQLite |
| Added in Commit | Introduced in Release | Format |
| --------------- | ----------------------------------------------------------------------- | ------ |
| | [v9.6.1](https://github.com/TagStudioDev/TagStudio/releases/tag/v9.6.1) | SQLite |
- Applies repairs to the `tag_parents` table, removing rows that reference child tags that have been deleted.
+19 -20
View File
@@ -47,7 +47,7 @@ Images will generate thumbnails the first time they are viewed or since the last
### :material-movie-open: Videos
Video thumbnails will default to the closest viable frame from the middle of the video. Both thumbnail generation and video playback in the Preview Panel requires [FFmpeg](install.md#optional-dependencies) installed on your system.
Video thumbnails will default to the closest viable frame from the middle of the video. Both thumbnail generation and video playback in the Preview Panel requires [FFmpeg](install.md#third-party-dependencies) installed on your system.
| Filetype | Extensions | Dependencies |
| --------------------- | ----------------------- | :----------: |
@@ -65,7 +65,7 @@ Video thumbnails will default to the closest viable frame from the middle of the
### :material-sine-wave: Audio
Audio thumbnails will default to embedded cover art (if any) and fallback to generated waveform thumbnails. Audio file playback is supported in the Preview Panel if you have [FFmpeg](install.md#optional-dependencies) installed on your system. Audio waveforms are currently not cached.
Audio thumbnails will default to embedded cover art (if any) and fallback to generated waveform thumbnails. Audio file playback is supported in the Preview Panel if you have [FFmpeg](install.md#third-party-dependencies) installed on your system. Audio waveforms are currently not cached.
| Filetype | Extensions | Dependencies |
| ------------------- | ------------------------ | :----------: |
@@ -82,24 +82,23 @@ Audio thumbnails will default to embedded cover art (if any) and fallback to gen
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" } |
| Clip Studio Paint | `.clip` | Embedded thumbnail |
| 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 |
| Paint.NET | `.pdn` | Embedded thumbnail |
| PDF | `.pdf` | First page render |
| Photoshop | `.psd` | Flattened image render |
| Pixelmator Pro (Apple Creator Studio) | `.pxd` | Embedded thumbnail |
| 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" } |
| Clip Studio Paint | `.clip` | Embedded thumbnail |
| 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 |
| Paint.NET | `.pdn` | 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-archive: Archives
+2 -2
View File
@@ -32,8 +32,9 @@ extra:
nav:
- Home:
- index.md
- Installing:
- Getting Started:
- install.md
- usage.md
- Developers:
- developing.md
- contributing.md
@@ -41,7 +42,6 @@ nav:
- Help:
- help/ffmpeg.md
- Using TagStudio:
- usage.md
- libraries.md
- entries.md
- preview-support.md
+1 -1
View File
@@ -76,7 +76,7 @@ ruff = ["ruff==0.15.17"]
[tool.hatch.build.targets.wheel]
packages = ["src/tagstudio"]
[tool.pytest]
[tool.pytest.ini_options]
qt_api = "pyside6"
pythonpath = ["src"]
filterwarnings = [
+10 -11
View File
@@ -12,14 +12,14 @@ import structlog
logger = structlog.get_logger(__name__)
FILETYPE_EQUIVALENTS = [
{"aif", "aiff", "aifc"},
{"html", "htm", "xhtml", "shtml", "dhtml"},
{"jfif", "jpeg_large", "jpeg", "jpg_large", "jpg"},
{"json", "jsonc", "json5"},
{"md", "markdown", "mkd", "rmd"},
{"tar.gz", "tgz"},
{"xml", "xul"},
{"yaml", "yml"},
set(["aif", "aiff", "aifc"]),
set(["html", "htm", "xhtml", "shtml", "dhtml"]),
set(["jfif", "jpeg_large", "jpeg", "jpg_large", "jpg"]),
set(["json", "jsonc", "json5"]),
set(["md", "markdown", "mkd", "rmd"]),
set(["tar.gz", "tgz"]),
set(["xml", "xul"]),
set(["yaml", "yml"]),
]
@@ -75,7 +75,7 @@ class MediaCategory:
extensions (set[str]): The set of file extensions associated with this category.
Includes leading ".", all lowercase, and does not need to be unique to this category.
is_iana (bool): Represents whether this is an IANA registered category.
is_iana (bool): Represents whether or not this is an IANA registered category.
"""
media_type: MediaType
@@ -257,7 +257,6 @@ class MediaCategories:
".odt",
".pages",
".pdf",
".pxd",
".rtf",
".tex",
".wpd",
@@ -337,7 +336,7 @@ class MediaCategories:
".webp",
}
_INSTALLER_SET: set[str] = {".appx", ".msi", ".msix"}
_IWORK_SET: set[str] = {".key", ".numbers", ".pages"}
_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"}
+13 -22
View File
@@ -623,7 +623,7 @@ class ThumbRenderer(QObject):
image (Image.Image): The image to apply the edge to.
edge (tuple[Image.Image, Image.Image]): The edge images to apply.
Item 0 is the inner highlight, and item 1 is the outer shadow.
faded (bool): Whether to apply a faded version of the edge.
faded (bool): Whether or not to apply a faded version of the edge.
Used for light themes.
"""
opacity: float = 1.0 if not faded else 0.8
@@ -847,7 +847,7 @@ class ThumbRenderer(QObject):
@staticmethod
def _krita_thumb(filepath: Path) -> Image.Image | None:
"""Extract and render a thumbnail for a Krita file.
"""Extract and render a thumbnail for an Krita file.
Args:
filepath (Path): The path of the file.
@@ -1218,20 +1218,14 @@ class ThumbRenderer(QObject):
return im
@staticmethod
def _apple_embedded_thumb(filepath: Path) -> Image.Image | None:
"""Extract and render an apple embedded thumbnail (iWork, Apple Creative Studio).
def _iwork_thumb(filepath: Path) -> Image.Image | None:
"""Extract and render a thumbnail for an Apple iWork (Pages, Numbers, Keynote) file.
Args:
filepath (Path): The path of the file.
"""
thumb_files: list[str] = [
"preview.jpg",
"QuickLook/Preview.heic",
"QuickLook/Thumbnail.jpg",
"QuickLook/Thumbnail.heic",
"QuickLook/Thumbnail.webp",
"QuickLook/Icon.webp",
]
preview_thumb_dir = "preview.jpg"
quicklook_thumb_dir = "QuickLook/Thumbnail.jpg"
im: Image.Image | None = None
def get_image(path: str) -> Image.Image | None:
@@ -1246,10 +1240,10 @@ class ThumbRenderer(QObject):
thumb: Image.Image | None = None
# Check if the file exists in the zip
for thumb_file in thumb_files:
if thumb_file in zip_file.namelist():
thumb = get_image(thumb_file)
break
if preview_thumb_dir in zip_file.namelist():
thumb = get_image(preview_thumb_dir)
elif quicklook_thumb_dir in zip_file.namelist():
thumb = get_image(quicklook_thumb_dir)
else:
logger.error("Couldn't render thumbnail", filepath=filepath)
@@ -1320,7 +1314,7 @@ class ThumbRenderer(QObject):
page_size *= size / page_size.height()
else:
page_size *= size / page_size.width()
# Enlarge image for anti-aliasing
# Enlarge image for antialiasing
scale_factor = 2.5
page_size *= scale_factor
# Render image with no anti-aliasing for speed
@@ -1871,11 +1865,8 @@ class ThumbRenderer(QObject):
):
image = self._open_doc_thumb(_filepath)
# Apple iWork Suite ============================================
elif (
MediaCategories.is_ext_in_category(ext, MediaCategories.IWORK_TYPES)
or ext == ".pxd"
):
image = self._apple_embedded_thumb(_filepath)
elif MediaCategories.is_ext_in_category(ext, MediaCategories.IWORK_TYPES):
image = self._iwork_thumb(_filepath)
# Plain Text ===================================================
elif MediaCategories.is_ext_in_category(
ext, MediaCategories.PLAINTEXT_TYPES, mime_fallback=True
+1 -35
View File
@@ -4,7 +4,6 @@
"about.description": "TagStudio es una aplicación para organizar fotografías y archivos que utiliza un sistema de etiquetas subyacentes centrado en dar libertad y flexibilidad al usuario. Sin programas ni formatos propios, ni un mar de archivos y sin trastornar completamente la estructura de tu sistema de archivos.",
"about.documentation": "Documentación",
"about.module.found": "Encontrado",
"about.modules.title": "Modulos Opcionales",
"about.title": "Acerca de TagStudio",
"about.version": "Versión",
"about.version.latest": "{built_version} (Última versión: {latest_version})",
@@ -69,7 +68,7 @@
"entries.unlinked.remove": "Eliminar Entradas No Vinculadas",
"entries.unlinked.remove_alt": "Quit&ar entradas desvinculadas",
"entries.unlinked.scanning": "Buscando entradas no enlazadas en la biblioteca...",
"entries.unlinked.search_and_relink": "&Buscar && Revincular",
"entries.unlinked.search_and_relink": "&Buscar && volver a vincular",
"entries.unlinked.title": "Corregir entradas no vinculadas",
"entries.unlinked.unlinked_count": "Entradas no vinculadas: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status}<br>{ffprobe}: {ffprobe_status}",
@@ -197,36 +196,6 @@
"json_migration.title.new_lib": "<h2>v9.5+ biblioteca</h2>",
"json_migration.title.old_lib": "<h2>v9.4 biblioteca</h2>",
"landing.open_create_library": "Abrir/Crear biblioteca {shortcut}",
"language.am": "Idioma amhárico",
"language.ceb": "Cebuano",
"language.cs": "Checo",
"language.da": "Danés",
"language.de": "Alemán",
"language.el": "Griego",
"language.en": "Inglés",
"language.es": "Español",
"language.fi": "Finlandés",
"language.fil": "Filipino",
"language.fr": "Francés",
"language.hu": "Húngaro",
"language.is": "Islandés",
"language.it": "Italiano",
"language.ja": "Japonés",
"language.nb_NO": "Noruego (bokmål)",
"language.nl": "Neerlandés",
"language.pl": "Polaco",
"language.pt": "Portugués",
"language.pt_BR": "Portugués (Brasil)",
"language.qpv": "Viossa",
"language.ro": "Rumano",
"language.ru": "Ruso",
"language.sv": "Sueco",
"language.ta": "Tamil",
"language.th": "Tailandés",
"language.tok": "Toki Pona",
"language.tr": "Turco",
"language.zh_Hans": "Chino (simplificado)",
"language.zh_Hant": "Chino (tradicional)",
"library.missing": "Falta la ubicación",
"library.name": "Biblioteca",
"library.refresh.scanning.plural": "Escaneando directorios en busca de nuevos archivos...\n{searched_count} archivos buscados, {found_count} nuevos archivos encontrados",
@@ -308,7 +277,6 @@
"select.all": "Seleccionar todo",
"select.clear": "Borrar selección",
"select.inverse": "Invertir selección",
"settings.appearance": "Apariencia",
"settings.cached_thumb_resolution.label": "Resolución Miniaturas de vídeo en caché",
"settings.clear_thumb_cache.title": "Borrar cache de las miniaturas",
"settings.dateformat.english": "Inglés",
@@ -325,8 +293,6 @@
"settings.infinite_scroll": "Desplazamiento infinito",
"settings.language": "Idioma",
"settings.library": "Ajustes de la biblioteca",
"settings.localization": "Localización",
"settings.media": "Contenido",
"settings.open_library_on_start": "Abrir biblioteca al iniciar",
"settings.page_size": "Tamaño de la página",
"settings.restart_required": "Por favor, reinicia TagStudio para que se los cambios surtan efecto.",