Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with modifying pictures and only the 'modified' date gets changed instead of the 'made' date as well. #4

Open
Aqqly opened this issue Apr 9, 2022 · 6 comments

Comments

@Aqqly
Copy link

Aqqly commented Apr 9, 2022

Hi @holwech, thank you for WhatsApp Backup Fixer to begin with.

I understand how your script works and what it does, but I'm certain that there's something wrong with it. I did multiple reproduction steps. The issue is that the dates of WhatsApp images don't get changed properly, once I run the script it sets the 'modified' date of said image(s) to the current date (so, when the script ran). With WhatsApp videos it does change the 'modified' date to the one it retrieves from the filename, but it also doesn't change the 'made' date.

So, I would like to ask you if 1) you can fix that the date gets changed for the pictures, that seems totally broken right now and 2) if you can make it so that it modifies the 'made' date instead of only the 'modified' date. Most mobile phones, and please correct me if I'm wrong, will sort the pictures by 'made' date rather than 'modified'. At least my phone does and others that I know of. Due to this it'll still be messed up and take away the meaningfulness of this script.

I'm on Windows 11 by the way, I've also tried BATCHIFIER, it changes the dates of pictures too but also only the 'modified' date.

@dariustanrd
Copy link

dariustanrd commented Apr 12, 2022

@FrappuccinoCaramel I just faced the same problem.

You can replace the following:

original get_date function to:

def get_date(filename):
    date_str = filename.split('-')[1]
    date_datetime = datetime.strptime(date_str, '%Y%m%d')
    date_str = date_datetime.strftime("%Y:%m:%d %H:%M:%S")
    return date_str, date_datetime

original elif block to:

elif filename.endswith('jpg') or filename.endswith('jpeg'):
    date_str, date_datetime = get_date(filename)
    zeroth_ifd = {piexif.ImageIFD.DateTime: date_str} # ModifyDate (does not actually change, since this script itself modifies the image)
    exif_ifd = {piexif.ExifIFD.DateTimeOriginal: date_str, # date/time when original image was taken
                piexif.ExifIFD.DateTimeDigitized: date_str # CreateDate
                }
    exif_dict = {"0th":zeroth_ifd, "Exif":exif_ifd}
    exif_bytes = piexif.dump(exif_dict)
    piexif.insert(exif_bytes, file_path)
    # change modify date manually
    utime = time.mktime(date_datetime.timetuple())
    os.utime(file_path, (utime, utime))

@Aqqly
Copy link
Author

Aqqly commented Apr 14, 2022

Hi @dariustanrd, thank you so much for sharing your recommended solution!

I've edited the script and replaced that function and block with your code in the same indentation style. When I tried running it the following error came, unfortunately:

Traceback (most recent call last):
  File "D:\Users\-\Downloads\WhatsAppBackupFixer\test_images\fix_exif.py", line 35, in <module>
    date_str, date_datetime = get_date(filename)
ValueError: too many values to unpack (expected 2)

I'm not really into Python so I likely won't be able to fix it myself.

@dariustanrd
Copy link

@FrappuccinoCaramel here's the full script that worked for me!

I added more filetypes (audio, docs, stickers) as i realised WhatsApp's naming convention for them are similar too.

from datetime import datetime
import piexif
import re, os, time

folder = './'

def get_datetime(filename):
    date_str = filename.split('-')[1]
    date_datetime = datetime.strptime(date_str, '%Y%m%d')
    return date_datetime

def get_date(filename):
    date_str = filename.split('-')[1]
    date_datetime = datetime.strptime(date_str, '%Y%m%d')
    date_str = date_datetime.strftime("%Y:%m:%d %H:%M:%S")
    return date_str, date_datetime

fn_regex = re.compile(r'(IMG|VID|AUD|DOC|STK)-(\d{8})-WA.*\.(jpe?g|mp4|3gp|aac|m4a|opus|mp3|pdf|xlsx|webp)')

filenames = [fn for fn in os.listdir(folder) if re.match(fn_regex, fn)]

num_files = len(filenames)
print("Number of files: {}".format(num_files))

for i, filename in enumerate(filenames):
    file_path = os.path.join(folder,filename)
    if filename.endswith('mp4') or filename.endswith('3gp') or \
        filename.endswith('aac') or filename.endswith('m4a') or filename.endswith('opus') or filename.endswith('mp3') or \
        filename.endswith('pdf') or filename.endswith('xlsx') or \
        filename.endswith('webp'):
        date_datetime = get_datetime(filename)
        # change modify date
        modTime = time.mktime(date_datetime.timetuple())
        os.utime(file_path, (modTime, modTime))

    elif filename.endswith('jpg') or filename.endswith('jpeg'):
        date_str, date_datetime = get_date(filename)
        zeroth_ifd = {piexif.ImageIFD.DateTime: date_str} # ModifyDate (does not actually change, since this script modifies the file)
        exif_ifd = {piexif.ExifIFD.DateTimeOriginal: date_str, # date/time when original image was taken
                    piexif.ExifIFD.DateTimeDigitized: date_str # CreateDate
                    }
        exif_dict = {"0th":zeroth_ifd, "Exif":exif_ifd}
        exif_bytes = piexif.dump(exif_dict)
        piexif.insert(exif_bytes, file_path)
        # change modify date
        utime = time.mktime(date_datetime.timetuple())
        os.utime(file_path, (utime, utime))

    num_digits = len(str(num_files))
    print("{num:{width}}/{max} - {filename}"
            .format(num=i+1, width=num_digits, max=num_files, filename=folder+filename))
print('\nDone!')

@Aqqly
Copy link
Author

Aqqly commented Apr 21, 2022

@dariustanrd Thank you so much! I ran your edit of the code without any problems, it did just like you said it would. Great work. Maybe it would be nice to create a PR, because I feel like your changes are literally what the original code should've been.

@caweidmann
Copy link

For me the video part didn't work. Leaving this here in case others bump into this.

In order to get video dates fixed (Windows only solution) I did the following:

pip install win32-setctime

Then I modified the script to the following:

# right at the top of the file
from win32_setctime import setctime

and directly below the following code:

os.utime(folder + filename, (modTime, modTime))

add the following line:

setctime(folder + filename, modTime)

Then I ran the script, then I had to zip up the files, copy the zip to the phone and then extract the files (because copying them over just like that caused the "created" date to get changed).

@holwech
Copy link
Owner

holwech commented May 1, 2022

Very nice @dariustanrd! If you want, you can create a PR and I'll merge your changes and add a mention of your contribution in the readme.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants