Skip to main content

Fileee.com Upload manager

Fileee.com hat im kostenfreien Service eine Uploadgrenze von 10 Dokumenten, wir müssen also einen Watchdog haben der Fileee nach und nach je nach Erlaubnis füttert.

Setup

Fileee schaut auf WebDav von Nextcloud, daher brauche ich keine Spielereien mit Webcrawlern. Dieses WebDav Folder ist natürlich synchronisiert.

Generator: Perplexity Pro - 2025-02-03

pip install watchdog

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Fileee Upload Manager - Windows Background Service
Verwaltet die Warteschlange für Fileee.com Uploads mit monatlichem Limit
"""

import os
import sys
import time
import json
import shutil
from datetime import datetime
from pathlib import Path
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class FileeeUploadManager:
    def __init__(self, queue_folder, target_folder, monthly_limit=10):
        self.queue_folder = Path(queue_folder)
        self.target_folder = Path(target_folder)
        self.monthly_limit = monthly_limit
        self.state_file = self.queue_folder / '.fileee_state.json'
        self.queue = []
        self.monthly_distribution = {}
        
        # Erstelle Ordner falls nicht vorhanden
        self.queue_folder.mkdir(parents=True, exist_ok=True)
        self.target_folder.mkdir(parents=True, exist_ok=True)
        
        self.load_state()
        
    def get_current_month_key(self):
        """Gibt aktuellen Monat im Format MMYY zurück"""
        now = datetime.now()
        return f"{now.month:02d}{str(now.year)[-2:]}"
    
    def get_month_with_offset(self, offset):
        """Berechnet Monat mit Offset im Format MMYY"""
        now = datetime.now()
        month = now.month + offset
        year = now.year
        
        while month > 12:
            month -= 12
            year += 1
        
        return f"{month:02d}{str(year)[-2:]}"
    
    def count_existing_files_in_month(self, month_key):
        """Zählt vorhandene PDFs im Monatsordner"""
        month_folder = self.target_folder / month_key
        if not month_folder.exists():
            return 0
        pdf_files = list(month_folder.glob('*.pdf'))
        return len(pdf_files)
    
    def scan_queue(self):
        """Scannt Warteschlangen-Ordner nach PDFs"""
        pdf_files = list(self.queue_folder.glob('*.pdf'))
        
        for pdf_file in pdf_files:
            if not any(f['path'] == str(pdf_file) for f in self.queue):
                self.queue.append({
                    'path': str(pdf_file),
                    'name': pdf_file.name,
                    'added': datetime.now().isoformat(),
                    'status': 'pending',
                    'scheduled_month': None
                })
        
        self.distribute_files()
        self.save_state()
        print(f"[INFO] {len(self.queue)} Dateien in Warteschlange")
    
    def distribute_files(self):
        """Verteilt Dateien auf Monate basierend auf Limit"""
        self.monthly_distribution = {}
        month_offset = 0
        
        # Sortiere nach Hinzufügedatum
        self.queue.sort(key=lambda x: x['added'])
        
        for file in self.queue:
            target_month = self.get_month_with_offset(month_offset)
            
            if target_month not in self.monthly_distribution:
                self.monthly_distribution[target_month] = []
            
            # Wenn Monat voll, gehe zum nächsten
            if len(self.monthly_distribution[target_month]) >= self.monthly_limit:
                month_offset += 1
                target_month = self.get_month_with_offset(month_offset)
                if target_month not in self.monthly_distribution:
                    self.monthly_distribution[target_month] = []
            
            self.monthly_distribution[target_month].append(file)
            file['scheduled_month'] = target_month
            
            current_month = self.get_current_month_key()
            file['status'] = 'scheduled' if target_month == current_month else 'pending'
    
    def process_current_month(self):
        """Verschiebt Dateien für aktuellen Monat in Zielordner"""
        current_month = self.get_current_month_key()
        
        if current_month not in self.monthly_distribution:
            return
        
        month_folder = self.target_folder / current_month
        month_folder.mkdir(exist_ok=True)
        
        for file in self.monthly_distribution[current_month]:
            if file['status'] == 'scheduled':
                source = Path(file['path'])
                if source.exists():
                    dest = month_folder / source.name
                    try:
                        shutil.move(str(source), str(dest))
                        print(f"[SUCCESS] Verschoben: {source.name} → {current_month}/")
                        self.queue.remove(file)
                    except Exception as e:
                        print(f"[ERROR] Fehler beim Verschieben von {source.name}: {e}")
        
        self.distribute_files()
        self.save_state()
    
    def save_state(self):
        """Speichert aktuellen Zustand"""
        state = {
            'queue': self.queue,
            'monthly_distribution': self.monthly_distribution,
            'last_update': datetime.now().isoformat()
        }
        with open(self.state_file, 'w', encoding='utf-8') as f:
            json.dump(state, f, indent=2, ensure_ascii=False)
    
    def load_state(self):
        """Lädt gespeicherten Zustand"""
        if self.state_file.exists():
            try:
                with open(self.state_file, 'r', encoding='utf-8') as f:
                    state = json.load(f)
                    self.queue = state.get('queue', [])
                    self.monthly_distribution = state.get('monthly_distribution', {})
                    print(f"[INFO] Zustand geladen: {len(self.queue)} Dateien")
            except Exception as e:
                print(f"[WARNING] Fehler beim Laden des Zustands: {e}")
    
    def run(self):
        """Hauptschleife"""
        print("[INFO] Fileee Upload Manager gestartet")
        print(f"[INFO] Warteschlange: {self.queue_folder}")
        print(f"[INFO] Zielordner: {self.target_folder}")
        print(f"[INFO] Monatslimit: {self.monthly_limit}")
        
        self.scan_queue()
        
        # Verarbeite initial
        self.process_current_month()
        
        last_check_day = datetime.now().day
        
        while True:
            try:
                # Prüfe auf neuen Monat
                current_day = datetime.now().day
                if current_day != last_check_day and current_day == 1:
                    print("[INFO] Neuer Monat erkannt, verarbeite Warteschlange...")
                    self.scan_queue()
                    self.process_current_month()
                    last_check_day = current_day
                
                # Scanne alle 5 Minuten
                time.sleep(300)
                self.scan_queue()
                self.process_current_month()
                
            except KeyboardInterrupt:
                print("\n[INFO] Service wird beendet...")
                self.save_state()
                break
            except Exception as e:
                print(f"[ERROR] Unerwarteter Fehler: {e}")
                time.sleep(60)

if __name__ == '__main__':
    # Konfiguration
    QUEUE_FOLDER = r'WEBDAV-QUEUE'
    TARGET_FOLDER = r'WEBDAV-FOLDER'
    MONTHLY_LIMIT = 10
    
    # Starte Manager
    manager = FileeeUploadManager(QUEUE_FOLDER, TARGET_FOLDER, MONTHLY_LIMIT)
    manager.run()

Das ganze schreibt ihr in einen Ordner ohne Leerzeichen und könnt es dann als Windows Service definieren.
Zum Beispiel mit dem Non-Sucking-Service-Manager - geht sicher auch irgendwie ohne... Aber wie der Name schon sagt, der Weg würde sicher nicht so geil sein...

nssm install FileeeUploadManager PYTHON.EXE SCRIPT.PY
nssm set FileeeUploadManager AppDirectory "SCRIPTORDNER"
nssm set FileeeUploadManager DisplayName "Fileee Upload Manager"
nssm set FileeeUploadManager Description "Verwaltet Fileee.com Upload-Warteschlange"
nssm set FileeeUploadManager Start SERVICE_AUTO_START

Bei Fehlern braucht ihr 

nssm set FileeeUploadManager AppStderr LOGFILE
nssm set FileeeUploadManager AppStdout LOGFILE

Darauf seht ihr den neuen Dienst im Service Manager (services.msc) und ihr habt einen Hintergrundprozess der monatlich 10 Files von einem anderen Ordner in euren Webdav Ordner schiebt...

Ob man es brauchen kann oder nicht... War ein kleines Feierabendprojekt bei mir...