Sunday, October 25, 2020

#1 2020-10-16 05:41:40 am

KniazidisR
Member
Registered: 2019-03-03
Posts: 1344

Remove Duplicate photos from Photos library of Photos.app

One cool script I wrote just now.
Use on your risk. You can undo the action from trash anyway.

Applescript:


use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

-- classes, constants, and enums used
property NSURLAddedToDirectoryDateKey : a reference to current application's NSURLAddedToDirectoryDateKey
property NSSortDescriptor : a reference to current application's NSSortDescriptor
property NSMutableArray : a reference to current application's NSMutableArray
property NSURLIsDirectoryKey : a reference to current application's NSURLIsDirectoryKey
property |NSURL| : a reference to current application's |NSURL|
property NSFileManager : a reference to current application's NSFileManager
property NSURLIsPackageKey : a reference to current application's NSURLIsPackageKey
property NSURLPathKey : a reference to current application's NSURLPathKey
property NSArray : a reference to current application's NSArray
property NSString : a reference to current application's NSString
property NSCalendar : a reference to current application's NSCalendar
property photosLibraryPath : POSIX path of (path to pictures folder) & "Screenshots/Photos Library.photoslibrary/"
property originals : photosLibraryPath & "originals"
property derivatives : photosLibraryPath & "resources/derivatives"

-- get all photos and sort them by date added
set theURL to my (|NSURL|'s fileURLWithPath:originals)
set theOptions to 6 -- NSDirectoryEnumerationSkipsPackageDescendants & NSDirectoryEnumerationSkipsHiddenFiles
set theEnumerator to NSFileManager's |defaultManager|()'s enumeratorAtURL:theURL includingPropertiesForKeys:{} options:theOptions errorHandler:(missing value)
set thePhotos to my filesAndPackagesInURLArray:(theEnumerator's allObjects())
set theURL to my (|NSURL|'s fileURLWithPath:derivatives)
set theEnumerator to NSFileManager's |defaultManager|()'s enumeratorAtURL:theURL includingPropertiesForKeys:{} options:theOptions errorHandler:(missing value)
set otherPhotos to my filesAndPackagesInURLArray:(theEnumerator's allObjects())
set thePhotos to NSArray's arrayWithArray:((thePhotos as list) & (otherPhotos as list))
set thePhotos to my sortFilesOrPaths:thePhotos
set theCount to thePhotos count

-- get date added of each photo. (We delete only the later added photos)
set theDatesAdded to {}
repeat with i from 1 to theCount
   set aPhoto to item i of thePhotos
   set aDate to (aPhoto's resourceValuesForKeys:{NSURLAddedToDirectoryDateKey} |error|:(missing value))
   set end of theDatesAdded to (my makeASDateFrom:(aDate as date))
end repeat
set thePhotos to thePhotos as list

-- with System Events getting the sizes of the files is faster than with AsObjC
set theSizes to {}
repeat with aPhoto in thePhotos
   tell application "System Events" to set end of theSizes to size of (aPhoto as alias)
end repeat

-- collect duplicate photos order numbers
set forDeleteFlags to {}
repeat with i from 1 to theCount - 1
   if i is in forDeleteFlags then set i to i + 1
   set aPhoto to (item i of thePhotos) as alias
   set aDate to item i of theDatesAdded
   set aSize to item i of theSizes
   set MD5checkSum to last word of (do shell script "md5 '" & POSIX path of aPhoto & "'")
   repeat with j from i + 1 to theCount
       set bPhoto to (item j of thePhotos) as alias
       set bSize to item j of theSizes
       if bSize = aSize then
           if not (j is in forDeleteFlags) then
               set MD5checkSum2 to last word of (do shell script "md5 '" & POSIX path of bPhoto & "'")
               if (MD5checkSum2 is MD5checkSum) then set end of forDeleteFlags to j
           end if
       end if
   end repeat
end repeat

-- delete duplicates
repeat with i from 1 to theCount
   if i is in forDeleteFlags then tell application "Finder" to delete (item i of thePhotos)
end repeat

on sortFilesOrPaths:listOfFilesOrPaths
   set theResults to NSMutableArray's array()
   repeat with aFile in listOfFilesOrPaths
       set theValues to (aFile's resourceValuesForKeys:{NSURLAddedToDirectoryDateKey} |error|:(missing value))
       set theValues to theValues's mutableCopy()
       (theValues's setObject:aFile forKey:"theURLKey")
       (theResults's addObject:theValues)
   end repeat
   set sortDesc to NSSortDescriptor's sortDescriptorWithKey:NSURLAddedToDirectoryDateKey ascending:true selector:"compare:"
   theResults's sortUsingDescriptors:{sortDesc}
   return theResults's valueForKey:"theURLKey"
end sortFilesOrPaths:

on makeASDateFrom:theNSDate
   set theCalendar to NSCalendar's currentCalendar()
   set comps to theCalendar's componentsInTimeZone:(missing value) fromDate:theNSDate
   tell (current date) to set {theASDate, year, day, its month, day, time} to ¬
       {it, comps's |year|(), 1, comps's |month|(), comps's |day|(), (comps's hour()) * hours + (comps's minute()) * minutes + (comps's |second|())}
   return theASDate
end makeASDateFrom:

on filesAndPackagesInURLArray:theURLs
   set itemURLs to NSMutableArray's array()
   repeat with aURL in theURLs -- is it a directory?
       set {theResult, theValue, theError} to (aURL's getResourceValue:(reference) forKey:NSURLIsDirectoryKey |error|:(reference))
       if theValue as boolean then -- is it a package?
           set {theResult, theValue, theError} to (aURL's getResourceValue:(reference) forKey:NSURLIsPackageKey |error|:(reference))
           if theValue as boolean then (itemURLs's addObject:aURL)
       else
           (itemURLs's addObject:aURL)
       end if
   end repeat
   return itemURLs
end filesAndPackagesInURLArray:


Model: MacBook Pro
OS X: Catalina 10.15.4
Web Browser: Safari 13.1
Ram: 4 GB

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)