Compare commits

..

2 Commits

Author SHA1 Message Date
Kameron Kenny 3e211a609a
checksum stuff 2024-10-06 15:46:11 -04:00
Kameron Kenny 4a6baea929
refactor dialogs 2024-10-06 15:45:05 -04:00
20 changed files with 471 additions and 220 deletions

View File

@ -14,7 +14,8 @@
<string>BitMover</string> <string>BitMover</string>
</property> </property>
<property name="windowIcon"> <property name="windowIcon">
<iconset theme="applications-science"/> <iconset theme="applications-science">
<normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="unifiedTitleAndToolBarOnMac"> <property name="unifiedTitleAndToolBarOnMac">
<bool>true</bool> <bool>true</bool>
@ -95,7 +96,7 @@
<rect> <rect>
<x>910</x> <x>910</x>
<y>610</y> <y>610</y>
<width>311</width> <width>541</width>
<height>211</height> <height>211</height>
</rect> </rect>
</property> </property>
@ -344,7 +345,7 @@
<height>41</height> <height>41</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2" rowstretch="0,0" columnstretch="0,0,0,0,0"> <layout class="QGridLayout" name="gridLayout_2" rowstretch="0" columnstretch="0,0,0,0,0">
<item row="0" column="2"> <item row="0" column="2">
<spacer name="horizontalSpacer_3"> <spacer name="horizontalSpacer_3">
<property name="orientation"> <property name="orientation">

View File

