import dialog

This commit is contained in:
Kameron Kenny 2024-09-24 10:12:47 -04:00
parent f49cd5df6a
commit 96111a4f65
No known key found for this signature in database
GPG Key ID: E5006629839D2276
16 changed files with 1010 additions and 137 deletions

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1473</width> <width>1463</width>
<height>928</height> <height>928</height>
</rect> </rect>
</property> </property>
@ -107,7 +107,7 @@
<number>20</number> <number>20</number>
</property> </property>
<item row="6" column="0"> <item row="6" column="0">
<widget class="QLabel" name="l_camera"> <widget class="QLabel" name="l_meta_06">
<property name="font"> <property name="font">
<font> <font>
<italic>true</italic> <italic>true</italic>
@ -120,7 +120,7 @@
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QLabel" name="l_iso"> <widget class="QLabel" name="l_meta_04">
<property name="font"> <property name="font">
<font> <font>
<italic>true</italic> <italic>true</italic>
@ -133,7 +133,7 @@
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLabel" name="label_data_width_height"> <widget class="QLabel" name="l_meta_content_01">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
@ -153,7 +153,7 @@
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="7" column="0">
<widget class="QLabel" name="l_lens"> <widget class="QLabel" name="l_meta_07">
<property name="font"> <property name="font">
<font> <font>
<italic>true</italic> <italic>true</italic>
@ -166,7 +166,7 @@
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QLabel" name="l_dpi"> <widget class="QLabel" name="l_meta_02">
<property name="font"> <property name="font">
<font> <font>
<italic>true</italic> <italic>true</italic>
@ -179,7 +179,7 @@
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="5" column="0">
<widget class="QLabel" name="l_aperture"> <widget class="QLabel" name="l_meta_05">
<property name="font"> <property name="font">
<font> <font>
<italic>true</italic> <italic>true</italic>
@ -192,28 +192,28 @@
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="4" column="1">
<widget class="QLabel" name="label_data_iso"> <widget class="QLabel" name="l_meta_content_04">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="5" column="1">
<widget class="QLabel" name="label_data_aperture"> <widget class="QLabel" name="l_meta_content_05">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="7" column="1">
<widget class="QLabel" name="label_data_lens"> <widget class="QLabel" name="l_meta_content_07">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="l_megapixels"> <widget class="QLabel" name="l_meta_03">
<property name="font"> <property name="font">
<font> <font>
<italic>true</italic> <italic>true</italic>
@ -226,14 +226,14 @@
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="3" column="1">
<widget class="QLabel" name="label_data_megapixels"> <widget class="QLabel" name="l_meta_content_03">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="l_width_height"> <widget class="QLabel" name="l_meta_01">
<property name="font"> <property name="font">
<font> <font>
<italic>true</italic> <italic>true</italic>
@ -246,21 +246,21 @@
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLabel" name="label_data_date_time_created"> <widget class="QLabel" name="l_meta_content_date_time_c">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="6" column="1">
<widget class="QLabel" name="label_data_camera"> <widget class="QLabel" name="l_meta_content_06">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="0"> <item row="8" column="0">
<widget class="QLabel" name="l_zoom"> <widget class="QLabel" name="l_meta_08">
<property name="font"> <property name="font">
<font> <font>
<italic>true</italic> <italic>true</italic>
@ -273,14 +273,14 @@
</widget> </widget>
</item> </item>
<item row="8" column="1"> <item row="8" column="1">
<widget class="QLabel" name="label_data_zoom"> <widget class="QLabel" name="l_meta_content_08">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLabel" name="label_data_dpi"> <widget class="QLabel" name="l_meta_content_02">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
@ -313,32 +313,32 @@
<x>910</x> <x>910</x>
<y>10</y> <y>10</y>
<width>541</width> <width>541</width>
<height>71</height> <height>31</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLineEdit" name="eventName"/>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="labelEvent"> <widget class="QLabel" name="labelEvent">
<property name="text"> <property name="text">
<string>Event Label</string> <string>Event</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1">
<widget class="QLineEdit" name="eventName"/>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="gridLayoutWidget_4"> <widget class="QWidget" name="gridLayoutWidget_4">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>910</x> <x>910</x>
<y>90</y> <y>50</y>
<width>221</width> <width>182</width>
<height>41</height> <height>91</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2" rowstretch="0" columnstretch="0,1"> <layout class="QGridLayout" name="gridLayout_2" rowstretch="0,0" columnstretch="0,1">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
<property name="font"> <property name="font">
@ -354,18 +354,68 @@
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLCDNumber" name="lcd_files_found"/> <widget class="QLCDNumber" name="lcd_files_found"/>
</item> </item>
<item row="1" column="1">
<widget class="QLCDNumber" name="lcd_files_imported"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="text">
<string>Files Imported</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="gridLayoutWidget_5"> <widget class="QWidget" name="gridLayoutWidget_5">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>1140</x> <x>1100</x>
<y>90</y> <y>50</y>
<width>311</width> <width>351</width>
<height>46</height> <height>93</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="gridLayout_3">
<item row="2" column="1">
<widget class="QProgressBar" name="progressBar_importing_2">
<property name="value">
<number>24</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLCDNumber" name="lcd_import_progress">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLCDNumber" name="lcd_current_file_progress">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="l_proecessing_progress">
<property name="text">
<string>Processing Progress</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="l_current_file_progress">
<property name="text">
<string>Current File Progress</string>
</property>
</widget>
</item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QProgressBar" name="progressBar_processing"> <widget class="QProgressBar" name="progressBar_processing">
<property name="value"> <property name="value">
@ -373,6 +423,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1">
<widget class="QProgressBar" name="progressBar_importing">
<property name="value">
<number>24</number>
</property>
</widget>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="l_import_progress"> <widget class="QLabel" name="l_import_progress">
<property name="text"> <property name="text">
@ -380,17 +437,34 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="2">
<widget class="QLabel" name="l_proecessing_progress"> <widget class="QLCDNumber" name="lcd_processing_progress">
<property name="text"> <property name="frameShape">
<string>Processing Progress</string> <enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="0" column="3">
<widget class="QProgressBar" name="progressBar_importing"> <widget class="QLabel" name="label_2">
<property name="value"> <property name="text">
<number>24</number> <string>%</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_5">
<property name="text">
<string>%</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="label_6">
<property name="text">
<string>%</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -680,7 +754,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1473</width> <width>1463</width>
<height>24</height> <height>24</height>
</rect> </rect>
</property> </property>

View File

