Skip to content

Commit 29be0a6

Browse files
committed
feat: add option to ignore dir content via .ts_noindex file
feat: multiple directories per library
1 parent 6e5a1a0 commit 29be0a6

36 files changed

+725
-305
lines changed

.github/workflows/mypy.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
run: |
2626
python -m pip install --upgrade uv
2727
uv pip install --system -r requirements.txt
28-
uv pip install --system mypy==1.11.2
28+
uv pip install --system mypy==1.13.0
2929
mkdir tagstudio/.mypy_cache
3030
3131
- uses: tsuyoshicho/action-mypy@v4

requirements-dev.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ ruff==0.6.4
22
pre-commit==3.7.0
33
pytest==8.2.0
44
Pyinstaller==6.6.0
5-
mypy==1.11.2
5+
mypy==1.13.0
66
syrupy==4.7.1
77
pytest-qt==4.4.0
88
pytest-cov==5.0.0

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ Pillow==10.3.0
44
PySide6==6.7.1
55
PySide6_Addons==6.7.1
66
PySide6_Essentials==6.7.1
7-
typing_extensions>=3.10.0.0,<=4.11.0
7+
typing_extensions==4.12.2
88
ujson>=5.8.0,<=5.9.0
99
numpy==1.26.4
1010
rawpy==0.21.0
1111
pillow-heif==0.16.0
1212
chardet==5.2.0
1313
structlog==24.4.0
14-
SQLAlchemy==2.0.34
14+
SQLAlchemy==2.0.36
1515
pydub==0.25.1
1616
mutagen==1.47.0
1717
numpy==1.26.4

tagstudio/src/core/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
VERSION_BRANCH: str = "EXPERIMENTAL" # Usually "" or "Pre-Release"
33

44
# The folder & file names where TagStudio keeps its data relative to a library.
5-
TS_FOLDER_NAME: str = ".TagStudio"
65
BACKUP_FOLDER_NAME: str = "backups"
76
COLLAGE_FOLDER_NAME: str = "collages"
7+
TS_FOLDER_NOINDEX: str = ".ts_noindex"
88

99
FONT_SAMPLE_TEXT: str = (
1010
"""ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!?@$%(){}[]"""

tagstudio/src/core/driver.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import structlog
44
from PySide6.QtCore import QSettings
5-
from src.core.constants import TS_FOLDER_NAME
65
from src.core.enums import SettingItems
76
from src.core.library.alchemy.library import LibraryStatus
87

@@ -14,27 +13,26 @@ class DriverMixin:
1413

1514
def evaluate_path(self, open_path: str | None) -> LibraryStatus:
1615
"""Check if the path of library is valid."""
17-
library_path: Path | None = None
16+
storage_path: Path | None = None
1817
if open_path:
19-
library_path = Path(open_path)
20-
if not library_path.exists():
18+
storage_path = Path(open_path)
19+
if not storage_path.exists():
2120
logger.error("Path does not exist.", open_path=open_path)
2221
return LibraryStatus(success=False, message="Path does not exist.")
2322
elif self.settings.value(
2423
SettingItems.START_LOAD_LAST, defaultValue=True, type=bool
2524
) and self.settings.value(SettingItems.LAST_LIBRARY):
26-
library_path = Path(str(self.settings.value(SettingItems.LAST_LIBRARY)))
27-
if not (library_path / TS_FOLDER_NAME).exists():
25+
storage_path = Path(str(self.settings.value(SettingItems.LAST_LIBRARY)))
26+
if not storage_path.exists():
2827
logger.error(
2928
"TagStudio folder does not exist.",
30-
library_path=library_path,
31-
ts_folder=TS_FOLDER_NAME,
29+
storage_path=storage_path,
3230
)
3331
self.settings.setValue(SettingItems.LAST_LIBRARY, "")
3432
# dont consider this a fatal error, just skip opening the library
35-
library_path = None
33+
storage_path = None
3634

3735
return LibraryStatus(
3836
success=True,
39-
library_path=library_path,
37+
storage_path=storage_path,
4038
)

tagstudio/src/core/enums.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
from uuid import uuid4
44

55

6-
class SettingItems(str, enum.Enum):
6+
class SettingItems(enum.StrEnum):
77
"""List of setting item names."""
88

99
START_LOAD_LAST = "start_load_last"
10-
LAST_LIBRARY = "last_library"
10+
LAST_LIBRARY = "last_storage"
1111
LIBS_LIST = "libs_list"
1212
WINDOW_SHOW_LIBS = "window_show_libs"
13+
WINDOW_SHOW_DIRS = "window_show_dirs"
1314
AUTOPLAY = "autoplay_videos"
1415

1516

@@ -25,12 +26,6 @@ class Theme(str, enum.Enum):
2526
COLOR_DISABLED_BG = "#65440D12"
2627

2728

28-
class OpenStatus(enum.IntEnum):
29-
NOT_FOUND = 0
30-
SUCCESS = 1
31-
CORRUPTED = 2
32-
33-
3429
class MacroID(enum.Enum):
3530
AUTOFILL = "autofill"
3631
SIDECAR = "sidecar"
@@ -64,4 +59,4 @@ class LibraryPrefs(DefaultEnum):
6459
IS_EXCLUDE_LIST = True
6560
EXTENSION_LIST: list[str] = [".json", ".xmp", ".aae"]
6661
PAGE_SIZE: int = 500
67-
DB_VERSION: int = 2
62+
LIBRARY_NAME: str = "TS Library"

tagstudio/src/core/library/alchemy/enums.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import enum
2-
from dataclasses import dataclass
2+
from dataclasses import dataclass, field
33
from pathlib import Path
44

55

@@ -50,17 +50,20 @@ class SearchMode(enum.IntEnum):
5050
OR = 1
5151

5252

53-
class ItemType(enum.Enum):
54-
ENTRY = 0
55-
COLLATION = 1
56-
TAG_GROUP = 2
53+
class ItemType(enum.IntEnum):
54+
NONE = 0
55+
ENTRY = 1
56+
COLLATION = 2
57+
TAG_GROUP = 3
5758

5859

5960
@dataclass
6061
class FilterState:
6162
"""Represent a state of the Library grid view."""
6263

6364
# these should remain
65+
include_folders: set[int] = field(default_factory=set)
66+
exclude_folders: set[int] = field(default_factory=set)
6467
page_index: int | None = None
6568
page_size: int | None = None
6669
search_mode: SearchMode = SearchMode.AND # TODO - actually implement this
@@ -81,6 +84,13 @@ class FilterState:
8184
# a generic query to be parsed
8285
query: str | None = None
8386

87+
def toggle_folder(self, folder_id: int):
88+
# check if any filter is active and adjust that one, as they are disjunctive
89+
if self.include_folders:
90+
self.include_folders ^= {folder_id}
91+
else:
92+
self.exclude_folders ^= {folder_id}
93+
8494
def __post_init__(self):
8595
# strip values automatically
8696
if query := (self.query and self.query.strip()):
@@ -109,6 +119,9 @@ def __post_init__(self):
109119
self.name = self.name and self.name.strip()
110120
self.id = int(self.id) if str(self.id).isnumeric() else self.id
111121

122+
if self.include_folders and self.exclude_folders:
123+
raise ValueError("Can't combine include_folders and exclude_folders.")
124+
112125
if self.page_index is None:
113126
self.page_index = 0
114127
if self.page_size is None:

0 commit comments

Comments
 (0)