aboutsummaryrefslogtreecommitdiffstats
path: root/scanner/TreeWalker.py
blob: 4855d2021409ead20b054804cfe1e65d28eebf21 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import os
import os.path
import sys
from datetime import datetime
from PhotoAlbum import Photo, Album, PhotoAlbumEncoder
from CachePath import *
import json

class TreeWalker:
	def __init__(self, album_path, cache_path):
		self.album_path = os.path.abspath(album_path)
		self.cache_path = os.path.abspath(cache_path)
		set_cache_path_base(self.album_path)
		self.all_albums = list()
		self.all_photos = list()
		self.walk(self.album_path)
		self.big_lists()
		self.remove_stale()
		message("complete", "")
	def walk(self, path):
		next_level()
		message("walking", os.path.basename(path))
		cache = os.path.join(self.cache_path, json_cache(path))
		cached = False
		cached_album = None
		if os.path.exists(cache):
			try:
				cached_album = Album.from_cache(cache)
				if file_mtime(path) <= file_mtime(cache):
					message("full cache", os.path.basename(path))
					cached = True
					album = cached_album
					for photo in album.photos:
						self.all_photos.append(photo)
				else:
					message("partial cache", os.path.basename(path))
			except KeyboardInterrupt:
				raise
			except:
				message("corrupt cache", os.path.basename(path))
				cached_album = None
		if not cached:
			album = Album(path)
		for entry in os.listdir(path):
			if entry[0] == '.':
				continue
			try:
				entry = entry.decode(sys.getfilesystemencoding())
			except KeyboardInterrupt:
				raise
			except:
				pass
			entry = os.path.join(path, entry)
			if os.path.isdir(entry):
				album.add_album(self.walk(entry))
			elif not cached and os.path.isfile(entry):
				next_level()
				cache_hit = False
				if cached_album:
					cached_photo = cached_album.photo_from_path(entry)
					if cached_photo and file_mtime(entry) <= cached_photo.attributes["dateTimeFile"]:
						message("cache hit", os.path.basename(entry))
						cache_hit = True
						photo = cached_photo
				if not cache_hit:
					message("metainfo", os.path.basename(entry))
					photo = Photo(entry, self.cache_path)
				if photo.is_valid:
					self.all_photos.append(photo)
					album.add_photo(photo)
				else:
					message("unreadable", os.path.basename(entry))
				back_level()
		if not album.empty:
			message("caching", os.path.basename(path))
			album.cache(self.cache_path)
			self.all_albums.append(album)
		else:
			message("empty", os.path.basename(path))
		back_level()
		return album
	def big_lists(self):
		photo_list = []
		self.all_photos.sort()
		for photo in self.all_photos:
			photo_list.append(photo.path)
		message("caching", "all photos path list")
		fp = open(os.path.join(self.cache_path, "all_photos.json"), 'w')
		json.dump(photo_list, fp, cls=PhotoAlbumEncoder)
		fp.close()
		photo_list.reverse()
		message("caching", "latest photos path list")
		fp = open(os.path.join(self.cache_path, "latest_photos.json"), 'w')
		json.dump(photo_list[0:27], fp, cls=PhotoAlbumEncoder)
		fp.close()
		
	def remove_stale(self):
		message("cleanup", "building stale list")
		all_cache_entries = { "all_photos.json": True, "latest_photos.json": True }
		for album in self.all_albums:
			all_cache_entries[album.cache_path] = True
		for photo in self.all_photos:
			for entry in photo.image_caches:
				all_cache_entries[entry] = True
		message("cleanup", "searching for stale cache entries")
		for cache in os.listdir(self.cache_path):
			try:
				cache = cache.decode(sys.getfilesystemencoding())
			except KeyboardInterrupt:
				raise
			except:
				pass
			if cache not in all_cache_entries:
				message("cleanup", os.path.basename(cache))
				os.unlink(os.path.join(self.cache_path, cache))