Skip to content

Commit 116d3c0

Browse files
authored
Merge pull request #5 from doomedramen/master
fix: use SHA-256 content hash in processed-file marker to handle same…
2 parents 42bb8f3 + a7fdecb commit 116d3c0

1 file changed

Lines changed: 65 additions & 19 deletions

File tree

plugin.py

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
If not, see <https://www.gnu.org/licenses/>.
2222
2323
"""
24+
import hashlib
25+
import json
2426
import logging
2527
import os
2628
from configparser import NoSectionError, NoOptionError
@@ -102,6 +104,39 @@ def custom_stream_mapping(self, stream_info: dict, stream_id: int):
102104
}
103105

104106

107+
def file_sha256(path, chunk_size=16 * 1024 * 1024):
108+
digest = hashlib.sha256()
109+
with open(path, 'rb') as f:
110+
for chunk in iter(lambda: f.read(chunk_size), b''):
111+
digest.update(chunk)
112+
return digest.hexdigest()
113+
114+
115+
def load_marker(raw):
116+
"""Parse a stored marker. Returns a dict, or None if nothing stored."""
117+
if not raw:
118+
return None
119+
try:
120+
marker = json.loads(raw)
121+
if isinstance(marker, dict):
122+
return marker
123+
except Exception:
124+
pass
125+
# Backwards-compat: old format was a plain loudnorm string
126+
return {'version': 1, 'filtergraph': raw, 'sha256': None}
127+
128+
129+
def make_marker(settings, path):
130+
stat = os.stat(path)
131+
return json.dumps({
132+
'version': 2,
133+
'filtergraph': audio_filtergraph(settings),
134+
'sha256': file_sha256(path),
135+
'size': stat.st_size,
136+
'mtime_ns': stat.st_mtime_ns,
137+
})
138+
139+
105140
def audio_filtergraph(settings):
106141
i = settings.get_setting('I')
107142
if not i:
@@ -122,28 +157,39 @@ def file_already_normalised(settings, path):
122157
directory_info = UnmanicDirectoryInfo(os.path.dirname(path))
123158

124159
try:
125-
previous_loudnorm_filtergraph = directory_info.get('normalise_aac', os.path.basename(path))
126-
except NoSectionError as e:
127-
previous_loudnorm_filtergraph = ''
128-
except NoOptionError as e:
129-
previous_loudnorm_filtergraph = ''
160+
raw_marker = directory_info.get('normalise_aac', os.path.basename(path))
161+
except (NoSectionError, NoOptionError):
162+
raw_marker = ''
130163
except Exception as e:
131164
logger.debug("Unknown exception {}.".format(e))
132-
previous_loudnorm_filtergraph = ''
165+
raw_marker = ''
133166

134-
if previous_loudnorm_filtergraph:
135-
logger.debug("File's stream was previously normalised with {}.".format(previous_loudnorm_filtergraph))
136-
# This stream already has been normalised
137-
if settings.get_setting('ignore_previously_processed'):
138-
logger.debug("Plugin configured to ignore previously normalised streams")
139-
return True
140-
elif audio_filtergraph(settings) in previous_loudnorm_filtergraph:
141-
# The previously normalised stream matches what is already configured
142-
logger.debug(
143-
"Stream was previously normalised with the same settings as what the plugin is currently configured")
144-
return True
167+
marker = load_marker(raw_marker)
168+
169+
if not marker:
170+
return False
171+
172+
stored_sha256 = marker.get('sha256')
173+
if not stored_sha256:
174+
# Old marker has no content hash — treat as stale so replaced files are reprocessed
175+
logger.debug("normalise_aac marker has no content hash; reprocessing '{}'.".format(path))
176+
return False
177+
178+
current_sha256 = file_sha256(path)
179+
if current_sha256 != stored_sha256:
180+
logger.debug("File content changed since last normalisation; reprocessing '{}'.".format(path))
181+
return False
182+
183+
logger.debug("File '{}' content matches stored marker.".format(path))
184+
185+
if settings.get_setting('ignore_previously_processed'):
186+
logger.debug("Plugin configured to ignore previously normalised streams.")
187+
return True
188+
189+
if marker.get('filtergraph') == audio_filtergraph(settings):
190+
logger.debug("File was previously normalised with the same settings.")
191+
return True
145192

146-
# Default to...
147193
return False
148194

149195

@@ -283,7 +329,7 @@ def on_postprocessor_task_results(data):
283329
# Loop over the destination_files list and update the directory info file for each one
284330
for destination_file in data.get('destination_files'):
285331
directory_info = UnmanicDirectoryInfo(os.path.dirname(destination_file))
286-
directory_info.set('normalise_aac', os.path.basename(destination_file), audio_filtergraph(settings))
332+
directory_info.set('normalise_aac', os.path.basename(destination_file), make_marker(settings, destination_file))
287333
directory_info.save()
288334
logger.debug("Normalise AAC info written for '{}'.".format(destination_file))
289335

0 commit comments

Comments
 (0)