Merge remote-tracking branch 'origin/master'

This commit is contained in:
2026-01-05 06:33:28 +01:00
31 changed files with 2216537 additions and 13 deletions

17
.gitignore vendored
View File

@@ -1,14 +1,7 @@
# PyCharm / IntelliJ .venv/*
.idea/ .idea/
# Python
__pycache__/ __pycache__/
*.pyc # Neignorovat tyto typy
*.pyo !*.jsonl
*.pyd !*.txt
*.log !*.log
# Virtualenv
.venv/
# created by virtualenv automatically
.venv/Lib

54807
1_NAHRAT_NA_SERVER.txt Normal file

File diff suppressed because it is too large Load Diff

2099
2_JIZ_EXISTUJI_JINDE.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
import fitz import fitz
from pathlib import Path from pathlib import Path
BASE_DIR = Path(r"z:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeFlattenStamp") BASE_DIR = Path(r"u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeFlattenStamp")
def flatten_pdf_rasterize(input_pdf: Path): def flatten_pdf_rasterize(input_pdf: Path):
print(f"Processing: {input_pdf.name}") print(f"Processing: {input_pdf.name}")

View File

@@ -0,0 +1,74 @@
import fitz
from pathlib import Path
import platform
import sys
import tempfile
import os
HOSTNAME = platform.node().upper()
if HOSTNAME in {"SESTRA", "POHODA"}:
DROPBOX_DRIVE = Path(r"Z:\\")
elif HOSTNAME == "Z230":
DROPBOX_DRIVE = Path(r"U:\\")
else:
print(f"❌ Unknown computer name: {HOSTNAME}")
sys.exit(1)
BASE_DIR = (
DROPBOX_DRIVE
/ "Dropbox"
/ "Ordinace"
/ "Dokumentace_ke_zpracování"
/ "AdobeFlattenStamp"
)
def flatten_pdf_rasterize_overwrite(input_pdf: Path):
print(f"Processing: {input_pdf.name}")
doc = fitz.open(input_pdf)
new_doc = fitz.open()
for page in doc:
pix = page.get_pixmap(dpi=400)
new_page = new_doc.new_page(
width=page.rect.width,
height=page.rect.height
)
new_page.insert_image(new_page.rect, pixmap=pix)
# safe overwrite
with tempfile.NamedTemporaryFile(
suffix=".pdf",
delete=False,
dir=input_pdf.parent
) as tmp:
tmp_path = Path(tmp.name)
new_doc.save(tmp_path, deflate=True)
new_doc.close()
doc.close()
os.replace(tmp_path, input_pdf)
print(f" ✔ Overwritten: {input_pdf.name}")
def main():
print(f"🖥 Running on: {HOSTNAME}")
print(f"📁 Base directory: {BASE_DIR}")
if not BASE_DIR.exists():
print("❌ Base directory does not exist!")
sys.exit(1)
pdfs = list(BASE_DIR.glob("*.pdf"))
if not pdfs:
print("No PDF files found.")
return
for pdf in pdfs:
flatten_pdf_rasterize_overwrite(pdf)
print("\n✅ All files processed and originals overwritten.")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,145 @@
import fitz # PyMuPDF
import pytesseract
from PIL import Image
import io
import os
import re
# --- NASTAVENÍ ---
INPUT_FOLDER = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller'
OUTPUT_FOLDER = os.path.join(INPUT_FOLDER, '_HOTOVO_ULTIMATE')
# Cesta k Tesseractu
PATH_TO_TESSERACT = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
# 1. Jak moc "ošklivý" (malý) má být viditelný obrázek?
VISUAL_DPI = 150
VISUAL_THRESHOLD = 150
# 2. Jak kvalitní má být předloha pro čtení (OCR)?
OCR_DPI = 300
def setup_tesseract():
if not os.path.exists(PATH_TO_TESSERACT):
print(f"CHYBA: Tesseract nenalezen na: {PATH_TO_TESSERACT}")
return False
pytesseract.pytesseract.tesseract_cmd = PATH_TO_TESSERACT
return True
def get_rc_from_text(text):
"""Najde RČ v textu a vrátí ho bez lomítka."""
# Hledá formát: 6 čísel, volitelně lomítko/mezera, 3-4 čísla
matches = re.findall(r'\b(\d{6})\s*[\/]?\s*(\d{3,4})\b', text)
for head, tail in matches:
full_rc = f"{head}{tail}"
# Základní kontrola délky a čísel
if len(full_rc) in [9, 10] and full_rc.isdigit():
return full_rc
return None
def process_ultimate_method():
if not setup_tesseract():
return
if not os.path.exists(OUTPUT_FOLDER):
os.makedirs(OUTPUT_FOLDER)
files = [f for f in os.listdir(INPUT_FOLDER) if f.lower().endswith('.pdf')]
print(f"Startuji 'ULTIMATE' zpracování {len(files)} souborů.")
print("-" * 70)
for filename in files:
input_path = os.path.join(INPUT_FOLDER, filename)
try:
print(f"Zpracovávám: {filename} ...")
doc_src = fitz.open(input_path)
final_doc = fitz.open()
detected_rc = None
for page_num, page in enumerate(doc_src):
# --- KROK A: OCR (Vysoká kvalita pro čtení) ---
# 1. Vyrenderujeme kvalitní obrázek pro Tesseract
mat_ocr = fitz.Matrix(OCR_DPI / 72, OCR_DPI / 72)
pix_ocr = page.get_pixmap(matrix=mat_ocr, colorspace=fitz.csGRAY)
img_ocr = Image.frombytes("L", [pix_ocr.width, pix_ocr.height], pix_ocr.samples)
# 2. Tesseract vytvoří PDF stránku (Text + Velký obrázek)
pdf_bytes = pytesseract.image_to_pdf_or_hocr(img_ocr, extension='pdf', lang='ces')
# 3. Otevřeme tuto stránku v paměti
ocr_page_doc = fitz.open("pdf", pdf_bytes)
ocr_page = ocr_page_doc[0]
# Přečteme text pro hledání RČ
if not detected_rc:
text_content = ocr_page.get_text()
detected_rc = get_rc_from_text(text_content)
# --- KROK B: Visual (Nízká kvalita pro oči/úsporu) ---
# 1. Vyrenderujeme malý obrázek
mat_vis = fitz.Matrix(VISUAL_DPI / 72, VISUAL_DPI / 72)
pix_vis = page.get_pixmap(matrix=mat_vis, colorspace=fitz.csGRAY)
img_vis = Image.frombytes("L", [pix_vis.width, pix_vis.height], pix_vis.samples)
# 2. Binarizace (Threshold)
img_vis_bw = img_vis.point(lambda x: 255 if x > VISUAL_THRESHOLD else 0, mode='1')
# 3. Uložíme do bufferu
buffer_vis = io.BytesIO()
img_vis_bw.save(buffer_vis, format="PNG", optimize=True)
# --- KROK C: Výměna (The Switch) ---
# 1. Smažeme velký obrázek z Tesseract stránky (text zůstane)
images = ocr_page.get_images()
if images:
xref = images[0][0]
ocr_page.delete_image(xref)
# 2. Vložíme náš malý obrázek
# Použijeme rect (rozměry) stránky, aby obrázek seděl přesně na celou stranu
ocr_page.insert_image(ocr_page.rect, stream=buffer_vis.getvalue(), keep_proportion=True)
# 3. Vložíme upravenou stránku do finálního PDF
final_doc.insert_pdf(ocr_page_doc)
# --- KROK D: Uložení ---
if detected_rc:
new_filename = f"{detected_rc}.pdf"
print(f" -> Nalezeno RČ: {detected_rc}")
else:
new_filename = f"{os.path.splitext(filename)[0]}_ocr.pdf"
print(f" -> RČ nenalezeno.")
# Řešení duplicit (pokud soubor už existuje)
counter = 1
base_name_check = os.path.splitext(new_filename)[0]
while os.path.exists(os.path.join(OUTPUT_FOLDER, new_filename)):
new_filename = f"{base_name_check}_{counter}.pdf"
counter += 1
output_path = os.path.join(OUTPUT_FOLDER, new_filename)
# Uložení s kompresí
final_doc.save(output_path, garbage=4, deflate=True)
final_doc.close()
doc_src.close()
# Výpis velikosti
size_kb = os.path.getsize(output_path) / 1024
print(f" -> Uloženo: {new_filename} ({size_kb:.1f} kB)")
print("-" * 40)
except Exception as e:
print(f"CHYBA u {filename}: {e}")
print("\nHOTOVO.")
if __name__ == "__main__":
process_ultimate_method()