@ -11,14 +11,15 @@ from PyQt6.QtWidgets import QMainWindow, QApplication, QFileDialog
from _BitMover_MainWindow import Ui_MainWindow from _BitMover_MainWindow import Ui_MainWindow
from _configure import CONFIG_FILE, Configure from _configure import CONFIG_FILE, Configure
from _find_files import FindFiles from _find_files import FindFiles
from _find_files_dialog import FindProgress from _dialog_find_files import FindProgress
from _import_dialog import DialogImport from _dialog_import import DialogImport
from _dialog_checksum_progress import DialogChecksumProgress
# from _media_import import MediaImporter # from _media_import import MediaImporter
from _preview import MediaPreview from _preview import MediaPreview
from _thread_my_stuff import Worker from _thread_my_stuff import Worker
from _media_file import MediaFile from _media_file import MediaFile
from _file_stuff import path_exists,is_dir,is_file,create_folder,cmp_files from _file_stuff import path_exists,is_file,create_folder,cmp_hashes
from _hashing import hash_path from _verify_file_checksum import FileHash
basedir = os.path.dirname(__file__) basedir = os.path.dirname(__file__)
@ -44,10 +45,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.chunk_size = (16 * 1024) * 1 self.chunk_size = (16 * 1024) * 1
self.load_config() self.load_config()
self.destination_original_path = None
self.path_file_source = None self.path_file_source = None
self.path_file_destination = None self.path_file_destination = None
self.path_file_destination_original = None self.path_file_destination_original = None
self.checksum_fph = None
# File Stuff # File Stuff
self.total_files = 0 self.total_files = 0
@ -58,6 +59,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.imp_dialog = DialogImport() self.imp_dialog = DialogImport()
self.find_files_dialog = FindProgress() self.find_files_dialog = FindProgress()
self.checksum_progress_dialog = DialogChecksumProgress()
self.widgets_config() self.widgets_config()
@ -131,7 +133,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.lineEdit_dst_dir.setText(self.dst_dir) self.lineEdit_dst_dir.setText(self.dst_dir)
def get_source_path_hash(self,f): def get_source_path_hash(self,f):
self.source_path_hash = hash_path(f) self.source_path_hash = FileHash(f).path_hash
return self.source_path_hash return self.source_path_hash
def verify_checksum_changed(self): def verify_checksum_changed(self):
@ -407,8 +409,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
current_file_progress_callback, current_file_progress_callback,
imported_file_count_callback, imported_file_count_callback,
found_file_callback, found_file_callback,
total_file_count_callback total_file_count_callback,
): checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback):
""" Copy Files. """ """ Copy Files. """
count = int(0) count = int(0)
for line in range(self.file_list.count()): for line in range(self.file_list.count()):
@ -423,29 +427,37 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.files[sph]['name']) self.files[sph]['name'])
self.path_file_destination = path.join(self.dst_dir, self.path_file_destination = path.join(self.dst_dir,
self.files[sph]['name']) self.files[sph]['name'])
self.destination_original_path = path.join(self.dst_dir,
self.files[sph]['folders']['destination_original'])
self.path_file_destination_original = path.join(self.dst_dir,
self.files[sph]['folders']['destination_original'],
self.files[sph]['name'])
self.imp_dialog.set_importing_file(self.path_file_source) self.imp_dialog.set_importing_file(self.path_file_source)
self.copy_a_file( self.copy_a_file(
sph, sph,
self.path_file_destination,
progress_callback, progress_callback,
current_file_progress_callback, current_file_progress_callback,
imported_file_count_callback, imported_file_count_callback,
found_file_callback, found_file_callback,
total_file_count_callback total_file_count_callback,
) checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback)
print(f'check_store_original({sph}): {self.check_store_original(sph)}')
if self.check_store_original(sph) is True: if self.check_store_original(sph) is True:
self.path_file_destination_original = path.join(self.dst_dir,
self.files[sph]['folders']['destination_original'],
self.files[sph]['name'])
self.copy_a_file(sph, self.copy_a_file(sph,
self.path_file_destination_original,
progress_callback, progress_callback,
current_file_progress_callback, current_file_progress_callback,
imported_file_count_callback, imported_file_count_callback,
found_file_callback, found_file_callback,
total_file_count_callback) total_file_count_callback,
checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback)
count += 1 count += 1
@ -455,37 +467,48 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def copy_a_file(self, def copy_a_file(self,
fph, fph,
target,
progress_callback, progress_callback,
current_file_progress_callback, current_file_progress_callback,
imported_file_count_callback, imported_file_count_callback,
found_file_callback, found_file_callback,
total_file_count_callback): total_file_count_callback,
checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback):
size = path.getsize(self.path_file_source) size = path.getsize(self.path_file_source)
create_folder(self.dst_dir) target_dir = os.path.dirname(target)
create_folder(target_dir)
self.check_duplicate(fph)
dup_check = self.check_duplicate(fph,target,target_dir,
progress_callback,
current_file_progress_callback,
imported_file_count_callback,
found_file_callback,
total_file_count_callback,
checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback)
if dup_check is False:
if self.is_video(fph): if self.is_video(fph):
self.chunk_size = (1024 * 1024) * 5 self.chunk_size = (1024 * 1024) * 5
else: else:
self.chunk_size = (16 * 1024) * 1 self.chunk_size = (16 * 1024) * 1
with open(self.path_file_source, 'rb') as fs: with open(self.path_file_source, 'rb') as fs:
with open(self.path_file_destination, 'wb') as fd: with open(target, 'wb') as fd:
while True: while True:
chunk = fs.read(self.chunk_size) chunk = fs.read(self.chunk_size)
if not chunk: if not chunk:
break break
fd.write(chunk) fd.write(chunk)
dst_size = path.getsize(self.path_file_destination) dst_size = path.getsize(target)
current_file_progress_callback.emit(round((dst_size / size) * 100, 1)) current_file_progress_callback.emit(round((dst_size / size) * 100, 1))
def check_store_original(self,sph): def check_store_original(self,sph):
if self.config['store_originals'] is True: if self.config['store_originals'] is True:
if self.is_image(sph): if self.is_image(sph):
self.dst_dir = self.destination_original_path
self.path_file_destination = self.path_file_destination_original
r = True r = True
else: else:
r = False r = False
@ -494,15 +517,103 @@ class MainWindow(QMainWindow, Ui_MainWindow):
return r return r
def check_duplicate(self,sph): def get_checksum(self,_pf,
if path_exists(self.path_file_destination): progress_callback,
check_match = cmp_files(self.path_file_source, self.path_file_destination) current_file_progress_callback,
imported_file_count_callback,
found_file_callback,
total_file_count_callback,
checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback):
sph = FileHash(_pf).path_hash
self.path_file_source = os.path.join(self.files[sph]['folders']['source_path'],
self.files[sph]['name'])
self.path_file_destination = os.path.join(self.files[sph]['folders']['destination'],
self.files[sph]['name'])
if self.store_originals is True:
self.path_file_destination_original = os.path.join(
self.files[sph]['folders']['destination_original'],
self.files[sph]['name'])
def set_checksum(_pf):
print(f'set_checksum, _pf: {_pf}')
if path_exists(_pf) and is_file(_pf):
self.files[sph]['xx_checksum'][_pf] = FileHash(_pf).get_hash(_pf,
progress_callback,
current_file_progress_callback,
imported_file_count_callback,
found_file_callback,
total_file_count_callback,
checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback)
else:
print(f"set_checksum: {_pf} doesn't exist yet or isn't a real file.")
if self.files[sph].get('xx_checksum') is None:
self.files[sph]['xx_checksum'] = {}
set_checksum(self.path_file_source)
set_checksum(self.path_file_destination)
if self.store_originals is True:
set_checksum(self.path_file_destination_original)
else:
if self.files[sph]['xx_checksum'].get(self.path_file_source) is None:
set_checksum(self.path_file_source)
if self.files[sph]['xx_checksum'].get(self.path_file_destination) is None:
set_checksum(self.path_file_destination)
if self.store_originals is True:
if self.files[sph]['xx_checksum'].get(self.path_file_destination_original) is None:
set_checksum(self.path_file_destination_original)
# self.checksum_progress_dialog.close_dialog()
def check_duplicate(self,
sph,
target,
target_dir,
progress_callback,
current_file_progress_callback,
imported_file_count_callback,
found_file_callback,
total_file_count_callback,
checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback):
if path_exists(target):
print(f'Path Exists: path_file_source: {self.path_file_source}\ntarget: {target}')
self.get_checksum(self.path_file_source,
progress_callback,
current_file_progress_callback,
imported_file_count_callback,
found_file_callback,
total_file_count_callback,
checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback)
hash1 = self.files[sph]['xx_checksum'][self.path_file_source]
hash2 = self.files[sph]['xx_checksum'][target]
check_match = cmp_hashes(hash1,hash2)
if check_match is False: if check_match is False:
print(f'\nFound duplicate for {self.path_file_source}, renaming destination with hash appended.') print(f'\nFound duplicate for {self.path_file_source}, renaming destination with hash appended.')
base, extension = path.splitext(self.files[sph]['name']) base, extension = path.splitext(self.files[sph]['name'])
f_xxhash = xx_hash(self.path_file_destination) file_name_hash = base + '_' + hash2 + extension
file_name_hash = base + '_' + f_xxhash + extension rename(target, path.join(target_dir, file_name_hash))
rename(self.path_file_destination, path.join(self.dst_dir, file_name_hash)) r = False # This is false because we move the original conflict out of the way.
else:
print(f"\n########################\nFound duplicate for: {self.path_file_source}\n"
f"at: {target}... \nHashes MATCH\n"
f"########################")
r = True
else:
# No duplicate
r = False
return r
# END from _media_import.py # END from _media_import.py
@ -533,17 +644,99 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.thread_complete) self.thread_complete)
worker.signals.finished.connect( worker.signals.finished.connect(
self.worker_thread_done) self.worker_thread_done)
worker.signals.finished.connect(
self.compare_imported_checksums)
worker.signals.checksum_dialog_open.connect(
self.checksum_progress_dialog.open_dialog)
worker.signals.checksum_file.connect(
self.checksum_progress_dialog.set_file)
worker.signals.checksum_progress.connect(
self.checksum_progress_dialog.set_progress)
worker.signals.finished.connect(
self.checksum_progress_dialog.close_dialog)
# Execute # Execute
self.threadpool.start(worker) self.threadpool.start(worker)
def verify_checksum(self): def compare_imported_checksums(self):
# fh_match = FileHash() # if self.config['verify_checksum'] is True:
print(f'verify_checksum,self.config: {self.config}') # self.checksum_fph = fph
# Initialize Widgets
self.checksum_progress_dialog.set_progress(0)
worker = Worker(self.t_compare_imported_checksums)
worker.signals.started.connect(
self.worker_thread_started)
worker.signals.started.connect(
self.checksum_progress_dialog.open_dialog)
worker.signals.found_file.connect(
self.checksum_progress_dialog.set_file)
worker.signals.progress.connect(
self.checksum_progress_dialog.set_progress)
worker.signals.finished.connect(
self.thread_complete)
worker.signals.finished.connect(
self.worker_thread_done)
worker.signals.finished.connect(
self.checksum_progress_dialog.close_dialog)
worker.signals.checksum_dialog_open.connect(
self.checksum_progress_dialog.open_dialog)
worker.signals.checksum_file.connect(
self.checksum_progress_dialog.set_file)
worker.signals.checksum_progress.connect(
self.checksum_progress_dialog.set_progress)
worker.signals.finished.connect(
self.checksum_progress_dialog.close_dialog)
# Execute
self.threadpool.start(worker)
def t_compare_imported_checksums(self,
progress_callback,
current_file_progress_callback,
imported_file_count_callback,
found_file_callback,
total_file_count_callback,
checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback):
for file in self.files:
_pf = os.path.join(self.files[file]['folders']['source_path'],
self.files[file]['name'])
print(f"source_path: {self.files[file]['folders']['source_path']}")
print(f"name: {self.files[file]['name']}")
print(f'_pf: {_pf}')
self.get_checksum(_pf,
progress_callback,
current_file_progress_callback,
imported_file_count_callback,
found_file_callback,
total_file_count_callback,
checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback)
i = 0
c = {}
for checksum in self.files[file]['xx_checksum']:
c[i] = self.files[file]['xx_checksum'][checksum]
if i > 0:
p = i - 1
if c[i] == c[p]:
self.files[file]['checksum_match'] = True
print(f'Checksums match for: {self.files[file]["name"]}')
else:
self.files[file]['checksum_match'] = False
print(f'Checksum failed for: {self.files[file]["name"]}')
i += 1
# Main App
app = QApplication(sys.argv) app = QApplication(sys.argv)
# Main Window
window = MainWindow() window = MainWindow()
# Show Window
window.show() window.show()
app.exec() app.exec()

View File

@ -50,7 +50,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, 610, 541, 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)

View File

@ -62,35 +62,35 @@
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="2" column="2"> <item row="2" column="2">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="l_hash_dest">
<property name="text"> <property name="text">
<string>TextLabel</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLabel" name="label"> <widget class="QLabel" name="l_path_file_source">
<property name="text"> <property name="text">
<string>TextLabel</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="l_path_file_dest">
<property name="text"> <property name="text">
<string>TextLabel</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="2"> <item row="0" column="2">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="l_hash_source">
<property name="text"> <property name="text">
<string>TextLabel</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label_title_source">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>80</width> <width>80</width>
@ -109,7 +109,7 @@
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QLabel" name="label_7"> <widget class="QLabel" name="label_title_dest">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>80</width> <width>80</width>
@ -129,7 +129,7 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="label_title_comparing_files">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>20</x> <x>20</x>

View File

@ -0,0 +1,73 @@
# Form implementation generated from reading ui file '_ComparisonDialog.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_FileComparisonDialog(object):
def setupUi(self, FileComparisonDialog):
FileComparisonDialog.setObjectName("FileComparisonDialog")
FileComparisonDialog.resize(1588, 753)
self.tableWidget = QtWidgets.QTableWidget(parent=FileComparisonDialog)
self.tableWidget.setGeometry(QtCore.QRect(20, 90, 1551, 651))
self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
self.tableWidget.setTabKeyNavigation(False)
self.tableWidget.setProperty("showDropIndicator", False)
self.tableWidget.setRowCount(2)
self.tableWidget.setColumnCount(5)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.horizontalHeader().setDefaultSectionSize(300)
self.tableWidget.verticalHeader().setVisible(True)
self.gridLayoutWidget = QtWidgets.QWidget(parent=FileComparisonDialog)
self.gridLayoutWidget.setGeometry(QtCore.QRect(240, 11, 981, 71))
self.gridLayoutWidget.setObjectName("gridLayoutWidget")
self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.l_hash_dest = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.l_hash_dest.setText("")
self.l_hash_dest.setObjectName("l_hash_dest")
self.gridLayout.addWidget(self.l_hash_dest, 2, 2, 1, 1)
self.l_path_file_source = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.l_path_file_source.setText("")
self.l_path_file_source.setObjectName("l_path_file_source")
self.gridLayout.addWidget(self.l_path_file_source, 0, 1, 1, 1)
self.l_path_file_dest = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.l_path_file_dest.setText("")
self.l_path_file_dest.setObjectName("l_path_file_dest")
self.gridLayout.addWidget(self.l_path_file_dest, 2, 1, 1, 1)
self.l_hash_source = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.l_hash_source.setText("")
self.l_hash_source.setObjectName("l_hash_source")
self.gridLayout.addWidget(self.l_hash_source, 0, 2, 1, 1)
self.label_title_source = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.label_title_source.setMaximumSize(QtCore.QSize(80, 16777215))
self.label_title_source.setBaseSize(QtCore.QSize(0, 0))
self.label_title_source.setObjectName("label_title_source")
self.gridLayout.addWidget(self.label_title_source, 0, 0, 1, 1)
self.label_title_dest = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.label_title_dest.setMaximumSize(QtCore.QSize(80, 16777215))
self.label_title_dest.setBaseSize(QtCore.QSize(0, 0))
self.label_title_dest.setObjectName("label_title_dest")
self.gridLayout.addWidget(self.label_title_dest, 2, 0, 1, 1)
self.label_title_comparing_files = QtWidgets.QLabel(parent=FileComparisonDialog)
self.label_title_comparing_files.setGeometry(QtCore.QRect(20, 10, 231, 61))
font = QtGui.QFont()
font.setPointSize(28)
self.label_title_comparing_files.setFont(font)
self.label_title_comparing_files.setObjectName("label_title_comparing_files")
self.retranslateUi(FileComparisonDialog)
QtCore.QMetaObject.connectSlotsByName(FileComparisonDialog)
def retranslateUi(self, FileComparisonDialog):
_translate = QtCore.QCoreApplication.translate
FileComparisonDialog.setWindowTitle(_translate("FileComparisonDialog", "Dialog"))
self.label_title_source.setText(_translate("FileComparisonDialog", "Source"))
self.label_title_dest.setText(_translate("FileComparisonDialog", "Destination"))
self.label_title_comparing_files.setText(_translate("FileComparisonDialog", "Comparing Files"))

