Organizzare le foto in automatico con Python: come ho creato il mio Photo Organizer

Se sei come me, ogni volta che torni da un viaggio o da un evento speciale ti ritrovi con decine (o centinaia!) di foto sparse ovunque: sulla SD della fotocamera, sul telefono, magari anche sul cloud… E poi rimandiamo sempre il momento di organizzarle, finendo in un caos totale.

Ecco perché ho deciso di creare un piccolo programma Python che potesse fare tutto il lavoro sporco per me. Oggi ti presento il mio Photo Organizer, uno script che ordina automaticamente immagini, video e file RAW, dividendo tutto per anno e mese

Come funziona?

Il funzionamento è semplice:

  1. Gli dici dove si trovano i tuoi file (ad esempio la scheda SD della fotocamera).
  2. Gli dici dove vuoi che vengano salvati (un hard disk, una cartella sul PC…).
  3. Il programma analizza ogni file e lo sposta nella cartella giusta, basandosi sulla data di creazione.

Ad esempio, una foto scattata il 10 agosto 2023 finirà in:

/Tuodisco/JPG/2023/10-Agosto/nomedelfile.jpg

Lo script riconosce automaticamente:

  • Foto classiche (.jpg, .png, ecc.)
  • Video (.mp4, .mov, ecc.)
  • Immagini RAW da fotocamere professionali (.nef, .cr2…)

E se un file è già presente, non lo ricopia. Tutto è documentato in un file di log!

Un’occhiata al codice (semplificata!)

Ecco un pezzetto chiave del codice che decide dove mettere ogni file:

def get_dest_path(cfile, HD, file):
   datafile = 
datetime.datetime.fromtimestamp(os.path.getmtime(cfile))
   Anno = HD + datafile.strftime("%Y")
   GiornoMese = Anno + "/" + datafile.strftime("%d") + "-" + 
   mesi[int(datafile.strftime("%m"))-1]
   return os.path.join(GiornoMese, file)

In pratica, prende la data di modifica del file, la trasforma in anno/mese/giorno, e costruisce il percorso finale dove copiare il file.

Perché ho usato Python?

Python è uno dei linguaggi più semplici e versatili: perfetto per chi vuole automatizzare attività ripetitive senza impazzire. Inoltre, grazie a librerie come os, shutil e tqdm, possiamo:

  • Cercare file dentro cartelle e sottocartelle
  • Copiarli in modo sicuro
  • Visualizzare il progresso dell’operazione

Come usarlo?

python Photo-Organizer.py /percorso/della/SD /percorso/dell/harddisk/

E voilà, il tuo archivio fotografico è pronto!

Vuoi provarlo anche tu?

Questo tipo di script è perfetto per chi vuole iniziare con l’automazione in Python. Se vuoi provare anche tu, scrivimi e sarò felice di condividere lo script o aiutarti a personalizzarlo!

import os
import datetime
import shutil
import sys
import logging
from tqdm import tqdm

# Configura il logging
logging.basicConfig(
    filename='photo_organizer.log',  # Nome del file di log
    level=logging.INFO,  # Impostiamo il livello di log (INFO, DEBUG, ERROR, etc.)
    format='%(asctime)s - %(levelname)s - %(message)s',  # Formato del log
)

mesi = ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"]

img = (".jpg", ".jpeg", ".jfif", ".pjpeg", ".pjp", ".png", ".gif", ".webp", ".svg", ".apng", ".avif")

video = (".webm", ".mts", ".m2ts", ".TS", ".mov", ".mp4", ".m4p", ".m4v", ".mxf")

imgraw = (".nef", ".cr2", ".cr3")

def main():
    if len(sys.argv) < 3:
        print_help()
        sys.exit(1)

    SD = sys.argv[1]
    HardDisk = sys.argv[2]    
    logging.info(f"Percorso SD: {SD}")
    logging.info(f"Percorso HD: {HardDisk}")

    JPG = HardDisk + "JPG/"
    RAW = HardDisk + "RAW/"
    VIDEO = HardDisk + "VIDEO/"

    NumJPGCopiati = 0
    NumJPGNonCopiati = 0
    NumRAWCopiati = 0
    NumRAWNonCopiati = 0
    NumVIDEOCopiati = 0
    NumVIDEONonCopiati = 0
    NumFileEstSbagliata = 0
    NumFileNonCopiati = 0
    file_list = []
    
    for root, dirs, files in os.walk(SD):
        for file in files:
            file_list.append((root, file))

    for root, file in tqdm(file_list, desc="Copia file", unit="file"):
        if is_image(file):
            if copia_file(JPG, root, file):
                NumJPGCopiati += 1
            else:
                NumJPGNonCopiati += 1
        elif is_raw(file):
            if copia_file(RAW, root, file):
                NumRAWCopiati += 1
            else:
                NumRAWNonCopiati += 1
        elif is_video(file):
            if copia_file(VIDEO, root, file):
                NumVIDEOCopiati += 1
            else:
                NumVIDEONonCopiati += 1
        else:
            logging.warning(f"{file} - Estensione Sbagliata")
            NumFileEstSbagliata += 1

    logging.info(f"Numero JPG COPIATI = {NumJPGCopiati}")
    logging.info(f"Numero JPG Non COPIATI = {NumJPGNonCopiati}")
    logging.info(f"Numero RAW COPIATI = {NumRAWCopiati}")
    logging.info(f"Numero RAW Non COPIATI = {NumRAWNonCopiati}")
    logging.info(f"Numero VIDEO COPIATI = {NumVIDEOCopiati}")
    logging.info(f"Numero VIDEO Non COPIATI = {NumVIDEONonCopiati}")
    logging.info(f"Numero Estensione Sbagliata = {NumFileEstSbagliata}")
    
    TotaleCopiati = NumJPGCopiati + NumRAWCopiati + NumVIDEOCopiati
    TotaleNonCopiati = NumJPGNonCopiati + NumRAWNonCopiati + NumVIDEONonCopiati + NumFileEstSbagliata
    
    logging.info(f"Numero FILE Copiati Totali = {TotaleCopiati}")
    logging.info(f"Numero FILE Non Copiati Totali = {TotaleNonCopiati}")
    logging.info(f"Numero FILE Totali = {TotaleCopiati + TotaleNonCopiati}")

def print_help():
    print("Utilizzo:")
    print("  python Photo-Organizer.py <PERCORSO_SORGENTE> <PERCORSO_DESTINAZIONE> ...")
    print("Esempio:")
    print("  python Photo-Organizer.py /media/davide/NIKON D500/DCIM/115ND500/ /home/davide/Immagini/")
    print("\nDescrizione:")
    print("  Questo script accetta due argomenti e copia ")
    print("  immagini (.jpg, .jpeg, .jfif, .pjpeg, .pjp, .png, .gif, .webp, .svg, .apng, .avif)")
    print("  video (.webm, .mts, .m2ts, .TS, .mov, .mp4, .m4p, .m4v, .mxf)")
    print("  immagini RAW (.nef,.cr2,.cr3)")
    print("  Se non inserisci argomenti, mostra questo messaggio di aiuto.")

def get_dest_path(cfile, HD, file):
    datafile = datetime.datetime.fromtimestamp(os.path.getmtime(cfile))
    Anno = HD + datafile.strftime("%Y")
    GiornoMese = Anno + "/" + datafile.strftime("%d") + "-" + mesi[int(datafile.strftime("%m"))-1]
    return os.path.join(GiornoMese, file)

def is_image(file):
    return os.path.splitext(file)[1].lower() in img

def is_raw(file):
    return os.path.splitext(file)[1].lower() in imgraw

def is_video(file):
    return os.path.splitext(file)[1].lower() in video

def copia_file(HD, root, file):
    cfile = os.path.join(root, file)
    dest_path = get_dest_path(cfile, HD, file)
    if os.path.exists(dest_path):
        logging.info(f"{file} - Già Esistente.")
        return False
    else:
        os.makedirs(os.path.dirname(dest_path), exist_ok=True)
        shutil.copyfile(cfile, dest_path)
        logging.info(f"{file} - Copiato con successo in {dest_path}")
        return True

if __name__ == "__main__":
    main()

Spieghiamo i nodi di Node-RED

Node-RED è uno strumento di programmazione per collegare insieme dispositivi hardware, API e servizi online. Fornisce un editor basato su browser che semplifica il collegamento dei flussi utilizzando l’ampia gamma di nodi che può essere distribuita al runtime con un solo clic.

I nodi sono la parte fondamentale di Node-RED, iniziamo con i due che si usano più di tutti, l’iniect e il debug