View File

@@ -0,0 +1,205 @@
import fitz # PyMuPDF
import pytesseract
from PIL import Image
import io
import os
import re
import fdb # Firebeird database library
# ==========================================
# KONFIGURACE
# ==========================================
# 1. Cesty k souborům
INPUT_FOLDER = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller'
OUTPUT_FOLDER = os.path.join(INPUT_FOLDER, '_HOTOVO_MEDICUS')
# 2. Tesseract OCR
PATH_TO_TESSERACT = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
# 3. Kvalita výstupu (Ultimate metoda)
VISUAL_DPI = 150 # Pro zobrazení (malé)
VISUAL_THRESHOLD = 150 # Práh černé
OCR_DPI = 300 # Pro čtení (velké)
# 4. Databáze MEDICUS (Firebird)
DB_CONFIG = {
'host': "192.168.1.4",
'port': 3050,
'database': r"z:\Medicus 3\data\MEDICUS.FDB",
'user': "SYSDBA",
'password': "masterkey",
'charset': "WIN1250" # Čeština ve Windows
}
# ==========================================
# FUNKCE
# ==========================================
def setup_tesseract():
if not os.path.exists(PATH_TO_TESSERACT):
print(f"CHYBA: Tesseract nenalezen na: {PATH_TO_TESSERACT}")
return False
pytesseract.pytesseract.tesseract_cmd = PATH_TO_TESSERACT
return True
def get_rc_candidates(text):
"""Vrátí seznam RČ nalezených v textu, očistěných od mezer a lomítek."""
candidates = set()
# Regex bere i mezery: 75 05 12 / 1234
pattern = r'\b\d{2}\s*\d{2}\s*\d{2}\s*[\/]?\s*\d{3,4}\b'
matches = re.findall(pattern, text)
for match in matches:
# Odstraníme vše kromě čísel -> vznikne čisté RČ pro DB
clean = re.sub(r'[^\d]', '', match)
if len(clean) in [9, 10]:
candidates.add(clean)
return list(candidates)
def get_patient_from_db(rc_clean):
"""
Vrátí (True, "Prijmeni, Jmeno") pokud najde RČ v tabulce KAR.
"""
con = None
try:
con = fdb.connect(**DB_CONFIG)
cur = con.cursor()
# Medicus má RČ bez lomítka, takže se ptáme rovnou
sql = "SELECT prijmeni, jmeno FROM kar WHERE rodcis = ?"
cur.execute(sql, (rc_clean,))
row = cur.fetchone()
if row:
# row[0] = Prijmeni, row[1] = Jmeno
# .strip() je nutný, databáze vrací mezery na konci (CHAR field)
prijmeni = str(row[0]).strip()
jmeno = str(row[1]).strip()
formatted_name = f"{prijmeni}, {jmeno}"
return True, formatted_name
else:
return False, None
except Exception as e:
print(f" [DB ERROR] {e}")
return False, None
finally:
if con:
con.close()
def process_medicus_final():
if not setup_tesseract():
return
if not os.path.exists(OUTPUT_FOLDER):
os.makedirs(OUTPUT_FOLDER)
files = [f for f in os.listdir(INPUT_FOLDER) if f.lower().endswith('.pdf')]
print(f"Startuji zpracování {len(files)} souborů.")
print(f"Výstupní formát: 'RC Prijmeni, Jmeno.pdf'")
print("-" * 70)
for filename in files:
input_path = os.path.join(INPUT_FOLDER, filename)
try:
print(f"Zpracovávám: {filename}")
doc_src = fitz.open(input_path)
final_doc = fitz.open()
found_rc = None
found_name = None
# --- 1. PRŮCHOD STRÁNKAMI ---
for page_num, page in enumerate(doc_src):
# A) PŘÍPRAVA OCR VRSTVY (High Res)
mat_ocr = fitz.Matrix(OCR_DPI / 72, OCR_DPI / 72)
pix_ocr = page.get_pixmap(matrix=mat_ocr, colorspace=fitz.csGRAY)
img_ocr = Image.frombytes("L", [pix_ocr.width, pix_ocr.height], pix_ocr.samples)
# Tesseract vytvoří PDF stránku
pdf_bytes = pytesseract.image_to_pdf_or_hocr(img_ocr, extension='pdf', lang='ces')
ocr_page_doc = fitz.open("pdf", pdf_bytes)
ocr_page = ocr_page_doc[0]
# B) HLEDÁNÍ PACIENTA (pokud ještě nemáme)
if not found_rc:
text = ocr_page.get_text()
candidates = get_rc_candidates(text)
for cand in candidates:
print(f" -> Ověřuji v DB: {cand} ...", end=" ")
exists, name_str = get_patient_from_db(cand)
if exists:
print(f"NALEZEN: {name_str}")
found_rc = cand
found_name = name_str
break # Máme ho!
else:
print("Nenalezen.")
# C) PŘÍPRAVA VIZUÁLNÍ VRSTVY (Low Res - Zmenšení)
mat_vis = fitz.Matrix(VISUAL_DPI / 72, VISUAL_DPI / 72)
pix_vis = page.get_pixmap(matrix=mat_vis, colorspace=fitz.csGRAY)
img_vis = Image.frombytes("L", [pix_vis.width, pix_vis.height], pix_vis.samples)
# Threshold
img_vis_bw = img_vis.point(lambda x: 255 if x > VISUAL_THRESHOLD else 0, mode='1')
buffer_vis = io.BytesIO()
img_vis_bw.save(buffer_vis, format="PNG", optimize=True)
# D) PROHOZENÍ OBRÁZKŮ (Ultimate trick)
images = ocr_page.get_images()
if images:
xref = images[0][0]
ocr_page.delete_image(xref) # Smaže velký
# Vloží malý
ocr_page.insert_image(ocr_page.rect, stream=buffer_vis.getvalue(), keep_proportion=True)
# Přidá stránku do finálního PDF
final_doc.insert_pdf(ocr_page_doc)
# --- 2. ULOŽENÍ SOUBORU ---
if found_rc and found_name:
# Formát: 1234567890 NOVAK, JAN.pdf
# Odstraníme případné nepovolené znaky ve jméně (pro jistotu)
safe_name = re.sub(r'[\\/*?:"<>|]', "", found_name)
new_filename = f"{found_rc} {safe_name}.pdf"
else:
new_filename = f"{os.path.splitext(filename)[0]}_neovereno.pdf"
# Řešení konfliktů (kdyby soubor už existoval)
counter = 1
base_name = os.path.splitext(new_filename)[0]
while os.path.exists(os.path.join(OUTPUT_FOLDER, new_filename)):
new_filename = f"{base_name}_{counter}.pdf"
counter += 1
output_path = os.path.join(OUTPUT_FOLDER, new_filename)
final_doc.save(output_path, garbage=4, deflate=True)
final_doc.close()
doc_src.close()
size_kb = os.path.getsize(output_path) / 1024
print(f" -> Uloženo: {new_filename} ({size_kb:.1f} kB)")
print("-" * 70)
except Exception as e:
print(f"CHYBA: {e}")
print("\nHOTOVO.")
if __name__ == "__main__":
process_medicus_final()

