Last active
March 13, 2021 05:30
-
-
Save barezina/a7d11d9c7a8b0ef8c435758406743347 to your computer and use it in GitHub Desktop.
ios backup extractor - restores an iTunes backup to it's original files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sqlite3 | |
import os | |
import uuid | |
import shutil | |
import re | |
print('ios backup python script for linux (ubuntu)') | |
# this function helps traverse the returned results from the db | |
def dict_factory(cursor, row): | |
d = {} | |
for idx, col in enumerate(cursor.description): | |
d[col[0]] = row[idx] | |
return d | |
# set this to the path of your itunes backup | |
backuppath = '/media/bob/Crucial M2 NVME 1TB/Users/bob/Apple/MobileSync/Backup/00008030-000C70E03688802E/' | |
extractedFilePath = '/media/bob/Crucial M2 SATA 1TB/' | |
# read the manifest file to figure out what to map the files/names to | |
conn = sqlite3.connect(backuppath + 'Manifest.db') | |
conn.row_factory = dict_factory | |
c = conn.cursor() | |
c.execute(""" | |
select substr(fileId, 0, 3) as folder, fileID, relativePath | |
from Files | |
""") | |
results = c.fetchall() | |
# make folders to categorise the files | |
if not os.path.isdir(extractedFilePath + '000_extracted_files/'): | |
os.makedirs(extractedFilePath + '000_extracted_files/') | |
if not os.path.isdir(extractedFilePath + '000_extracted_files/photos/'): | |
os.makedirs(extractedFilePath + '000_extracted_files/photos') | |
if not os.path.isdir(extractedFilePath + '000_extracted_files/videos/'): | |
os.makedirs(extractedFilePath + '000_extracted_files/videos') | |
if not os.path.isdir(extractedFilePath + '000_extracted_files/png/'): | |
os.makedirs(extractedFilePath + '000_extracted_files/png') | |
if not os.path.isdir(extractedFilePath + '000_extracted_files/databases/'): | |
os.makedirs(extractedFilePath + '000_extracted_files/databases') | |
if not os.path.isdir(extractedFilePath + '000_extracted_files/other/'): | |
os.makedirs(extractedFilePath + '000_extracted_files/other') | |
if not os.path.isdir(extractedFilePath + '000_extracted_files/raws/'): | |
os.makedirs(extractedFilePath + '000_extracted_files/raws') | |
# for every file in the database, map it's hashed name to its real name and | |
# copy to a folder that makes sense | |
for row in results: | |
# Get the information for this file out of the database row | |
folder = row['folder'] | |
fileID = row['fileID'] | |
relativePath = row['relativePath'] | |
# make the whole path lowercase (and shorter, and replace out spaces and problem characters) | |
relativePath = relativePath.lower() | |
relativePath = re.sub('[^a-z0-9./\-_]', '-', relativePath) | |
# split the path into segments (folder, filename, extension) | |
# add the first eight characters from the hash so we can refer back to the db later if need be. | |
fileName = relativePath.split('/').pop() | |
prefix = str(fileID)[:8] | |
pathElements = relativePath.split('/') | |
pathElements.pop() | |
pathOnly = '/'.join(pathElements) | |
fileNameElements = fileName.split('.') | |
fileNameOnly = fileNameElements.pop(0) | |
fileNameOnly = fileNameOnly[:26] | |
extension = '.'.join(fileNameElements) | |
if len(extension) < 1: | |
# if the file doesnt have an extension, just skip it | |
continue | |
newFolder = '' | |
# figure out which folder this file belongs in | |
if extension == 'jpg' or extension == 'jpeg' or extension == 'elif': | |
newFolder = 'photos/' | |
elif extension == 'cr2': | |
newFolder = 'raws/' | |
elif extension == 'png': | |
newFolder = 'png/' | |
elif extension == 'mp4' or extension == 'mov' or extension == 'avi': | |
newFolder = 'videos/' | |
elif extension == 'db' or extension == 'sqlite': | |
newFolder = 'databases/' | |
else: | |
newFolder = 'other/' | |
extension = '.' + extension | |
newExtension = extension | |
if newExtension == '.jpeg': | |
newExtension = '.jpg' | |
oldApplePath = backuppath + folder + '/' + fileID | |
newBackupPath = extractedFilePath + '000_extracted_files/' + newFolder + fileNameOnly + '_' + prefix + newExtension | |
if os.path.exists(oldApplePath): | |
# If the old file exists, copy it to the new destination with the proper name | |
print(oldApplePath + ' -> ' + newBackupPath) | |
shutil.copyfile(oldApplePath, newBackupPath) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment