Backup iMessage Photo’s using a Python Script

Share on:

I wrote this quick python script to backup my iMessage photo’s that I received, as I currently have to manually save individual photo’s to my camera roll or somewhere else on my MAC. Which tbh is pretty annoying, as I just want everything backed up into my photo’s directory.

After taking a look in Cyber Space for a quick and easy way, I just found heaps of programs that either required me shelling out a few bucks or just didn’t meet my simple requirements which were:

  • Run as a scheduled task
  • Backup all photo’s from iMessage directory to any destination I specify
  • Compare the source and destination files so only new/unique photo’s are copied
  • Rename all photo’s to date-time based on the EXIF tag in the photo

So as already mentioned, I created the following script to do what I needed:

 1#!/usr/bin/python
 2# Created Nov 2015 - Tony Sangha (tonysangha.com)
 3 
 4import os
 5import sys
 6import hashlib
 7import shutil
 8import exifread
 9from datetime import datetime
10from random import randint
11 
12# Declare empty dictionary/lists for use later in the code
13src_dict = {}  # Store all files in source
14dst_dict = {}  # Store all files in destination
15non_exif_filenames = []  # Store FileNames without DateTime EXIF TAG
16# Path to iMessage directory, based upon User Log
17path = "/Users/" + os.getlogin() + "/Library/Messages/Attachments/"
18 
19 
20def md5(fname):
21    """ return HASH value for file """
22    hash = hashlib.md5()
23    with open(fname, "rb") as f:
24        for chunk in iter(lambda: f.read(4096), b""):
25            hash.update(chunk)
26    return hash.hexdigest()
27 
28 
29def imageType(rawname):
30    """ Return the File Extension """
31    return os.path.splitext(rawname)[1]
32 
33 
34def renamePics(filename, rawName):
35    """ If the file contains the EXIF tags for DateTime, use tag to
36    rename picture, otherwise just return the original filename with a 
37    random prefix to help in the event there are duplicate filenames but
38    hash value differs """
39    f = open(filename, 'rb')
40    processed = exifread.process_file(f)
41    stripped = str(processed.get('Image DateTime'))
42    if processed.get('Image DateTime') is not None:
43        dt = datetime.strptime(stripped, '%Y:%m:%d %H:%M:%S')
44        return '{2:02}-{1}-{0}_{03}.{04}.{05}'.format(dt.day, dt.month,
45                                                      dt.year, dt.hour,
46                                                      dt.minute, dt.second) \
47            + imageType(rawName)
48    else:
49        return str(randint(0, 999999)) + "-" + rawName
50 
51 
52def populateDict(directory, diction):
53    """ Method injests a directiory and creates a dictionary to represent
54    the contents of the directory. The HASH value (unique) is used as the
55    dictionary key and filename and path as values associated to the key """
56    for root, dirs, files in os.walk(directory):
57        for name in files:
58            if str(name).endswith((".jpg", ".JPEG", ".JPG", ".PNG", ".png")):
59                newName = renamePics(os.path.abspath(os.path.join
60                                                     (directory, root, name)),
61                                     name)
62                diction[md5(os.path.abspath(os.path.join(directory, root, name)))] \
63                    = name, \
64                    os.path.abspath(os.path.join(directory, root, name)), \
65                    newName
66    return diction
67 
68 
69def rename(oldName, newName, destination):
70    """ Rename the files in the destination """
71    return os.rename((destination) + "/" + str(oldName), (destination) + "/"
72                     + str(newName))
73 
74 
75def copyFiles(destination):
76    """ Execute copy function of files """
77    for x in range(len(src_dict)):
78        if src_dict.keys()[x] in dst_dict:
79            pass
80        else:
81            shutil.copy(src_dict.values()[x][1], destination)
82            rename(
83                src_dict.values()[x][0], src_dict.values()[x][2], destination)
84 
85 
86def main(argv):
87    populateDict(path, src_dict)
88    populateDict(argv[1], dst_dict)
89    copyFiles(argv[1])
90 
91 
92if __name__ == "__main__":
93    main(sys.argv)

If you download the script (copy and paste into a file ending with .py) and save it in a directory of your choice, you will need to do change the execution parameters, which can be done from the terminal via

1chmod a+x iMessage.py

You will also need to install the Python module exifread, which can be done by executing either of the following two commands on the terminal:

1sudo easy_install exifread
2sudo pip install exifread

Once you have done that, you can run the script from the terminal by typing:

1./iMessage.py destinationDirectory

I actually have added this as a cronjob on my MAC so I never need to run it manually and know all my photo’s are safely backed up.