dev #1
|
@ -14,7 +14,8 @@
|
|||
<string>BitMover</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset theme="applications-science"/>
|
||||
<iconset theme="applications-science">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="unifiedTitleAndToolBarOnMac">
|
||||
<bool>true</bool>
|
||||
|
@ -95,7 +96,7 @@
|
|||
<rect>
|
||||
<x>910</x>
|
||||
<y>610</y>
|
||||
<width>311</width>
|
||||
<width>541</width>
|
||||
<height>211</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -344,7 +345,7 @@
|
|||
<height>41</height>
|
||||
</rect>
|
||||
</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">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
|
|
313
BitMover_ui.py
313
BitMover_ui.py
|
@ -11,14 +11,15 @@ from PyQt6.QtWidgets import QMainWindow, QApplication, QFileDialog
|
|||
from _BitMover_MainWindow import Ui_MainWindow
|
||||
from _configure import CONFIG_FILE, Configure
|
||||
from _find_files import FindFiles
|
||||
from _find_files_dialog import FindProgress
|
||||
from _import_dialog import DialogImport
|
||||
from _dialog_find_files import FindProgress
|
||||
from _dialog_import import DialogImport
|
||||
from _dialog_checksum_progress import DialogChecksumProgress
|
||||
# from _media_import import MediaImporter
|
||||
from _preview import MediaPreview
|
||||
from _thread_my_stuff import Worker
|
||||
from _media_file import MediaFile
|
||||
from _file_stuff import path_exists,is_dir,is_file,create_folder,cmp_files
|
||||
from _hashing import hash_path
|
||||
from _file_stuff import path_exists,is_file,create_folder,cmp_hashes
|
||||
from _verify_file_checksum import FileHash
|
||||
|
||||
|
||||
basedir = os.path.dirname(__file__)
|
||||
|
@ -31,23 +32,23 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||
self.setupUi(self)
|
||||
self.setWindowTitle("BitMover")
|
||||
self.setWindowIcon(QIcon(os.path.join(basedir,'assets', 'forklift.ico')))
|
||||
self.threadpool = QThreadPool()
|
||||
self.config = None
|
||||
self.src_dir = None
|
||||
self.dst_dir = None
|
||||
self.verify_checksum = None
|
||||
self.cleanup_files = None
|
||||
self.store_originals = None
|
||||
self.file_types = None
|
||||
self.source_path_hash = None
|
||||
self.search_types = None
|
||||
self.chunk_size = (16 * 1024) * 1
|
||||
self.threadpool = QThreadPool()
|
||||
self.config = None
|
||||
self.src_dir = None
|
||||
self.dst_dir = None
|
||||
self.verify_checksum = None
|
||||
self.cleanup_files = None
|
||||
self.store_originals = None
|
||||
self.file_types = None
|
||||
self.source_path_hash = None
|
||||
self.search_types = None
|
||||
self.chunk_size = (16 * 1024) * 1
|
||||
self.load_config()
|
||||
|
||||
self.destination_original_path = None
|
||||
self.path_file_source = None
|
||||
self.path_file_destination = None
|
||||
self.path_file_destination_original = None
|
||||
self.path_file_source = None
|
||||
self.path_file_destination = None
|
||||
self.path_file_destination_original = None
|
||||
self.checksum_fph = None
|
||||
|
||||
# File Stuff
|
||||
self.total_files = 0
|
||||
|
@ -58,6 +59,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||
|
||||
self.imp_dialog = DialogImport()
|
||||
self.find_files_dialog = FindProgress()
|
||||
self.checksum_progress_dialog = DialogChecksumProgress()
|
||||
|
||||
self.widgets_config()
|
||||
|
||||
|
@ -131,7 +133,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||
self.lineEdit_dst_dir.setText(self.dst_dir)
|
||||
|
||||
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
|
||||
|
||||
def verify_checksum_changed(self):
|
||||
|
@ -407,8 +409,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||
current_file_progress_callback,
|
||||
imported_file_count_callback,
|
||||
found_file_callback,
|
||||
total_file_count_callback
|
||||
):
|
||||
total_file_count_callback,
|
||||
checksum_file_callback,
|
||||
checksum_progress_callback,
|
||||
checksum_dialog_open_callback):
|
||||
""" Copy Files. """
|
||||
count = int(0)
|
||||
for line in range(self.file_list.count()):
|
||||
|
@ -423,29 +427,37 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||
self.files[sph]['name'])
|
||||
self.path_file_destination = path.join(self.dst_dir,
|
||||
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.copy_a_file(
|
||||
sph,
|
||||
self.path_file_destination,
|
||||
progress_callback,
|
||||
current_file_progress_callback,
|
||||
imported_file_count_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:
|
||||
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.path_file_destination_original,
|
||||
progress_callback,
|
||||
current_file_progress_callback,
|
||||
imported_file_count_callback,
|
||||
found_file_callback,
|
||||
total_file_count_callback)
|
||||
total_file_count_callback,
|
||||
checksum_file_callback,
|
||||
checksum_progress_callback,
|
||||
checksum_dialog_open_callback)
|
||||
|
||||
count += 1
|
||||
|
||||
|
@ -455,37 +467,48 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||
|
||||
def copy_a_file(self,
|
||||
fph,
|
||||
target,
|
||||
progress_callback,
|
||||
current_file_progress_callback,
|
||||
imported_file_count_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)
|
||||
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):
|
||||
self.chunk_size = (1024 * 1024) * 5
|
||||
else:
|
||||
self.chunk_size = (16 * 1024) * 1
|
||||
|
||||
if self.is_video(fph):
|
||||
self.chunk_size = (1024 * 1024) * 5
|
||||
else:
|
||||
self.chunk_size = (16 * 1024) * 1
|
||||
|
||||
with open(self.path_file_source, 'rb') as fs:
|
||||
with open(self.path_file_destination, 'wb') as fd:
|
||||
while True:
|
||||
chunk = fs.read(self.chunk_size)
|
||||
if not chunk:
|
||||
break
|
||||
fd.write(chunk)
|
||||
dst_size = path.getsize(self.path_file_destination)
|
||||
current_file_progress_callback.emit(round((dst_size / size) * 100, 1))
|
||||
with open(self.path_file_source, 'rb') as fs:
|
||||
with open(target, 'wb') as fd:
|
||||
while True:
|
||||
chunk = fs.read(self.chunk_size)
|
||||
if not chunk:
|
||||
break
|
||||
fd.write(chunk)
|
||||
dst_size = path.getsize(target)
|
||||
current_file_progress_callback.emit(round((dst_size / size) * 100, 1))
|
||||
|
||||
def check_store_original(self,sph):
|
||||
if self.config['store_originals'] is True:
|
||||
if self.is_image(sph):
|
||||
self.dst_dir = self.destination_original_path
|
||||
self.path_file_destination = self.path_file_destination_original
|
||||
r = True
|
||||
else:
|
||||
r = False
|
||||
|
@ -494,15 +517,103 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||
|
||||
return r
|
||||
|
||||
def check_duplicate(self,sph):
|
||||
if path_exists(self.path_file_destination):
|
||||
check_match = cmp_files(self.path_file_source, self.path_file_destination)
|
||||
def get_checksum(self,_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):
|
||||
|
||||
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:
|
||||
print(f'\nFound duplicate for {self.path_file_source}, renaming destination with hash appended.')
|
||||
base, extension = path.splitext(self.files[sph]['name'])
|
||||
f_xxhash = xx_hash(self.path_file_destination)
|
||||
file_name_hash = base + '_' + f_xxhash + extension
|
||||
rename(self.path_file_destination, path.join(self.dst_dir, file_name_hash))
|
||||
file_name_hash = base + '_' + hash2 + extension
|
||||
rename(target, path.join(target_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
|
||||
|
||||
|
@ -533,17 +644,99 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||
self.thread_complete)
|
||||
worker.signals.finished.connect(
|
||||
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
|
||||
self.threadpool.start(worker)
|
||||
|
||||
def verify_checksum(self):
|
||||
# fh_match = FileHash()
|
||||
print(f'verify_checksum,self.config: {self.config}')
|
||||
def compare_imported_checksums(self):
|
||||
# if self.config['verify_checksum'] is True:
|
||||
# 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)
|
||||
|
||||
# Main Window
|
||||
window = MainWindow()
|
||||
# Show Window
|
||||
window.show()
|
||||
|
||||
app.exec()
|
|
@ -50,7 +50,7 @@ class Ui_MainWindow(object):
|
|||
self.file_list.setGeometry(QtCore.QRect(20, 160, 871, 701))
|
||||
self.file_list.setObjectName("file_list")
|
||||
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.grid_metadata = QtWidgets.QGridLayout(self.gridLayoutWidget_2)
|
||||
self.grid_metadata.setContentsMargins(0, 0, 0, 0)
|
||||
|
|
|
@ -62,35 +62,35 @@
|
|||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<widget class="QLabel" name="l_hash_dest">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<widget class="QLabel" name="l_path_file_source">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<widget class="QLabel" name="l_path_file_dest">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<widget class="QLabel" name="l_hash_source">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<widget class="QLabel" name="label_title_source">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
|
@ -109,7 +109,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<widget class="QLabel" name="label_title_dest">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
|
@ -129,7 +129,7 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<widget class="QLabel" name="label_title_comparing_files">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
|
|
|
@ -29,34 +29,38 @@ class Ui_FileComparisonDialog(object):
|
|||
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))
|
||||
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_5.setFont(font)
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.label_title_comparing_files.setFont(font)
|
||||
self.label_title_comparing_files.setObjectName("label_title_comparing_files")
|
||||
|
||||
self.retranslateUi(FileComparisonDialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(FileComparisonDialog)
|
||||
|
@ -64,10 +68,6 @@ class Ui_FileComparisonDialog(object):
|
|||
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"))
|
||||
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"))
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from PyQt6.QtWidgets import QDialog
|
||||
from _Window_import_dialog import Ui_DialogImport
|
||||
from _Window_checksum_progress_dialog import Ui_ChecksumProgressDialog
|
||||
|
||||
class DialogImport(QDialog, Ui_DialogImport):
|
||||
class DialogChecksumProgress(QDialog, Ui_ChecksumProgressDialog):
|
||||
def __init__(self,*args,**kwargs):
|
||||
super(DialogImport,self).__init__(*args,**kwargs)
|
||||
super(DialogChecksumProgress,self).__init__(*args,**kwargs)
|
||||
self.setupUi(self)
|
||||
# self.import_dialog = UI_DialogImport()
|
||||
# self.ui_import_dialog = Ui_DialogImport()
|
||||
|
@ -13,33 +13,27 @@ class DialogImport(QDialog, Ui_DialogImport):
|
|||
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 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_import_dialog(self):
|
||||
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_importing(self, n):
|
||||
print("%d%% done" % n)
|
||||
self.progressBar_importing.setValue(int(n))
|
||||
self.lcd_import_progress.display(n)
|
||||
def set_progress(self, n):
|
||||
# print("%d%% done" % n)
|
||||
self.progressBar_getting_checksum.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)
|
||||
def set_file(self,f):
|
||||
self.l_content_checksum_filename.setText(f)
|
|
@ -1,5 +1,5 @@
|
|||
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):
|
||||
def __init__(self,*args,**kwargs):
|
||||
|
@ -26,6 +26,6 @@ class FindProgress(QDialog, Ui_FindProgress):
|
|||
self.hide()
|
||||
|
||||
def set_progress_finding_files(self,n):
|
||||
print("%d%% done" % n)
|
||||
# print("%d%% done" % n)
|
||||
self.progressBar_importing.setValue(float(n))
|
||||
self.lcd_import_progress.display(n)
|
|
@ -1,5 +1,5 @@
|
|||
from PyQt6.QtWidgets import QDialog
|
||||
from _import_dialog_Window import Ui_DialogImport
|
||||
from _Window_import_dialog import Ui_DialogImport
|
||||
|
||||
class DialogImport(QDialog, Ui_DialogImport):
|
||||
def __init__(self,*args,**kwargs):
|
||||
|
@ -14,11 +14,16 @@ class DialogImport(QDialog, Ui_DialogImport):
|
|||
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()
|
||||
if self.is_shown() is False:
|
||||
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()
|
||||
else:
|
||||
print('Import Dialog already open.')
|
||||
else:
|
||||
self.close_import_dialog()
|
||||
|
||||
def close_import_dialog(self):
|
||||
print('close_import_dialog')
|
||||
|
@ -28,12 +33,12 @@ class DialogImport(QDialog, Ui_DialogImport):
|
|||
self.hide()
|
||||
|
||||
def set_progress_importing(self, n):
|
||||
print("%d%% done" % 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)
|
||||
# print("%d%% done" % n)
|
||||
self.progressBar_importing_2.setValue(int(n))
|
||||
self.lcd_current_file_progress.display(n)
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ import yaml
|
|||
from tqdm import tqdm
|
||||
|
||||
### Local Imports
|
||||
from _hashing import xx_hash
|
||||
# from _hashing import xx_hash
|
||||
from _verify_file_checksum import FileHash
|
||||
|
||||
def check_log_dir(d):
|
||||
create_folder(d)
|
||||
|
@ -38,10 +39,14 @@ def cmp_files(f1,f2):
|
|||
#TODO: Determine if path is actually a file
|
||||
#TODO: Determine if the hash has already been stored and use it if so
|
||||
|
||||
hash1 = xx_hash(f1)
|
||||
hash2 = xx_hash(f2)
|
||||
hash1 = FileHash(f1).file_hash
|
||||
hash2 = FileHash(f2).file_hash
|
||||
return hash1 == hash2
|
||||
|
||||
def cmp_hashes(h1,h2):
|
||||
""" compare two files """
|
||||
return h1 == h2
|
||||
|
||||
def path_access_read(path):
|
||||
""" make sure we can read from the path """
|
||||
val = os.access(path, os.R_OK)
|
||||
|
|
|
@ -29,7 +29,10 @@ class FindFiles:
|
|||
current_file_progress_callback,
|
||||
imported_file_count_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)
|
||||
if len(self.search_types) > 0:
|
||||
for folder, subfolders, filename in os.walk(self.src_dir):
|
||||
|
|
36
_hashing.py
36
_hashing.py
|
@ -8,28 +8,24 @@ import os
|
|||
import xxhash
|
||||
from tqdm import tqdm
|
||||
|
||||
def xx_hash(file):
|
||||
""" calculates and returns file hash based on xxHash """
|
||||
size = os.path.getsize(file)
|
||||
hasher = xxhash.xxh64()
|
||||
# def xx_hash(file):
|
||||
# """ calculates and returns file hash based on xxHash """
|
||||
# size = os.path.getsize(file)
|
||||
# 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):
|
||||
""" Generate xxHashes """
|
||||
|
|
|
@ -2,7 +2,7 @@ import os.path
|
|||
import sys
|
||||
|
||||
from _audio import AudioFile
|
||||
from _hashing import hash_path
|
||||
from _verify_file_checksum import FileHash
|
||||
from _video import VideoFile
|
||||
from _photo import PhotoFile
|
||||
from _file_stuff import (get_file_name,
|
||||
|
@ -23,7 +23,7 @@ class MediaFile:
|
|||
self.store_originals = self.config['store_originals']
|
||||
self.src_dir = os.path.dirname(self.path_file_name)
|
||||
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.dotted_file_ext = get_dotted_file_ext(self.file_name)
|
||||
self.file_ext = get_file_ext(self.file_name)
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#!/usr/bin/env python
|
||||
from PIL import Image
|
||||
|
||||
from _media_file import MediaFile
|
||||
from _raw_photo import extract_jpg_thumb
|
||||
from _video import VideoFile
|
||||
from _hashing import hash_path
|
||||
from _verify_file_checksum import FileHash
|
||||
|
||||
class MediaPreview:
|
||||
def __init__(self,path_file_name,media_files):
|
||||
|
@ -12,7 +10,7 @@ class MediaPreview:
|
|||
self.path_file_name = path_file_name
|
||||
self.media_files_list = media_files
|
||||
# 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')
|
||||
self.thumbnail = 'thumbnail.jpg'
|
||||
self.file_type = self.media_files_list[self.source_path_hash]['file_type']
|
||||
|
|
|
@ -31,6 +31,9 @@ class WorkerSignals(QObject):
|
|||
imported_file_count = pyqtSignal(int)
|
||||
found_file = pyqtSignal(str)
|
||||
total_file_count = pyqtSignal(int)
|
||||
checksum_progress = pyqtSignal(int)
|
||||
checksum_file = pyqtSignal(str)
|
||||
checksum_dialog_open = pyqtSignal(bool)
|
||||
|
||||
class Worker(QRunnable):
|
||||
"""
|
||||
|
@ -60,6 +63,9 @@ class Worker(QRunnable):
|
|||
self.kwargs['imported_file_count_callback'] = self.signals.imported_file_count
|
||||
self.kwargs['found_file_callback'] = self.signals.found_file
|
||||
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()
|
||||
def run(self):
|
||||
|
|
|
@ -2,47 +2,52 @@ import os
|
|||
import xxhash
|
||||
|
||||
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)
|
||||
self.files = files
|
||||
self.chunk_size = kwargs['chunk_size']
|
||||
self.path_file = path_file
|
||||
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)
|
||||
hasher = xxhash.xxh64()
|
||||
|
||||
#todo: add callbacks
|
||||
chunk_count = 0
|
||||
|
||||
checksum_file_callback.emit(f)
|
||||
|
||||
with open(f, 'rb') as f:
|
||||
for chunk in iter(lambda: f.read(self.chunk_size),b""):
|
||||
hasher.update(chunk)
|
||||
chunk_count += 1
|
||||
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()
|
||||
checksum_dialog_open_callback.emit(False)
|
||||
|
||||
return file_hash
|
||||
|
||||
@staticmethod
|
||||
def t_verify_checksum(self,
|
||||
progress_callback,
|
||||
import_progress_callback,
|
||||
current_file_progress_callback,
|
||||
imported_file_count_callback,
|
||||
found_file,
|
||||
total_file_count):
|
||||
def hash_path(self):
|
||||
""" hashes a string passed as a path """
|
||||
|
||||
for file in self.files:
|
||||
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
|
||||
return self.path_hasher.hexdigest()
|
|
@ -1,5 +1,5 @@
|
|||
pyuic6 BitMover.ui -o _BitMover_MainWindow.py
|
||||
pyuic6 import_dialogue.ui -o _import_dialog_Window.py
|
||||
pyuic6 _finding_files_dialog.ui -o _finding_files_dialog_Window.py
|
||||
pyuic6 _ComparisonDialog.ui -o _comparison_dialog_Window.py
|
||||
pyuic6 _checksum_progress_dialog.ui -o _checksum_progress_dialog_Window.py
|
||||
pyuic6 import_dialogue.ui -o _Window_import_dialog.py
|
||||
pyuic6 _finding_files_dialog.ui -o _Window_finding_files_dialog.py
|
||||
pyuic6 _ComparisonDialog.ui -o _Window_comparison_dialog.py
|
||||
pyuic6 _checksum_progress_dialog.ui -o _Window_checksum_progress_dialog.py
|
||||
|
|
Loading…
Reference in New Issue