It works.

This commit is contained in:
Kameron Kenny 2024-09-17 14:47:20 -04:00
parent fc32855c86
commit e8861abbdc
No known key found for this signature in database
GPG Key ID: E5006629839D2276
5 changed files with 108 additions and 97 deletions

View File

@ -1,36 +1,32 @@
#!/usr/bin/env python #!/usr/bin/env python
import os import os
import sys import sys
# import time
from PyQt6.QtCore import *
from PyQt6.QtGui import *
from PyQt6.QtWidgets import *
import traceback import traceback
from PyQt6.QtCore import pyqtSignal, pyqtSlot, QRunnable, QObject, QThreadPool
from PyQt6.QtWidgets import QMainWindow, QApplication
from PyQt6.QtGui import QIcon,QPixmap
from PIL import Image
from configure import CONFIG_FILE, Configure from configure import CONFIG_FILE, Configure
from file_stuff import is_file, get_t_files from file_stuff import is_file
from BitMover_MainWindow import Ui_MainWindow from BitMover_MainWindow import Ui_MainWindow
from get_image_tag import get_exif_tag from get_image_tag import get_exif_tag
from media import Media from media import Media
from lumberjack import timber from lumberjack import timber
from raw_photo import extract_jpg_thumb from raw_photo import extract_jpg_thumb, get_raw_image_dimensions
log = timber(__name__) log = timber(__name__)
class WorkerSignals(QObject): class WorkerSignals(QObject):
""" """
Defines the signals available from a running worker thread. Defines the signals avail from a running worker thread.
Supported signals are: Supported signals are:
finished finished
No data No Data
error error
tuple (exctype, value, traceback.format_exc() ) tuple (exctype, value, traceback.format_exc() )
@ -40,17 +36,16 @@ class WorkerSignals(QObject):
progress progress
int indicating % progress int indicating % progress
""" """
started = pyqtSignal()
finished = pyqtSignal() finished = pyqtSignal()
error = pyqtSignal(tuple) error = pyqtSignal(tuple)
result = pyqtSignal(object) result = pyqtSignal(object)
progress = pyqtSignal(int) progress = pyqtSignal(int)
class Worker(QRunnable): class Worker(QRunnable):
""" """
Worker thread Worker Thread
Inherits from QRunnable to handler worker thread setup, signals and wrap-up. Inherits from QRunnable to handler worker thread setup, signals and wrap-up.
@ -64,7 +59,7 @@ class Worker(QRunnable):
def __init__(self,fn,*args,**kwargs): def __init__(self,fn,*args,**kwargs):
super(Worker,self).__init__() super(Worker,self).__init__()
# Store constructor arguments (re-used for processing) # Store constructor args (re-used for processing)
self.fn = fn self.fn = fn
self.args = args self.args = args
self.kwargs = kwargs self.kwargs = kwargs
@ -78,18 +73,18 @@ class Worker(QRunnable):
""" """
Initialise the runner function with passed args, kwargs. Initialise the runner function with passed args, kwargs.
""" """
# Retrieve args/kwargs here; and fire processing using them # Retrieve args/kwargs here; and fire processing using them
try: try:
self.signals.started.emit()
result = self.fn(*self.args, **self.kwargs) result = self.fn(*self.args, **self.kwargs)
except: except:
traceback.print_exc() traceback.print_exc()
exctype, value = sys.exc_info()[:2] exctype, value = sys.exc_info()[:2]
self.signals.error.emit((exctype,value,traceback.format_exc())) self.signals.error.emit((exctype,value,traceback.format_exc()))
else: else:
self.signals.result.emit(result) # Return the result of the processing self.signals.result.emit(result)
finally: finally:
self.signals.finished.emit() # Done self.signals.finished.emit()
# Subclass QMainWindow to customize your application's main window # Subclass QMainWindow to customize your application's main window
class MainWindow(QMainWindow, Ui_MainWindow): class MainWindow(QMainWindow, Ui_MainWindow):
@ -100,12 +95,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
c = Configure(CONFIG_FILE) c = Configure(CONFIG_FILE)
self.config = c.load_config() self.config = c.load_config()
self.total_files = 0 self.total_files = 0
self.file_total = 0
# self.t_find_files = threading.Thread(target=self.find_files) self.threads = {}
self.lcd_files_found.display(int(0))
self.set_progress(0, 0)
self.setWindowTitle("BitMover") self.setWindowTitle("BitMover")
self.setWindowIcon(QIcon('assets/forklift.png')) self.setWindowIcon(QIcon('assets/forklift.png'))
self.threadpool = QThreadPool()
print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())
self.src_dir = self.config['folders']['source']['base'] self.src_dir = self.config['folders']['source']['base']
self.dst_dir = self.config['folders']['destination']['base'] self.dst_dir = self.config['folders']['destination']['base']
@ -117,20 +117,24 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.pushButton_src_browse.clicked.connect(self.select_src_directory) self.pushButton_src_browse.clicked.connect(self.select_src_directory)
self.pushButton_dst_browse.clicked.connect(self.select_dst_directory) self.pushButton_dst_browse.clicked.connect(self.select_dst_directory)
self.pushButton_3_scan_dir.clicked.connect(self.find_files) self.pushButton_3_scan_dir.clicked.connect(self.find_files)
self.toggle_scan_button(True)
# self.pushButton_3_scan_dir.clicked.connect(self.t_find_files.start) # self.pushButton_3_scan_dir.clicked.connect(self.t_find_files.start)
self.lcd_files_found.display(int(0))
self.set_progress(0,0)
self.img_preview.setPixmap(QPixmap('assets/preview_placeholder.jpg')) self.img_preview.setPixmap(QPixmap('assets/preview_placeholder.jpg'))
self.img_preview.setScaledContents(True) self.img_preview.setScaledContents(True)
# self.img_preview.setFixedWidth(preview_width)
# self.img_preview.setFixedHeight(preview_height)
self.file_list.currentItemChanged.connect(self.index_changed) self.file_list.currentItemChanged.connect(self.index_changed)
self.threadpool = QThreadPool()
self.files = {} self.files = {}
def toggle_scan_button(self,enable=True):
if enable:
self.pushButton_3_scan_dir.setEnabled(True)
else:
self.pushButton_3_scan_dir.setDisabled(True)
def index_changed(self,i): def index_changed(self,i):
f = i.text() f = i.text()
@ -143,19 +147,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.label_data_date_time_created.setText(dtc) self.label_data_date_time_created.setText(dtc)
if m.file_type == 'image': if m.file_type == 'image':
# img = Image.open(f)
dpi = get_exif_tag(f,"xresolution") dpi = get_exif_tag(f,"xresolution")
width = get_exif_tag(f,"image width") if f.lower().endswith("jpg") or f.lower().endswith("jpeg"):
height = get_exif_tag(f,"image height") img = Image.open(f)
if width is None: width = img.width
get_exif_tag(f,"exifimagewidth") height = img.height
if height is None: else:
get_exif_tag(f,"exifimagelength") width = get_raw_image_dimensions(f)[1]
# width = img.width height = get_raw_image_dimensions(f)[0]
# height = img.height
size = f'{width}x{height}' size = f'{width}x{height}'
if width is not None and height is not None: if width is not None and height is not None:
mpixels = (width * height) / 1000000 mpixels = round((width * height) / 1000000, 1)
else: else:
mpixels = '' mpixels = ''
iso = get_exif_tag(f,"iso") iso = get_exif_tag(f,"iso")
@ -191,7 +193,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
jpg = extract_jpg_thumb(f) jpg = extract_jpg_thumb(f)
self.img_preview.setPixmap(QPixmap(jpg)) self.img_preview.setPixmap(QPixmap(jpg))
def select_src_directory(self): def select_src_directory(self):
directory = QFileDialog.getExistingDirectory(self, directory = QFileDialog.getExistingDirectory(self,
"Select Directory", "Select Directory",
@ -212,74 +213,99 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.dst_dir = directory self.dst_dir = directory
self.lineEdit_dst_dir.setText(self.dst_dir) self.lineEdit_dst_dir.setText(self.dst_dir)
def set_total_files(self,t):
self.total_files = t
self.lcd_files_found.display(self.total_files)
def progress_fn(self,n):
# print("%d%% done" % n)
self.progressBar_overall.setValue(int(n))
def set_progress(self,p,t): def set_progress(self,p,t):
""" """
set progress for bar, set progress for bar,
p = progress counter p = progress counter
t = target total t = target total
o = progress bar object
""" """
if int(t) == 0: if int(t) == 0:
t += 1 t += 1
#
# while QPainter.isActive(Ui_MainWindow.QPainter()):
# print('painter active')
# time.sleep(0.02)
percent_complete = (int(p) / int(t)) * 100 percent_complete = (int(p) / int(t)) * 100
self.progressBar_overall.setValue(int(percent_complete)) self.progressBar_overall.setValue(int(percent_complete))
def print_output(self, s): def get_t_files(self):
print(s) for folder, subfolders, filename in os.walk(self.src_dir):
for f_type in self.file_types:
def thread_complete(self): for ext in self.file_types[f_type]:
print("THREAD COMPLETE!") for file in filename:
if file.lower().endswith(ext):
def thread_find_files(self): current_file = os.path.join(folder, file)
print('in thread_find_files') if is_file(current_file):
print(self.src_dir) self.file_total += int(1)
worker = Worker(self.find_files()) else:
worker.signals.result.connect(self.print_output) print(f"Skipping {current_file} as it does not look like a real file.")
worker.signals.finished.connect(self.thread_complete)
worker.signals.progress.connect(self.progress_fn)
self.threadpool.start(worker)
def find_files(self):
""" find files to build a dictionary out of """
log.info('In find_files')
print(self.src_dir)
def t_find_files(self,progress_callback):
file_count = int(0) file_count = int(0)
file_total = get_t_files(self.src_dir,self.file_types) self.get_t_files()
self.set_total_files(self.file_total)
for folder, subfolders, filename in os.walk(self.src_dir): for folder, subfolders, filename in os.walk(self.src_dir):
for f_type in self.file_types: for f_type in self.file_types:
for ext in self.file_types[f_type]: for ext in self.file_types[f_type]:
# for file in tqdm(filename,
# desc='Finding ' + ext + ' Files in ' + folder):
for file in filename: for file in filename:
if file.lower().endswith(ext): if file.lower().endswith(ext):
current_file = os.path.join(folder, file) current_file = os.path.join(folder, file)
if is_file(current_file): if is_file(current_file):
file_count += int(1) file_count += int(1)
self.process_file(folder, file) self.process_file(current_file)
self.set_progress(file_count,file_total) # self.set_progress(file_count,file_total)
# time.sleep(.02) # time.sleep(.02)
else: else:
print(f"Skipping {current_file} as it does not look like a real file.") print(f"Skipping {current_file} as it does not look like a real file.")
progress_callback.emit((file_count / file_total) * 100) progress_callback.emit((file_count / self.file_total) * 100)
return "Done."
def print_output(self,s):
print(s)
def scan_thread_started(self):
print('scan thread started')
self.toggle_scan_button(False)
def scan_thread_done(self):
print('scan thread complete.')
self.toggle_scan_button(True)
def thread_complete(self):
print("THREAD COMPLETE.")
def find_files(self):
""" find files to build a dictionary out of """
worker = Worker(self.t_find_files)
# worker.signals.started.connect(self.toggle_scan_button(enable=False))
worker.signals.started.connect(self.scan_thread_started)
worker.signals.result.connect(self.print_output)
worker.signals.finished.connect(self.thread_complete)
worker.signals.finished.connect(self.scan_thread_done)
# worker.signals.finished.connect(self.toggle_scan_button(enable=True))
worker.signals.progress.connect(self.progress_fn)
# Execute.
self.threadpool.start(worker)
def get_event(self): def get_event(self):
event_name = self.eventName.text() event_name = self.eventName.text()
return event_name return event_name
def process_file(self,path_name, f_name): def process_file(self,p):
""" gather information and add to dictionary """ """ gather information and add to dictionary """
path_name = os.path.dirname(p)
f_name = os.path.basename(p)
event = self.get_event() event = self.get_event()
c = self.config c = self.config

View File

@ -19,7 +19,7 @@ args = parser.parse_args()
if args.folder: if args.folder:
FOLDER = args.folder FOLDER = args.folder
else: else:
print("you need to specify a folder.") print("you need to specify a folder. Dedup")
sys.exit() sys.exit()
if args.dryrun: if args.dryrun:
dry_run = True dry_run = True

View File

@ -126,18 +126,3 @@ def validate_config_dir_access(config):
accessible = True accessible = True
return accessible return accessible
def get_t_files(p,t):
total = int(0)
for folder, subfolders, filename in os.walk(p):
for f_type in t:
for ext in t[f_type]:
# for file in tqdm(filename,
# desc='Finding ' + ext + ' Files in ' + folder):
for file in filename:
if file.lower().endswith(ext):
current_file = os.path.join(folder, file)
if is_file(current_file):
total += int(1)
else:
print(f"Skipping {current_file} as it does not look like a real file.")
return total

View File

@ -21,8 +21,8 @@ def extract_jpg_thumb(raw_file_path):
return 'thumbnail.jpg' return 'thumbnail.jpg'
# thumbnail_path = extract_jpg_thumb('your_raw_image.nef') def get_raw_image_dimensions(raw_file_path):
# if thumbnail_path: i = imread(raw_file_path)
# print("Thumbnail extracted to:", thumbnail_path) height, width = i.raw_image.shape[:2]
# else:
# print("No thumbnail found or unsupported format.") return height,width

View File

@ -19,7 +19,7 @@ args = parser.parse_args()
if args.folder: if args.folder:
FOLDER = args.folder FOLDER = args.folder
else: else:
print("you need to specify a folder.") print("you need to specify a folder. Duh.")
sys.exit() sys.exit()
if args.dryrun: if args.dryrun:
dry_run = True dry_run = True