View File

@@ -0,0 +1,66 @@
import fitz # PyMuPDF
import os
def compress_and_grayscale_pdf(input_path, quality=60, dpi=150):
"""
input_path: Cesta k souboru
quality: Kvalita JPG komprese (1-100). 60 je dobrý kompromis pro čitelnost a velikost.
dpi: Rozlišení. 150 DPI stačí pro čtení na monitoru/běžný tisk. Pro menší velikost zkuste 96 nebo 72.
"""
# Kontrola existence souboru
if not os.path.exists(input_path):
print(f"Chyba: Soubor nebyl nalezen: {input_path}")
return
try:
# Otevření zdrojového PDF
doc = fitz.open(input_path)
new_doc = fitz.open() # Vytvoření nového prázdného PDF
print(f"Zpracovávám: {os.path.basename(input_path)}")
print(f"Původní velikost: {os.path.getsize(input_path) / 1024:.2f} KB")
for page_num, page in enumerate(doc):
# Nastavení matice pro změnu rozlišení (DPI)
# Standardní PDF má 72 DPI. Zoom = požadované DPI / 72
zoom = dpi / 72
matrix = fitz.Matrix(zoom, zoom)
# 1. Renderování stránky do obrázku (Pixmap)
# colorspace=fitz.csGRAY zajistí převod do černobílé (Grayscale)
pix = page.get_pixmap(matrix=matrix, colorspace=fitz.csGRAY)
# 2. Vytvoření nové stránky v cílovém dokumentu se stejnými rozměry
# Používáme původní rozměry stránky (rect), aby se PDF "nezmenšilo" vizuálně na monitoru
new_page = new_doc.new_page(width=page.rect.width, height=page.rect.height)
# 3. Vložení zmenšeného a odbarveného obrázku zpět
# stream=pix.tobytes("jpg") zajistí silnou kompresi
new_page.insert_image(page.rect, stream=pix.tobytes("jpg", jpg_quality=quality))
# Vytvoření názvu výstupního souboru
output_path = input_path.replace(".pdf", "_bw_small.pdf")
# Uložení s garbage collection (odstranění nepotřebných dat) a deflací
new_doc.save(output_path, garbage=4, deflate=True)
new_doc.close()
doc.close()
# Výpis výsledku
new_size = os.path.getsize(output_path)
print(f"Hotovo. Uloženo jako: {output_path}")
print(f"Nová velikost: {new_size / 1024:.2f} KB")
except Exception as e:
print(f"Došlo k chybě: {e}")
# --- SPUŠTĚNÍ ---
# Použití raw stringu (r''), aby Python neinterpretoval zpětná lomítka jako escape znaky
file_path = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller\90df6f84-72c8-40b8-8993-ce7e244b0cea.pdf'
# Můžete experimentovat s parametry.
# Pokud bude text nečitelný, zvyšte dpi na 200. Pokud je soubor moc velký, snižte quality na 40.
compress_and_grayscale_pdf(file_path, quality=50, dpi=120)

View File

@@ -0,0 +1,37 @@
import fitz # PyMuPDF
file_path = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller\90df6f84-72c8-40b8-8993-ce7e244b0cea.pdf'
doc = fitz.open(file_path)
print(f"Soubor: {file_path}")
print("-" * 40)
for i, page in enumerate(doc):
# Získání seznamu obrázků na stránce
images = page.get_images(full=True)
# Rozměry stránky v palcích (PDF body / 72)
page_w_inch = page.rect.width / 72
page_h_inch = page.rect.height / 72
if images:
for img in images:
xref = img[0]
base_img = doc.extract_image(xref)
w = base_img["width"]
h = base_img["height"]
ext = base_img["ext"]
# Výpočet DPI (Pixely / Palce)
dpi_x = w / page_w_inch
dpi_y = h / page_h_inch
print(f"Strana {i + 1}:")
print(f" - Rozměry obrázku: {w} x {h} px")
print(f" - Formát: {ext}")
print(f" - Reálné DPI: cca {int(dpi_x)}")
else:
print(f"Strana {i + 1}: Žádný vložený obrázek (vektorový text).")
print("-" * 40)

View File

@@ -0,0 +1,87 @@
import fitz # PyMuPDF
from PIL import Image
import io
import os
# --- NASTAVENÍ ---
INPUT_FILE = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller\90df6f84-72c8-40b8-8993-ce7e244b0cea.pdf'
# 1. Prahové hodnoty: Zúžíme výběr na nejpravděpodobnější rozsah
THRESHOLDS = [110, 130, 150, 170]
# 2. DPI Varianty k testování
# 131 = Přesná polovina originálu (váš nápad)
# 150 = Standard
# 200 = Vysoká kvalita
# 262 = Originál (žádná ztráta detailů, jen ztráta barev)
DPI_LIST = [131, 150, 200, 262]
def generate_final_matrix():
if not os.path.exists(INPUT_FILE):
print(f"Chyba: Soubor nenalezen.")
return
# Příprava složky
base_folder = os.path.dirname(INPUT_FILE)
filename = os.path.basename(INPUT_FILE)
name_without_ext = os.path.splitext(filename)[0]
output_dir = os.path.join(base_folder, "_TEST_DPI_MATH")
if not os.path.exists(output_dir):
os.makedirs(output_dir)
print(f"Generuji varianty do: {output_dir}")
print("-" * 80)
print(f"{'DPI':<5} | {'Práh':<6} | {'Velikost':<12} | {'Poznámka'}")
print("-" * 80)
doc = fitz.open(INPUT_FILE)
for dpi in DPI_LIST:
# Přednačtení stránek v daném DPI
pages_at_dpi = []
for page in doc:
zoom = dpi / 72
matrix = fitz.Matrix(zoom, zoom)
pix = page.get_pixmap(matrix=matrix, colorspace=fitz.csGRAY)
pages_at_dpi.append(pix)
for t in THRESHOLDS:
new_doc = fitz.open()
for i, pix in enumerate(pages_at_dpi):
# Binarizace
img = Image.frombytes("L", [pix.width, pix.height], pix.samples)
img_bw = img.point(lambda x: 255 if x > t else 0, mode='1')
# Uložení
buffer = io.BytesIO()
img_bw.save(buffer, format="PNG", optimize=True)
# Vložení zpět
orig_rect = doc[i].rect
new_page = new_doc.new_page(width=orig_rect.width, height=orig_rect.height)
new_page.insert_image(orig_rect, stream=buffer.getvalue())
# Uložení
output_name = f"dpi{dpi}_t{t}.pdf"
output_path = os.path.join(output_dir, output_name)
new_doc.save(output_path, garbage=4, deflate=True)
new_doc.close()
# Výpis
size_kb = os.path.getsize(output_path) / 1024
note = ""
if dpi == 131: note = "(Polovina originálu)"
if dpi == 262: note = "(Originální rozlišení)"
print(f"{dpi:<5} | {t:<6} | {size_kb:<9.2f} KB | {note}")
doc.close()
print("-" * 80)
if __name__ == "__main__":
generate_final_matrix()

View File