@ -2,70 +2,114 @@
import os import os
import sys import sys
from PyQt6.QtCore import QThreadPool from os import path, rename
from PyQt6.QtWidgets import QMainWindow, QApplication
from PyQt6.QtGui import QIcon,QPixmap
from configure import CONFIG_FILE, Configure from PyQt6.QtCore import QThreadPool
from file_stuff import is_file from PyQt6.QtGui import QIcon, QPixmap
from BitMover_MainWindow import Ui_MainWindow from PyQt6.QtWidgets import QMainWindow, QApplication, QFileDialog
from media import Media
from lumberjack import timber from _BitMover_MainWindow import Ui_MainWindow
from thread_my_stuff import Worker from _import_dialog import DialogImport
from img_preview import ImgPreview from _configure import CONFIG_FILE, Configure
from _file_stuff import is_file, create_folder, path_exists, cmp_files
from _hashing import xx_hash
from _img_preview import ImgPreview
from _lumberjack import timber
from _media import Media
from _thread_my_stuff import Worker
log = timber(__name__) log = timber(__name__)
basedir = os.path.dirname(__file__) basedir = os.path.dirname(__file__)
# TODO: verify source dir actually exists
# 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):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(MainWindow,self).__init__(*args,**kwargs) super(MainWindow,self).__init__(*args,**kwargs)
self.setupUi(self) self.setupUi(self)
self.setWindowTitle("BitMover") self.setWindowTitle("BitMover")
self.setWindowIcon(QIcon(os.path.join(basedir,'assets', 'forklift.ico'))) self.setWindowIcon(QIcon(os.path.join(basedir,'assets', 'forklift.ico')))
self.threadpool = QThreadPool()
c = Configure(CONFIG_FILE) c = Configure(CONFIG_FILE)
self.config = c.load_config() self.config = c.load_config()
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']
self.verify_checksum = self.config['verify_checksum']
self.cleanup_files = self.config['cleanup_sd']
self.store_originals = self.config['store_originals']
self.file_types = self.config['file_types'] self.file_types = self.config['file_types']
self.lineEdit_src_dir.setText(self.src_dir) # File Stuff
self.lineEdit_dst_dir.setText(self.dst_dir) self.total_files = 0
self.file_total = 0
self.files = {}
self.imp_dialog = DialogImport()
self.widgets_config()
def widgets_config(self):
# Button Setup # Button Setup
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_import.clicked.connect(self.import_files)
# Initialize widgets # Initialize widgets
self.lineEdit_src_dir.setText(self.src_dir)
self.lineEdit_dst_dir.setText(self.dst_dir)
self.toggle_scan_button(True)
self.toggle_import_button(False)
self.lcd_files_found.display(int(0)) self.lcd_files_found.display(int(0))
self.set_progress_processing(0) self.set_progress_processing(0)
self.set_progress_importing(0) self.set_progress_importing(0)
self.set_progress_current_file(0)
self.img_preview.setPixmap(QPixmap(os.path.join(basedir, self.img_preview.setPixmap(QPixmap(os.path.join(basedir,
'assets', 'assets',
'preview_placeholder.jpg'))) 'preview_placeholder.jpg')))
self.img_preview.setScaledContents(True) self.img_preview.setScaledContents(True)
self.file_list.currentItemChanged.connect(self.index_changed) self.file_list.currentItemChanged.connect(self.index_changed)
self.checkBox_verify_checksum.setChecked(self.verify_checksum)
# File Stuff self.checkBox_cleanup_files.setChecked(self.cleanup_files)
self.total_files = 0 self.checkBox_store_originals.setChecked(self.store_originals)
self.file_total = 0 self.checkBox_verify_checksum.checkStateChanged.connect(self.verify_checksum_changed)
self.files = {} self.checkBox_cleanup_files.checkStateChanged.connect(self.cleanup_files_changed)
self.checkBox_store_originals.checkStateChanged.connect(self.store_originals_changed)
self.clear_metadata()
# Setup thread pool # Setup thread pool
self.threadpool = QThreadPool()
print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount()) print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())
def verify_checksum_changed(self):
if self.checkBox_verify_checksum.isChecked():
self.config['verify_checksum'] = True
else:
self.config['verify_checksum'] = False
print(f"verify_checksums: {self.config['verify_checksums']}")
def cleanup_files_changed(self):
if self.checkBox_cleanup_files.isChecked():
self.config['cleanup_sd'] = True
else:
self.config['cleanup_sd'] = False
print(f"cleanup_sd: {self.config['cleanup_sd']}")
def store_originals_changed(self):
if self.checkBox_store_originals.isChecked():
self.config['store_originals'] = True
else:
self.config['store_originals'] = False
print(f"store_originals: {self.config['store_originals']}")
def toggle_scan_button(self,enable=True): def toggle_scan_button(self,enable=True):
self.pushButton_3_scan_dir.setEnabled(enable) self.pushButton_3_scan_dir.setEnabled(enable)
def toggle_import_button(self,enable=True):
self.pushButton_import.setEnabled(enable)
def update_preview(self,i): def update_preview(self,i):
preview = ImgPreview(file=i.text(), event=self.get_event(), config=self.config) preview = ImgPreview(file=i.text(), event=self.get_event(), config=self.config)
self.label_data_date_time_created.setText(preview.dtc) self.l_meta_content_date_time_c.setText(preview.dtc)
path_hash = preview.path_hash path_hash = preview.path_hash
self.l_data_file_source_path.setText( self.l_data_file_source_path.setText(
@ -76,17 +120,67 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.img_preview.setPixmap(QPixmap(preview.thumbnail)) self.img_preview.setPixmap(QPixmap(preview.thumbnail))
self.img_preview.setFixedHeight(self.img_preview.width() / preview.thumbnail_ratio) self.img_preview.setFixedHeight(self.img_preview.width() / preview.thumbnail_ratio)
self.update_metadata(preview)
def update_metadata(self,preview):
self.clear_metadata()
if preview.file_type == 'image': if preview.file_type == 'image':
self.label_data_width_height.setText(str(preview.size)) self.l_meta_01.setText('Size')
self.label_data_dpi.setText(str(preview.dpi)) self.l_meta_02.setText('dpi')
self.label_data_iso.setText(str(preview.iso)) self.l_meta_03.setText('ISO')
self.label_data_lens.setText(str(preview.lens)) self.l_meta_04.setText('Lens')
self.label_data_zoom.setText(str(preview.zoom)) self.l_meta_05.setText('Focal Length')
self.label_data_camera.setText(str(preview.camera)) self.l_meta_06.setText('Camera')
self.label_data_aperture.setText(str(preview.aperture)) self.l_meta_07.setText('Aperture')
self.label_data_megapixels.setText(str(preview.mpixels)) self.l_meta_08.setText('Megapixels')
self.l_meta_content_01.setText(str(preview.size))
self.l_meta_content_02.setText(str(preview.dpi))
self.l_meta_content_03.setText(str(preview.iso))
self.l_meta_content_04.setText(str(preview.lens))
self.l_meta_content_05.setText(str(preview.zoom))
self.l_meta_content_06.setText(str(preview.camera))
self.l_meta_content_07.setText(str(preview.aperture))
self.l_meta_content_08.setText(str(preview.mpixels))
elif preview.file_type == 'video':
self.l_meta_01.setText('Size')
self.l_meta_02.setText('Frames / Second')
self.l_meta_03.setText('Bit Depth')
self.l_meta_04.setText('Duration')
self.l_meta_05.setText('Encoder')
self.l_meta_06.setText('Codec')
self.l_meta_07.setText('Profile')
self.l_meta_08.setText('Pix Format')
self.l_meta_content_01.setText(str(preview.size))
self.l_meta_content_02.setText(str(preview.video_framerate))
self.l_meta_content_03.setText(str(preview.video_bit_depth))
self.l_meta_content_04.setText(str(preview.video_duration))
self.l_meta_content_05.setText(str(preview.video_encoding))
self.l_meta_content_06.setText(str(preview.video_codec))
self.l_meta_content_07.setText(str(preview.video_profile))
self.l_meta_content_08.setText(str(preview.video_pix_format))
def clear_metadata(self):
self.l_meta_01.setText('')
self.l_meta_02.setText('')
self.l_meta_03.setText('')
self.l_meta_04.setText('')
self.l_meta_05.setText('')
self.l_meta_06.setText('')
self.l_meta_07.setText('')
self.l_meta_08.setText('')
self.l_meta_content_01.setText('')
self.l_meta_content_02.setText('')
self.l_meta_content_03.setText('')
self.l_meta_content_04.setText('')
self.l_meta_content_05.setText('')
self.l_meta_content_06.setText('')
self.l_meta_content_07.setText('')
self.l_meta_content_08.setText('')
def index_changed(self,i): def index_changed(self,i):
self.clear_metadata()
if i is None: if i is None:
self.img_preview.setPixmap(QPixmap(os.path.join(basedir, self.img_preview.setPixmap(QPixmap(os.path.join(basedir,
'assets', 'assets',
@ -118,13 +212,23 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.total_files = t self.total_files = t
self.lcd_files_found.display(self.total_files) self.lcd_files_found.display(self.total_files)
def set_imported_files(self,t):
self.lcd_files_imported.display(t)
def set_progress_processing(self, n): def set_progress_processing(self, n):
# print("%d%% done" % n) # print("%d%% done" % n)
self.progressBar_processing.setValue(int(n)) self.progressBar_processing.setValue(int(n))
self.lcd_processing_progress.display(n)
def set_progress_importing(self, n): def set_progress_importing(self, n):
# print("%d%% done" % n) # print("%d%% done" % n)
self.progressBar_importing.setValue(int(n)) self.progressBar_importing.setValue(int(n))
self.lcd_import_progress.display(n)
def set_progress_current_file(self, n):
# print("%d%% done" % n)
self.progressBar_importing_2.setValue(int(n))
self.lcd_current_file_progress.display(n)
def get_t_files(self,search_types): def get_t_files(self,search_types):
for folder, subfolders, filename in os.walk(self.src_dir): for folder, subfolders, filename in os.walk(self.src_dir):
@ -138,10 +242,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
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.")
def t_find_files(self,progress_callback): def t_find_files(self,
progress_callback,
import_progress_callback,
current_file_progress_callback,):
file_count = int(0) file_count = int(0)
search_types = [] search_types = []
if self.checkBox_search_for_images.isChecked(): if self.checkBox_search_for_images.isChecked():
@ -164,8 +269,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
if is_file(current_file): if is_file(current_file):
file_count += int(1) file_count += int(1)
self.process_file(current_file) self.process_file(current_file)
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.")
@ -175,17 +278,161 @@ class MainWindow(QMainWindow, Ui_MainWindow):
return "Done." return "Done."
def t_copy_files(self,
progress_callback,
import_progress_callback,
current_file_progress_callback):
""" Copy Files. """
# imp_dialog = DialogImport()
count = int(0)
chunk_size = 16 * 1024
for file in self.files:
self.imp_dialog.set_importing_file(path.join(
self.files[file]['folders']['source_path'],
self.files[file]['name']))
create_folder(self.files[file]['folders']['destination'])
if self.files[file]['type'] == 'video':
chunk_size = (1024 * 1024) * 5
file_exists = path_exists(path.join(
self.files[file]['folders']['destination'],
self.files[file]['name']))
if file_exists is True:
check_match = cmp_files(
path.join(
self.files[file]['folders']['source_path'],
self.files[file]['name']),
path.join(
self.files[file]['folders']['destination'],
self.files[file]['name']
)
)
if check_match is False:
print(f'\nFound duplicate for {self.files[file]["folders"]["source_path"]}/{self.files[file]["name"]}, renaming destination with hash appended.')
base, extension = path.splitext(self.files[file]['name'])
f_xxhash = xx_hash(path.join(
self.files[file]['folders']['destination'],
self.files[file]['name']))
file_name_hash = base + '_' + f_xxhash + extension
rename(path.join(
self.files[file]['folders']['destination'],
self.files[file]['name']),
path.join(
self.files[file]['folders']['destination'],
file_name_hash))
size = path.getsize(
path.join(
self.files[file]['folders']['source_path'],
self.files[file]['name'])
)
with open(path.join(
self.files[file]['folders']['source_path'],
self.files[file]['name']), 'rb') as fs:
with open(
path.join(
self.files[file]['folders']['destination'],
self.files[file]['name']), 'wb') as fd:
while True:
chunk = fs.read(chunk_size)
if not chunk:
break
fd.write(chunk)
dst_size = path.getsize(
path.join(
self.files[file]['folders']['destination'],
self.files[file]['name']
)
)
current_file_progress_callback.emit(round(( dst_size / size ) * 100, 1))
if self.config['store_originals'] is True:
if self.files[file]['type'] == 'image':
create_folder(self.files[file]['folders']['destination_original'])
file_exists = path_exists(path.join(
self.files[file]['folders']['destination_original'],
self.files[file]['name']))
if file_exists is True:
check_match = cmp_files(
path.join(
self.files[file]['folders']['source_path'],
self.files[file]['name']),
path.join(
self.files[file]['folders']['destination_original'],
self.files[file]['name']
)
)
if check_match is False:
print(f'\nFound duplicate for {self.files[file]["folders"]["source_path"]}/{self.files[file]["name"]}, renaming destination with hash appended.')
base, extension = path.splitext(self.files[file]['name'])
f_xxhash = xx_hash(path.join(
self.files[file]['folders']['destination_original'],
self.files[file]['name']))
file_name_hash = base + '_' + f_xxhash + extension
rename(path.join(
self.files[file]['folders']['destination_original'],
self.files[file]['name']),
path.join(
self.files[file]['folders']['destination_original'],
file_name_hash))
size = path.getsize(
path.join(
self.files[file]['folders']['source_path'],
self.files[file]['name'])
)
with open(path.join(
self.files[file]['folders']['source_path'],
self.files[file]['name']), 'rb') as fs:
with open(
path.join(
self.files[file]['folders']['destination_original'],
self.files[file]['name']), 'wb') as fd:
while True:
chunk = fs.read(chunk_size)
if not chunk:
break
fd.write(chunk)
dst_size = path.getsize(
path.join(
self.files[file]['folders']['destination_original'],
self.files[file]['name']
)
)
current_file_progress_callback.emit(round((dst_size / size) * 100, 1))
count += 1
self.set_imported_files(count)
import_progress_callback.emit(round((count / self.file_total) * 100, 1))
self.imp_dialog.add_to_imported_list(
path.join(
self.files[file]['folders']['source_path'],
self.files[file]['name']))
@staticmethod @staticmethod
def print_output(s): def print_output(s):
print(s) print(s)
def scan_thread_started(self): def worker_thread_started(self):
print('scan thread started') print('scan thread started')
self.toggle_scan_button(False) self.toggle_scan_button(False)
self.toggle_import_button(False)
def scan_thread_done(self): def worker_thread_done(self):
print('scan thread complete.') print('scan thread complete.')
self.toggle_scan_button(True) self.toggle_scan_button(True)
if 0 < len(self.files):
self.toggle_import_button(True)
else:
self.toggle_import_button(False)
@staticmethod @staticmethod
def thread_complete(): def thread_complete():
@ -209,15 +456,46 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.files = {} self.files = {}
worker = Worker(self.t_find_files) worker = Worker(self.t_find_files)
worker.signals.started.connect(self.scan_thread_started) worker.signals.started.connect(self.worker_thread_started)
worker.signals.result.connect(self.print_output) worker.signals.result.connect(self.print_output)
worker.signals.finished.connect(self.thread_complete) worker.signals.finished.connect(self.thread_complete)
worker.signals.finished.connect(self.scan_thread_done) worker.signals.finished.connect(self.worker_thread_done)
worker.signals.progress.connect(self.set_progress_processing) worker.signals.progress.connect(self.set_progress_processing)
# Execute. # Execute.
self.threadpool.start(worker) self.threadpool.start(worker)
def import_files(self):
"""
Import found files
"""
# Open Dialog
# imp_dialog = DialogImport()
# imp_dialog.open_import_dialog()
# Initialize Widgets
self.lcd_files_imported.display(int(0))
self.set_progress_importing(0)
self.set_progress_current_file(0)
self.imp_dialog.set_progress_importing(0)
self.imp_dialog.set_progress_current_file(0)
worker = Worker(self.t_copy_files)
worker.signals.started.connect(self.worker_thread_started)
worker.signals.started.connect(self.imp_dialog.open_import_dialog)
worker.signals.result.connect(self.print_output)
worker.signals.finished.connect(self.thread_complete)
worker.signals.finished.connect(self.worker_thread_done)
worker.signals.import_progress.connect(self.set_progress_importing)
worker.signals.import_progress.connect(self.imp_dialog.set_progress_importing)
worker.signals.current_file_progress.connect(self.set_progress_current_file)
worker.signals.current_file_progress.connect(self.imp_dialog.set_progress_current_file)
# 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
@ -231,7 +509,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
event = self.get_event() event = self.get_event()
c = self.config c = self.config
log.debug(f'process_file({path_name}, {f_name}, {event}, {c})') # print(f'process_file({path_name}, {f_name}, {event}, {c})')
m = Media(os.path.join(path_name,f_name),event, c) m = Media(os.path.join(path_name,f_name),event, c)
i = m.source_path_hash i = m.source_path_hash

View File

@ -12,7 +12,7 @@ from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object): class Ui_MainWindow(object):
def setupUi(self, MainWindow): def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow") MainWindow.setObjectName("MainWindow")
MainWindow.resize(1473, 928) MainWindow.resize(1463, 928)
self.centralwidget = QtWidgets.QWidget(parent=MainWindow) self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
self.centralwidget.setObjectName("centralwidget") self.centralwidget.setObjectName("centralwidget")
self.gridLayoutWidget = QtWidgets.QWidget(parent=self.centralwidget) self.gridLayoutWidget = QtWidgets.QWidget(parent=self.centralwidget)
@ -47,7 +47,7 @@ class Ui_MainWindow(object):
self.file_list.setGeometry(QtCore.QRect(20, 160, 871, 701)) self.file_list.setGeometry(QtCore.QRect(20, 160, 871, 701))
self.file_list.setObjectName("file_list") self.file_list.setObjectName("file_list")
self.gridLayoutWidget_2 = QtWidgets.QWidget(parent=self.centralwidget) self.gridLayoutWidget_2 = QtWidgets.QWidget(parent=self.centralwidget)
self.gridLayoutWidget_2.setGeometry(QtCore.QRect(910, 610, 311, 211)) self.gridLayoutWidget_2.setGeometry(QtCore.QRect(910, 650, 311, 211))
self.gridLayoutWidget_2.setObjectName("gridLayoutWidget_2") self.gridLayoutWidget_2.setObjectName("gridLayoutWidget_2")
self.grid_metadata = QtWidgets.QGridLayout(self.gridLayoutWidget_2) self.grid_metadata = QtWidgets.QGridLayout(self.gridLayoutWidget_2)
self.grid_metadata.setContentsMargins(0, 0, 0, 0) self.grid_metadata.setContentsMargins(0, 0, 0, 0)
@ -154,7 +154,7 @@ class Ui_MainWindow(object):
self.grid_metadata.addWidget(self.l_meta_content_02, 2, 1, 1, 1) self.grid_metadata.addWidget(self.l_meta_content_02, 2, 1, 1, 1)
self.grid_metadata.setColumnStretch(1, 1) self.grid_metadata.setColumnStretch(1, 1)
self.l_exif_ffprobe_title = QtWidgets.QLabel(parent=self.centralwidget) self.l_exif_ffprobe_title = QtWidgets.QLabel(parent=self.centralwidget)
self.l_exif_ffprobe_title.setGeometry(QtCore.QRect(910, 590, 371, 16)) self.l_exif_ffprobe_title.setGeometry(QtCore.QRect(910, 630, 371, 16))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(18) font.setPointSize(18)
font.setBold(True) font.setBold(True)
@ -173,7 +173,7 @@ class Ui_MainWindow(object):
self.eventName.setObjectName("eventName") self.eventName.setObjectName("eventName")
self.gridLayout.addWidget(self.eventName, 0, 1, 1, 1) self.gridLayout.addWidget(self.eventName, 0, 1, 1, 1)
self.gridLayoutWidget_4 = QtWidgets.QWidget(parent=self.centralwidget) self.gridLayoutWidget_4 = QtWidgets.QWidget(parent=self.centralwidget)
self.gridLayoutWidget_4.setGeometry(QtCore.QRect(910, 50, 221, 41)) self.gridLayoutWidget_4.setGeometry(QtCore.QRect(910, 50, 182, 91))
self.gridLayoutWidget_4.setObjectName("gridLayoutWidget_4") self.gridLayoutWidget_4.setObjectName("gridLayoutWidget_4")
self.gridLayout_2 = QtWidgets.QGridLayout(self.gridLayoutWidget_4) self.gridLayout_2 = QtWidgets.QGridLayout(self.gridLayoutWidget_4)
self.gridLayout_2.setContentsMargins(0, 0, 0, 0) self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
@ -187,35 +187,73 @@ class Ui_MainWindow(object):
self.lcd_files_found = QtWidgets.QLCDNumber(parent=self.gridLayoutWidget_4) self.lcd_files_found = QtWidgets.QLCDNumber(parent=self.gridLayoutWidget_4)
self.lcd_files_found.setObjectName("lcd_files_found") self.lcd_files_found.setObjectName("lcd_files_found")
self.gridLayout_2.addWidget(self.lcd_files_found, 0, 1, 1, 1) self.gridLayout_2.addWidget(self.lcd_files_found, 0, 1, 1, 1)
self.lcd_files_imported = QtWidgets.QLCDNumber(parent=self.gridLayoutWidget_4)
self.lcd_files_imported.setObjectName("lcd_files_imported")
self.gridLayout_2.addWidget(self.lcd_files_imported, 1, 1, 1, 1)
self.label_4 = QtWidgets.QLabel(parent=self.gridLayoutWidget_4)
font = QtGui.QFont()
font.setPointSize(18)
self.label_4.setFont(font)
self.label_4.setObjectName("label_4")
self.gridLayout_2.addWidget(self.label_4, 1, 0, 1, 1)
self.gridLayout_2.setColumnStretch(1, 1) self.gridLayout_2.setColumnStretch(1, 1)
self.gridLayoutWidget_5 = QtWidgets.QWidget(parent=self.centralwidget) self.gridLayoutWidget_5 = QtWidgets.QWidget(parent=self.centralwidget)
self.gridLayoutWidget_5.setGeometry(QtCore.QRect(1140, 50, 311, 46)) self.gridLayoutWidget_5.setGeometry(QtCore.QRect(1100, 50, 351, 93))
self.gridLayoutWidget_5.setObjectName("gridLayoutWidget_5") self.gridLayoutWidget_5.setObjectName("gridLayoutWidget_5")
self.gridLayout_3 = QtWidgets.QGridLayout(self.gridLayoutWidget_5) self.gridLayout_3 = QtWidgets.QGridLayout(self.gridLayoutWidget_5)
self.gridLayout_3.setContentsMargins(0, 0, 0, 0) self.gridLayout_3.setContentsMargins(0, 0, 0, 0)
self.gridLayout_3.setObjectName("gridLayout_3") self.gridLayout_3.setObjectName("gridLayout_3")
self.progressBar_importing_2 = QtWidgets.QProgressBar(parent=self.gridLayoutWidget_5)
self.progressBar_importing_2.setProperty("value", 24)
self.progressBar_importing_2.setObjectName("progressBar_importing_2")
self.gridLayout_3.addWidget(self.progressBar_importing_2, 2, 1, 1, 1)
self.lcd_import_progress = QtWidgets.QLCDNumber(parent=self.gridLayoutWidget_5)
self.lcd_import_progress.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
self.lcd_import_progress.setObjectName("lcd_import_progress")
self.gridLayout_3.addWidget(self.lcd_import_progress, 1, 2, 1, 1)
self.lcd_current_file_progress = QtWidgets.QLCDNumber(parent=self.gridLayoutWidget_5)
self.lcd_current_file_progress.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
self.lcd_current_file_progress.setObjectName("lcd_current_file_progress")
self.gridLayout_3.addWidget(self.lcd_current_file_progress, 2, 2, 1, 1)
self.l_proecessing_progress = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.l_proecessing_progress.setObjectName("l_proecessing_progress")
self.gridLayout_3.addWidget(self.l_proecessing_progress, 0, 0, 1, 1)
self.l_current_file_progress = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.l_current_file_progress.setObjectName("l_current_file_progress")
self.gridLayout_3.addWidget(self.l_current_file_progress, 2, 0, 1, 1)
self.progressBar_processing = QtWidgets.QProgressBar(parent=self.gridLayoutWidget_5) self.progressBar_processing = QtWidgets.QProgressBar(parent=self.gridLayoutWidget_5)
self.progressBar_processing.setProperty("value", 24) self.progressBar_processing.setProperty("value", 24)
self.progressBar_processing.setObjectName("progressBar_processing") self.progressBar_processing.setObjectName("progressBar_processing")
self.gridLayout_3.addWidget(self.progressBar_processing, 0, 1, 1, 1) self.gridLayout_3.addWidget(self.progressBar_processing, 0, 1, 1, 1)
self.l_import_progress = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.l_import_progress.setObjectName("l_import_progress")
self.gridLayout_3.addWidget(self.l_import_progress, 1, 0, 1, 1)
self.l_proecessing_progress = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.l_proecessing_progress.setObjectName("l_proecessing_progress")
self.gridLayout_3.addWidget(self.l_proecessing_progress, 0, 0, 1, 1)
self.progressBar_importing = QtWidgets.QProgressBar(parent=self.gridLayoutWidget_5) self.progressBar_importing = QtWidgets.QProgressBar(parent=self.gridLayoutWidget_5)
self.progressBar_importing.setProperty("value", 24) self.progressBar_importing.setProperty("value", 24)
self.progressBar_importing.setObjectName("progressBar_importing") self.progressBar_importing.setObjectName("progressBar_importing")
self.gridLayout_3.addWidget(self.progressBar_importing, 1, 1, 1, 1) self.gridLayout_3.addWidget(self.progressBar_importing, 1, 1, 1, 1)
self.l_import_progress = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.l_import_progress.setObjectName("l_import_progress")
self.gridLayout_3.addWidget(self.l_import_progress, 1, 0, 1, 1)
self.lcd_processing_progress = QtWidgets.QLCDNumber(parent=self.gridLayoutWidget_5)
self.lcd_processing_progress.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
self.lcd_processing_progress.setFrameShadow(QtWidgets.QFrame.Shadow.Plain)
self.lcd_processing_progress.setObjectName("lcd_processing_progress")
self.gridLayout_3.addWidget(self.lcd_processing_progress, 0, 2, 1, 1)
self.label_2 = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.label_2.setObjectName("label_2")
self.gridLayout_3.addWidget(self.label_2, 0, 3, 1, 1)
self.label_5 = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.label_5.setObjectName("label_5")
self.gridLayout_3.addWidget(self.label_5, 1, 3, 1, 1)
self.label_6 = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.label_6.setObjectName("label_6")
self.gridLayout_3.addWidget(self.label_6, 2, 3, 1, 1)
self.img_preview = QtWidgets.QLabel(parent=self.centralwidget) self.img_preview = QtWidgets.QLabel(parent=self.centralwidget)
self.img_preview.setGeometry(QtCore.QRect(910, 110, 541, 371)) self.img_preview.setGeometry(QtCore.QRect(910, 150, 541, 371))
self.img_preview.setAutoFillBackground(True) self.img_preview.setAutoFillBackground(True)
self.img_preview.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.img_preview.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.img_preview.setText("") self.img_preview.setText("")
self.img_preview.setObjectName("img_preview") self.img_preview.setObjectName("img_preview")
self.gridLayoutWidget_6 = QtWidgets.QWidget(parent=self.centralwidget) self.gridLayoutWidget_6 = QtWidgets.QWidget(parent=self.centralwidget)
self.gridLayoutWidget_6.setGeometry(QtCore.QRect(910, 490, 541, 91)) self.gridLayoutWidget_6.setGeometry(QtCore.QRect(910, 530, 541, 91))
self.gridLayoutWidget_6.setObjectName("gridLayoutWidget_6") self.gridLayoutWidget_6.setObjectName("gridLayoutWidget_6")
self.grid_metadata_2 = QtWidgets.QGridLayout(self.gridLayoutWidget_6) self.grid_metadata_2 = QtWidgets.QGridLayout(self.gridLayoutWidget_6)
self.grid_metadata_2.setContentsMargins(0, 0, 0, 0) self.grid_metadata_2.setContentsMargins(0, 0, 0, 0)
@ -322,7 +360,7 @@ class Ui_MainWindow(object):
self.horizontalLayout_3.addWidget(self.pushButton_3_scan_dir) self.horizontalLayout_3.addWidget(self.pushButton_3_scan_dir)
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(parent=MainWindow) self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1473, 24)) self.menubar.setGeometry(QtCore.QRect(0, 0, 1463, 24))
self.menubar.setObjectName("menubar") self.menubar.setObjectName("menubar")
self.menuBit_Mover = QtWidgets.QMenu(parent=self.menubar) self.menuBit_Mover = QtWidgets.QMenu(parent=self.menubar)
self.menuBit_Mover.setObjectName("menuBit_Mover") self.menuBit_Mover.setObjectName("menuBit_Mover")
@ -356,8 +394,13 @@ class Ui_MainWindow(object):
self.l_exif_ffprobe_title.setText(_translate("MainWindow", "Exif / ffprobe Data")) self.l_exif_ffprobe_title.setText(_translate("MainWindow", "Exif / ffprobe Data"))
self.labelEvent.setText(_translate("MainWindow", "Event")) self.labelEvent.setText(_translate("MainWindow", "Event"))
self.label_3.setText(_translate("MainWindow", "Files Found")) self.label_3.setText(_translate("MainWindow", "Files Found"))
self.l_import_progress.setText(_translate("MainWindow", "Import Progress")) self.label_4.setText(_translate("MainWindow", "Files Imported"))
self.l_proecessing_progress.setText(_translate("MainWindow", "Processing Progress")) self.l_proecessing_progress.setText(_translate("MainWindow", "Processing Progress"))
self.l_current_file_progress.setText(_translate("MainWindow", "Current File Progress"))
self.l_import_progress.setText(_translate("MainWindow", "Import Progress"))
self.label_2.setText(_translate("MainWindow", "%"))
self.label_5.setText(_translate("MainWindow", "%"))
self.label_6.setText(_translate("MainWindow", "%"))
self.l_file_source_path.setText(_translate("MainWindow", "Source Path")) self.l_file_source_path.setText(_translate("MainWindow", "Source Path"))
self.l_file_dest_path.setText(_translate("MainWindow", "Destination Path")) self.l_file_dest_path.setText(_translate("MainWindow", "Destination Path"))
self.checkBox_verify_checksum.setToolTip(_translate("MainWindow", "After copying, verify that the hash of the original file equals the hash of the copied file.")) self.checkBox_verify_checksum.setToolTip(_translate("MainWindow", "After copying, verify that the hash of the original file equals the hash of the copied file."))

View File

@ -6,7 +6,7 @@ Load the config file from yaml file
import sys import sys
import os import os
import yaml import yaml
from lumberjack import timber from _lumberjack import timber
basedir = os.path.dirname(__file__) basedir = os.path.dirname(__file__)
files = {} files = {}

View File

@ -10,8 +10,8 @@ from tqdm import tqdm
### Local Imports ### Local Imports
# from configure import Configure, CONFIG_FILE # from configure import Configure, CONFIG_FILE
from hashing import xx_hash from _hashing import xx_hash
from lumberjack import timber from _lumberjack import timber
def check_log_dir(d): def check_log_dir(d):
create_folder(d) create_folder(d)

View File

@ -7,7 +7,7 @@ from uu import Error
import exifread import exifread
from datetime import datetime from datetime import datetime
from lumberjack import timber from _lumberjack import timber
log = timber(__name__) log = timber(__name__)
@ -49,16 +49,16 @@ def get_exif_tag(p,t):
with open(p, "rb") as f: with open(p, "rb") as f:
try: try:
tags = exifread.process_file(f) tags = exifread.process_file(f)
print(f'{p}: {tags}') # print(f'{p}: {tags}')
except Error as e: except Error as e:
return f'Received Error: {e} when trying to open {p}' return f'Received Error: {e} when trying to open {p}'
finally: finally:
f.close() f.close()
for tag in tags: for tag in tags:
print(tag) # print(tag)
if t in tag.lower(): if t in tag.lower():
print(tags[tag]) # print(tags[tag])
return tags[tag] return tags[tag]
else: else:
pass pass

View File

@ -8,7 +8,7 @@ import os
import xxhash import xxhash
from tqdm import tqdm from tqdm import tqdm
# from configure import Configure, CONFIG_FILE # from configure import Configure, CONFIG_FILE
from lumberjack import timber from _lumberjack import timber
# c = Configure(CONFIG_FILE) # c = Configure(CONFIG_FILE)
# config = c.load_config() # config = c.load_config()

View File

@ -1,9 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
from media import Media from _media import Media
from get_image_tag import get_exif_tag from _get_image_tag import get_exif_tag
from PIL import Image from PIL import Image
from raw_photo import get_raw_image_dimensions, extract_jpg_thumb from _raw_photo import get_raw_image_dimensions, extract_jpg_thumb
from _video import Video from _video import Video
class ImgPreview: class ImgPreview:

45
_import_dialog.py Normal file
View File

@ -0,0 +1,45 @@
from PyQt6.QtWidgets import QDialog
from _import_dialog_Window import Ui_DialogImport
class DialogImport(QDialog, Ui_DialogImport):
def __init__(self,*args,**kwargs):
super(DialogImport,self).__init__(*args,**kwargs)
self.setupUi(self)
# self.import_dialog = UI_DialogImport()
# self.ui_import_dialog = Ui_DialogImport()
print('DialogImport')
def is_shown(self):
print(f'is_shown: {self.isVisible()}')
return self.isVisible()
def open_import_dialog(self):
print(f'open_import_dialog: {self.is_shown()}')
if not self.is_shown():
print('Inside if not self.is_shown')
print('showing window')
self.show()
def close_import_dialog(self):
print('close_import_dialog')
if self.is_shown():
print('inside self.is_shown()')
print('hiding window')
self.hide()
def set_progress_importing(self, n):
print("%d%% done" % n)
self.progressBar_importing.setValue(int(n))
self.lcd_import_progress.display(n)
def set_progress_current_file(self, n):
print("%d%% done" % n)
self.progressBar_importing_2.setValue(int(n))
self.lcd_current_file_progress.display(n)
def set_importing_file(self,f):
self.l_importing_file_name.setText(f)
def add_to_imported_list(self,n):
self.set_importing_file('')
self.list_imported.addItem(n)

91
_import_dialog_Window.py Normal file
View File

@ -0,0 +1,91 @@
# Form implementation generated from reading ui file 'import_dialogue.ui'
#
# Created by: PyQt6 UI code generator 6.4.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_DialogImport(object):
def setupUi(self, DialogImport):
DialogImport.setObjectName("DialogImport")
DialogImport.resize(640, 880)
self.gridLayoutWidget_5 = QtWidgets.QWidget(parent=DialogImport)
self.gridLayoutWidget_5.setGeometry(QtCore.QRect(20, 20, 601, 61))
self.gridLayoutWidget_5.setObjectName("gridLayoutWidget_5")
self.gridLayout_3 = QtWidgets.QGridLayout(self.gridLayoutWidget_5)
self.gridLayout_3.setContentsMargins(0, 0, 0, 0)
self.gridLayout_3.setObjectName("gridLayout_3")
self.label_5 = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.label_5.setObjectName("label_5")
self.gridLayout_3.addWidget(self.label_5, 0, 3, 1, 1)
self.label_6 = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.label_6.setObjectName("label_6")
self.gridLayout_3.addWidget(self.label_6, 1, 3, 1, 1)
self.progressBar_importing = QtWidgets.QProgressBar(parent=self.gridLayoutWidget_5)
self.progressBar_importing.setProperty("value", 24)
self.progressBar_importing.setObjectName("progressBar_importing")
self.gridLayout_3.addWidget(self.progressBar_importing, 0, 1, 1, 1)
self.l_import_progress = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.l_import_progress.setObjectName("l_import_progress")
self.gridLayout_3.addWidget(self.l_import_progress, 0, 0, 1, 1)
self.lcd_import_progress = QtWidgets.QLCDNumber(parent=self.gridLayoutWidget_5)
self.lcd_import_progress.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
self.lcd_import_progress.setObjectName("lcd_import_progress")
self.gridLayout_3.addWidget(self.lcd_import_progress, 0, 2, 1, 1)
self.lcd_current_file_progress = QtWidgets.QLCDNumber(parent=self.gridLayoutWidget_5)
self.lcd_current_file_progress.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
self.lcd_current_file_progress.setObjectName("lcd_current_file_progress")
self.gridLayout_3.addWidget(self.lcd_current_file_progress, 1, 2, 1, 1)
self.progressBar_importing_2 = QtWidgets.QProgressBar(parent=self.gridLayoutWidget_5)
self.progressBar_importing_2.setProperty("value", 24)
self.progressBar_importing_2.setObjectName("progressBar_importing_2")
self.gridLayout_3.addWidget(self.progressBar_importing_2, 1, 1, 1, 1)
self.l_current_file_progress = QtWidgets.QLabel(parent=self.gridLayoutWidget_5)
self.l_current_file_progress.setObjectName("l_current_file_progress")
self.gridLayout_3.addWidget(self.l_current_file_progress, 1, 0, 1, 1)
self.verticalLayoutWidget = QtWidgets.QWidget(parent=DialogImport)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(20, 90, 601, 80))
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.l_importing_header = QtWidgets.QLabel(parent=self.verticalLayoutWidget)
font = QtGui.QFont()
font.setPointSize(24)
font.setBold(True)
self.l_importing_header.setFont(font)
self.l_importing_header.setObjectName("l_importing_header")
self.verticalLayout.addWidget(self.l_importing_header)
self.l_importing_file_name = QtWidgets.QLabel(parent=self.verticalLayoutWidget)
self.l_importing_file_name.setText("")
self.l_importing_file_name.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
self.l_importing_file_name.setWordWrap(True)
self.l_importing_file_name.setObjectName("l_importing_file_name")
self.verticalLayout.addWidget(self.l_importing_file_name)
self.l_imported_list_header = QtWidgets.QLabel(parent=DialogImport)
self.l_imported_list_header.setGeometry(QtCore.QRect(20, 180, 181, 30))
font = QtGui.QFont()
font.setPointSize(28)
self.l_imported_list_header.setFont(font)
self.l_imported_list_header.setObjectName("l_imported_list_header")
self.list_imported = QtWidgets.QListWidget(parent=DialogImport)
self.list_imported.setGeometry(QtCore.QRect(15, 211, 611, 651))
self.list_imported.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.NoSelection)
self.list_imported.setObjectName("list_imported")
self.retranslateUi(DialogImport)
QtCore.QMetaObject.connectSlotsByName(DialogImport)
def retranslateUi(self, DialogImport):
_translate = QtCore.QCoreApplication.translate
DialogImport.setWindowTitle(_translate("DialogImport", "Dialog"))
self.label_5.setText(_translate("DialogImport", "%"))
self.label_6.setText(_translate("DialogImport", "%"))
self.l_import_progress.setText(_translate("DialogImport", "Import Progress"))
self.l_current_file_progress.setText(_translate("DialogImport", "Current File Progress"))
self.l_importing_header.setText(_translate("DialogImport", "Importing:"))
self.l_imported_list_header.setText(_translate("DialogImport", "Imported:"))

View File

@ -0,0 +1,85 @@
#!/usr/bin/env python
"""
Functions to copy bits around ...
"""
from os import system,path,rename
from tqdm import tqdm
from _file_stuff import create_folder, cmp_files, path_exists
from _lumberjack import timber
from _hashing import xx_hash
# from configure import Configure, CONFIG_FILE
# c = Configure(CONFIG_FILE)
# config = c.load_config()
log = timber(__name__)
def copy_with_progress(s,d,f):
""" Copy a file with the progress bar """
log.debug(f'copy_with_progress({s},{d},{f})')
size = path.getsize(s)
with open(s, 'rb') as fs:
with open(d, 'wb') as fd:
# with tqdm(total=size, unit='B', unit_scale=True, desc=f'Copying {f}') as pbar:
while True:
chunk = fs.read(4096)
if not chunk:
break
fd.write(chunk)
# pbar.update(len(chunk))
def copy_from_source(source_path,dest_path,file_name):
""" Copy file from source to destination """
log.debug(f'copy_from_source({source_path},{dest_path},{file_name}')
file_exists = path_exists(path.join(dest_path,file_name))
if file_exists is True:
log.debug(f'\nFound {file_name} at destination, checking if they match.')
check_match = cmp_files(
path.join(source_path,file_name),
path.join(dest_path, file_name))
if check_match is False:
log.warn(f'\nFound duplicate for {source_path}/{file_name}, \
renaming destination with hash appended.')
base, extension = path.splitext(file_name)
#md5 = md5_hash(os.path.join(dest_path, file_name))
f_xxhash = xx_hash(path.join(dest_path, file_name))
#file_name_hash = base + '_' + md5 + extension
file_name_hash = base + '_' + f_xxhash + extension
rename(path.join(dest_path, file_name),
path.join(dest_path, file_name_hash))
else:
log.info(f'\n{file_name} hashes match')
# remove(path.join(source_path,file_name))
# f.pop(file_name)
return
# create_folder(dest_path)
# shutil.copy(os.path.join(source_path,file_name), dest_path)
copy_with_progress(path.join(source_path, file_name),
path.join(dest_path, file_name),
file_name)
system('clear')
def copy_files(f,config):
""" Copy Files. """
log.debug(f'copy_files({f})')
system('clear')
for file in tqdm(f, desc="Copying Files:"):
create_folder(f[file]['folders']['destination'])
copy_from_source(f[file]['folders']['source_path'],
f[file]['folders']['destination'],
f[file]['name'])
if config['store_originals'] is True:
if f[file]['type'] == 'image':
create_folder(f[file]['folders']['destination_original'])
copy_from_source(f[file]['folders']['destination'],
f[file]['folders']['destination_original'],
f[file]['name'])

View File

@ -4,15 +4,16 @@
Create the media object Create the media object
""" """
import os import os
from os import path
from datetime import datetime from datetime import datetime
import ffmpeg import ffmpeg
import sys import sys
#Local Imports #Local Imports
from hashing import xx_hash, hash_path from _hashing import xx_hash, hash_path
from get_image_tag import get_image_date from _get_image_tag import get_image_date
# from configure import files # from configure import files
from lumberjack import timber from _lumberjack import timber
log = timber(__name__) log = timber(__name__)
@ -31,9 +32,9 @@ class Media:
self.file_ext = self.dotted_file_ext.split('.')[1] self.file_ext = self.dotted_file_ext.split('.')[1]
self.file_type = self.get_file_type() self.file_type = self.get_file_type()
self.capture_date = get_capture_date(source_path,self.file_type) self.capture_date = get_capture_date(source_path,self.file_type)
self.store_originals = config['store_originals'] self.store_originals = self.configuration['store_originals']
self.destination_path = self.set_destination_path()
self.destination_originals_path = '' self.destination_originals_path = ''
self.destination_path = self.set_destination_path()
self.filehash = '' # Only populate this one if it's called upon. self.filehash = '' # Only populate this one if it's called upon.
@ -53,14 +54,24 @@ class Media:
p = p + '-' + self.event_name p = p + '-' + self.event_name
if self.file_type == 'image': if self.file_type == 'image':
# print(f'store_originals: {self.store_originals}')
p = p + '/PHOTO' p = p + '/PHOTO'
if self.file_ext.lower() in ('jpg', 'jpeg'): if self.file_ext.lower() in ('jpg', 'jpeg'):
# print(f'store_originals: {self.store_originals}')
if self.store_originals is True: if self.store_originals is True:
self.destination_originals_path = p + '/ORIGINALS/JPG' self.destination_originals_path = path.join(
p,
self.configuration['folders']['originals'],
'JPG')
# print(self.destination_originals_path)
p = p + '/JPG' p = p + '/JPG'
else: else:
if self.store_originals is True: if self.store_originals is True:
self.destination_originals_path = p + '/ORIGINALS/RAW' self.destination_originals_path = path.join(
p,
self.configuration['folders']['originals'],
'RAW')
# print(self.destination_originals_path)
p = p + '/RAW' p = p + '/RAW'
elif self.file_type == 'video': elif self.file_type == 'video':
p = p + '/VIDEO' p = p + '/VIDEO'
@ -89,25 +100,25 @@ class Media:
def get_file_type(self): def get_file_type(self):
""" determine if the extension is in the list of file types """ """ determine if the extension is in the list of file types """
log.debug(f'get_file_type():') # log.debug(f'get_file_type():')
for t in self.configuration['file_types']: for t in self.configuration['file_types']:
log.debug(f'Checking if file is part of {t}') # log.debug(f'Checking if file is part of {t}')
for e in self.configuration['file_types'][t]: for e in self.configuration['file_types'][t]:
log.debug(f'Checking if {self.file_ext.lower()} ends with {e}') # log.debug(f'Checking if {self.file_ext.lower()} ends with {e}')
if self.file_ext.lower().endswith(e): if self.file_ext.lower().endswith(e):
log.debug(self.file_ext + ' ends with ' + e) # log.debug(self.file_ext + ' ends with ' + e)
return t return t
else: # else:
log.debug(self.file_ext + f' does not end with {e}') # log.debug(self.file_ext + f' does not end with {e}')
def get_capture_date(path, f_type): def get_capture_date(p, f_type):
""" get capture date from meta """ """ get capture date from meta """
log.debug(f'get_capture_date({path}, {f_type}') # log.debug(f'get_capture_date({p}, {f_type}')
if f_type == 'image': if f_type == 'image':
stamp = get_image_date(path) stamp = get_image_date(p)
elif f_type == 'video': elif f_type == 'video':
try: try:
@ -116,31 +127,31 @@ def get_capture_date(path, f_type):
'%Y-%m-%dT%H:%M:%S.%f%z') '%Y-%m-%dT%H:%M:%S.%f%z')
except: except:
try: try:
stamp = datetime.fromtimestamp(os.path.getctime(path)) stamp = datetime.fromtimestamp(os.path.getctime(p))
except: except:
try: try:
stamp = datetime.strptime( stamp = datetime.strptime(
str('1900:01:01 00:00:00'), '%Y:%m:%d %H:%M:%S') str('1900:01:01 00:00:00'), '%Y:%m:%d %H:%M:%S')
except: except:
log.critical(f'\nCould not get timestamp for {path}. Giving up.') # log.critical(f'\nCould not get timestamp for {p}. Giving up.')
sys.exit() sys.exit()
elif f_type == 'audio': elif f_type == 'audio':
try: try:
stamp = datetime.strptime(ffmpeg.probe( stamp = datetime.strptime(ffmpeg.probe(
path)['format']['tags']['date'], '%Y-%m-%d') p)['format']['tags']['date'], '%Y-%m-%d')
except KeyError as ke: except KeyError as ke:
log.warning(f'\nError: {ke} for {path}. Trying getctime...') # log.warning(f'\nError: {ke} for {p}. Trying getctime...')
try: try:
stamp = datetime.fromtimestamp(os.path.getctime(path)) stamp = datetime.fromtimestamp(os.path.getctime(p))
except: except:
log.critical(f'\nCould not get timestamp for {path}. Giving up.') # log.critical(f'\nCould not get timestamp for {p}. Giving up.')
sys.exit() sys.exit()
else: else:
try: try:
stamp = datetime.fromtimestamp(os.path.getctime(path)) stamp = datetime.fromtimestamp(os.path.getctime(p))
except: except:
log.critical(f'\nCould not get timestamp for {path}. Giving up.') # log.critical(f'\nCould not get timestamp for {p}. Giving up.')
sys.exit() sys.exit()
year = stamp.strftime("%Y") year = stamp.strftime("%Y")

View File

@ -27,6 +27,9 @@ class WorkerSignals(QObject):
error = pyqtSignal(tuple) error = pyqtSignal(tuple)
result = pyqtSignal(object) result = pyqtSignal(object)
progress = pyqtSignal(int) progress = pyqtSignal(int)
import_progress = pyqtSignal(int)
current_file_progress = pyqtSignal(float)
# current_import_file = pyqtSignal()
class Worker(QRunnable): class Worker(QRunnable):
""" """
@ -52,6 +55,9 @@ class Worker(QRunnable):
# Add the callback to our kwargs # Add the callback to our kwargs
self.kwargs['progress_callback'] = self.signals.progress self.kwargs['progress_callback'] = self.signals.progress
self.kwargs['import_progress_callback'] = self.signals.import_progress
self.kwargs['current_file_progress_callback'] = self.signals.current_file_progress
# self.kwargs['current_import_file'] = self.signals.current_import_file
@pyqtSlot() @pyqtSlot()
def run(self): def run(self):

View File

@ -2,6 +2,7 @@
import sys import sys
import ffmpeg import ffmpeg
import time
class Video: class Video:
def __init__(self,max_width=1024,*args,**kwargs): def __init__(self,max_width=1024,*args,**kwargs):
@ -12,15 +13,63 @@ class Video:
self.out = 'thumbnail.jpg' self.out = 'thumbnail.jpg'
self.max_width = max_width self.max_width = max_width
self.stream = {
'video': {},
'format': {},
'audio': {}
}
self.stream['video']['duration'] = ''
self.stream['video']['creation_time'] = ''
self.stream['video']['encoding_brand'] = ''
self.stream['video']['codec_name'] = ''
self.stream['video']['codec_long_name'] = ''
self.stream['video']['profile'] = ''
self.stream['video']['size'] = {}
self.stream['video']['size']['width'] = int()
self.stream['video']['size']['height'] = int()
self.stream['video']['display_aspect_ratio'] = str()
self.stream['video']['level'] = ''
self.stream['video']['color_range'] = ''
self.stream['video']['field_order'] = ''
self.stream['video']['is_avc'] = ''
self.stream['video']['r_frame_rate'] = '' # -> expect for 120fps: 120000/1001
self.stream['video']['avg_frame_rate'] = '' # -> expect for 120fps: 120000/1001
self.stream['video']['time_base'] = '' # -> expect for 120fps: 1/120000
self.stream['video']['bit_rate'] = ''
self.stream['video']['bits_per_raw_sample'] = ''
self.stream['video']['nb_frames'] = ''
self.stream['video']['language'] = ''
self.stream['video']['handler_name'] = ''
self.stream['video']['encoder'] = ''
self.stream['video']['pix_fmt'] = ''
self.stream['format'] = {}
self.stream['format']['major_brand'] = ''
self.stream['format']['compatible_brands'] = ''
self.stream['format']['creation_time'] = ''
self.stream['audio'] = {}
self.stream['audio']['codec_long_name'] = ''
self.stream['audio']['channels'] = ''
self.stream['audio']['sample_fmt'] = ''
self.stream['audio']['sample_rate'] = ''
self.stream['audio']['bits_per_sample'] = ''
self.stream['audio']['bit_rate'] = ''
@staticmethod
def convert_from_seconds(s):
seconds = s
return time.strftime("%H:%M:%S", time.gmtime(seconds))
def gen_video_thumbnail(self): def gen_video_thumbnail(self):
""" """
Generate a thumbnail from a video Generate a thumbnail from a video
""" """
self.get_video_meta()
probe = ffmpeg.probe(self.file) time = self.stream['video']['seconds'] // 5
time = float(probe['streams'][0]['duration']) // 5 v_width = int(self.stream['video']['size']['width'])
v_width = probe['streams'][0]['width'] width = self.set_thumb_width(v_width)
width = self.set_width(v_width)
try: try:
( (
@ -35,10 +84,44 @@ class Video:
return self.out return self.out
def set_width(self,v_width): def set_thumb_width(self, v_width):
if v_width > self.max_width: if v_width > self.max_width:
width = self.max_width width = self.max_width
else: else:
width = v_width width = v_width
return width return width
def get_video_meta(self):
probe = ffmpeg.probe(self.file)
if 'video' == probe['streams'][0]['codec_type'].lower():
video_stream = probe['streams'][0]
elif 'video' == probe['streams'][1]['codec_type'].lower():
video_stream = probe['streams'][1]
elif 'video' == probe['streams'][2]['codec_type'].lower():
video_stream = probe['streams'][2]
if 'audio' == probe['streams'][0]['codec_type'].lower():
audio_stream = probe['streams'][0]
elif 'audio' == probe['streams'][1]['codec_type'].lower():
audio_stream = probe['streams'][1]
elif 'audio' == probe['streams'][2]['codec_type'].lower():
audio_stream = probe['streams'][2]
format_stream = probe['format']
self.stream['video']['size']['width'] = video_stream['width']
self.stream['video']['size']['height'] = video_stream['height']
self.stream['video']['r_frame_rate'] = video_stream['r_frame_rate']
self.stream['video']['bits_per_raw_sample'] = video_stream['bits_per_raw_sample']
self.stream['video']['seconds'] = float(video_stream['duration'])
self.stream['video']['duration'] = self.convert_from_seconds(
self.stream['video']['seconds']
)
self.stream['video']['encoding_brand'] = format_stream['tags']['major_brand']
self.stream['video']['codec_long_name'] = video_stream['codec_long_name']
self.stream['video']['profile'] = video_stream['profile']
self.stream['video']['pix_fmt'] = video_stream['pix_fmt']
return self.stream

156
import_dialogue.ui Normal file
View File

@ -0,0 +1,156 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogImport</class>
<widget class="QDialog" name="DialogImport">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>640</width>
<height>880</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QWidget" name="gridLayoutWidget_5">
<property name="geometry">
<rect>
<x>20</x>
<y>20</y>
<width>601</width>
<height>61</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="3">
<widget class="QLabel" name="label_5">
<property name="text">
<string>%</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_6">
<property name="text">
<string>%</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QProgressBar" name="progressBar_importing">
<property name="value">
<number>24</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="l_import_progress">
<property name="text">
<string>Import Progress</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLCDNumber" name="lcd_import_progress">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLCDNumber" name="lcd_current_file_progress">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QProgressBar" name="progressBar_importing_2">
<property name="value">
<number>24</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="l_current_file_progress">
<property name="text">
<string>Current File Progress</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>90</y>
<width>601</width>
<height>80</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="l_importing_header">
<property name="font">
<font>
<pointsize>24</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Importing:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="l_importing_file_name">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QLabel" name="l_imported_list_header">
<property name="geometry">
<rect>
<x>20</x>
<y>180</y>
<width>181</width>
<height>30</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>28</pointsize>
</font>
</property>
<property name="text">
<string>Imported:</string>
</property>
</widget>
<widget class="QListWidget" name="list_imported">
<property name="geometry">
<rect>
<x>15</x>
<y>211</y>
<width>611</width>
<height>651</height>
</rect>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1 +1,2 @@
pyuic6 BitMover.ui -o _BitMover_MainWindow.py pyuic6 BitMover.ui -o _BitMover_MainWindow.py
pyuic6 import_dialogue.ui -o _import_dialog_Window.py