2 from degal.concurrent import task |
2 from degal.concurrent import task |
3 from degal import templates |
3 from degal import templates |
4 |
4 |
5 def render_image_html (ctx, image) : |
5 def render_image_html (ctx, image) : |
6 """ |
6 """ |
7 Render the thumbnails and .html for one image |
7 Render and write out the static .html file for the give image. |
8 """ |
8 """ |
9 |
9 |
10 ctx.log_debug("%s", image.html) |
10 ctx.log_debug("%s", image.html) |
11 |
11 |
12 # render output |
12 # render full-xhtml-document |
13 tpl = templates.master(ctx.gallery, image, |
13 tpl = templates.master(ctx.gallery, image, |
|
14 # with content |
14 templates.image_page(image) |
15 templates.image_page(image) |
15 ) |
16 ) |
16 |
17 |
17 # write output |
18 # write output |
18 tpl.render_file(image.html) |
19 tpl.render_file(image.html) |
19 |
20 |
20 def update_image_thumbs (image) : |
21 def update_image_thumbs (image) : |
21 """ |
22 """ |
22 Render the thubmnails for the given image, returning the image. |
23 Update/render and write out the thumbnails (thumb+preview) for the given image, returning the image object |
|
24 itself. |
23 |
25 |
24 This /should/ be threadsafe. |
26 This /should/ be threadsafe. XXX: but it probably isn't entirely. |
25 """ |
27 """ |
26 |
28 |
27 # this will unconditionally update the image |
29 # this will unconditionally update the image |
28 image.update() |
30 image.update() |
29 |
31 |
30 return image |
32 return image |
31 |
33 |
32 def render_folder_images (ctx, images, for_update=True) : |
34 def render_folder_images (ctx, images) : |
33 """ |
35 """ |
34 Render the given series of images |
36 Render the given series of images (html+thumbnails) as required based on the settings. |
|
37 |
|
38 This is capable of rendering the given set of images in parallel. |
35 """ |
39 """ |
36 |
40 |
37 # XXX: handle this thumb-update/html-update stuff better |
41 # first, update HTML |
38 |
|
39 # render all HTML |
|
40 for image in images : |
42 for image in images : |
41 render_image_html(ctx, image) |
43 if ctx.config.force_html or image.stale() : |
42 |
44 render_image_html(ctx, image) |
43 |
45 |
44 # render the thumbnails concurrently |
46 # define the render-tasks |
45 for image in ctx.concurrent.execute( |
47 tasks = (task(update_image_thumbs, image) for image in images if ctx.config.force_thumb or image.stale()) |
46 task(update_image_thumbs, image) |
48 |
47 |
49 # render the thumbnails themselves concurrently, returning the rendered Image objects |
48 for image in images |
50 for image in ctx.concurrent.execute(tasks) : |
49 |
|
50 # only test if not already filtered for update |
|
51 # XXX: externalize logic |
|
52 if for_update or ctx.config.force_thumb or image.stale() |
|
53 ) : |
|
54 # log image path |
51 # log image path |
55 ctx.log_info("%s", image) |
52 ctx.log_info("%s", image) |
56 |
53 |
57 # release large objects that are not needed anymore |
54 # release large objects that are not needed anymore |
58 image.cleanup() |
55 image.cleanup() |
59 |
56 |
60 def render_folder_html (ctx, folder) : |
57 def render_folder_html (ctx, folder) : |
61 """ |
58 """ |
62 Render the .html output for one folder |
59 Render and write out the required static .html files for the given folder. |
|
60 |
|
61 This will paginate large numbers of images, handle Folders with only subfolders within as a single page, and as |
|
62 a bonus, will not render anything for (non-recursively) empty folders. |
63 """ |
63 """ |
64 |
64 |
65 # render each page separately |
65 # render each page separately |
66 for page in xrange(folder.page_count) : |
66 for page in xrange(folder.page_count) : |
67 # output .html page |
67 # output .html path |
68 html = folder.html_page(page) |
68 html = folder.html_page(page) |
69 |
69 |
70 ctx.log_debug("%s", html) |
70 ctx.log_debug("%s", html) |
71 |
71 |
72 # render template |
72 # render full-html template |
73 tpl = templates.master(ctx.gallery, folder, |
73 tpl = templates.master(ctx.gallery, folder, |
|
74 # content |
74 templates.folder_page(folder, page) |
75 templates.folder_page(folder, page) |
75 ) |
76 ) |
76 |
77 |
77 # write output |
78 # write output |
78 tpl.render_file(html) |
79 tpl.render_file(html) |
79 |
80 |
80 def render_folder (ctx, folder) : |
81 def render_folder (ctx, folder) : |
81 """ |
82 """ |
82 Render the HTML/images for this folder if needed, and recrurse into subfolders. |
83 Recursively render a folder, with render_folder_images and render_folder. |
83 |
84 |
84 Returns True if any sub-images were found, False if this folder and all subfolders were completely empty and no |
85 This does a depth-first search of subfolders. |
85 HTML was generated. |
|
86 |
86 |
87 XXX: this logic is too complicated for one function. For one module? |
87 Updates the Images as needed (based on config.force_thumbs/config.force_html). |
|
88 |
|
89 Currently, this will always update the .html for non-empty Folders. |
88 """ |
90 """ |
89 |
91 |
90 # flag to track if we've rendered any contents. |
92 # do depth-first recursion |
91 empty = True |
93 for subfolder in folder.subfolders : |
|
94 render_folder(ctx, subfolder) |
|
95 |
|
96 if folder.empty : |
|
97 # warn |
|
98 ctx.log_debug("%s - empty, skipping", folder) |
|
99 |
|
100 return |
|
101 |
|
102 # force-update HTML, every time |
|
103 render_folder_html(ctx, folder) |
92 |
104 |
93 if ctx.config.force_html or ctx.config.force_thumb : |
105 # get the list of images that we are going to update, only those that are stale unless any force_update |
94 # index all |
106 update_images = list(folder.index_images(for_update=(not ctx.config.force_update))) |
95 for_update = False |
107 |
|
108 if update_images : |
|
109 # status |
|
110 ctx.log_info("%s - rendering %d/%d images", folder, len(update_images), len(folder.images)) |
96 |
111 |
|
112 # update images as needed |
|
113 render_folder_images(ctx, folder.images) |
|
114 |
97 else : |
115 else : |
98 # only new images |
116 # nothing to do |
99 for_update = True |
117 ctx.log_info("%s - up-to-date", folder) |
100 |
|
101 # full count of images |
|
102 image_count = len(folder.images) |
|
103 |
|
104 # index selected images |
|
105 new_images = list(folder.index_images(for_update=for_update)) |
|
106 |
|
107 # index subfolders |
|
108 for subfolder in folder.subfolders : |
|
109 if render_folder(ctx, subfolder) : |
|
110 # positive assertion |
|
111 empty = False |
|
112 |
|
113 if folder.images : |
|
114 empty = False |
|
115 |
|
116 # only render HTML if needed |
|
117 if not empty : |
|
118 # update folder index |
|
119 render_folder_html(ctx, folder) |
|
120 |
|
121 # only render new images if needed |
|
122 if new_images or ctx.config.force_html : |
|
123 ctx.log_info("%s - render %d/%d images", folder, len(new_images), image_count) |
|
124 |
|
125 # update images |
|
126 render_folder_images(ctx, new_images, for_update) |
|
127 |
|
128 else : |
|
129 ctx.log_info("%s - up to date", folder) |
|
130 |
|
131 # return flag |
|
132 return empty |
|
133 |
118 |
134 @command |
119 @command |
135 def main (ctx) : |
120 def main (ctx) : |
136 """ |
121 """ |
137 Scan the gallery for new folders/images, and render updated ones |
122 Scan the gallery for new folders/images, and render updated ones |
138 """ |
123 """ |
139 |
124 |
140 # render the gallery |
125 # render the gallery root as a folder |
141 render_folder(ctx, ctx.gallery) |
126 render_folder(ctx, ctx.gallery) |
142 |
127 |