@@ -0,0 +1,95 @@
import fitz # PyMuPDF
from PIL import Image
import io
import os
import shutil
# --- VAŠE VÍTĚZNÉ NASTAVENÍ ---
CHOSEN_DPI = 150
CHOSEN_THRESHOLD = 150
# Cesty
INPUT_FOLDER = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller'
OUTPUT_SUBFOLDER = '_HOTOVO'
def process_all_files():
# Vytvoření výstupní složky
output_dir = os.path.join(INPUT_FOLDER, OUTPUT_SUBFOLDER)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# Nalezení všech PDF (ignorujeme již hotové v podsložkách)
files = [f for f in os.listdir(INPUT_FOLDER) if f.lower().endswith('.pdf')]
print(f"Startuji zpracování {len(files)} souborů.")
print(f"Nastavení: DPI={CHOSEN_DPI}, Práh={CHOSEN_THRESHOLD}")
print("-" * 60)
success_count = 0
for filename in files:
input_path = os.path.join(INPUT_FOLDER, filename)
# Přidáme '_bw' do názvu, aby se to nepletlo
name_without_ext = os.path.splitext(filename)[0]
output_filename = f"{name_without_ext}_bw.pdf"
output_path = os.path.join(output_dir, output_filename)
try:
# Zpracování jednoho souboru
process_single_pdf(input_path, output_path)
# Výpis výsledku
orig_size = os.path.getsize(input_path) / 1024
new_size = os.path.getsize(output_path) / 1024
ratio = (1 - (new_size / orig_size)) * 100
print(f"[OK] {filename}")
print(f" {orig_size:.1f} kB -> {new_size:.1f} kB (úspora {ratio:.0f} %)")
success_count += 1
# --- VOLITELNÉ: SMAZÁNÍ ORIGINÁLU ---
# Pokud chcete, aby skript po úspěchu smazal původní velký soubor,
# odkomentujte následující řádek (odstraňte mřížku #):
# os.remove(input_path)
except Exception as e:
print(f"[CHYBA] {filename}: {e}")
print("-" * 60)
print(f"Hotovo. Úspěšně zpracováno {success_count} z {len(files)} souborů.")
print(f"Výstupy jsou ve složce: {output_dir}")
def process_single_pdf(input_path, output_path):
doc = fitz.open(input_path)
new_doc = fitz.open()
for page in doc:
# 1. Renderování stránky (Downsampling na 150 DPI)
zoom = CHOSEN_DPI / 72
matrix = fitz.Matrix(zoom, zoom)
pix = page.get_pixmap(matrix=matrix, colorspace=fitz.csGRAY)
# 2. Binarizace (Threshold 150)
img = Image.frombytes("L", [pix.width, pix.height], pix.samples)
img_bw = img.point(lambda x: 255 if x > CHOSEN_THRESHOLD else 0, mode='1')
# 3. Uložení 1-bitového obrázku
buffer = io.BytesIO()
img_bw.save(buffer, format="PNG", optimize=True)
# 4. Vložení do nového PDF
# Zachováme fyzické rozměry stránky (aby se netiskla jako známka)
new_page = new_doc.new_page(width=page.rect.width, height=page.rect.height)
new_page.insert_image(page.rect, stream=buffer.getvalue())
# Uložení s maximální kompresí
new_doc.save(output_path, garbage=4, deflate=True)
new_doc.close()
doc.close()
if __name__ == "__main__":
process_all_files()

View File

@@ -0,0 +1,67 @@
import fitz # PyMuPDF
import pytesseract
from PIL import Image
import os
import re
# --- NASTAVENÍ ---
PATH_TO_TESSERACT = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
INPUT_FILE = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller\6ed31e44-0e7d-4118-8912-c3e583781459.pdf'
# Nastavíme Tesseract
pytesseract.pytesseract.tesseract_cmd = PATH_TO_TESSERACT
def debug_ocr_output():
if not os.path.exists(INPUT_FILE):
print(f"Soubor nenalezen: {INPUT_FILE}")
return
print(f"ANALÝZA SOUBORU: {os.path.basename(INPUT_FILE)}")
doc = fitz.open(INPUT_FILE)
# Projdeme první stranu (RČ bývá tam)
for i, page in enumerate(doc):
if i > 0: break # Stačí nám 1. strana pro test
print(f"\n--- STRANA {i + 1} (300 DPI) ---")
# 1. Renderování ve vysoké kvalitě (stejně jako v 'Ultimate' skriptu)
# Pokud je sken nekvalitní, Tesseract potřebuje velké rozlišení
zoom = 300 / 72
matrix = fitz.Matrix(zoom, zoom)
pix = page.get_pixmap(matrix=matrix, colorspace=fitz.csGRAY)
img = Image.frombytes("L", [pix.width, pix.height], pix.samples)
# 2. OCR - Získání surového textu
# config='--psm 3' je standardní automatická segmentace stránky
raw_text = pytesseract.image_to_string(img, lang='ces', config='--psm 3')
print(">>> SUROVÝ TEXT Z TESSERACTU (ZAČÁTEK) <<<")
print("-" * 50)
print(raw_text)
print("-" * 50)
print(">>> SUROVÝ TEXT Z TESSERACTU (KONEC) <<<")
# 3. Test Regexu na tomto textu
print("\n--- TEST HLEDÁNÍ RČ ---")
# Standardní Regex
strict_pattern = r'\b\d{6}\s*[\/]?\s*\d{3,4}\b'
strict_matches = re.findall(strict_pattern, raw_text)
print(f"Přísný filtr (očekává jen čísla): {strict_matches}")
# Volnější Regex (hledá i chyby OCR jako 'O' místo '0' nebo 'l' místo '1')
# \d -> číslice
# [O0] -> nula nebo O
# [lI1] -> jednička, malé L nebo velké i
loose_pattern = r'\b[0-9O]{6}\s*[\/ilI1]?\s*[0-9O]{3,4}\b'
loose_matches = re.findall(loose_pattern, raw_text)
if loose_matches and not strict_matches:
print(f"⚠️ POZOR: Našel jsem RČ jen pomocí volného filtru (obsahuje překlepy OCR): {loose_matches}")
print(" -> Bude potřeba upravit čistící funkci.")
if __name__ == "__main__":
debug_ocr_output()

View File

@@ -0,0 +1,67 @@
import fitz # PyMuPDF
import pytesseract
from PIL import Image
import os
import re
# --- NASTAVENÍ ---
PATH_TO_TESSERACT = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
INPUT_FILE = r'u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\AdobeMakeSmaller\9b79f621-30ad-4468-85fe-6f2fd76289ce.pdf'
# Nastavíme Tesseract
pytesseract.pytesseract.tesseract_cmd = PATH_TO_TESSERACT
def debug_ocr_output():
if not os.path.exists(INPUT_FILE):
print(f"Soubor nenalezen: {INPUT_FILE}")
return
print(f"ANALÝZA SOUBORU: {os.path.basename(INPUT_FILE)}")
doc = fitz.open(INPUT_FILE)
# Projdeme první stranu (RČ bývá tam)
for i, page in enumerate(doc):
if i > 0: break # Stačí nám 1. strana pro test
print(f"\n--- STRANA {i + 1} (300 DPI) ---")
# 1. Renderování ve vysoké kvalitě (stejně jako v 'Ultimate' skriptu)
# Pokud je sken nekvalitní, Tesseract potřebuje velké rozlišení
zoom = 300 / 72
matrix = fitz.Matrix(zoom, zoom)
pix = page.get_pixmap(matrix=matrix, colorspace=fitz.csGRAY)
img = Image.frombytes("L", [pix.width, pix.height], pix.samples)
# 2. OCR - Získání surového textu
# config='--psm 3' je standardní automatická segmentace stránky
raw_text = pytesseract.image_to_string(img, lang='ces', config='--psm 3')
print(">>> SUROVÝ TEXT Z TESSERACTU (ZAČÁTEK) <<<")
print("-" * 50)
print(raw_text)
print("-" * 50)
print(">>> SUROVÝ TEXT Z TESSERACTU (KONEC) <<<")
# 3. Test Regexu na tomto textu
print("\n--- TEST HLEDÁNÍ RČ ---")
# Standardní Regex
strict_pattern = r'\b\d{6}\s*[\/]?\s*\d{3,4}\b'
strict_matches = re.findall(strict_pattern, raw_text)
print(f"Přísný filtr (očekává jen čísla): {strict_matches}")
# Volnější Regex (hledá i chyby OCR jako 'O' místo '0' nebo 'l' místo '1')
# \d -> číslice
# [O0] -> nula nebo O
# [lI1] -> jednička, malé L nebo velké i
loose_pattern = r'\b[0-9O]{6}\s*[\/ilI1]?\s*[0-9O]{3,4}\b'
loose_matches = re.findall(loose_pattern, raw_text)
if loose_matches and not strict_matches:
print(f"⚠️ POZOR: Našel jsem RČ jen pomocí volného filtru (obsahuje překlepy OCR): {loose_matches}")
print(" -> Bude potřeba upravit čistící funkci.")
if __name__ == "__main__":
debug_ocr_output()

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-

55855
SEZNAM_K_NAHRANI.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,136 @@
import os
import pymysql
import sys
import blake3 # Nutné: pip install blake3
# ==============================
# ⚙️ NASTAVENÍ
# ==============================
LOCAL_ROOT = r"U:\#Syncthing"
# !!! AŽ SI BUDEŠ JISTÝ, ZMĚŇ NA True !!!
DELETE_MODE = False
# Hledáme shodu pouze v souborech, které jsou na serveru v této cestě:
REMOTE_FOLDER_FILTER = "/#ColdData/Porno/"
# DB Nastavení
DB_HOST = "192.168.1.76"
DB_PORT = 3307
DB_USER = "root"
DB_PASS = "Vlado9674+"
DB_NAME = "torrents"
DB_TABLE = "file_md5_index"
# ==============================
def get_db_connection():
try:
return pymysql.connect(
host=DB_HOST, port=DB_PORT, user=DB_USER, password=DB_PASS,
database=DB_NAME, cursorclass=pymysql.cursors.DictCursor
)
except Exception as e:
sys.exit(f"❌ Chyba DB: {e}")
def calculate_blake3(file_path):
"""Spočítá BLAKE3 hash souboru"""
h = blake3.blake3()
try:
with open(file_path, "rb") as f:
while True:
chunk = f.read(4 * 1024 * 1024) # 4MB chunks
if not chunk:
break
h.update(chunk)
return h.digest()
except OSError:
return None
def main():
print(f"🚀 TERMINÁTOR: Mazání podle obsahu (BLAKE3)")
print(f" 📂 Zdroj: {LOCAL_ROOT}")
print(f" 🎯 DB filtr: {REMOTE_FOLDER_FILTER}")
print(f" 🛠 Mód: {'🔴 OSTRÝ (MAZÁNÍ)' if DELETE_MODE else '🟢 SIMULACE (BEZPEČNÝ)'}")
print("=====================================================")
# 1. NAČTENÍ HASHŮ Z DB
print("📡 Stahuji hashe ze serveru...")
remote_hashes = set()
conn = get_db_connection()
with conn.cursor() as cursor:
sql = f"SELECT blake3 FROM {DB_TABLE} WHERE full_path LIKE %s"
cursor.execute(sql, (f"%{REMOTE_FOLDER_FILTER}%",))
rows = cursor.fetchall()
for row in rows:
remote_hashes.add(row['blake3'])
print(f"✅ V paměti mám {len(remote_hashes):,} unikátních hashů ze serveru.")
print("=====================================================")
# 2. SKENOVÁNÍ A MAZÁNÍ
count_scanned = 0
count_match = 0
size_freed = 0
for root, dirs, files in os.walk(LOCAL_ROOT):
# Přeskočit syncthing složky
if ".stfolder" in dirs: dirs.remove(".stfolder")
if ".stversions" in dirs: dirs.remove(".stversions")
for filename in files:
file_path = os.path.join(root, filename)
count_scanned += 1
# Výpis práce
print(f"⏳ [{count_scanned}] Zpracovávám: {filename}")
# Spočítat lokální hash
local_hash = calculate_blake3(file_path)
if local_hash is None:
print(f" ⚠️ Chyba čtení souboru!")
continue
# Zobrazíme kousek hashe pro kontrolu (převedeme na hex text)
hash_preview = local_hash.hex()[:8]
# JE TEN HASH V DATABÁZI?
if local_hash in remote_hashes:
count_match += 1
file_size = os.path.getsize(file_path)
size_freed += file_size
print(f" ✅ SHODA (Hash: {hash_preview}...) -> {'🗑️ MAŽU' if DELETE_MODE else '📦 NAŠEL BYCH'}")
if DELETE_MODE:
try:
os.remove(file_path)
# Pokus o smazání prázdné složky
try:
os.rmdir(root)
except:
pass
except OSError as e:
print(f" ❌ Chyba mazání: {e}")
else:
print(f" ❌ Žádná shoda (Hash: {hash_preview}...) -> Nechávám být")
print("\n\n📊 VÝSLEDEK")
print("=====================================================")
print(f"🔎 Prošlo rukama: {count_scanned:,} souborů")
print(f"🗑️ Smazáno/Shoda: {count_match:,} souborů")
print(f"💾 Ušetřené místo: {size_freed / (1024 * 1024):.2f} MB")
print("=====================================================")
if not DELETE_MODE and count_match > 0:
print("💡 TIP: Až budeš připraven, změň v kódu: DELETE_MODE = True")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,134 @@
import os
import blake3
import sys
import json
from tqdm import tqdm
# ==============================
# ⚙️ NASTAVENÍ
# ==============================
LOCAL_ROOT = r"U:\#Syncthing"
CACHE_FILE = "local_hashes.jsonl"
ERROR_LOG = "errors_scan.txt"
def calculate_blake3_hex(file_path):
h = blake3.blake3()
# Zde ošetříme chyby při otevírání/čtení souboru
try:
with open(file_path, "rb") as f:
while True:
chunk = f.read(4 * 1024 * 1024)
if not chunk: break
h.update(chunk)
return h.hexdigest()
except Exception as e:
# Vyhodíme výjimku nahoru, abychom ji zachytili v hlavní smyčce i s názvem souboru
raise e
def count_files(path):
print("⏳ Sčítám soubory...", end="\r")
total = 0
for root, dirs, files in os.walk(path):
if ".stfolder" in dirs: dirs.remove(".stfolder")
if ".stversions" in dirs: dirs.remove(".stversions")
total += len(files)
print(f"✅ Celkem souborů: {total:,}")
return total
def load_processed_files(cache_file):
"""Načte cesty souborů, které už máme hotové"""
processed = set()
if os.path.exists(cache_file):
print("📥 Načítám již hotové záznamy pro navázání...")
try:
with open(cache_file, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line: continue
try:
data = json.loads(line)
processed.add(data["p"]) # "p" je cesta
except:
continue
except Exception as e:
print(f"⚠️ Chyba při čtení cache (nevadí, jedeme dál): {e}")
print(f"⏭ Přeskočím {len(processed):,} již hotových souborů.")
return processed
def main():
print("🚀 KROK 1: Generování cache (RESUMABLE + SAFE MODE)")
print(f"📂 Zdroj: {LOCAL_ROOT}")
print(f"💾 Výstup: {CACHE_FILE}")
print("===================================")
# 1. Zjistit celkový počet
total_files = count_files(LOCAL_ROOT)
# 2. Zjistit, co už máme hotové
processed_paths = load_processed_files(CACHE_FILE)
errors = 0
newly_processed = 0
# Otevřeme v režimu 'a' (APPEND) - připisování na konec
with open(CACHE_FILE, "a", encoding="utf-8") as f_out:
with tqdm(total=total_files, unit="file", dynamic_ncols=True) as pbar:
# Pokud už máme nějaká data, aktualizujeme progress bar
if processed_paths:
pbar.update(len(processed_paths))
for root, dirs, files in os.walk(LOCAL_ROOT):
if ".stfolder" in dirs: dirs.remove(".stfolder")
if ".stversions" in dirs: dirs.remove(".stversions")
for filename in files:
file_path = os.path.join(root, filename)
# === SKIPPER: Pokud už to máme, jdeme dál ===
if file_path in processed_paths:
continue
# ============================================
# Pro dlouhé názvy ořízneme text v progress baru
short_name = (filename[:30] + '...') if len(filename) > 30 else filename
pbar.set_description(f"Hash: {short_name}")
# === SAFE BLOCK: Try-Except uvnitř smyčky ===
try:
hex_hash = calculate_blake3_hex(file_path)
if hex_hash:
record = {"h": hex_hash, "p": file_path}
f_out.write(json.dumps(record, ensure_ascii=False) + "\n")
# Flush, aby se to zapsalo na disk hned (pro jistotu)
if newly_processed % 100 == 0:
f_out.flush()
newly_processed += 1
except Exception as e:
errors += 1
error_msg = f"❌ CHYBA: {filename} -> {e}\n"
# Zapíšeme chybu do logu, aby to nerušilo output
with open(ERROR_LOG, "a", encoding="utf-8") as ferr:
ferr.write(error_msg)
# Posuneme progress bar
pbar.update(1)
print("\n\n✅ HOTOVO.")
print(f"📄 Nově přidáno: {newly_processed}")
print(f"⏭ Přeskočeno: {len(processed_paths)}")
if errors > 0:
print(f"⚠️ Počet chyb: {errors} (Detaily viz soubor '{ERROR_LOG}')")
if __name__ == "__main__":
main()

150
Syncthing/03 Terminator.py Normal file
View File

@@ -0,0 +1,150 @@
import os
import pymysql
import sys
import json
from tqdm import tqdm
# ==============================
# ⚙️ NASTAVENÍ
# ==============================
CACHE_FILE = "local_hashes.jsonl"
# !!! ZMĚŇ NA True PRO SKUTEČNÉ MAZÁNÍ !!!
DELETE_MODE = True
# Filtr DB (Hledáme shodu jen v této složce na serveru)
REMOTE_FOLDER_FILTER = "/#ColdData/Porno/"
DB_CONFIG = {
"host": "192.168.1.76",
"port": 3307,
"user": "root",
"password": "Vlado9674+",
"database": "torrents",
}
# ==============================
def get_remote_hashes():
print("📡 Stahuji hashe z DB (filtr: " + REMOTE_FOLDER_FILTER + ")...")
hashes = set()
try:
conn = pymysql.connect(**DB_CONFIG, cursorclass=pymysql.cursors.DictCursor)
with conn.cursor() as cursor:
# Stáhneme hashe souborů, které jsou v cílové složce
sql = f"SELECT blake3 FROM file_md5_index WHERE full_path LIKE %s"
cursor.execute(sql, (f"%{REMOTE_FOLDER_FILTER}%",))
for row in cursor.fetchall():
# DB vrací bytes, my potřebujeme HEX string (stejný jako v JSONL)
hashes.add(row['blake3'].hex())
conn.close()
except Exception as e:
sys.exit(f"❌ Chyba DB: {e}")
return hashes
def count_lines(filename):
"""Spočítá řádky pro progress bar"""
print("⏳ Sčítám záznamy v cache...", end="\r")
with open(filename, "r", encoding="utf-8") as f:
return sum(1 for _ in f)
def main():
print("🚀 KROK 2: Terminátor (Mazání podle cache)")
print(f"📂 Cache soubor: {CACHE_FILE}")
print(f"🛠 Mód: {'🔴 OSTRÝ (MAZÁNÍ)' if DELETE_MODE else '🟢 SIMULACE (JEN VÝPIS)'}")
print("===================================")
if not os.path.exists(CACHE_FILE):
sys.exit("❌ Cache soubor neexistuje! Spusť nejdřív KROK 1.")
# 1. Stáhnout DB
remote_hashes = get_remote_hashes()
print(f"✅ DB načtena: {len(remote_hashes):,} unikátních hashů ze serveru.")
# 2. Spočítat řádky pro progress bar
total_lines = count_lines(CACHE_FILE)
print(f"✅ Cache obsahuje: {total_lines:,} lokálních souborů ke kontrole.")
print("🔍 Jdu porovnávat...")
count_deleted = 0
freed_space = 0
errors = 0
# Otevření souboru pro logování smazaných (volitelné)
log_name = "deleted_files.log" if DELETE_MODE else "would_delete.log"
with open(CACHE_FILE, "r", encoding="utf-8") as f_in, \
open(log_name, "w", encoding="utf-8") as f_log:
# Progress bar
with tqdm(total=total_lines, unit="file", dynamic_ncols=True) as pbar:
for line in f_in:
pbar.update(1)
line = line.strip()
if not line: continue
try:
data = json.loads(line)
local_hash = data["h"]
file_path = data["p"]
except:
continue # Vadný řádek
# Kontrola existence souboru (mohli jsme ho už smazat ručně)
if not os.path.exists(file_path):
continue
# --- HLAVNÍ LOGIKA ---
if local_hash in remote_hashes:
# SHODA! Soubor je na serveru -> SMAZAT lokálně
try:
size = os.path.getsize(file_path)
if DELETE_MODE:
os.remove(file_path)
status = "SMAZÁNO"
# Pokus o smazání prázdné složky
try:
os.rmdir(os.path.dirname(file_path))
except:
pass
else:
status = "NAŠEL BYCH"
count_deleted += 1
freed_space += size
# Zápis do logu
f_log.write(f"{file_path}\n")
# Aktualizace popisku (jen občas, aby to neblikalo moc rychle)
if count_deleted % 10 == 0:
pbar.set_description(f"Mazání: {count_deleted} files")
except OSError as e:
errors += 1
# print(f"❌ Chyba u {file_path}: {e}")
print("\n\n📊 VÝSLEDEK")
print("===================================")
print(f"🔎 Zkontrolováno: {total_lines:,}")
print(f"🗑️ {'Smazáno' if DELETE_MODE else 'K smazání'}: {count_deleted:,}")
print(f"💾 Ušetřeno místo: {freed_space / (1024 * 1024 * 1024):.2f} GB")
print(f"📝 Seznam souborů: '{log_name}'")
if errors > 0:
print(f"⚠️ Chyb při mazání: {errors}")
if not DELETE_MODE and count_deleted > 0:
print("\n💡 LÍBÍ SE TI VÝSLEDEK? Změň nahoře: DELETE_MODE = True")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,128 @@
import pymysql
import sys
import os
from tqdm import tqdm
# ==============================
# ⚙️ NASTAVENÍ
# ==============================
# Soubor je nyní přímo ve složce s tímto skriptem
PHYSICAL_LIST_FILE = "physical_files_list.txt"
# DB Nastavení
DB_CONFIG = {
"host": "192.168.1.76",
"port": 3307,
"user": "root",
"password": "Vlado9674+",
"database": "torrents",
}
# ==============================
def get_db_paths():
print("📡 Stahuji seznam cest z MySQL (to chvilku potrvá)...")
paths = set()
try:
conn = pymysql.connect(**DB_CONFIG)
cursor = conn.cursor()
# Stáhneme VŠECHNY cesty, které jsou v #ColdData
# LIKE optimalizace: MySQL použije index, pokud sloupec full_path má index
sql = "SELECT full_path FROM file_md5_index WHERE full_path LIKE '/mnt/user/#ColdData/%'"
cursor.execute(sql)
for row in cursor.fetchall():
paths.add(row[0])
conn.close()
except Exception as e:
sys.exit(f"❌ Chyba DB: {e}")
return paths
def main():
print("🚀 AUDIT: Fyzický disk vs. Databáze")
print(f"📂 Vstup: {PHYSICAL_LIST_FILE} (Lokální)")
print("=====================================================")
if not os.path.exists(PHYSICAL_LIST_FILE):
sys.exit(f"❌ Soubor '{PHYSICAL_LIST_FILE}' nenalezen ve složce projektu!")
# 1. Načíst DB do paměti
db_paths = get_db_paths()
print(f"✅ V DB načteno: {len(db_paths):,} záznamů.")
# 2. Příprava na hledání "Ghost files"
ghost_check_set = db_paths.copy()
# 3. Spočítat řádky pro progress bar
print("⏳ Sčítám řádky v souboru...", end="\r")
try:
total_lines = sum(1 for _ in open(PHYSICAL_LIST_FILE, 'r', encoding='utf-8', errors='ignore'))
except:
total_lines = 0
# 4. Porovnání
print(f"🔍 Jdu porovnávat {total_lines:,} souborů...")
missing_in_db = 0
found_ok = 0
physical_count = 0
f_missing = open("report_CHYBI_V_DB.txt", "w", encoding="utf-8")
with open(PHYSICAL_LIST_FILE, "r", encoding="utf-8", errors="ignore") as f:
with tqdm(total=total_lines, unit="file", dynamic_ncols=True) as pbar:
for line in f:
line = line.strip()
if not line: continue
# Očekáváme formát: /mnt/user/.../soubor|velikost
try:
parts = line.rsplit("|", 1)
path = parts[0]
except IndexError:
continue
physical_count += 1
# --- KONTROLA ---
if path in db_paths:
found_ok += 1
# Odebrat ze seznamu duchů (našli jsme ho)
if path in ghost_check_set:
ghost_check_set.remove(path)
else:
# Je na disku, není v DB
missing_in_db += 1
f_missing.write(f"{path}\n")
pbar.update(1)
f_missing.close()
# Zbytek jsou duchové
ghost_files = list(ghost_check_set)
with open("report_NAVIC_V_DB.txt", "w", encoding="utf-8") as f_ghost:
f_ghost.write("TOTO JSOU ZÁZNAMY V DB, KTERÉ NA DISKU NEEXISTUJÍ:\n")
for p in ghost_files:
f_ghost.write(f"{p}\n")
print("\n\n📊 VÝSLEDEK AUDITU")
print("=====================================================")
print(f"💾 Fyzických souborů: {physical_count:,}")
print(f"✅ V pořádku (V DB): {found_ok:,}")
print("-----------------------------------------------------")
print(f"❌ CHYBÍ V DB (Re-index): {missing_in_db:,}")
print(f" -> 'report_CHYBI_V_DB.txt'")
print("-----------------------------------------------------")
print(f"👻 NAVÍC V DB (Smazat): {len(ghost_files):,}")
print(f" -> 'report_NAVIC_V_DB.txt'")
print("=====================================================")
if __name__ == "__main__":
main()

1251
Syncthing/deleted_files.log Normal file

File diff suppressed because it is too large Load Diff

56120
Syncthing/local_hashes.jsonl Normal file

File diff suppressed because it is too large Load Diff

1949854
Syncthing/physical_files_list.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
/mnt/user/#ColdData/physical_files_list.txt

View File

@@ -0,0 +1,4 @@
TOTO JSOU ZÁZNAMY V DB, KTERÉ NA DISKU NEEXISTUJÍ:
/mnt/user/#ColdData/#40 SP1 SBS2003 ENG SP1/#2 WSS2003SP1-kb841876-fullfile-ENU_2.exe
/mnt/user/#ColdData/#40 SP1 SBS2003 ENG SP1/tcmd852ax32.exe
/mnt/user/#ColdData/#40 SP1 SBS2003 ENG SP1/#2 WSS2003SP1-kb841876-fullfile-ENU.exe

1251
Syncthing/would_delete.log Normal file

File diff suppressed because it is too large Load Diff

152
TestDupliciSyncThing2.py Normal file
View File

@@ -0,0 +1,152 @@
import os
import pymysql
import sys
# ==============================
# ⚙️ NASTAVENÍ
# ==============================
LOCAL_ROOT = r"U:\#Syncthing"
# Cíl, kam to chceš nahrát (pro kontrolu přesné shody)
TARGET_SUBFOLDER = "Porno"
REMOTE_SHARE_KEY = "#ColdData"
# DB Nastavení
DB_HOST = "192.168.1.76"
DB_PORT = 3307
DB_USER = "root"
DB_PASS = "Vlado9674+"
DB_NAME = "torrents"
DB_TABLE = "file_md5_index"
# ==============================
def get_db_connection():
try:
return pymysql.connect(
host=DB_HOST, port=DB_PORT, user=DB_USER, password=DB_PASS,
database=DB_NAME, cursorclass=pymysql.cursors.DictCursor
)
except Exception as e:
sys.exit(f"❌ Chyba DB: {e}")
def normalize_path(path):
return path.replace("\\", "/").lower()
def main():
print(f"🚀 KŘÍŽOVÁ KONTROLA (Co nahrát vs. Co už někde je)")
print("=====================================================")
# 1. NAČÍST CELOU DB (pro hledání zatoulaných souborů)
print("📡 Stahuji kompletní index serveru (Jméno + Velikost)...")
# Mapa: (jmeno, velikost) -> [seznam cest]
global_map = {}
conn = get_db_connection()
with conn.cursor() as cursor:
# Stáhneme vše z #ColdData
sql = f"SELECT file_name, file_size, full_path FROM {DB_TABLE} WHERE full_path LIKE %s"
cursor.execute(sql, (f"%/{REMOTE_SHARE_KEY}/%",))
rows = cursor.fetchall()
for row in rows:
fname = row['file_name'].lower()
size = row['file_size']
path = row['full_path']
key = (fname, size)
if key not in global_map:
global_map[key] = []
global_map[key].append(path)
print(f"✅ Index načten ({len(rows):,} souborů).")
# 2. DEFINICE CÍLOVÉ CESTY (pro kontrolu přesné shody)
# Cesta v DB vypadá např: /mnt/disk1/#ColdData/Porno/Slozka/Film.avi
# My budeme kontrolovat, jestli soubor už je v "cílové logické cestě"
target_pattern_part = f"/{REMOTE_SHARE_KEY}/{TARGET_SUBFOLDER}/".lower()
# 3. SKENOVÁNÍ LOKÁLNÍHO DISKU
print(f"📂 Skenuji {LOCAL_ROOT} a třídím...")
count_upload = 0
count_move = 0
count_ok = 0
f_upload = open("1_NAHRAT_NA_SERVER.txt", "w", encoding="utf-8")
f_move = open("2_JIZ_EXISTUJI_JINDE.txt", "w", encoding="utf-8")
f_upload.write("TOTO JSOU DATA, KTERÁ NA SERVERU VŮBEC NEJSOU:\n")
f_move.write("TOTO NAHRAJEŠ ZBYTEČNĚ (Už to tam je, ale v jiné složce):\n")
for root, dirs, files in os.walk(LOCAL_ROOT):
if ".stfolder" in dirs: dirs.remove(".stfolder")
if ".stversions" in dirs: dirs.remove(".stversions")
for filename in files:
fname_lower = filename.lower()
local_full_path = os.path.join(root, filename)
try:
local_size = os.path.getsize(local_full_path)
# Relativní cesta, kam bys to nahrál (např. Herci/Film.avi)
rel_path = os.path.relpath(local_full_path, LOCAL_ROOT)
clean_rel_path = normalize_path(rel_path)
except OSError:
continue
key = (fname_lower, local_size)
# --- LOGIKA ROZHODOVÁNÍ ---
if key in global_map:
# Soubor (stejné jméno a velikost) na serveru EXISTUJE.
# Otázka je: Je ve správné složce?
server_paths = global_map[key]
is_in_target = False
# Zkontrolujeme, zda alespoň jedna cesta na serveru odpovídá té, kam to chceš nahrát
# Tedy jestli obsahuje /#ColdData/Porno/ + tvoji relativní cestu
# Hledaný koncový řetězec: "porno/herci/film.avi"
target_suffix = f"{TARGET_SUBFOLDER}/{clean_rel_path}".lower()
for path in server_paths:
if path.lower().endswith(target_suffix):
is_in_target = True
break
if is_in_target:
# Je to tam, kde to má být.
count_ok += 1
else:
# Je to na serveru, ale JINDE.
count_move += 1
f_move.write(f"SOUBOR: {clean_rel_path}\n")
f_move.write(f" >>> Nalezen jinde: {server_paths[0]}\n")
else:
# Na serveru není vůbec (ani jinde).
count_upload += 1
f_upload.write(f"{local_full_path}\n")
if (count_upload + count_move + count_ok) % 1000 == 0:
print(f" ... zpracováno {count_upload + count_move + count_ok} ...", end="\r")
f_upload.close()
f_move.close()
print("\n\n📊 FINÁLNÍ REPORT")
print("=====================================================")
print(f"✅ UŽ TAM JE (Správně): {count_ok:,}")
print(f"📦 UŽ TAM JE (Ale jinde): {count_move:,} -> Koukni do 2_JIZ_EXISTUJI_JINDE.txt")
print(f"🚀 MUSÍŠ NAHRÁT (Nové): {count_upload:,} -> Seznam v 1_NAHRAT_NA_SERVER.txt")
print("=====================================================")
if __name__ == "__main__":
main()

153
TestduplicitSyncThing.py Normal file
View File

@@ -0,0 +1,153 @@
import os
import pymysql
import sys
# ==============================
# ⚙️ NASTAVENÍ
# ==============================
LOCAL_ROOT = r"U:\#Syncthing"
# DB Připojení
DB_HOST = "192.168.1.76"
DB_PORT = 3307 # Port pro tvou DB
DB_USER = "root"
DB_PASS = "Vlado9674+" # Tvé heslo
DB_NAME = "torrents"
DB_TABLE = "file_md5_index"
REMOTE_SHARE_KEY = "#ColdData"
# ==============================
def get_db_connection():
try:
return pymysql.connect(
host=DB_HOST,
port=DB_PORT,
user=DB_USER,
password=DB_PASS,
database=DB_NAME,
cursorclass=pymysql.cursors.DictCursor
)
except Exception as e:
print(f"❌ CHYBA: Nelze se připojit k MySQL na {DB_HOST}:{DB_PORT}.")
print(f" Detail: {e}")
sys.exit(1)
def normalize_path(path):
"""
1. Převede Windows '\\' na Linux '/'
2. Převede vše na malá písmena (aby 'Foto.jpg' == 'foto.JPG')
"""
return path.replace("\\", "/").lower()
def get_local_files(root_path):
print(f"📂 Skenuji lokální disk: {root_path}")
local_files = set()
if not os.path.exists(root_path):
print(f"❌ Chyba: Cesta {root_path} neexistuje.")
return local_files
count = 0
for root, dirs, files in os.walk(root_path):
# Ignorovat systémové složky Syncthingu
if ".stfolder" in dirs: dirs.remove(".stfolder")
if ".stversions" in dirs: dirs.remove(".stversions")
for file in files:
full_path = os.path.join(root, file)
try:
rel_path = os.path.relpath(full_path, root_path)
except ValueError:
continue
# NORMALIZACE (Lomítka + Malá písmena)
clean_path = normalize_path(rel_path)
local_files.add(clean_path)
count += 1
if count % 1000 == 0:
print(f" ... načteno {count} lokálních souborů ...", end="\r")
print(f"✅ Lokálně nalezeno: {len(local_files):,} souborů.")
return local_files
def get_remote_files_from_db():
print(f"📡 Připojuji se k DB '{DB_NAME}' a stahuji seznam...")
conn = get_db_connection()
remote_files = set()
try:
with conn.cursor() as cursor:
sql = f"SELECT full_path FROM {DB_TABLE} WHERE full_path LIKE %s"
cursor.execute(sql, (f"%/{REMOTE_SHARE_KEY}/%",))
rows = cursor.fetchall()
print(f" ... DB vrátila {len(rows):,} řádků. Zpracovávám...")
for row in rows:
full_path_db = row['full_path']
if f"/{REMOTE_SHARE_KEY}/" in full_path_db:
parts = full_path_db.split(f"/{REMOTE_SHARE_KEY}/")
if len(parts) > 1:
rel_path = parts[1]
# NORMALIZACE (Lomítka + Malá písmena)
clean_path = normalize_path(rel_path)
remote_files.add(clean_path)
finally:
conn.close()
print(f"✅ V DB nalezeno: {len(remote_files):,} unikátních cest.")
return remote_files
def main():
print("🚀 HLEDÁNÍ DUPLIKÁTŮ (Case Insensitive)")
print("=======================================")
local_set = get_local_files(LOCAL_ROOT)
remote_set = get_remote_files_from_db()
print("\n🔍 Porovnávám (všechna písmena ignorují velikost)...")
# Průnik
duplicates = local_set.intersection(remote_set)
only_local = local_set - remote_set
print("\n📊 VÝSLEDKY")
print("=======================================")
print(f"🏠 Celkem lokálně: {len(local_set):,}")
print(f"☁️ Celkem v DB: {len(remote_set):,}")
print("---------------------------------------")
print(f"👯 SHODA (DUPLIKÁTY): {len(duplicates):,}")
print(f"🆕 UNIKÁTNÍ (JEN DOMA): {len(only_local):,}")
print("=======================================\n")
if duplicates:
file_dup = "report_DUPLIKATY.txt"
with open(file_dup, "w", encoding="utf-8") as f:
for item in sorted(duplicates):
f.write(f"{item}\n")
print(f"💾 Seznam duplikátů (malá písmena) uložen do: {file_dup}")
if only_local:
file_new = "report_NOVE_SOUBORY.txt"
with open(file_new, "w", encoding="utf-8") as f:
for item in sorted(only_local):
f.write(f"{item}\n")
print(f"💾 Seznam nových souborů uložen do: {file_new}")
input("\nStiskni ENTER pro ukončení...")
if __name__ == "__main__":
main()

52
report_DUPLIKATY.txt Normal file
View File

@@ -0,0 +1,52 @@
záleský vojtěch - převzetí (2025)/01 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/02 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/03 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/04 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/05 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/06 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/07 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/08 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/09 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/10 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/11 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/12 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/13 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/14 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/15 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/16 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/17 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/18 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/19 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/20 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/21 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/22 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/23 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/24 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/25 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/26 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/27 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/28 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/29 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/30 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/31 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/32 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/33 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/34 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/35 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/36 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/37 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/38 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/39 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/40 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/41 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/42 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/43 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/44 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/45 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/46 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/47 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/48 - [vojtěch záleský] - převzetí.mp3
záleský vojtěch - převzetí (2025)/audiokniha-prevzeti-vojtech-zalesky-original.jpg
záleský vojtěch - převzetí (2025)/audiokniha-prevzeti-vojtech-zalesky.jpg
záleský vojtěch - převzetí (2025)/folder.jpg
záleský vojtěch - převzetí (2025)/info.txt

56068
report_NOVE_SOUBORY.txt Normal file

File diff suppressed because it is too large Load Diff

32214
report_ROZDILNE_CESTY.txt Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff