modify structure of node tree in python (application cherrytree) - python

I take notes with cherrytree, an hierarchical note taking application written in python. A shortcut allows to insert date node, and the structure of date nodes in the tree is as follows:
├─ year
│ └─ month1
│ │ └─ day1
│ │ └─ day2
│ └─ month2
├─ year2
├─ a user node
I'd like to insert date nodes in a parent node named "journal" or whatever, as follows:
├─ journal
│ └─ year1
│ │ └─ month1
│ │ │ └─ day1
│ │ └─ month2
│ └─ year2
├─ a user node
The function node_date in core.py is:
def node_date(self, *args):
"""Insert Date Node in Tree"""
now_year = time.strftime("%Y").decode(locale.getlocale()[1])
now_month =time.strftime("%B").decode(locale.getlocale()[1])
now_day = time.strftime("%A %d %B %Y").decode(locale.getlocale()[1])
#print now_year, now_month, now_day
if self.curr_tree_iter:
curr_depth = self.treestore.iter_depth(self.curr_tree_iter)
if curr_depth == 0:
if self.treestore[self.curr_tree_iter][1] == now_year:
self.node_child_exist_or_create(self.curr_tree_iter, now_month)
self.node_date()
return
else:
if self.treestore[self.curr_tree_iter][1] == now_month\
and self.treestore[self.treestore.iter_parent(self.curr_tree_iter)][1] == now_year:
self.node_child_exist_or_create(self.curr_tree_iter, now_day)
return
if self.treestore[self.curr_tree_iter][1] == now_year:
self.node_child_exist_or_create(self.curr_tree_iter, now_month)
self.node_date()
return
self.node_child_exist_or_create(None, now_year)
self.node_date()
Could someone help me to adapt it? I'm not a developer (my skills in python stop at modifying now_day date format in the way I prefer...), and I'd like to separate notes and journal nodes, without having to move manually the date node automatically created by shortcut. Thank you for your help.

I got help on a project repo issue. My node_date method is now:
def node_date(self, *args):
"""Insert Date Node in Tree"""
top_node = "journal"
now_year = time.strftime("%Y").decode(locale.getlocale()[1])
now_month =time.strftime("%Y-%B").decode(locale.getlocale()[1])
now_day = time.strftime("%A %d %B %Y").decode(locale.getlocale()[1])
#print now_year, now_month, now_day
self.node_child_exist_or_create(None, top_node)
self.node_child_exist_or_create(self.curr_tree_iter, now_year)
self.node_child_exist_or_create(self.curr_tree_iter, now_month)
self.node_child_exist_or_create(self.curr_tree_iter, now_day)
As I said to the contributor, I don't understand why all thoses if/else in the project code while his solution is so simple, but for now it seems to work in the way I wanted.

Related

Print on the same line

