'How can I iterate across the photos on my connected iPhone from Windows 7 in Python?
When I connect my iPhone to my Windows 7 system, the Windows Explorer opens a Virtual Folder to the DCIM content. I can access the shell library interface via Pywin32 (218) as mentioned here: Can I use library abstractions in python?
Given a user-facing editing path (SIGDN_DESKTOPABSOLUTEEDITING) that works in the Windows Explorer, and launches the Windows Photo Viewer:
Computer\My iPhone\Internal Storage\DCIM\828RTETC\IMG_2343.JPG
How can I obtain a parsing path (SIGDN_DESKTOPABSOLUTEPARSING) for use with SHCreateItemFromParsingName() to create a ShellItem? (From which I'd bind a stream and copy to a local disk like this: Can images be read from an iPhone programatically using CreateFile in Windows? )
from win32com.shell import shell
edit_path = r'Computer\My iPhone\Internal Storage\DCIM\828RTETC\IMG_2343.JPG'
parse_path = # How to convert edit_path to a SIGDN_DESKTOPABSOLUTEPARSING path?
i = shell.SHCreateItemFromParsingName(parse_path, None, shell.IID_IShellItem)
The final goal will be to iterate the DCIM "folder" via something like the IShellFolder interface, and copy the most recent photos to the local disk. I don't want to have to open a FileOpenDialog for the parsing name. But before getting to that point, I thought creating a ShellItem for one of the files would be a good test.
Solution 1:[1]
Thanks for the above information, with it I was able to make a python implementation for moving photos from iPhone X to Windows10 PC. Key functions below
# imports probably needed
from win32com.shell import shell, shellcon
from win32com.propsys import propsys
import pythoncom
# Recursive function to browse into a non filesystem path
def recurse_and_get_ishellfolder(base_ishellfolder, path):
splitted_path = path.split("\\", 1)
for pidl in base_ishellfolder:
if base_ishellfolder.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL) == splitted_path[0]:
break
folder = base_ishellfolder.BindToObject(pidl, None, shell.IID_IShellFolder)
if len(splitted_path) > 1:
# More to recurse
return recurse_and_get_ishellfolder(folder, splitted_path[1])
else:
return folder
# How to move non filesystem file to filesystem patj
def move_file_by_pidl_to_path(src_ishellfolder, src_pidl, dst_path, dst_filename):
pidl_folder_dst, flags = shell.SHILCreateFromPath(dst_path, 0)
dst_ishellfolder = shell.SHGetDesktopFolder().BindToObject(pidl_folder_dst, None, shell.IID_IShellFolder)
fidl = shell.SHGetIDListFromObject(src_ishellfolder) # Grab the PIDL from the folder object
didl = shell.SHGetIDListFromObject(dst_ishellfolder) # Grab the PIDL from the folder object
si = shell.SHCreateShellItem(fidl, None, src_pidl) # Create a ShellItem of the source file
dst = shell.SHCreateItemFromIDList(didl)
pfo = pythoncom.CoCreateInstance(shell.CLSID_FileOperation, None, pythoncom.CLSCTX_ALL, shell.IID_IFileOperation)
pfo.SetOperationFlags(shellcon.FOF_NOCONFIRMATION | shellcon.FOF_SILENT | shellcon.FOF_NOERRORUI)
pfo.MoveItem(si, dst, dst_filename) # Schedule an operation to be performed
pfo.PerformOperations()
return not pfo.GetAnyOperationsAborted()
# Bonus: get file modification datetime for a non filesystem file
DATE_PROP_KEY = propsys.PSGetPropertyKeyFromName("System.DateModified")
DATE_PROP_PARSE_STR = '%Y/%m/%d:%H:%M:%S.%f' # not sure bout the f modifier but it does not really matter
def getmodified_datetime_by_pidl(src_ishellfolder, src_pidl):
fidl = shell.SHGetIDListFromObject(src_ishellfolder) # Grab the PIDL from the folder object
si = shell.SHCreateShellItem(fidl, None, src_pidl) # Create a ShellItem of the source file
ps = propsys.PSGetItemPropertyHandler(si)
date_str = ps.GetValue(DATE_PROP_KEY).ToString()
return datetime.strptime(date_str, DATE_PROP_PARSE_STR)
# Example photo moving main logic
def move_files():
main_folder = recurse_and_get_ishellfolder(shell.SHGetDesktopFolder(), "This Pc\\path\\to\\DCIM")
for photo_folder_pidl in main_folder:
folder_name = main_folder.GetDisplayNameOf(photo_folder_pidl, shellcon.SHGDN_NORMAL)
folder = main_folder.BindToObject(photo_folder_pidl, None, shell.IID_IShellFolder)
for pidl in folder:
child_name = folder.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL)
file_mod_date = getmodified_datetime_by_pidl(folder, pidl)
if not older_than_datetime or file_mod_date < older_than_datetime:
print("Transferring file: " + child_name)
move_file_by_pidl_to_path(...)
else:
print("Skipping too recent file: " + child_name)
Full script for moving photos: https://gitlab.com/lassi.niemisto/iphone-photo-dump
EDIT: Key parts from linked implementation copied here as code
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
