w22
This commit is contained in:
@@ -4,7 +4,8 @@
|
||||
"Bash(.venv\\\\Scripts\\\\python.exe 10_collect_metadata.py --source demo_fotky --limit 3 --dry-run)",
|
||||
"Bash(PGPASSWORD=\"\" psql -h 192.168.1.76 -p 5432 -U vladimir.buzalka -d fotky_buzalkovi -c \"\\\\dt\")",
|
||||
"PowerShell($env:PGPASSWORD = \"\"; psql -h 192.168.1.76 -p 5432 -U vladimir.buzalka -d fotky_buzalkovi -c \"\\\\dt\" 2>&1)",
|
||||
"PowerShell(python -c \"import psycopg2; conn = psycopg2.connect\\(host='192.168.1.76', port=5432, user='vladimir.buzalka', password='', dbname='fotky_buzalkovi'\\); cur = conn.cursor\\(\\); cur.execute\\(\\\\\"SELECT table_name FROM information_schema.tables WHERE table_schema='public' ORDER BY table_name\\\\\"\\); rows = cur.fetchall\\(\\); print\\([r[0] for r in rows]\\); conn.close\\(\\)\" 2>&1)"
|
||||
"PowerShell(python -c \"import psycopg2; conn = psycopg2.connect\\(host='192.168.1.76', port=5432, user='vladimir.buzalka', password='', dbname='fotky_buzalkovi'\\); cur = conn.cursor\\(\\); cur.execute\\(\\\\\"SELECT table_name FROM information_schema.tables WHERE table_schema='public' ORDER BY table_name\\\\\"\\); rows = cur.fetchall\\(\\); print\\([r[0] for r in rows]\\); conn.close\\(\\)\" 2>&1)",
|
||||
"PowerShell(Rename-Item -Path \"C:\\\\Users\\\\vlado\\\\PycharmProjects\\\\fotkyBuzalkovi\\\\00 PictureCollector\\\\collect_pictures.py\" -NewName \"collect_pictures_linux.py\")"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+31
-1
@@ -11,6 +11,21 @@ Tabulky:
|
||||
|
||||
Bezpečné pro opakované spuštění (pokračuje tam, kde skončilo).
|
||||
Bezpečné pro souběžný běh na více strojích (ON CONFLICT v SQL).
|
||||
|
||||
Předpoklad pro hostname a ukládání cest do DB:
|
||||
Skript běží na dvou Unraid serverech s různým přístupem k zálohovacímu share:
|
||||
|
||||
hostname = Tower1 (druhý Unraid server — vlastník zálohy):
|
||||
Zálohovací share je nativní: /mnt/user/ZalohaVsechObrazku/
|
||||
Cesta se ukládá do DB beze změny — je již v kanonickém tvaru.
|
||||
|
||||
hostname = tower (první Unraid server — zálohu zapisuje přes remote mount):
|
||||
Zálohovací share je mountován jako: /mnt/remotes/TOWER1.LAN_ZalohaVsechObrazku/
|
||||
Fyzické kopírování probíhá přes tento remote mount, ale do DB se ukládá
|
||||
vždy nativní Tower1 cesta: /mnt/user/ZalohaVsechObrazku/...
|
||||
(PATH_NORMALIZE_MAP zajistí přepis prefixu před INSERTem).
|
||||
|
||||
Tím jsou cesty v DB jednotné bez ohledu na to, který server zálohu pořídil.
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -45,6 +60,12 @@ ZALOHA_DIR_MAP = {
|
||||
}
|
||||
ZALOHA_DIR_DEFAULT = Path("/mnt/remotes/TOWER1.LAN_ZalohaVsechObrazku")
|
||||
|
||||
# Normalizace cesty pro DB — vždy ukládáme nativní Tower1 cestu,
|
||||
# bez ohledu na to, přes jaký mount skript soubor fyzicky zapsal.
|
||||
PATH_NORMALIZE_MAP = {
|
||||
"/mnt/remotes/TOWER1.LAN_ZalohaVsechObrazku": "/mnt/user/ZalohaVsechObrazku",
|
||||
}
|
||||
|
||||
EXCLUDED_DIR_NAMES_LOWER = {"zalohavsechobrazku", "zálohavsechobrázku", "zálohavsechobrazku"}
|
||||
|
||||
BATCH_SIZE = 500
|
||||
@@ -119,6 +140,15 @@ def compute_blake3(path: Path, chunk: int = 1 << 20) -> str:
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def normalize_path_for_db(path: Path) -> str:
|
||||
"""Převede fyzickou cestu zálohy na nativní Tower1 cestu pro uložení do DB."""
|
||||
s = str(path)
|
||||
for remote, native in PATH_NORMALIZE_MAP.items():
|
||||
if s.startswith(remote):
|
||||
return native + s[len(remote):]
|
||||
return s
|
||||
|
||||
|
||||
def dest_path_for(source: Path, hostname: str) -> Path:
|
||||
try:
|
||||
relative = source.relative_to(SOURCE_BASE)
|
||||
@@ -237,7 +267,7 @@ def process(conn, hostname):
|
||||
t_copy = time.perf_counter()
|
||||
|
||||
cur = conn.cursor()
|
||||
cur.execute(SQL_INSERT_ZALOHA, (hash_val, str(dest), source.name, velikost))
|
||||
cur.execute(SQL_INSERT_ZALOHA, (hash_val, normalize_path_for_db(dest), source.name, velikost))
|
||||
row = cur.fetchone()
|
||||
if row:
|
||||
zaloha_id = row[0]
|
||||
@@ -10,6 +10,14 @@ Příklad: \\Tower1\ZalohaVsechObrazku\JMENO-PC\D\Foto\2023\img.jpg
|
||||
|
||||
Bezpečné pro opakované spuštění (pokračuje tam kde skončilo).
|
||||
Bezpečné pro souběžný běh na více strojích (ON CONFLICT v SQL).
|
||||
|
||||
Předpoklad pro ukládání cest do DB:
|
||||
Ať už je hostname Windows stroje jakýkoliv, Tower1 (druhý Unraid server)
|
||||
je vždy dostupný jako \\Tower1\ZalohaVsechObrazku\...
|
||||
Fyzické kopírování probíhá přes tuto UNC cestu, ale do DB se ukládá
|
||||
vždy nativní Linux cesta Tower1, tj. /mnt/user/ZalohaVsechObrazku/...
|
||||
(\\Tower1 → /mnt/user, zpětná lomítka → dopředná lomítka).
|
||||
Tím jsou cesty v DB jednotné bez ohledu na to, který stroj zálohu pořídil.
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -39,6 +47,19 @@ DB_CONFIG = {
|
||||
|
||||
ZALOHA_DIR = Path(r"\\Tower1\ZalohaVsechObrazku")
|
||||
|
||||
# Normalizace cesty pro DB — Windows UNC cestu převedeme na nativní Tower1 Linux cestu.
|
||||
# \\Tower1\ZalohaVsechObrazku\... → /mnt/user/ZalohaVsechObrazku/...
|
||||
WINDOWS_UNC_PREFIX = r"\\Tower1"
|
||||
LINUX_NATIVE_PREFIX = "/mnt/user"
|
||||
|
||||
|
||||
def normalize_path_for_db(path: Path) -> str:
|
||||
"""Převede \\Tower1\ZalohaVsechObrazku\... na /mnt/user/ZalohaVsechObrazku/..."""
|
||||
s = str(path)
|
||||
if s.startswith(WINDOWS_UNC_PREFIX):
|
||||
return LINUX_NATIVE_PREFIX + s[len(WINDOWS_UNC_PREFIX):].replace("\\", "/")
|
||||
return s
|
||||
|
||||
JPEG_EXTENSIONS = {".jpg", ".jpeg"}
|
||||
|
||||
EXCLUDED_DIR_NAMES_LOWER = {
|
||||
@@ -244,7 +265,7 @@ def process(conn, hostname, drives):
|
||||
t_copy = time.perf_counter()
|
||||
|
||||
cur = conn.cursor()
|
||||
cur.execute(SQL_INSERT_ZALOHA, (hash_val, str(dest), source.name, velikost))
|
||||
cur.execute(SQL_INSERT_ZALOHA, (hash_val, normalize_path_for_db(dest), source.name, velikost))
|
||||
row = cur.fetchone()
|
||||
if row:
|
||||
zaloha_id = row[0]
|
||||
|
||||
@@ -347,7 +347,13 @@ def iter_photos(source: Path):
|
||||
dirs[:] = [d for d in dirs if not d.startswith(".")]
|
||||
for fname in files:
|
||||
if Path(fname).suffix.lower() in SUPPORTED_EXTENSIONS:
|
||||
yield Path(root) / fname
|
||||
p = Path(root) / fname
|
||||
# Přeskočit symlinky které vedou mimo share (WinError 3 - \\mnt\user\...)
|
||||
try:
|
||||
p.stat()
|
||||
except OSError:
|
||||
continue
|
||||
yield p
|
||||
|
||||
|
||||
def count_photos(source: Path) -> int:
|
||||
|
||||
@@ -63,8 +63,14 @@ DB_CONFIG = {
|
||||
}
|
||||
|
||||
# Překlad: Linux NFS cesta (jak je uložena v DB) → Windows UNC
|
||||
LINUX_PREFIX = "/mnt/remotes/TOWER1.LAN_ZalohaVsechObrazku"
|
||||
WINDOWS_UNC = "//Tower1/ZalohaVsechObrazku"
|
||||
# Záznamy v DB mohou mít různé Linux prefixy podle toho, odkud byl scan spuštěn.
|
||||
PATH_MAPPINGS = [
|
||||
("/mnt/remotes/TOWER1.LAN_ZalohaVsechObrazku", "//Tower1/ZalohaVsechObrazku"),
|
||||
("/mnt/user/ZalohaVsechObrazku", "//Tower1/ZalohaVsechObrazku"),
|
||||
]
|
||||
# Zpětná kompatibilita
|
||||
LINUX_PREFIX = PATH_MAPPINGS[0][0]
|
||||
WINDOWS_UNC = PATH_MAPPINGS[0][1]
|
||||
|
||||
SUPPORTED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".heic", ".tiff", ".tif", ".webp", ".bmp"}
|
||||
|
||||
@@ -93,10 +99,11 @@ MIME_MAP = {
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def linux_to_windows(linux_path: str) -> Path:
|
||||
"""Převede /mnt/remotes/TOWER1.LAN_ZalohaVsechObrazku/... na //Tower1/ZalohaVsechObrazku/..."""
|
||||
if linux_path.startswith(LINUX_PREFIX):
|
||||
rel = linux_path[len(LINUX_PREFIX):] # začíná /
|
||||
return Path(WINDOWS_UNC + rel)
|
||||
"""Převede Linux NFS cestu na Windows UNC podle tabulky PATH_MAPPINGS."""
|
||||
for linux_prefix, windows_unc in PATH_MAPPINGS:
|
||||
if linux_path.startswith(linux_prefix):
|
||||
rel = linux_path[len(linux_prefix):] # začíná /
|
||||
return Path(windows_unc + rel)
|
||||
return Path(linux_path)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user