Skip to content

Commit 85c21eb

Browse files
Switch score algorithm vom NCC to SSIM to prevent triggers when content moves
Also reduced threshold to 0.9
1 parent 8903776 commit 85c21eb

File tree

3 files changed

+30
-29
lines changed

3 files changed

+30
-29
lines changed

Shared/Sources/Shared/JFLiterals.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,12 @@ public let kPythonPath = "/usr/bin/python3"
6666
public let kConvertPath = "/usr/bin/convert"
6767

6868
/// The file containing the ncc information
69-
public let kNccFile = "ncc"
69+
public let kScoreFile = "ncc"
7070
/// The filename of the file containing the visual diff representation
7171
public let kDiffFile = "diff.png"
7272

73-
/// The threshold value the bot uses. If the NCC value is below this, a notification is triggered
74-
public let kNccThreshold = 0.999
73+
/// The threshold value the bot uses. If the SSIM value is below this, a notification is triggered
74+
public let kComparisonThreshold = 0.9
7575
/// The duration for which a screenshot capture error has to persist for the user to be notified. Set to 0 to immediately notify on errors
7676
public let kErrorReportDuration: TimeInterval = 120 * 60 // 2 hours
7777
/// The string used to separate the values in the urls.list file

urlwatcher/Sources/urlwatcher/Functions.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -231,25 +231,25 @@ func rollBack(_ oldImage: String, to latestImage: String) throws {
231231
}
232232

233233
// Calculates the normalized cross-correlation
234-
func screenshotNCC(_ oldImage: String, _ latestImage: String, diffFile: String) throws -> Double? {
235-
let nccPipe = Pipe()
234+
func screenshotScore(_ oldImage: String, _ latestImage: String, diffFile: String) throws -> Double? {
235+
let pipe = Pipe()
236236
let result = try bash("compare", arguments: [
237237
"-quiet",
238238
"-alpha", "deactivate",
239-
"-metric", "NCC",
239+
"-metric", "SSIM",
240240
oldImage,
241241
latestImage,
242242
diffFile
243-
], standardOutput: nccPipe, standardError: nccPipe)
243+
], standardOutput: pipe, standardError: pipe)
244244

245-
let nccData = nccPipe.fileHandleForReading.readDataToEndOfFile()
246-
guard let nccString = String(data: nccData, encoding: .utf8) else {
245+
let scoreData = pipe.fileHandleForReading.readDataToEndOfFile()
246+
guard let scoreString = String(data: scoreData, encoding: .utf8) else {
247247
return nil
248248
}
249249

250250
// If the images are different-sized, we don't need to treat this as an error.
251-
// Instead, we just notify the user about it by setting the NCC to 0
252-
if nccString.contains("compare: image widths or heights differ") {
251+
// Instead, we just notify the user about it by setting the score to 0
252+
if scoreString.contains("compare: image widths or heights differ") {
253253
return 0
254254
}
255255

@@ -260,7 +260,7 @@ func screenshotNCC(_ oldImage: String, _ latestImage: String, diffFile: String)
260260
return nil
261261
}
262262

263-
return Double(nccString)
263+
return Double(scoreString)
264264
}
265265

266266
func checkUnmute(_ entry: inout URLEntry) throws -> Bool {

urlwatcher/Sources/urlwatcher/main.swift

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,17 @@ do {
152152

153153
let tempDiff = "\(entryPath)/diff.temp"
154154

155-
guard let ncc = try screenshotNCC(oldImage, latestImage, diffFile: tempDiff) else {
156-
print("Error checking screenshot NCC.")
155+
guard let score = try screenshotScore(oldImage, latestImage, diffFile: tempDiff) else {
156+
print("Error checking screenshot score.")
157157
try handleScreenshotError(entry: entry)
158158
try rollBack(oldImage, to: latestImage)
159159
// Continue with the next entry
160160
continue
161161
}
162162

163163
// If the website changed
164-
if ncc < kNccThreshold {
165-
print("Possible change detected (NCC: \(ncc)). Confirming...")
164+
if score < kComparisonThreshold {
165+
print("Possible change detected (score: \(score)). Confirming...")
166166

167167
// Take another screenshot to confirm its not just a one-time loading error or inconsistency
168168
// Delete the changed screenshot, otherwise we cannot confirm that taking the screenshot was a success
@@ -173,18 +173,18 @@ do {
173173
continue
174174
}
175175

176-
guard let newNCC = try screenshotNCC(oldImage, latestImage, diffFile: tempDiff) else {
176+
guard let newScore = try screenshotScore(oldImage, latestImage, diffFile: tempDiff) else {
177177
// Error while confirming screenshot
178-
print("Error confirming screenshot NCC.")
178+
print("Error confirming screenshot score.")
179179
try handleScreenshotError(entry: entry)
180180
try rollBack(oldImage, to: latestImage)
181181
// Continue with the next entry
182182
continue
183183
}
184184

185-
if newNCC < kNccThreshold {
185+
if newScore < kComparisonThreshold {
186186
// If the second screenshot also shows changes, we notify the user
187-
print("Change confirmed. NCC: \(newNCC). Notifying user.")
187+
print("Change confirmed. Score: \(newScore). Notifying user.")
188188

189189
// Save the temp file persistently
190190
let diffFile = "\(entryPath)/\(kDiffFile)"
@@ -197,27 +197,28 @@ do {
197197
try fileManager.moveItem(atPath: tempDiff, toPath: diffFile)
198198
}
199199

200-
// Generate detailed NCC information
201-
let nccFile = "\(entryPath)/\(kNccFile)"
202-
if fileManager.fileExists(atPath: nccFile) {
203-
try fileManager.removeItem(atPath: nccFile)
200+
// Generate detailed score information
201+
let scoreFile = "\(entryPath)/\(kScoreFile)"
202+
if fileManager.fileExists(atPath: scoreFile) {
203+
try fileManager.removeItem(atPath: scoreFile)
204204
}
205+
// TODO: Duplicated in Functions.swift
205206
try bash("compare", arguments: [
206207
"-verbose",
207208
"-alpha", "deactivate",
208-
"-metric", "NCC",
209+
"-metric", "SSIM",
209210
oldImage,
210211
latestImage,
211212
"/dev/null"
212-
], standardOutput: FileHandle(forWritingAtPath: nccFile))
213+
], standardOutput: FileHandle(forWritingAtPath: scoreFile))
213214

214215
// Notify the user
215-
try sendTelegramMessage("\(entry.name) has changed. NCC: \(ncc)\(ncc != newNCC ? ", \(newNCC)" : "")", to: Int(entry.chatID), image: latestImage)
216+
try sendTelegramMessage("\(entry.name) has changed. Score: \(score)\(score != newScore ? ", \(newScore)" : "")", to: Int(entry.chatID), image: latestImage)
216217
} else {
217-
print("Change not confirmed. NCC: \(newNCC)")
218+
print("Change not confirmed. Score: \(newScore)")
218219
}
219220
} else {
220-
print("No change detected. NCC: \(ncc)")
221+
print("No change detected. Score: \(score)")
221222
}
222223

223224
// Clean up any temp diff files

0 commit comments

Comments
 (0)