Backup iMessage Photo’s using a Python Script

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:

#!/usr/bin/python
# Created Nov 2015 - Tony Sangha (tonysangha.com)

import os
import sys
import hashlib
import shutil
import exifread
from datetime import datetime
from random import randint

# Declare empty dictionary/lists for use later in the code
src_dict = {}  # Store all files in source
dst_dict = {}  # Store all files in destination
non_exif_filenames = []  # Store FileNames without DateTime EXIF TAG
# Path to iMessage directory, based upon User Log
path = "/Users/" + os.getlogin() + "/Library/Messages/Attachments/"


def md5(fname):
    """ return HASH value for file """
    hash = hashlib.md5()
    with open(fname, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash.update(chunk)
    return hash.hexdigest()


def imageType(rawname):
    """ Return the File Extension """
    return os.path.splitext(rawname)[1]


def renamePics(filename, rawName):
    """ If the file contains the EXIF tags for DateTime, use tag to
    rename picture, otherwise just return the original filename with a 
    random prefix to help in the event there are duplicate filenames but
    hash value differs """
    f = open(filename, 'rb')
    processed = exifread.process_file(f)
    stripped = str(processed.get('Image DateTime'))
    if processed.get('Image DateTime') is not None:
        dt = datetime.strptime(stripped, '%Y:%m:%d %H:%M:%S')
        return '{2:02}-{1}-{0}_{03}.{04}.{05}'.format(dt.day, dt.month,
                                                      dt.year, dt.hour,
                                                      dt.minute, dt.second) \
            + imageType(rawName)
    else:
        return str(randint(0, 999999)) + "-" + rawName


def populateDict(directory, diction):
    """ Method injests a directiory and creates a dictionary to represent
    the contents of the directory. The HASH value (unique) is used as the
    dictionary key and filename and path as values associated to the key """
    for root, dirs, files in os.walk(directory):
        for name in files:
            if str(name).endswith((".jpg", ".JPEG", ".JPG", ".PNG", ".png")):
                newName = renamePics(os.path.abspath(os.path.join
                                                     (directory, root, name)),
                                     name)
                diction[md5(os.path.abspath(os.path.join(directory, root, name)))] \
                    = name, \
                    os.path.abspath(os.path.join(directory, root, name)), \
                    newName
    return diction


def rename(oldName, newName, destination):
    """ Rename the files in the destination """
    return os.rename((destination) + "/" + str(oldName), (destination) + "/"
                     + str(newName))


def copyFiles(destination):
    """ Execute copy function of files """
    for x in range(len(src_dict)):
        if src_dict.keys()[x] in dst_dict:
            pass
        else:
            shutil.copy(src_dict.values()[x][1], destination)
            rename(
                src_dict.values()[x][0], src_dict.values()[x][2], destination)


def main(argv):
    populateDict(path, src_dict)
    populateDict(argv[1], dst_dict)
    copyFiles(argv[1])


if __name__ == "__main__":
    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

chmod 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:

sudo easy_install exifread
sudo pip install exifread

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

./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.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s