Sunday, April 6, 2014

python 3 code to rename files using kid's age

When I had a kid, I wanted to automatically rename all the pictures and videos with his age (in years, months, and days as '##Y##M##D_'), so I wrote a simple matlab script and posted it here. Since matlab is way overkill, I just converted it to python. I don't know a good python script posting site, so I'm just going to stick it here.

Here's what I came up with:
       

# rename_media_by_age()
# 
# automatically rename pictures and videos to start with age
# from specified date. Written for baby pictures.
# Example: Changes name from 'foo' to '##Y##M##D_foo'
# ie - 'foo.jpg' to '01Y03M10D_foo.jpg' if pic taken 1 year, 3 months, 10
# days after birth
# 
# I tried to keep it simple, so I just copy it into a folder with files I
# want to rename and then run it
# I put all video files in a subfolder called 'videos'
# change variable folder_videos below if you do something different
# 
# my files came from many different sources 
# (iPhone, android phone, multiple cameras, ipcamera)
# and they don't all have the same info, so here's what I came up with
#
# for *.jpg pictures:
# - try to read exif info 
# - if that doesn't work, I use FileModDate
#
# for videos:
# mp4 files from android phone
# -named as VID_YYYYMMDD_HHMMSS.mp4
# -I use picasa, which doesn't like mp4 files, so I rename as .mov
# -then just use the date from the original filename
# mov files from iphone & camera
# - use file modification date
#
# exif code stolen from here:
# http://code.activestate.com/recipes/578672-sort-images-from-different-sources-by-picture-take/
#
#
# v1 - Nathan Tomlin. Feb 12, 2012. nathan.a.tomlin@gmail.com
# v2 - Feb 28, 2012. Fixed error in .jpg renaming and added .wmv check
# v3 - Aug 11, 2013. Fixed error in age rename and added .mp4 check
# v4 - Apr 5, 2014. Convert from matlab to python, remove .3gp & .wmv code
#



import os
import glob
import re
from PIL import Image
from datetime import datetime
from math import floor

dtime0 = datetime(2010,1,1,8,23,00) # birthday - basis of file renames
 # format (YYYY,MM,DD,HH,MM,SS)

    
regexp_str = '\d\dY\d\dM\d\dD_' # this is the regexp used to match names
 # current looking for '##Y##M##D_*' where # = number

#folder_pics = os.getcwd()
folder_videos = 'videos' # just set as empty string ('') if videos in same directory as pictures
 # this defaults to look for 'videos' folder in start folder


def check_filename(filename):
        # check whether file already has correct name 
        imatch = re.search(regexp_str,filename)
        return imatch


def get_image_creation_datetime(filename):
### exif code stolen from here:
### http://code.activestate.com/recipes/578672-sort-images-from-different-sources-by-picture-take/
    try:
        img = Image.open(filename)
    except (Exception) as e:
        print('Image.open failed on',filename, "due to", e)
        #mtime = "?"
    else:
        # read exif data and set mtime to be earliest datatime found
        exif_data = img._getexif()
        mtime = "?"
        if 306 in exif_data and exif_data[306] < mtime: # 306 = DateTime
            mtime = exif_data[306]
        if 36867 in exif_data and exif_data[36867] < mtime: # 36867 = DateTimeOriginal
            mtime = exif_data[36867]
        if 36868 in exif_data and exif_data[36868] < mtime: # 36868 = DateTimeDigitized
            mtime = exif_data[36868]
            
        if mtime != "?":    # got a valid datetime from exif data
            dtime = datetime.strptime(mtime, "%Y:%m:%d %H:%M:%S")
        else:    # no exif data - use file modification time instead
            print(filename, "could not find exif creation time!")
            dtime = get_file_mod_datetime(filename)       
    return dtime

def get_file_mod_datetime(filename):
    #t = os.path.getctime(filename)
    #print(datetime.fromtimestamp(t))
    t = os.path.getmtime(filename)
    dtime = datetime.fromtimestamp(t)
    return dtime


def date2agestr(dtime):
    # convert from datetime to agestr ##Y##M##D_ format
    d = dtime - dtime0
    days = d.days
    Ydays = 365.25      # average days/year
    Mdays = Ydays/12    # average 30.4375 days/month...
    Y = floor(days/Ydays)
    M = floor((days - Y*Ydays)/Mdays)    
    D = round(days - Y*Ydays - M*Mdays)
    agestr = str(Y).zfill(2) + 'Y' + str(M).zfill(2) + 'M' + str(D).zfill(2) + 'D_'
    return agestr


def rename(name_old,agestr,ext=''):
    # rename file with new name: append agestr to old name
    # change file extension if input ext
    name_new = agestr + name_old
    name_base = name_new[:-4]
    if ext == '':
        name_ext = name_new[-4:]
    else:
        name_ext = ext
        name_new = name_base + name_ext
    # check whether name already exists
    if os.path.isfile(name_new):
        k=0
        while os.path.isfile(name_new):
            name_new = name_base + '_' + str(k) + name_ext
            k+=1
    try:
        os.rename(name_old,name_new)
        #print(name_old,name_new)
    except (Exception) as e:
        print('os.rename failed for',name_old,'to',name_new,'due to',e)
    return name_new


if __name__=="__main__":
    
    # jpg files
    ext = '.jpg'
    files = glob.glob('*'+ext)
    k = 0;
    for file in files:
        # check whether file already has correct name 
        imatch = check_filename(file)
        #filename = files[m]
        if imatch == None: # file did not match, need to fix name           
            dtime = get_image_creation_datetime(file)   # datetime from exif
            agestr = date2agestr(dtime) # generate age string ('##Y##M##D_')
            rename(file,agestr) # rename
            k+=1
    print('renamed',str(k),ext,'files')


    # change to video directory
    os.chdir(folder_videos)


    # .mov videos from iphone & camera in form MVI_####.mov or IMG_####.mov
    #   use file modification date for datetime
    ext = '.mov'
    files = glob.glob('*'+ext)
    k = 0;
    for file in files:
        # check whether file already has correct name 
        imatch = check_filename(file)
        if imatch == None: # file did not match, need to fix name           
            dtime = get_file_mod_datetime(file) # datetime from file mod
            agestr = date2agestr(dtime) # generate age string ('##Y##M##D_')
            filenew = rename(file,agestr)   # rename
            k+=1
    print('renamed',str(k),ext,'files')


    # .mp4 videos from android phone in form VID_yyyymmdd_HHMMSS
    #   just read name to get datetime
    # picasa seems to have problem with .mp4, so rename to .mov
    ext = '.mp4'
    ext2 = '.mov'
    files = glob.glob('*'+ext)
    k = 0;
    for file in files:
        # check whether file already has correct name 
        imatch = check_filename(file)
        if imatch == None: # file did not match, need to fix name           
            dtime = datetime.strptime(file, 'VID_%Y%m%d_%H%M%S'+ext) # datetime from filename
            agestr = date2agestr(dtime) # generate age string ('##Y##M##D_')
            filenew = rename(file,agestr,ext2)  # rename & change extension
            k+=1
    print('renamed',str(k),ext,'files to',ext2,'files')


    # change back to pics directory
    #os.chdir(folder_pics)


       
 

No comments:

Post a Comment