A little backstory: I'm making a multitool for a bigger program but ran into an issue that I really can't get my head around. It's just print statements that are used for showing the user all the avalible options. I apologise if there's any wrong grammar or if I've misspelled some words, if something is unreadable feel free to let me know and I can explain what I meant.
Problem: I want them to get printed on the same row under the credline_mid. Pic 1 = How it prints it Pic 2 = a recreation made in paint that shows how I want to have it. Any help that could be given would be much appreciated.
[Pic 1]
[Pic 2]
Code:
def logo_mid():
print(Fore.MAGENTA + r"""____/\\\_______/\\\_____________________________/\\\\\\\\\\\\\\\_________________________________/\\\\\\______
___\///\\\___/\\\/_____________________________\///////\\\/////_________________________________\////\\\______
_____\///\\\\\\/_____________________________________\/\\\_________________________________________\/\\\______
_______\//\\\\___________________/\\\\\\\\\\\________\/\\\____________/\\\\\_________/\\\\\________\/\\\______
________\/\\\\__________________\///////////_________\/\\\__________/\\\///\\\_____/\\\///\\\______\/\\\______
________/\\\\\\______________________________________\/\\\_________/\\\__\//\\\___/\\\__\//\\\_____\/\\\______
______/\\\////\\\____________________________________\/\\\________\//\\\__/\\\___\//\\\__/\\\______\/\\\______
____/\\\/___\///\\\__________________________________\/\\\_________\///\\\\\/_____\///\\\\\/_____/\\\\\\\\\___
___\///_______\///___________________________________\///____________\/////_________\/////______\/////////____""")
def credline_mid():
print("""
_____________________________________________Made by [EN/SWE] PewPew#4450______________________________________________""")
def fav_options():
print("""
╔═══════════════╗
║ Favorites ║
╠══╦════════════╣
│1 │Inject │
│2 │Reinstall │
│3 │Quit X-Tool │
└──┴────────────┘""", end='')
def installer_options():
print("""
╔══════════════════╗
║ File installer ║
╠══╦═══════════════╣
│4 │Visuals │
│5 │Translations │
│6 │ASI plugins │
│7 │LUA scripts │
│8 │UI configs │
│9 │XML maps │
│10│Vehicles │
│11│Outfits │
│12│Headers │
└──┴───────────────┘""", end='')
def delete_options():
print("""
╔══════════════════╗
║ Delete Options ║
╠══╦═══════════════╣
│13│Translations │
│14│Hotkeys │
│15│Saved options │
│16│Headers │
│17│ASI Files │
│18│LUA Scripts │
│19│Reinstall │
└──┴───────────────┘""", end='')
def social_options():
print("""
╔══════════════════╗
║ Social Links ║
╠══════════════════╣
│ X-Force Socials │
├──┬───────────────┤
│20│Youtube Channel│
│21│Discord Server │
│22│Dashboard │
│23│Forum │
├──┴───────────────┤
│ My Own Socials │
├──┬───────────────┤
│24│Shop │
│25│Youtube Channel│
│26│Discord Server │
└──┴───────────────┘""", end='')
def misc_options():
print("""
╔══════════════════╗
║ Misc ║
╠══╦═══════════════╣
│27│X-Tool Tutorial│
│28│Credits │
│29│X-Tool Support │
│30│Update checker │
│31│Changelog │
│32│Dev-Mode │
│33│Quit X-Tool │
│34│Inject │
└──┴───────────────┘""", end='')
def settings_options():
print("""
╔════════════════════╗
║ Settings ║
╠══╦═════════════════╣
│35│UI-Editor │
│36│Sound Editor │
│37│Favorites Editor │
│38│Reset X-Tool │
│39│Hotkeys │
└──┴─────────────────┘""", end='')
logo_mid()
credline_mid()
fav_options()
installer_options()
delete_options()
social_options()
misc_options()
settings_options()
I've tried putting end='' on the end of the print statement but didnt work.
Then I looked for some stack overflow threads that fit my problem, unfortunately I didn't find anything.
Lastly I tried using our beloved friend chatgpt but unfortunately no help there.
First, seprate menus into just strings
fav_options = """╔═══════════════╗
║ Favorites ║
╠══╦════════════╣
│1 │Inject │
│2 │Reinstall │
│3 │Quit X-Tool │
└──┴────────────┘""";
installer_options = """╔══════════════════╗
║ File installer ║
╠══╦═══════════════╣
│4 │Visuals │
│5 │Translations │
│6 │ASI plugins │
│7 │LUA scripts │
│8 │UI configs │
│9 │XML maps │
│10│Vehicles │
│11│Outfits │
│12│Headers │
└──┴───────────────┘""";
Then make a list of them , and place them in a 2D array
menus = [fav_options, installer_options]
full_menu = [m.splitlines() for m in menus]
And iterate each line, replacing None (returned from zip_longest when the zip is out of range) with the width of the column.
from itertools import zip_longest
for row in zip_longest(*full_menu):
line = []
for i, menu in enumerate(row):
if menu == None:
line.append(' ' * len(full_menu[i][0])) # get width of menu header
else:
line.append(menu)
print(' '.join(line))
Example output
╔═══════════════╗ ╔══════════════════╗
║ Favorites ║ ║ File installer ║
╠══╦════════════╣ ╠══╦═══════════════╣
│1 │Inject │ │4 │Visuals │
│2 │Reinstall │ │5 │Translations │
│3 │Quit X-Tool │ │6 │ASI plugins │
└──┴────────────┘ │7 │LUA scripts │
│8 │UI configs │
│9 │XML maps │
│10│Vehicles │
│11│Outfits │
│12│Headers │
└──┴───────────────┘
the "multitool" is controlled either thrue voice controll, inputing a number
You could run an REST API, or other RPC server and still send requests to that via voice... You ideally would not use input() for that.

Build a tree from a list of objects

I am trying to build a tree from a list of objects, which are characterised by several properties.
Each object can have 3 properties that play a role in building a tree, that is velocity altitude exposure.
#Data structure
class Test():
pass
tests = []
for el in data:
test = Test()
test.velocity = el[0] #100km/h or 120km/h or 140km/h
test.altitude = el[1] #20m or 40m or 60m
test.exposure = el[2] #10uSv or 20uSv or 30uSv
#more data is assigned which is not shown as irrelevant
tests.append(test)
# I am trying to build a data tree like the one below.
# Obviously it would be different than this one and depend on actual data input.
# Example built statically using anytree
Tests
├── 100km/h
│ ├── 20m
│ │ └── 10uSv
│ ├── 40m
│ │ └── 10uSv
│ └── 60m
│ └── 20uSv
├── 120km/h
│ ├── 40m
│ │ ├── 20uSv
│ │ └── 30uSv
│ └── 60m
│ ├── 20uSv
│ └── 30uSv
└── 140km/h
└── 20m
└── 30uSv
Although this problem looks simple (might not be) I just can not figure it out.
Cheers!
You dont provide original data, so I tried to guess them.
I started with constructing nested dicts and then converting them to anytree format with recursive function.
Here is the code:
import itertools
import anytree
data = [
['100km/h', '20m', '10uSv'],
['100km/h', '40m', '10uSv'],
['100km/h', '60m', '20uSv'],
['120km/h', '40m', '20uSv'],
['120km/h', '40m', '30uSv'],
['120km/h', '60m', '20uSv'],
['120km/h', '60m', '30uSv'],
['140km/h', '20m', '30uSv'],
]
# Construct nested dicts
res = {'Tests': {}}
for a, b, c in data:
res['Tests'].setdefault(a, {}).setdefault(b, {}).setdefault(c, True)
__import__('pprint').pprint(res)
# {'Tests': {'100km/h': {'20m': {'10uSv': True},
# '40m': {'10uSv': True},
# '60m': {'20uSv': True}},
# '120km/h': {'40m': {'20uSv': True, '30uSv': True},
# '60m': {'20uSv': True, '30uSv': True}},
# '140km/h': {'20m': {'30uSv': True}}}}
# Convert nested dicts to anytree format
def dict_to_tree(d, parent=None):
if isinstance(d, bool):
return
for key in d:
node = anytree.Node(key, parent)
dict_to_tree(d[key], node)
root = anytree.Node('Tests')
dict_to_tree(res['Tests'], root)
for pre, fill, node in anytree.RenderTree(root):
print(f'{pre}{node.name}')
# Tests
# ├── 100km/h
# │ ├── 20m
# │ │ └── 10uSv
# │ ├── 40m
# │ │ └── 10uSv
# │ └── 60m
# │ └── 20uSv
# ├── 120km/h
# │ ├── 40m
# │ │ ├── 20uSv
# │ │ └── 30uSv
# │ └── 60m
# │ ├── 20uSv
# │ └── 30uSv
# └── 140km/h
# └── 20m
# └── 30uSv

Automatically save files in a particular folder using python

I have a pandas dataframe df that looks like this:
user date lat lon
Peter 2019-03-04 37.749798 -122.492301
Peter 2019-03-04 37.751028 -122.492291
Peter 2019-03-04 37.751698 -122.491701
Peter 2019-03-04 37.751800 -122.489748
David 2019-03-04 38.122893 -122.242051
David 2019-03-04 38.124108 -122.239079
David 2019-03-04 38.127434 -122.238672
Emma 2019-03-04 37.893635 -122.076538
Joyce 2019-03-04 37.536206 -121.997080
Joyce 2019-03-04 37.538044 -121.993153
Joyce 2019-03-04 37.540443 -121.991415
Using the loop below I am able to create four separate .html files that are named after the users in the user column (Peter.html, David.html, Emma.html, Joyce.html) and show the coordinates per user on a Folium map.
def create_user_map(user):
#create the map
return map
for user in users:
user_map = create_user_map(user)
user_file = f"{user}.html"
user_map.save(user_file)
Now I would like to automatically store these files in the folder structure below using python. How can I extend the loop above to achieve this?
Report/
├── Reports per date/
│ ├── 2019-03-01/
│ ├── 2019-03-02/
│ ├── 2019-03-03/
│ └── 2019-03-04/
│ └── Users/
│ └── Peter/
│ └── Peter.html
│ └── David/
│ └── David.html
│ └── Emma/
│ └── Emma.html
│ └── Joyce/
│ └── Joyce.html
│
└── Reports per month/
First, you've got to make the directories, you can automate this as follows:
import os
directories = ["Reports", "Reports/Reports per date"]
for directory in required_directories: # check if the directory exists
if not os.path.isdir(directory):
os.mkdir(directory) # create the directory
You would also need to do the same thing for the date:
from datetime import datetime
date = datetime.today().strftime("%Y-%m-%d") # just an example for date
if not os.path.isdir(f"Reports/Reports per date/{date}"):
os.mkdir(directory) # create the directory
'''
Then for each user, you need to create the directory, then save the file:
'''
for user in users:
user_map = create_user_map(user)
if not os.path.isdir(f"Reports/Reports per date/{date}/{user}"):
os.mkdir(directory) # create the directory
user_file = f"Reports/Reports per date/{date}/{user}/{user}.html"
user_map.save(user_file)
Putting everything together:
import os
from datetime import datetime
def create_user_map(user):
#create the map
return map
# initialize directories
directories = ["Reports", "Reports/Reports per date"]
for directory in required_directories:
if not os.path.isdir(directory):
os.mkdir(directory)
# initialize date directory
date = datetime.today().strftime("%Y-%m-%d")
if not os.path.isdir(f"Reports/Reports per date/{date}"):
os.mkdir(directory)
# for each user create the map then save html file
for user in users:
user_map = create_user_map(user)
if not os.path.isdir(f"Reports/Reports per date/{date}/{user}"):
os.mkdir(directory)
user_file = f"Reports/Reports per date/{date}/{user}/{user}.html"
user_map.save(user_file)
I assume that at some point you've pulled the date for each entry, likely when you're creating the map, so lets call that variable 'user_date'
import os
for user in users:
user_map = create_user_map(user)
if os.direxists('./%/'%(user_date)):
user_file = f"./%s/{user}.html"%(user_date)
else:
os.mkdir('./%/'%(user_date))
user_file = f"./%s/{user}.html"%(user_date)
user_map.save(user_file)
This should create the directory for each date (if it does not already exist), set the user_file, and then save it.

importlib.reload() not realoading

I am trying to create a leetcode like online judge. I need to reload the submission module but import.reload() does not work.
The code:
class Test:
current_exercise = None
current_name = None
def _import(self, exercise):
exercise = 'exercise' # for testing
if exercise == self.current_name:
module = sys.modules[f'puzzles.{exercise}']
self.current_exercise = importlib.reload(module) # <---- not working
else:
self.current_name = exercise
self.current_exercise = __import__(f'puzzles.{exercise}').exercise
def _test(self, exercise):
solution = self._import(exercise)
print(self.current_exercise.main())
if __name__=='__main__':
import shutil
t= Test()
# first run
t._test('exercise')
# copy another solution.py for reload test
shutil.copy(f"./puzzles/other_exercise/solution.py", f"./puzzles/exercise/solution.py")
# second run
t._test('exercise')
My directory;
.
├── codetest.py
├── puzzles
│   ├── __init__.py
│   ├── exercise
│   │   ├── __init__.py
│   │   ├── solution.py
│ ├── other_exercise
│ │ ├── __init__.py
│ │ ├── solution.py
exercise/solution.py:
def main():
print('EXERCISE')
exercise/init.py
from .solution import main
from .test import cases
other_exercise/solution.py:
def main():
print('OTHER EXERCISE')
Output:
> EXERCISE
> EXERCISE # <--- not sucessfull, should be 'OTHER EXERCISE'
This works:
import sys
import time
import importlib
class Test:
current_exercise = None
current_name = None
def _import(self, exercise):
if exercise == self.current_name:
self.current_exercise.solution = importlib.reload(self.current_exercise.solution)
else:
self.current_name = exercise
self.current_exercise = importlib.import_module(f'puzzles.{exercise}')
print('mod',self.current_exercise)
print('nam',self.current_exercise.__name__)
print('fil',self.current_exercise.__file__)
print('pkg',self.current_exercise.__package__)
def _test(self, exercise):
solution = self._import(exercise)
print(self.current_exercise.solution.main())
if __name__=='__main__':
import shutil
shutil.copy(f"./puzzles/exercise/solution.0", f"./puzzles/exercise/solution.py")
t= Test()
# first run
t._test('exercise')
# copy another solution.py for reload test
shutil.copy("./puzzles/other_exercise/solution.py", "./puzzles/exercise/solution.py")
print(open("./puzzles/exercise/solution.py").read())
# second run
t._test('exercise')
I went with an alternative; load solution.py as a text and create a module from that string. The module is not registered in sys.modules and can be overwritten. However imp is deprecated.
import imp
class Test:
current_exercise = None
def _import(self, exercise):
# load module code
with open(f'./puzzles/{exercise}/solution.py') as f:
code = f.read()
# register/create the module
self.current_exercise = imp.new_module('mymodule')
# import/fill the module
exec(code, self.current_exercise.__dict__)
def _test(self, exercise):
self._import(exercise)
print(self.current_exercise.main())

Copy images with EXIF(time) to new destination from several directories

