skilleter-thingy 0.0.25__tar.gz → 0.0.26__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of skilleter-thingy might be problematic. Click here for more details.
- {skilleter_thingy-0.0.25/skilleter_thingy.egg-info → skilleter_thingy-0.0.26}/PKG-INFO +1 -2
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/pyproject.toml +1 -2
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git_review.py +11 -5
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26/skilleter_thingy.egg-info}/PKG-INFO +1 -2
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy.egg-info/SOURCES.txt +0 -1
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy.egg-info/requires.txt +0 -1
- skilleter_thingy-0.0.25/skilleter_thingy/imagedupe.py +0 -281
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/LICENSE +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/README.md +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/setup.cfg +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/__init__.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/addpath.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/borger.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/colour.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/console_colours.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/dc_curses.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/dc_defaults.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/dc_util.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/dircolors.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/diskspacecheck.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/docker.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/docker_purge.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/ffind.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/files.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/ggit.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/ggrep.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git2.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git_br.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git_ca.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git_cleanup.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git_co.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git_common.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git_hold.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git_mr.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git_parent.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git_update.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/git_wt.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/gitcmp_helper.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/gitlab.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/gitprompt.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/gl.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/gphotosync.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/linecount.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/logger.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/moviemover.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/path.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/photodupe.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/phototidier.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/popup.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/process.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/py_audit.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/readable.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/remdir.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/rmdupe.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/rpylint.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/run.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/splitpics.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/strreplace.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/sysmon.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/tfm.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/tfm_pane.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/tfparse.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/tidy.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/trimpath.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/window_rename.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/xchmod.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy/yamlcheck.py +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy.egg-info/dependency_links.txt +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy.egg-info/entry_points.txt +0 -0
- {skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: skilleter_thingy
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.26
|
|
4
4
|
Summary: A collection of useful utilities, mainly aimed at making Git more friendly
|
|
5
5
|
Author-email: John Skilleter <john@skilleter.org.uk>
|
|
6
6
|
Project-URL: Home, https://skilleter.org.uk
|
|
@@ -18,7 +18,6 @@ Requires-Dist: pyaml
|
|
|
18
18
|
Requires-Dist: pygit2
|
|
19
19
|
Requires-Dist: python-dateutil
|
|
20
20
|
Requires-Dist: requests
|
|
21
|
-
Requires-Dist: numpy
|
|
22
21
|
|
|
23
22
|
# Thingy
|
|
24
23
|
|
|
@@ -7,7 +7,7 @@ name = "skilleter_thingy"
|
|
|
7
7
|
|
|
8
8
|
# Version must be incremented to install updated Thingy
|
|
9
9
|
|
|
10
|
-
version = "0.0.
|
|
10
|
+
version = "0.0.26"
|
|
11
11
|
|
|
12
12
|
authors = [
|
|
13
13
|
{name="John Skilleter", email="john@skilleter.org.uk"},
|
|
@@ -34,7 +34,6 @@ dependencies = [
|
|
|
34
34
|
"pygit2",
|
|
35
35
|
"python-dateutil",
|
|
36
36
|
"requests",
|
|
37
|
-
"numpy",
|
|
38
37
|
]
|
|
39
38
|
|
|
40
39
|
[project.urls]
|
|
@@ -514,6 +514,12 @@ class GitReview():
|
|
|
514
514
|
def show_file_list(self):
|
|
515
515
|
""" Draw the current page of the file list """
|
|
516
516
|
|
|
517
|
+
def format_change(prefix, value):
|
|
518
|
+
"""If value is 0 just return it as a string, otherwise apply the prefix and
|
|
519
|
+
return it (e.g. '+' or '-')"""
|
|
520
|
+
|
|
521
|
+
return f'{prefix}{value}' if value else '0'
|
|
522
|
+
|
|
517
523
|
for ypos in range(0, self.file_list_h):
|
|
518
524
|
|
|
519
525
|
normal_colour = curses.color_pair(COLOUR_NORMAL)
|
|
@@ -535,13 +541,13 @@ class GitReview():
|
|
|
535
541
|
# Diff stats, with or without non-whitespace changes
|
|
536
542
|
|
|
537
543
|
if self.show_none_whitespace_stats:
|
|
538
|
-
added =
|
|
539
|
-
deleted =
|
|
544
|
+
added = format_change('+', current_file["non-ws added"])
|
|
545
|
+
deleted = format_change('-', current_file["non-ws deleted"])
|
|
540
546
|
else:
|
|
541
|
-
added =
|
|
542
|
-
deleted =
|
|
547
|
+
added = format_change('+', current_file["added"])
|
|
548
|
+
deleted = format_change('-', current_file["deleted"])
|
|
543
549
|
|
|
544
|
-
status = f'{current_file["status"]} {
|
|
550
|
+
status = f'{current_file["status"]} {deleted:>4}/{added:>4}'
|
|
545
551
|
|
|
546
552
|
abspath = os.path.join(self.working_tree_dir, filename)
|
|
547
553
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: skilleter_thingy
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.26
|
|
4
4
|
Summary: A collection of useful utilities, mainly aimed at making Git more friendly
|
|
5
5
|
Author-email: John Skilleter <john@skilleter.org.uk>
|
|
6
6
|
Project-URL: Home, https://skilleter.org.uk
|
|
@@ -18,7 +18,6 @@ Requires-Dist: pyaml
|
|
|
18
18
|
Requires-Dist: pygit2
|
|
19
19
|
Requires-Dist: python-dateutil
|
|
20
20
|
Requires-Dist: requests
|
|
21
|
-
Requires-Dist: numpy
|
|
22
21
|
|
|
23
22
|
# Thingy
|
|
24
23
|
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Hash photos to find closely-similar images and report them"""
|
|
3
|
-
|
|
4
|
-
# TODO: Configurable hash type and stored in pickle data
|
|
5
|
-
# TODO: Option to pickle duplicates
|
|
6
|
-
# TODO: Check for files that are no longer present after scanning and remove them from the data
|
|
7
|
-
# TODO: Display duplicates - borrow code from imagedup
|
|
8
|
-
# TODO: Note that if a==b, we get reports for a==b and b==a so we need to do some filtering and decide on what's likely to be an original and what is a duplicate
|
|
9
|
-
# TODO: Maybe store file date, size and image dimensions in 'updated' for better comparisons
|
|
10
|
-
# TODO: Pickle data named for directories
|
|
11
|
-
# TODO: Use database instead of pickling - very slow to load big pickles - would facilitate scanning/checking specific directories
|
|
12
|
-
# TODO: If directories specified, the only scan and compare within those directories (but keep everything in pickle file (yes, it will get biggerer, and biggererer)
|
|
13
|
-
|
|
14
|
-
import threading
|
|
15
|
-
import queue
|
|
16
|
-
import sys
|
|
17
|
-
import os
|
|
18
|
-
import pickle
|
|
19
|
-
import argparse
|
|
20
|
-
from pathlib import PurePath
|
|
21
|
-
from typing import List, Union
|
|
22
|
-
|
|
23
|
-
from imagededup.methods import PHash
|
|
24
|
-
|
|
25
|
-
import matplotlib.gridspec as gridspec
|
|
26
|
-
import matplotlib.pyplot as plt
|
|
27
|
-
from matplotlib import figure
|
|
28
|
-
|
|
29
|
-
import numpy as np
|
|
30
|
-
from PIL import Image
|
|
31
|
-
|
|
32
|
-
################################################################################
|
|
33
|
-
|
|
34
|
-
PICKLE_FILE = 'imagedupe.pickle'
|
|
35
|
-
|
|
36
|
-
IMAGE_EXT_LIST = ('.jpeg', '.jpg', '.png', '.bmp', '.mpo', '.ppm', '.tif', '.tiff', '.gif', '.svg', '.pgm', '.pbm', '.webp')
|
|
37
|
-
|
|
38
|
-
PICKLE_VERSION = 1
|
|
39
|
-
|
|
40
|
-
NUM_THREADS = 24
|
|
41
|
-
|
|
42
|
-
################################################################################
|
|
43
|
-
|
|
44
|
-
def queue_files_to_hash(file_queue, directories):
|
|
45
|
-
"""Read all the specfied directories queue every file therein"""
|
|
46
|
-
|
|
47
|
-
# Walk each directory tree
|
|
48
|
-
|
|
49
|
-
for directory in directories:
|
|
50
|
-
print(f'Scanning directory tree {directory}')
|
|
51
|
-
|
|
52
|
-
for root, _, files in os.walk(directory):
|
|
53
|
-
print(f'Scanning directory {root}')
|
|
54
|
-
|
|
55
|
-
for file in files:
|
|
56
|
-
file_queue.put(os.path.join(root, file))
|
|
57
|
-
|
|
58
|
-
################################################################################
|
|
59
|
-
|
|
60
|
-
def hasher_thread(method, file_queue, hash_queue, hashes, updated):
|
|
61
|
-
"""Thread - reads a file from the queue and, if it is an unhashed or updated image
|
|
62
|
-
calculate the hash and post it and the modification time on the updated queue"""
|
|
63
|
-
|
|
64
|
-
while not file_queue.empty():
|
|
65
|
-
filepath = file_queue.get()
|
|
66
|
-
|
|
67
|
-
fileext = os.path.splitext(filepath)[1]
|
|
68
|
-
mod_time = os.path.getmtime(filepath)
|
|
69
|
-
|
|
70
|
-
# If the file type is an image and the file hasn't been hashed or the modification time has changed
|
|
71
|
-
# then save the hash and the modification time
|
|
72
|
-
|
|
73
|
-
if fileext.lower() in IMAGE_EXT_LIST and (filepath not in hashes or mod_time != updated[filepath]):
|
|
74
|
-
# Calculate the hash and store path, dimensions and file size under the hash entry in the hashes table
|
|
75
|
-
|
|
76
|
-
print(f'Calculating hash for {filepath}')
|
|
77
|
-
encoding = method.encode_image(image_file=filepath)
|
|
78
|
-
|
|
79
|
-
if encoding:
|
|
80
|
-
hash_queue.put({'filepath': filepath, 'encoding': encoding, 'updated': mod_time})
|
|
81
|
-
else:
|
|
82
|
-
print(f'Invalid image {filepath}')
|
|
83
|
-
|
|
84
|
-
file_queue.task_done()
|
|
85
|
-
|
|
86
|
-
################################################################################
|
|
87
|
-
|
|
88
|
-
def hash_directories(directories, method, hashes, updated):
|
|
89
|
-
"""Scan for new files and calculate their hashes"""
|
|
90
|
-
|
|
91
|
-
# Create the I/O queues
|
|
92
|
-
|
|
93
|
-
file_queue = queue.Queue()
|
|
94
|
-
hash_queue = queue.Queue()
|
|
95
|
-
|
|
96
|
-
# Queue the list of files to hash
|
|
97
|
-
|
|
98
|
-
queue_files_to_hash(file_queue, directories)
|
|
99
|
-
|
|
100
|
-
# Start the threads hashing away
|
|
101
|
-
|
|
102
|
-
thread_list = []
|
|
103
|
-
for _ in range(NUM_THREADS):
|
|
104
|
-
thread = threading.Thread(target=hasher_thread, daemon=True, args=(method, file_queue, hash_queue, hashes, updated))
|
|
105
|
-
thread.start()
|
|
106
|
-
thread_list.append(thread)
|
|
107
|
-
|
|
108
|
-
# Wait for the threads to stop working
|
|
109
|
-
|
|
110
|
-
print('Waiting for threads to terminate')
|
|
111
|
-
|
|
112
|
-
for thread in thread_list:
|
|
113
|
-
thread.join()
|
|
114
|
-
|
|
115
|
-
# Process the results
|
|
116
|
-
|
|
117
|
-
while not hash_queue.empty():
|
|
118
|
-
entry = hash_queue.get()
|
|
119
|
-
|
|
120
|
-
filepath = entry['filepath']
|
|
121
|
-
hashes[filepath] = entry['encoding']
|
|
122
|
-
updated[filepath] = entry['updated']
|
|
123
|
-
|
|
124
|
-
################################################################################
|
|
125
|
-
|
|
126
|
-
def plot_images(
|
|
127
|
-
orig: str,
|
|
128
|
-
image_list: List,
|
|
129
|
-
scores: bool = False,
|
|
130
|
-
outfile: str = None,
|
|
131
|
-
) -> None:
|
|
132
|
-
"""
|
|
133
|
-
Plotting function for plot_duplicates() defined below.
|
|
134
|
-
|
|
135
|
-
Args:
|
|
136
|
-
orig: filename for which duplicates are to be plotted.
|
|
137
|
-
image_list: List of duplicate filenames, could also be with scores (filename, score).
|
|
138
|
-
scores: Whether only filenames are present in the image_list or scores as well.
|
|
139
|
-
outfile: Name of the file to save the plot.
|
|
140
|
-
"""
|
|
141
|
-
|
|
142
|
-
def formatter(val: Union[int, np.float32]):
|
|
143
|
-
"""
|
|
144
|
-
For printing floats only upto 3rd precision. Ints are unchanged.
|
|
145
|
-
"""
|
|
146
|
-
if isinstance(val, np.float32):
|
|
147
|
-
return f'{val:.3f}'
|
|
148
|
-
|
|
149
|
-
return val
|
|
150
|
-
|
|
151
|
-
n_ims = len(image_list)
|
|
152
|
-
ncols = 4 # fixed for a consistent layout
|
|
153
|
-
nrows = int(np.ceil(n_ims / ncols)) + 1
|
|
154
|
-
fig = figure.Figure(figsize=(10, 14))
|
|
155
|
-
|
|
156
|
-
gs = gridspec.GridSpec(nrows=nrows, ncols=ncols)
|
|
157
|
-
ax = plt.subplot(
|
|
158
|
-
gs[0, 1:3]
|
|
159
|
-
) # Always plot the original image in the middle of top row
|
|
160
|
-
ax.imshow(Image.open(orig))
|
|
161
|
-
ax.set_title(f'Original Image: {format(orig)}')
|
|
162
|
-
ax.axis('off')
|
|
163
|
-
|
|
164
|
-
for i in range(0, n_ims):
|
|
165
|
-
row_num = (i // ncols) + 1
|
|
166
|
-
col_num = i % ncols
|
|
167
|
-
|
|
168
|
-
ax = plt.subplot(gs[row_num, col_num])
|
|
169
|
-
if scores:
|
|
170
|
-
ax.imshow(Image.open(image_list[i][0]))
|
|
171
|
-
val = formatter(image_list[i][1])
|
|
172
|
-
title = ' '.join([image_list[i][0], f'({val})'])
|
|
173
|
-
else:
|
|
174
|
-
ax.imshow(Image.open(image_list[i]))
|
|
175
|
-
title = image_list[i]
|
|
176
|
-
|
|
177
|
-
ax.set_title(title, fontsize=6)
|
|
178
|
-
ax.axis('off')
|
|
179
|
-
gs.tight_layout(fig)
|
|
180
|
-
|
|
181
|
-
if outfile:
|
|
182
|
-
plt.savefig(outfile)
|
|
183
|
-
|
|
184
|
-
plt.show()
|
|
185
|
-
plt.close()
|
|
186
|
-
|
|
187
|
-
################################################################################
|
|
188
|
-
|
|
189
|
-
def main():
|
|
190
|
-
"""Read the hashes and report duplicates in a vaguely civilised way"""
|
|
191
|
-
|
|
192
|
-
# Hashing and comparison method
|
|
193
|
-
|
|
194
|
-
method = PHash()
|
|
195
|
-
|
|
196
|
-
# Handle command line arguments
|
|
197
|
-
|
|
198
|
-
parser = argparse.ArgumentParser(description='Search for similar images')
|
|
199
|
-
parser.add_argument('--no-scan', action='store_true', help='Use pickled scan data without updating it')
|
|
200
|
-
parser.add_argument('--no-compare', action='store_true', help='Use pickled comparison data without updating it')
|
|
201
|
-
parser.add_argument('--show', action='store_true', help='Show duplicate images')
|
|
202
|
-
parser.add_argument('directories', nargs='*', action='store', help='Directories to search')
|
|
203
|
-
|
|
204
|
-
args = parser.parse_args()
|
|
205
|
-
|
|
206
|
-
breakpoint()
|
|
207
|
-
|
|
208
|
-
if not args.no_scan and not args.directories:
|
|
209
|
-
print('You must be specify at least one directory in order to perform a scan')
|
|
210
|
-
sys.exit(1)
|
|
211
|
-
|
|
212
|
-
# We pickle the current set of files, hashes and comparisons
|
|
213
|
-
|
|
214
|
-
try:
|
|
215
|
-
print('Loading cached data')
|
|
216
|
-
|
|
217
|
-
with open(PICKLE_FILE, 'rb') as pickles:
|
|
218
|
-
data = pickle.load(pickles)
|
|
219
|
-
|
|
220
|
-
if data['version'] != PICKLE_VERSION:
|
|
221
|
-
print(f'WARNING: Current version is {PICKLE_VERSION} but saved data is from version {data["version"]}. Interesting things could happen....')
|
|
222
|
-
|
|
223
|
-
hashes = data['hashes']
|
|
224
|
-
updated = data['updated']
|
|
225
|
-
duplicates = data.get('duplicates', None)
|
|
226
|
-
|
|
227
|
-
except (FileNotFoundError, EOFError):
|
|
228
|
-
if args.no_scan:
|
|
229
|
-
print('ERROR: Cannot use no-scan option as no cached scan data is available')
|
|
230
|
-
sys.exit(1)
|
|
231
|
-
|
|
232
|
-
hashes = {}
|
|
233
|
-
updated = {}
|
|
234
|
-
duplicates = {}
|
|
235
|
-
|
|
236
|
-
if args.no_compare and not duplicates:
|
|
237
|
-
print('ERROR: Cannot use no-compare option as no cached comparison data is available')
|
|
238
|
-
sys.exit(1)
|
|
239
|
-
|
|
240
|
-
if not args.no_scan:
|
|
241
|
-
# Scan for new values and calculate hashes
|
|
242
|
-
|
|
243
|
-
hash_directories(method, args.directories, hashes, updated)
|
|
244
|
-
|
|
245
|
-
if not args.no_compare:
|
|
246
|
-
# Look for duplicates
|
|
247
|
-
|
|
248
|
-
duplicates = method.find_duplicates(encoding_map=hashes)
|
|
249
|
-
|
|
250
|
-
# Pickle the updated results
|
|
251
|
-
|
|
252
|
-
with open(PICKLE_FILE, 'wb') as pickles:
|
|
253
|
-
dupe_data = {'hashes': hashes, 'updated': updated, 'version': PICKLE_VERSION, 'duplicates': duplicates}
|
|
254
|
-
pickle.dump(dupe_data, pickles)
|
|
255
|
-
|
|
256
|
-
# Report them
|
|
257
|
-
|
|
258
|
-
for entry in duplicates:
|
|
259
|
-
if duplicates[entry]:
|
|
260
|
-
print(f'{entry}: {duplicates[entry]}')
|
|
261
|
-
if args.show:
|
|
262
|
-
plot_duplicates(entry, duplicates[entry])
|
|
263
|
-
|
|
264
|
-
################################################################################
|
|
265
|
-
|
|
266
|
-
def photodupe():
|
|
267
|
-
"""Entry point"""
|
|
268
|
-
|
|
269
|
-
try:
|
|
270
|
-
main()
|
|
271
|
-
|
|
272
|
-
except KeyboardInterrupt:
|
|
273
|
-
sys.exit(1)
|
|
274
|
-
|
|
275
|
-
except BrokenPipeError:
|
|
276
|
-
sys.exit(2)
|
|
277
|
-
|
|
278
|
-
################################################################################
|
|
279
|
-
|
|
280
|
-
if __name__ == '__main__':
|
|
281
|
-
photodupe()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{skilleter_thingy-0.0.25 → skilleter_thingy-0.0.26}/skilleter_thingy.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|