questi due nodi servono a provare il codice l’iniect attraverso il timestamp ovvero i secondi della macchina in cui è installato e il debug che permette di visualizzare il risultato dei nodi precedenti nella barra di sinistra. L’iniect in particolare può anche impostare un uscita temporizzata che può comandare i nodi successivi.

REMOTE RED SU DIETPI

Con Remote-RED puoi accedere alla dashboard di Node-RED direttamente dal cellulare anche se non sei a casa. Puoi anche farti inviare notifiche da Node-RED. Le notifiche possono avere anche azioni a cui puoi rispondere direttamente.

Purtroppo su Dietpi non funziona perchè Remote-REDcomunica con il server attraverso SSH Client, Dietpi per default non ha nessun SSH Client. installarlo è semplice, basta aprire il software di dietpi con questo comando:

sudo apt install openvpn

VirtualBox Con NodeRed

Per poter sviluppare progetti con raspberry e con Node red, possiamo utilizzare una macchina virtuale con VirtualBox. oggi vi spiego come installare Dietpi e Node red su virtual box. Utilizzare una macchina virtuale per sviluppare il tutto è ottimo per poter testare i nostri programmi.

Sul sito Oracle VM VirtualBox possiamo scaricare l’ultima versione per il nostro sistema operativo.

Quando lo abbiamo installato possiamo scaricare l’immagine del sistema operativo Dietpi.

DietPi-VirtualBox-download-image

Una volta scaricato il SO, lo scompattiamo e importiamo l’applicazione virtuale

Lasciamo tutto invariato e clicchiamo su Importa, ci ritroveremo con una riga così:

Ora se avviamo il SO avremo un errore perchè non abbiamo installato l’Extension Pack lo scarichiamo da qui

Cliccandoci semplicemente sopra lo possiamo installare:

Accettiamo e si installa l’extension pack. Ora possiamo riavviare e aspettare che finisce di riavviarsi il sistema operativo.

quando si presenta questa schermata premere cancel per non cambiare la password di default. ora possiamo installare NodeRed, sul terminale digitiamo:

dietpi-config

uscirà questa maschera

selezionare Browse Software nell’elenco dovremo ricercare Node Red, vedi sotto:

ora possiamo selezionare Ok e Install nella schermata precedente. quando ha finito di installare possiamo riavviare il sistema e controllare l’indirizzo IP:

digitiamo indirizzoIP:1880 sul browser del PC come ad esempio questo:

192.168.1.49:1880

e avremo il sistema Node Red direttamente sul PC

questo è tutto, grazie per la lettura

Node-RED

Oggi parliamo di Node-RED,il sito ufficiale é: www.nodered.org/ ed è un potente strumento per la creazione di applicazioni Internet of Things (IoT) con l’obiettivo di semplificare il “collegamento” dei blocchi di codice per eseguire le attività. Utilizza un approccio di programmazione visuale che consente agli sviluppatori di collegare blocchi di codice predefiniti, noti come “nodi”, insieme per eseguire un’attività. I nodi collegati, solitamente con una combinazione di nodi di input, nodi di elaborazione e nodi di output, quando cablati insieme, costituiscono un “flusso”.

Originariamente sviluppato come progetto open source presso IBM alla fine del 2013, per soddisfare la necessità di collegare rapidamente hardware e dispositivi a servizi Web e altri software – come una sorta di colla per l’IoT – si è rapidamente evoluto fino a diventare una programmazione IoT per scopi generali attrezzo. È importante sottolineare che Node-RED ha rapidamente sviluppato una base di utenti significativa e in crescita e una comunità di sviluppatori attivi che stanno contribuendo con nuovi nodi che consentono ai programmatori di riutilizzare il codice Node-RED per un’ampia varietà di attività.

Sebbene Node-RED fosse originariamente progettato per funzionare con l’Internet of Things, ovvero dispositivi che interagiscono e controllano il mondo reale, man mano che si è evoluto, è diventato utile per una vasta gamma di applicazioni.

Installare e aggiornare Node-RED

il sito di Node-RED ha già scritto uno script per installare automaticamente Node-RED su Raspberry. Questo script lo aggiorna anche quando è già installato.

Basta copiare il codice aprire un terminale su Raspberry e copiarci dentro questa stringa:

bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)

Per funzionare hai bisogno di curl, se non è installato su raspberry perché ad esempio hai installato dietpi possiamo installarlo attraverso il terminale con questo codice:

sudo apt install build-essential git curl