View File

@ -1,73 +0,0 @@
# Form implementation generated from reading ui file '_ComparisonDialog.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_FileComparisonDialog(object):
def setupUi(self, FileComparisonDialog):
FileComparisonDialog.setObjectName("FileComparisonDialog")
FileComparisonDialog.resize(1588, 753)
self.tableWidget = QtWidgets.QTableWidget(parent=FileComparisonDialog)
self.tableWidget.setGeometry(QtCore.QRect(20, 90, 1551, 651))
self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
self.tableWidget.setTabKeyNavigation(False)
self.tableWidget.setProperty("showDropIndicator", False)
self.tableWidget.setRowCount(2)
self.tableWidget.setColumnCount(5)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.horizontalHeader().setDefaultSectionSize(300)
self.tableWidget.verticalHeader().setVisible(True)
self.gridLayoutWidget = QtWidgets.QWidget(parent=FileComparisonDialog)
self.gridLayoutWidget.setGeometry(QtCore.QRect(240, 11, 981, 71))
self.gridLayoutWidget.setObjectName("gridLayoutWidget")
self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.label_4 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.label_4.setObjectName("label_4")
self.gridLayout.addWidget(self.label_4, 2, 2, 1, 1)
self.label = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 1, 1, 1)
self.label_3 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 2, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 0, 2, 1, 1)
self.label_6 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.label_6.setMaximumSize(QtCore.QSize(80, 16777215))
self.label_6.setBaseSize(QtCore.QSize(0, 0))
self.label_6.setObjectName("label_6")
self.gridLayout.addWidget(self.label_6, 0, 0, 1, 1)
self.label_7 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
self.label_7.setMaximumSize(QtCore.QSize(80, 16777215))
self.label_7.setBaseSize(QtCore.QSize(0, 0))
self.label_7.setObjectName("label_7")
self.gridLayout.addWidget(self.label_7, 2, 0, 1, 1)
self.label_5 = QtWidgets.QLabel(parent=FileComparisonDialog)
self.label_5.setGeometry(QtCore.QRect(20, 10, 231, 61))
font = QtGui.QFont()
font.setPointSize(28)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
self.retranslateUi(FileComparisonDialog)
QtCore.QMetaObject.connectSlotsByName(FileComparisonDialog)
def retranslateUi(self, FileComparisonDialog):
_translate = QtCore.QCoreApplication.translate
FileComparisonDialog.setWindowTitle(_translate("FileComparisonDialog", "Dialog"))
self.label_4.setText(_translate("FileComparisonDialog", "TextLabel"))
self.label.setText(_translate("FileComparisonDialog", "TextLabel"))
self.label_3.setText(_translate("FileComparisonDialog", "TextLabel"))
self.label_2.setText(_translate("FileComparisonDialog", "TextLabel"))
self.label_6.setText(_translate("FileComparisonDialog", "Source"))
self.label_7.setText(_translate("FileComparisonDialog", "Destination"))
self.label_5.setText(_translate("FileComparisonDialog", "Comparing Files"))

View File

@ -0,0 +1,39 @@
from PyQt6.QtWidgets import QDialog
from _Window_checksum_progress_dialog import Ui_ChecksumProgressDialog
class DialogChecksumProgress(QDialog, Ui_ChecksumProgressDialog):
def __init__(self,*args,**kwargs):
super(DialogChecksumProgress,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_dialog(self,should_be_open):
if should_be_open is True:
if self.is_shown() is False:
print(f'open_checksum_dialog: {self.is_shown()}')
self.show()
else:
print('Checksum dialog already open.')
else:
self.close_dialog()
def close_dialog(self):
print('close_import_dialog')
if self.is_shown():
print('inside self.is_shown()')
print('hiding window')
self.hide()
def set_progress(self, n):
# print("%d%% done" % n)
self.progressBar_getting_checksum.setValue(int(n))
# self.lcd_import_progress.display(n)
def set_file(self,f):
self.l_content_checksum_filename.setText(f)

View File

@ -1,5 +1,5 @@
from PyQt6.QtWidgets import QDialog from PyQt6.QtWidgets import QDialog
from _finding_files_dialog_Window import Ui_FindProgress from _Window_finding_files_dialog import Ui_FindProgress
class FindProgress(QDialog, Ui_FindProgress): class FindProgress(QDialog, Ui_FindProgress):
def __init__(self,*args,**kwargs): def __init__(self,*args,**kwargs):
@ -26,6 +26,6 @@ class FindProgress(QDialog, Ui_FindProgress):
self.hide() self.hide()
def set_progress_finding_files(self,n): def set_progress_finding_files(self,n):
print("%d%% done" % n) # print("%d%% done" % n)
self.progressBar_importing.setValue(float(n)) self.progressBar_importing.setValue(float(n))
self.lcd_import_progress.display(n) self.lcd_import_progress.display(n)

View File

@ -1,5 +1,5 @@
from PyQt6.QtWidgets import QDialog from PyQt6.QtWidgets import QDialog
from _import_dialog_Window import Ui_DialogImport from _Window_import_dialog import Ui_DialogImport
class DialogImport(QDialog, Ui_DialogImport): class DialogImport(QDialog, Ui_DialogImport):
def __init__(self,*args,**kwargs): def __init__(self,*args,**kwargs):
@ -14,11 +14,16 @@ class DialogImport(QDialog, Ui_DialogImport):
return self.isVisible() return self.isVisible()
def open_import_dialog(self): def open_import_dialog(self):
if self.is_shown() is False:
print(f'open_import_dialog: {self.is_shown()}') print(f'open_import_dialog: {self.is_shown()}')
if not self.is_shown(): if not self.is_shown():
print('Inside if not self.is_shown') print('Inside if not self.is_shown')
print('showing window') print('showing window')
self.show() self.show()
else:
print('Import Dialog already open.')
else:
self.close_import_dialog()
def close_import_dialog(self): def close_import_dialog(self):
print('close_import_dialog') print('close_import_dialog')
@ -28,12 +33,12 @@ class DialogImport(QDialog, Ui_DialogImport):
self.hide() self.hide()
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) self.lcd_import_progress.display(n)
def set_progress_current_file(self, n): def set_progress_current_file(self, n):
print("%d%% done" % n) # print("%d%% done" % n)
self.progressBar_importing_2.setValue(int(n)) self.progressBar_importing_2.setValue(int(n))
self.lcd_current_file_progress.display(n) self.lcd_current_file_progress.display(n)

View File

@ -9,7 +9,8 @@ import yaml
from tqdm import tqdm from tqdm import tqdm
### Local Imports ### Local Imports
from _hashing import xx_hash # from _hashing import xx_hash
from _verify_file_checksum import FileHash
def check_log_dir(d): def check_log_dir(d):
create_folder(d) create_folder(d)
@ -38,10 +39,14 @@ def cmp_files(f1,f2):
#TODO: Determine if path is actually a file #TODO: Determine if path is actually a file
#TODO: Determine if the hash has already been stored and use it if so #TODO: Determine if the hash has already been stored and use it if so
hash1 = xx_hash(f1) hash1 = FileHash(f1).file_hash
hash2 = xx_hash(f2) hash2 = FileHash(f2).file_hash
return hash1 == hash2 return hash1 == hash2
def cmp_hashes(h1,h2):
""" compare two files """
return h1 == h2
def path_access_read(path): def path_access_read(path):
""" make sure we can read from the path """ """ make sure we can read from the path """
val = os.access(path, os.R_OK) val = os.access(path, os.R_OK)

View File

@ -29,7 +29,10 @@ class FindFiles:
current_file_progress_callback, current_file_progress_callback,
imported_file_count_callback, imported_file_count_callback,
found_file_callback, found_file_callback,
total_file_count_callback): total_file_count_callback,
checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback):
file_count = int(0) file_count = int(0)
if len(self.search_types) > 0: if len(self.search_types) > 0:
for folder, subfolders, filename in os.walk(self.src_dir): for folder, subfolders, filename in os.walk(self.src_dir):

View File

@ -8,28 +8,24 @@ import os
import xxhash import xxhash
from tqdm import tqdm from tqdm import tqdm
def xx_hash(file): # def xx_hash(file):
""" calculates and returns file hash based on xxHash """ # """ calculates and returns file hash based on xxHash """
size = os.path.getsize(file) # size = os.path.getsize(file)
hasher = xxhash.xxh64() # hasher = xxhash.xxh64()
#
# with open(file, 'rb') as f:
# with tqdm(total=size,
# unit='B',
# unit_scale=True,
# desc=f'Getting hash for {os.path.basename(file)}') as pbar:
# for chunk in iter(lambda: f.read(4096), b""):
# hasher.update(chunk)
# pbar.update(len(chunk))
# file_hash = hasher.hexdigest()
#
# return file_hash
with open(file, 'rb') as f:
with tqdm(total=size,
unit='B',
unit_scale=True,
desc=f'Getting hash for {os.path.basename(file)}') as pbar:
for chunk in iter(lambda: f.read(4096), b""):
hasher.update(chunk)
pbar.update(len(chunk))
file_hash = hasher.hexdigest()
return file_hash
def hash_path(path):
""" hashes a string passed as a path """
hasher = xxhash.xxh64(path)
return hasher.hexdigest()
def gen_xxhashes(f): def gen_xxhashes(f):
""" Generate xxHashes """ """ Generate xxHashes """

View File

@ -2,7 +2,7 @@ import os.path
import sys import sys
from _audio import AudioFile from _audio import AudioFile
from _hashing import hash_path from _verify_file_checksum import FileHash
from _video import VideoFile from _video import VideoFile
from _photo import PhotoFile from _photo import PhotoFile
from _file_stuff import (get_file_name, from _file_stuff import (get_file_name,
@ -23,7 +23,7 @@ class MediaFile:
self.store_originals = self.config['store_originals'] self.store_originals = self.config['store_originals']
self.src_dir = os.path.dirname(self.path_file_name) self.src_dir = os.path.dirname(self.path_file_name)
self.base_dst_dir = self.config['folders']['destination']['base'] self.base_dst_dir = self.config['folders']['destination']['base']
self.source_path_hash = hash_path(self.path_file_name) self.source_path_hash = FileHash(self.path_file_name).path_file
self.file_name = get_file_name(self.path_file_name) self.file_name = get_file_name(self.path_file_name)
self.dotted_file_ext = get_dotted_file_ext(self.file_name) self.dotted_file_ext = get_dotted_file_ext(self.file_name)
self.file_ext = get_file_ext(self.file_name) self.file_ext = get_file_ext(self.file_name)

View File

@ -1,10 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
from PIL import Image from PIL import Image
from _media_file import MediaFile
from _raw_photo import extract_jpg_thumb from _raw_photo import extract_jpg_thumb
from _video import VideoFile from _video import VideoFile
from _hashing import hash_path from _verify_file_checksum import FileHash
class MediaPreview: class MediaPreview:
def __init__(self,path_file_name,media_files): def __init__(self,path_file_name,media_files):
@ -12,7 +10,7 @@ class MediaPreview:
self.path_file_name = path_file_name self.path_file_name = path_file_name
self.media_files_list = media_files self.media_files_list = media_files
# self.media_file = MediaFile(self.path_file_name) # self.media_file = MediaFile(self.path_file_name)
self.source_path_hash = hash_path(self.path_file_name) self.source_path_hash = FileHash(self.path_file_name).path_hash
# print(f'_preview.py,MediaPreview:\n\tpath_file_name: {self.path_file_name}\n\thash: {self.source_path_hash}\n\tmedia_files_list: {self.media_files_list}\n') # print(f'_preview.py,MediaPreview:\n\tpath_file_name: {self.path_file_name}\n\thash: {self.source_path_hash}\n\tmedia_files_list: {self.media_files_list}\n')
self.thumbnail = 'thumbnail.jpg' self.thumbnail = 'thumbnail.jpg'
self.file_type = self.media_files_list[self.source_path_hash]['file_type'] self.file_type = self.media_files_list[self.source_path_hash]['file_type']

View File

@ -31,6 +31,9 @@ class WorkerSignals(QObject):
imported_file_count = pyqtSignal(int) imported_file_count = pyqtSignal(int)
found_file = pyqtSignal(str) found_file = pyqtSignal(str)
total_file_count = pyqtSignal(int) total_file_count = pyqtSignal(int)
checksum_progress = pyqtSignal(int)
checksum_file = pyqtSignal(str)
checksum_dialog_open = pyqtSignal(bool)
class Worker(QRunnable): class Worker(QRunnable):
""" """
@ -60,6 +63,9 @@ class Worker(QRunnable):
self.kwargs['imported_file_count_callback'] = self.signals.imported_file_count self.kwargs['imported_file_count_callback'] = self.signals.imported_file_count
self.kwargs['found_file_callback'] = self.signals.found_file self.kwargs['found_file_callback'] = self.signals.found_file
self.kwargs['total_file_count_callback'] = self.signals.total_file_count self.kwargs['total_file_count_callback'] = self.signals.total_file_count
self.kwargs['checksum_file_callback'] = self.signals.checksum_file
self.kwargs['checksum_progress_callback'] = self.signals.checksum_progress
self.kwargs['checksum_dialog_open_callback'] = self.signals.checksum_dialog_open
@pyqtSlot() @pyqtSlot()
def run(self): def run(self):

View File

@ -2,47 +2,52 @@ import os
import xxhash import xxhash
class FileHash: class FileHash:
def __init__(self,files,*args,**kwargs): def __init__(self,
path_file,
chunk_size=1024 * 1024,
*args,
**kwargs):
super(FileHash,self).__init__(*args,**kwargs) super(FileHash,self).__init__(*args,**kwargs)
self.files = files self.path_file = path_file
self.chunk_size = kwargs['chunk_size'] self._path = os.path.dirname(self.path_file)
self.chunk_size = chunk_size
self.path_hasher = xxhash.xxh64(self._path)
# noinspection PyArgumentList
# self.file_hash = self.get_hash(self.path_file)
self.path_hash = self.hash_path()
def get_hash(self,f,
progress_callback,
current_file_progress_callback,
imported_file_count_callback,
found_file_callback,
total_file_count_callback,
checksum_file_callback,
checksum_progress_callback,
checksum_dialog_open_callback):
checksum_dialog_open_callback.emit(True)
@staticmethod
def xx_hash(self,f,progress_callback):
size = os.path.getsize(f) size = os.path.getsize(f)
hasher = xxhash.xxh64() hasher = xxhash.xxh64()
#todo: add callbacks
chunk_count = 0 chunk_count = 0
checksum_file_callback.emit(f)
with open(f, 'rb') as f: with open(f, 'rb') as f:
for chunk in iter(lambda: f.read(self.chunk_size),b""): for chunk in iter(lambda: f.read(self.chunk_size),b""):
hasher.update(chunk) hasher.update(chunk)
chunk_count += 1 chunk_count += 1
hashed_size = chunk_count * self.chunk_size hashed_size = chunk_count * self.chunk_size
progress_callback.emit(round((hashed_size / size) * 100, 1)) checksum_progress_callback.emit(round((hashed_size / size) * 100, 1))
file_hash = hasher.hexdigest() file_hash = hasher.hexdigest()
checksum_dialog_open_callback.emit(False)
return file_hash return file_hash
@staticmethod def hash_path(self):
def t_verify_checksum(self, """ hashes a string passed as a path """
progress_callback,
import_progress_callback,
current_file_progress_callback,
imported_file_count_callback,
found_file,
total_file_count):
for file in self.files: return self.path_hasher.hexdigest()
i = 0
c = {}
for checksum in self.files[file]['xx_checksum']:
c[i] = self.files[file]['xx_checksum'][checksum]
if i > 0:
p = i - 1
if c[i] == c[p]:
self.files[file]['checksum_match'] = True
else:
self.files[file]['checksum_match'] = False
i += 1
return self.files

View File

@ -1,5 +1,5 @@
pyuic6 BitMover.ui -o _BitMover_MainWindow.py pyuic6 BitMover.ui -o _BitMover_MainWindow.py
pyuic6 import_dialogue.ui -o _import_dialog_Window.py pyuic6 import_dialogue.ui -o _Window_import_dialog.py
pyuic6 _finding_files_dialog.ui -o _finding_files_dialog_Window.py pyuic6 _finding_files_dialog.ui -o _Window_finding_files_dialog.py
pyuic6 _ComparisonDialog.ui -o _comparison_dialog_Window.py pyuic6 _ComparisonDialog.ui -o _Window_comparison_dialog.py
pyuic6 _checksum_progress_dialog.ui -o _checksum_progress_dialog_Window.py pyuic6 _checksum_progress_dialog.ui -o _Window_checksum_progress_dialog.py