I have a problem, below is my root tree:
In my root I have that:
---dir1---sub1(images exif time 10:05:05 to 10:09:55)
---sub2(images exif time 10:11:15 to 10:15:42)
---sub3(images exif time 10:22:15 to 10:24:41)
---sub4(images exif time 10:28:15 to 10:35:40)
---dir2---sub1(images exif time 10:05:06 to 10:09:57)
---sub2(images exif time 10:11:15 to 10:15:40)
---sub3(images exif time 10:22:15 to 10:24:43)
---sub4(images exif time 10:28:15 to 10:35:40)
---sub5(images exif time 10:40:15 to 10:43:40)
---dir3---sub1(images exif time 10:05:05 to 10:09:54)
---sub2(images exif time 10:11:15 to 10:15:40)
---sub3(images exif time 10:22:15 to 10:24:41)
---sub4(images exif time 10:28:15 to 10:35:40)
---sub5(images exif time 10:40:15 to 10:43:42)
---dir4---sub1(images exif time 10:05:06 to 10:09:57)
---sub2(images exif time 10:11:15 to 10:15:40)
---sub3(images exif time 10:22:15 to 10:24:43)
---sub4(images exif time 10:28:15 to 10:35:40)
---sub5(images exif time 10:40:15 to 10:43:40)
---dir5---sub1(images exif time 10:05:05 to 10:09:54)
---sub2(images exif time 10:11:15 to 10:15:40)
---sub3(images exif time 10:22:15 to 10:24:41)
---sub4(images exif time 10:28:15 to 10:35:40)
---sub5(images exif time 10:40:15 to 10:43:42)
I have 5 dirs in my root and each contains sub-folders(with images) number of sub-folders it's not a same all the time, What I want to do is from first - dir1 get sub1 and put it to new destination folder after go to next dir (dir2) scan sub-folders to check exif(time) if its a same as sub1 from dir1 and copy it to same directory after go to next dir3 and do same for all others dir-s and subfolders, and after create newdir2 go and take sub2 from dir1 and do again same loop till end...
something like:
---newdir1---sub1(from dir1)
---sub1(from dir2)
---sub1(from dir3)
---sub1(from dir4)
---sub1(from dir5)
---newdir2---sub2(from dir1)
---sub2(from dir2)
---sub2(from dir3)
---sub2(from dir4)
---sub2(from dir5)
---newdir3---sub3(from dir1)
---sub3(from dir2)
---sub3(from dir3)
---sub3(from dir4)
---sub3(from dir5)
---newdir4---sub4(from dir1)
---sub4(from dir2)
---sub4(from dir3)
---sub4(from dir4)
---sub4(from dir5)
---newdir5---sub5(from dir2)
---sub5(from dir3)
---sub5(from dir4)
---sub5(from dir5)
I have a part of script with sort my images to dictionary by some time interval, how I can join it to my script?? to get my sub-s with same key to same dir ??:
import os
import exifread
from datetime import datetime, timedelta
TIME_RANGE = 2
src_root = 'F:\gopro_egouts\gopro_img_test\\2018-03-06'
dst_root = src_root + '-copie'
src_dirs_dict = {}
for cam_dir in os.listdir(src_root):
laps_root = os.path.join(src_root, cam_dir)
for lap_dir in os.listdir(laps_root):
files_root = os.path.join(laps_root, lap_dir)
min_time = None
max_time = None
for cam_file in os.listdir(files_root):
with open(os.path.join(files_root, cam_file), 'rb') as f:
tags = exifread.process_file(f, details=False, stop_tag="EXIF DateTimeOriginal")
time_taken = tags.get("EXIF DateTimeOriginal")
if time_taken:
file_time = datetime.strptime(str(time_taken), '%Y:%m:%d %H:%M:%S')
if min_time is not None:
if file_time < min_time:
min_time = file_time
else:
min_time = file_time
if max_time is not None:
if file_time > max_time:
max_time = file_time
else:
max_time = file_time
is_key = None
for key in src_dirs_dict.keys():
if (min_time >= key[0] and min_time < key[1]) \
or (max_time >= key[0] and max_time < key[1]):
is_key = key
break
min_time = min_time.replace(second=0)
max_time = min_time + timedelta(minutes=TIME_RANGE)
if is_key:
key_min, key_max = is_key
if min_time < key_min:
key_min = min_time
if max_time > key_max:
key_max = max_time
new_key = (key_min, key_max)
if new_key == is_key:
src_dirs_dict[new_key].append(files_root)
else:
src_dirs_dict[new_key] = src_dirs_dict.pop(is_key) + [files_root]
else:
new_key = (min_time, max_time)
src_dirs_dict[new_key] = [files_root]
print(src_dirs_dict)
My print showing me that:
{(datetime.datetime(2018, 3, 6, 10, 31), datetime.datetime(2018, 3, 6, 10, 32)): ['F:\\gopro_egouts\\gopro_img_test\\2018-03-06\\CAM0101 1\\Time Lapse 3',...
I have a working script with working well but taking a sub-folders one by one , and when some Time-lapse is missing, there I have a problem, his mixing my sub-s(automatically taking next one from next dir with wrong time), where I have to add my exif script from above to here(how modify it)... how to join it together???
Any help will be appreciated.
from collections import defaultdict
import shutil
import os
import re
src_root = r'F:\gp\gp_test\\2018-03-06'
dst_root = src_root + '-copie'
#os.makedirs(dst_root, exist_ok=True)
src_dirname, src_folders, _ = next(os.walk(src_root))
src_folders = sorted(src_folders)
src_folders = [os.path.join(src_root, folder) for folder in src_folders]
print(src_folders)
job = defaultdict(list)
print('mes {} dossier cam'.format(len(src_folders)))
for folder in src_folders:
print()
dirname, src_sub_folders, _ = next(os.walk(os.path.join(src_dirname, folder)))
src_sub_folders = sorted(src_sub_folders, key=lambda x: [re.search(r'(\D+)', x).group(1)] + list(map(int, re.findall(r'\d+', x))))
print("mes 5 CAM avec {} time laps '{}'".format(len(src_sub_folders), folder))
for index, sub_folder in enumerate(src_sub_folders, start=1):
job['Time Lapse-{}'.format(index)].append(os.path.join(dirname, sub_folder))
#print()
for dst_folder, src_folders in sorted(job.items()):
for index, src_folder in enumerate(src_folders, start=1):
dst_new_folder = os.path.join(dst_root, dst_folder, 'CAM-{}'.format(index))
print('{} -> {}'.format(src_folder, dst_new_folder))
shutil.copytree(src_folder, dst_new_folder)
#shutil.rmtree(src_root)
for root, dirs, files in os.walk(dst_root):
for f in files:
prefix = os.path.basename(root)
prefix1 = os.path.basename(src_root)
os.rename(os.path.join(root, f), os.path.join(root, "{}-{}-{}".format(prefix1, prefix, f)))
print("images rennomer ")
print("fini")
print("dossier supprimé")
I'm really sorry if that will be not to clear for users, but English it's not my strongest language ...
In a nutshell, you have images of the same set of events shot on a number of cameras.
Currently, they are grouped first by camera, then by event:
├── Camera1
│   ├── Event1
│   ├── Event2
│   ├── Event3
│   ├── Event4
│   └── Event5
├── Camera2
│   ├── Event1
│   ├── Event2
│   ├── Event3
│   ├── Event4
│   └── Event5
├── Camera3
│   ├── Event1
│   ├── Event2
│   ├── Event3
│   ├── Event4
│   └── Event5
├── Camera4
│   ├── Event1
│   ├── Event2
│   ├── Event3
│   ├── Event4
│   └── Event5
└── Camera5
├── Event1
├── Event2
├── Event3
├── Event4
└── Event5
... where some events may be missing and the event numbering may not match because one or more events may not be recorded by all cameras.
And you want the same set of images grouped first by event, then by camera:
├── Event1
│   ├── Camera1
│   ├── Camera2
│   ├── Camera3
│   ├── Camera4
│   └── Camera5
├── Event2
│   ├── Camera1
│   ├── Camera2
│   ├── Camera3
│   ├── Camera4
│   └── Camera5
├── Event3
│   ├── Camera1
│   ├── Camera2
│   ├── Camera3
│   ├── Camera4
│   └── Camera5
├── Event4
│   ├── Camera1
│   ├── Camera2
│   ├── Camera3
│   ├── Camera4
│   └── Camera5
└── Event5
├── Camera1
├── Camera2
├── Camera3
├── Camera4
└── Camera5
Here's an idea... I am kind of "thinking aloud" in pseudo-code:
Create the output directories {Event1..EventN}/Camera{1..N}
MissingDirectory=false
for each input directory Camera{1..N}
if this directory has the full number of subdirectories
copy all subdirectories to output area
else
MissingDirectory=true
end if
end for
if MissingDirectory
for each output Event directory
get times of all files from all cameras for current event
sort list and take median time of current event
end for
for each un-copied input directory
get the mean time of all the files in it
assign this directory's files to output directory with nearest median time
end for
endif
You can convert your EXIF times to pure seconds since midnight (s) with:
s = (hours*3600) + (minutes*60) + seconds
Here's a way to get the time (in seconds since midnight) that an image was taken:
import exifread
def getImageTime(filename):
"Read EXIF data of given file and return time in seconds since midnight"
f=open(filename,'rb')
tags=exifread.process_file(f)
DateTime=tags["EXIF DateTimeOriginal"].printable
# DateTime looks like: "2013:03:09 08:59:50"
Time=DateTime.split()[-1]
# Time looks like: "08:59:50"
h,m,s=Time.split(":")
# Return seconds since midnight: 32390
return (int(h)*3600) + (int(m)*60) + int(s)
s=getImageTime("image.jpg")
print(s)
After some more thought, this won't work very well if one of the cameras is set, say, 20 minutes different from the others, since all its images from all the sequences will tend to get put into the first or last directory. Needs some more thought...

Categories