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
+5 -12
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
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
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}")
+74
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()
+145
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()
+205
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()
+66
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)
+37
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)
+87
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()
+95
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()
+67
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()
+67
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()
@@ -1,3 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
+55855
View File
File diff suppressed because it is too large Load Diff
@@ -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()
+134
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
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()
+128
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()
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
/mnt/user/#ColdData/physical_files_list.txt
+4
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
File diff suppressed because it is too large Load Diff
+152
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
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
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
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff