pixboards 0.2.25__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. pixboards-0.2.25/PKG-INFO +92 -0
  2. pixboards-0.2.25/pixBoards/__init__.py +25 -0
  3. pixboards-0.2.25/pixBoards/__main__.py +4 -0
  4. pixboards-0.2.25/pixBoards/arguments.py +66 -0
  5. pixboards-0.2.25/pixBoards/boardmakers.py +321 -0
  6. pixboards-0.2.25/pixBoards/classes.py +83 -0
  7. pixboards-0.2.25/pixBoards/cli.py +112 -0
  8. pixboards-0.2.25/pixBoards/config_loader.py +64 -0
  9. pixboards-0.2.25/pixBoards/create.py +265 -0
  10. pixboards-0.2.25/pixBoards/db.py +57 -0
  11. pixboards-0.2.25/pixBoards/filemaking.py +42 -0
  12. pixboards-0.2.25/pixBoards/git.py +84 -0
  13. pixboards-0.2.25/pixBoards/imgchest.py +303 -0
  14. pixboards-0.2.25/pixBoards/log_utils.py +29 -0
  15. pixboards-0.2.25/pixBoards/nest_boards.py +24 -0
  16. pixboards-0.2.25/pixBoards/templates/__init__.py +5 -0
  17. pixboards-0.2.25/pixBoards/templates/__init__.py.bak +5 -0
  18. pixboards-0.2.25/pixBoards/templates/configTemplate.yml +20 -0
  19. pixboards-0.2.25/pixBoards/templates/favicon.png +0 -0
  20. pixboards-0.2.25/pixBoards/templates/index_template.html +30 -0
  21. pixboards-0.2.25/pixBoards/templates/template.css +206 -0
  22. pixboards-0.2.25/pixBoards/templates/template.html +39 -0
  23. pixboards-0.2.25/pixBoards/templates/template.js +56 -0
  24. pixboards-0.2.25/pixBoards.egg-info/PKG-INFO +92 -0
  25. pixboards-0.2.25/pixBoards.egg-info/SOURCES.txt +37 -0
  26. pixboards-0.2.25/pixBoards.egg-info/dependency_links.txt +1 -0
  27. pixboards-0.2.25/pixBoards.egg-info/entry_points.txt +2 -0
  28. pixboards-0.2.25/pixBoards.egg-info/requires.txt +8 -0
  29. pixboards-0.2.25/pixBoards.egg-info/top_level.txt +1 -0
  30. pixboards-0.2.25/pyproject.toml +3 -0
  31. pixboards-0.2.25/setup.cfg +4 -0
  32. pixboards-0.2.25/setup.py +47 -0
@@ -0,0 +1,92 @@
1
+ Metadata-Version: 2.1
2
+ Name: pixboards
3
+ Version: 0.2.25
4
+ Description-Content-Type: text/markdown
5
+
6
+ # notice
7
+
8
+ repo finally changed to [https://github.com/flynnsharwood/pixBoards.git](https://github.com/flynnsharwood/pixBoards.git)
9
+
10
+ Gui has not been set up yet. Don't try to run the gui.py
11
+
12
+ title and heading use the board name now. favicon added, can be changed, check the templates folder.
13
+
14
+ ~~if you are using the PyPi package, you will need to have a running postgres server, else it won't work.~~ It works now.
15
+
16
+ # pixBoards
17
+
18
+ pixBoards is a python library to help you organise your images and videos into masonry-containers (the pinterest layout)
19
+
20
+ It outputs simple html files with links to the images. Simplicity was the aim here, so don't expect fancy stuff in it.
21
+
22
+ It organises the images into "boards" which can be nested inside other boards. (Just think of them as a folder for now)
23
+
24
+ You can also automatically upload the files to imgchest and use those links in the output html files. You can then simply host these output files and you will have a working webpage. (If you had to use local files, you'd have to host the images too, which would be a pain in) (use --upload for that)
25
+
26
+ you can also use lists of imagelinks to create boards.
27
+
28
+ I also recently added the ability to use links in sidecarfiles to use as upload links instead of uploading the image to imgchest. (if you used a bulk downloader like gallery-dl, you'd be able to easily create such sidecar files every time you download.)
29
+
30
+ ### screenshots
31
+
32
+ example of index file
33
+ ![https://cdn.imgchest.com/files/4apc5px5gv4.png](https://cdn.imgchest.com/files/4apc5px5gv4.png)
34
+
35
+ example of image board
36
+ ![https://cdn.imgchest.com/files/yrgcnjaxew4.png](https://cdn.imgchest.com/files/yrgcnjaxew4.png)
37
+
38
+ ## how to use
39
+
40
+ first, rename the config_example.yml to config.yml. or start afresh, your choice.
41
+
42
+ if you wish to upload to imgchest and use those links instead, use `--upload`
43
+
44
+ If it is the first time you are uploading, you will have to install postgresql first if not already installed.
45
+
46
+
47
+ ### install
48
+
49
+ you can install the pixBoards package from PyPi
50
+
51
+ `pip install pixBoards`
52
+
53
+ or clone the repo.
54
+
55
+ `git clone https://github.com/flynnsharwood/boards_v2.git`
56
+
57
+ ### First time upload
58
+ If it is the first time you are uploading, you will have to install postgresql first if not already installed.
59
+
60
+ Also, if you have a LOT of files to upload for the first time, go to the uploader folder. [repo link](https://github.com/flynnsharwood/imgUploader)
61
+
62
+ 1. set up the directories list in config.yml
63
+ 1. run listFiles.py. it will create a file named "MediaFiles.py"
64
+ 2. now run calc_hex.py
65
+ 3. run fileListUpload.py
66
+
67
+ fileListUpload basically uploads in batches of 20, unlike the original script where it uploads each image individually. This will upload and cache the links and hashes to postgress db
68
+
69
+ ### Usage
70
+ simply use the binary file provided `boards.exe`
71
+
72
+ Or do `python3 cli.py` or `python3 __main__.py`
73
+
74
+ flags you might use
75
+
76
+ `--upload` ensure all files are being uploaded. If you have pictures with the same filenames in different folders, you might need to fix this.
77
+
78
+ `--gitPush` this will push your created html files to a github repo. set up your repo to trigger a gh_pages deployment every push.
79
+
80
+ `--config` change the config file being used
81
+
82
+
83
+ here is a link to an example board - [https://flynnsharwood.github.io/exampleBoard/index.html](https://flynnsharwood.github.io/exampleBoard/index.html)
84
+
85
+ ---
86
+ ## features
87
+
88
+ added an button to load a random page in 0.2.18
89
+
90
+
91
+ ---
92
+
@@ -0,0 +1,25 @@
1
+ import os
2
+ import subprocess
3
+
4
+ # this gets the latest git commit hash. i will not be setting the version in the setup.py.
5
+ # def get_git_version():
6
+ # try:
7
+ # commit_hash = (
8
+ # subprocess.check_output(["git", "rev-parse", "--short", "HEAD"])
9
+ # .decode()
10
+ # .strip()
11
+ # )
12
+ # return commit_hash
13
+ # except Exception:
14
+ # return "untracked"
15
+
16
+
17
+ # __version__ = get_git_version()
18
+ __version__ = "0.2.25"
19
+
20
+ templates_folder_path = os.path.join(
21
+ os.path.dirname(os.path.abspath(__file__)), "templates"
22
+ )
23
+
24
+ with open(os.path.join(templates_folder_path, "configTemplate.yml"), "r") as f:
25
+ configTemplate = f.read()
@@ -0,0 +1,4 @@
1
+ from pixBoards.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,66 @@
1
+ import argparse
2
+
3
+ # Parse arguments
4
+ parser = argparse.ArgumentParser(description="Generate HTML for media directories.")
5
+ parser.add_argument(
6
+ "--random",
7
+ type=int,
8
+ help="number of images to sample from all boards. "
9
+ "use a number higher than the number of total images, or a negative number,"
10
+ " to shuffle instead",
11
+ )
12
+ parser.add_argument(
13
+ "--recent",
14
+ "--desc",
15
+ type=int,
16
+ help="sorts filename by decending and truncates to input count.",
17
+ )
18
+ parser.add_argument(
19
+ "--ranDir",
20
+ type=str,
21
+ help="Directory to search images in for --random",
22
+ )
23
+ parser.add_argument("--dir", type=str, help="Directory to use for the images")
24
+ # parser.add_argument("--csvs", nargs="+", help="List of CSV files to use")
25
+ parser.add_argument(
26
+ "--useLists", action="store_true", help="Use list files from config"
27
+ )
28
+ parser.add_argument("--imageLists", nargs="+", help="List of imagelist files to use.")
29
+ parser.add_argument("--col", type=int, help="Number of columns to default to")
30
+ parser.add_argument("--margin", type=int, help="Margin in px")
31
+
32
+ parser.add_argument(
33
+ "--sidecar", action="store_true", default=False, help="use links from sidecar files"
34
+ )
35
+ parser.add_argument(
36
+ "--includeLocal",
37
+ action="store_true",
38
+ default=False,
39
+ help="include local files if using lists",
40
+ )
41
+ parser.add_argument(
42
+ "--makeConfig",
43
+ action="store_true",
44
+ default=False,
45
+ help="include local files if using lists",
46
+ )
47
+
48
+ # parser.add_argument("--rancount", type=int, help="number of images to sample from all boards. use a number higher than the number of total images to shuffle instead")
49
+ parser.add_argument(
50
+ "--upload", action="store_true", default=False, help="Upload images to Imgchest"
51
+ )
52
+ parser.add_argument("--config", type=str, default=False, help="config file to use")
53
+ parser.add_argument(
54
+ "--saveBoards", action="store_true", help="Save generated boards to PostgreSQL"
55
+ )
56
+ parser.add_argument(
57
+ "--gitPush", action="store_true", help="Push outputDir to existing Git repo"
58
+ )
59
+ parser.add_argument("--useSaved", action="store_true", help="use only saved images")
60
+ parser.add_argument(
61
+ "--reddit",
62
+ action="store_true",
63
+ help="this is helpful for --desc when using reddit images. (the id in the front of filename is converted to int using base 36)",
64
+ )
65
+
66
+ args = parser.parse_args()
@@ -0,0 +1,321 @@
1
+ import os
2
+ import random
3
+ from pathlib import Path
4
+
5
+ import psycopg2
6
+
7
+ from pixBoards.arguments import args
8
+ from pixBoards.classes import board
9
+ from pixBoards.imgchest import append_sidecar_links, process_images
10
+
11
+ # append_sidecar_links not working properly rn. a future me problem.
12
+ from pixBoards.log_utils import setup_logger
13
+
14
+ from pixBoards.config_loader import config, outputDir
15
+
16
+
17
+ # import yaml
18
+
19
+
20
+ logger = setup_logger(__name__)
21
+
22
+
23
+ # from pixBoards.config_loader import config
24
+
25
+
26
+ def boardsForImglist(imgList_List, listDir, paginate):
27
+ # Now I might need to sanitise the ( image list )list
28
+ # so that there aren't instances with the same name.
29
+ # But as the imagelist files are in the same folder,
30
+ # they won't have the same name, so I leave this for the future me.
31
+ os.makedirs(listDir, exist_ok=True)
32
+
33
+ boards = []
34
+
35
+ for idx, imgListFile in enumerate(imgList_List):
36
+ boardName = os.path.splitext(os.path.basename(imgListFile))[0]
37
+ with open(imgListFile, "r", encoding="utf-8") as f:
38
+ images = [line.strip() for line in f if line.strip()]
39
+
40
+ outputFile = listDir
41
+ logger.info(f"output file = {outputFile}")
42
+
43
+ b = board(
44
+ name=boardName,
45
+ output_file_loc=outputFile,
46
+ image_paths=images,
47
+ paginate=paginate,
48
+ # images_per_page=config["page_size"] if paginate else 10000,
49
+ img_list_status=True,
50
+ )
51
+ b.paginate_board()
52
+ boards.append(b)
53
+
54
+ return boards
55
+
56
+
57
+ def standardBoards(directories, outputDir, paginate, upload):
58
+ boards = []
59
+ # outputDir = Path(outputDir)
60
+ # outputDir.mkdir(parents=True, exist_ok=True)
61
+
62
+ media_extensions = (
63
+ ".jpg",
64
+ ".jpeg",
65
+ ".png",
66
+ ".gif",
67
+ ".bmp",
68
+ ".webp",
69
+ # ".heic", # i will possibly add support to convert these to normal imgs
70
+ # before using them.
71
+ ".mp4",
72
+ ".avi",
73
+ ".webm",
74
+ ".mov",
75
+ )
76
+
77
+ for d in directories:
78
+ # normalize to a Path
79
+ src_dir = Path(d)
80
+
81
+ if not src_dir.exists():
82
+ logger.warning(f"Skipping non-existent directory: {src_dir}")
83
+ continue
84
+
85
+ for root, dirs, files in os.walk(src_dir):
86
+ image_paths = []
87
+
88
+ for fname in sorted(files):
89
+ if fname.lower().endswith(media_extensions):
90
+ abs_path = Path(root) / fname
91
+ image_paths.append(abs_path.resolve().as_uri())
92
+
93
+ logger.debug(f"Processing {root} with {len(image_paths)} images.")
94
+
95
+ rel = Path(root).relative_to(os.path.dirname(src_dir))
96
+
97
+ board_name = str(rel).replace(os.sep, "_~")
98
+ output_path = outputDir # everything writes into this one folder
99
+ # collect local files
100
+ local_files = [
101
+ Path(root) / f
102
+ for f in sorted(files)
103
+ if f.lower().endswith(media_extensions)
104
+ ]
105
+ if not local_files:
106
+ logger.debug(f"No media in {root}, creating empty board.")
107
+ b = board(
108
+ name=board_name,
109
+ output_file_loc=str(outputDir),
110
+ image_paths=[],
111
+ paginate=paginate,
112
+ upload=upload,
113
+ dummy_status=True,
114
+ )
115
+ else:
116
+ # create a Board object and paginate it
117
+ b = board(
118
+ name=board_name,
119
+ output_file_loc=str(output_path),
120
+ image_paths=image_paths,
121
+ paginate=paginate,
122
+ upload=upload,
123
+ dummy_status=False,
124
+ )
125
+
126
+ b.paginate_board()
127
+ boards.append(b)
128
+
129
+ logger.debug(f"Board created: {board_name} ({len(image_paths)} images)")
130
+
131
+ return boards
132
+
133
+
134
+ def uploadBoards(directories, outputDir, paginate, upload=True):
135
+ def connect_db():
136
+ return psycopg2.connect(
137
+ dbname=config["dbname"],
138
+ user=config["user"],
139
+ password=config["password"],
140
+ host=config["host"],
141
+ )
142
+
143
+ conn = connect_db()
144
+ boards = []
145
+ outputDir = Path(outputDir)
146
+ outputDir.mkdir(parents=True, exist_ok=True)
147
+
148
+ media_extensions = (
149
+ ".jpg",
150
+ ".jpeg",
151
+ ".png",
152
+ ".gif",
153
+ ".bmp",
154
+ ".webp",
155
+ ".mp4",
156
+ ".avi",
157
+ ".webm",
158
+ )
159
+
160
+ for d in directories:
161
+ src_dir = Path(d)
162
+ if not src_dir.exists():
163
+ logger.warning(f"Skipping non-existent directory: {src_dir}")
164
+ continue
165
+
166
+ for root, _, files in os.walk(src_dir):
167
+ rel = Path(root).relative_to(os.path.dirname(src_dir))
168
+ board_name = (
169
+ src_dir.name if rel == Path(".") else str(rel).replace(os.sep, "_~")
170
+ )
171
+
172
+ local_files = [
173
+ Path(root) / f
174
+ for f in sorted(files)
175
+ if f.lower().endswith(media_extensions)
176
+ ]
177
+
178
+ if not local_files:
179
+ logger.debug(f"No media in {root}, creating empty board.")
180
+ boards.append(
181
+ board(
182
+ name=board_name,
183
+ output_file_loc=str(outputDir),
184
+ image_paths=[],
185
+ paginate=paginate,
186
+ upload=upload,
187
+ dummy_status=True,
188
+ )
189
+ )
190
+ continue
191
+
192
+ logger.debug(f"Uploading {len(local_files)} images from {root}…")
193
+ try:
194
+ # local_files = append_sidecar_links(local_files, conn) # fix this function.
195
+ # this function has problems in the images not being counted in the index maker or the randomiser.
196
+ http_links, hash_map = process_images(local_files, conn)
197
+ img_filenames = [f.name for f in local_files]
198
+ except Exception as e:
199
+ logger.error(f"Failed to upload images in {root}: {e}")
200
+ continue
201
+
202
+ b = board(
203
+ name=board_name,
204
+ output_file_loc=str(outputDir),
205
+ image_paths=http_links,
206
+ img_filenames=img_filenames,
207
+ paginate=paginate,
208
+ # images_per_page=(config["page_size"] if paginate else 10000),
209
+ upload=upload,
210
+ # no_of_imgs=len(http_links),
211
+ # outputDir=outputDir
212
+ )
213
+ b.link_hash_map = hash_map
214
+ b.paginate_board()
215
+ boards.append(b)
216
+ logger.debug(
217
+ f"Uploaded board created: {board_name} ({len(http_links)} images)"
218
+ )
219
+
220
+ conn.close()
221
+ return boards
222
+
223
+
224
+ def randomBoard(boards, count, outputDir, paginate, upload):
225
+ images = []
226
+ for b in boards:
227
+ images.extend(b.image_paths)
228
+
229
+ try:
230
+ ran_images = random.sample(images, count)
231
+ except:
232
+ random.shuffle(images)
233
+ ran_images = images
234
+
235
+ images = list({os.path.basename(p): p for p in images}.values())
236
+
237
+ ranBoard = board(
238
+ name="randomised_set",
239
+ output_file_loc=outputDir,
240
+ image_paths=ran_images,
241
+ paginate=paginate,
242
+ upload=upload,
243
+ dummy_status=False,
244
+ )
245
+
246
+ ranBoard.paginate_board()
247
+
248
+ logger.info(f"there were {len(images)} imgs")
249
+
250
+ return ranBoard
251
+
252
+
253
+ import re
254
+
255
+
256
+ def extract_reddit_id_as_int(path: str) -> int:
257
+ filename = os.path.basename(path)
258
+ # Split on space or %20
259
+ reddit_id = re.split(r"(?:\s|%20)", filename, maxsplit=1)[0]
260
+ return reddit_id
261
+
262
+
263
+ def descBoard(boards, count, outputDir, paginate, upload):
264
+ images = []
265
+ img_filenames = []
266
+
267
+ if upload:
268
+ for b in boards:
269
+ images.extend(b.image_paths)
270
+ img_filenames.extend(b.img_filenames)
271
+
272
+ # map filenames → paths
273
+ paired = list(zip(img_filenames, images))
274
+
275
+ # sort by filename (descending)
276
+ paired.sort(key=lambda x: x[0], reverse=True)
277
+
278
+ # deduplicate by filename
279
+ seen = {}
280
+ for fname, path in paired:
281
+ if fname not in seen:
282
+ seen[fname] = path
283
+ images = list(seen.values())
284
+
285
+ else:
286
+ for b in boards:
287
+ images.extend(b.image_paths)
288
+
289
+ if args.reddit:
290
+ images.sort(key=lambda x: extract_reddit_id_as_int(x), reverse=True)
291
+ else:
292
+ images.sort(key=lambda x: os.path.basename(x), reverse=True)
293
+
294
+ # deduplicate by basename
295
+ images = list({os.path.basename(p): p for p in images}.values())
296
+
297
+ # exclude top 10
298
+ top = 10
299
+ if count > 0:
300
+ images = images[top : count + top]
301
+ else:
302
+ images = images[top:]
303
+
304
+ desc_Board = board(
305
+ name="recent imgs",
306
+ output_file_loc=outputDir,
307
+ image_paths=images,
308
+ paginate=paginate,
309
+ upload=upload,
310
+ dummy_status=False,
311
+ )
312
+ desc_Board.paginate_board()
313
+
314
+ with open("desc_images.log", "w") as f:
315
+ for img in images:
316
+ f.write(f"{img}\n")
317
+ with open("desc_images_path.log", "w") as f:
318
+ for img in images:
319
+ f.write(f"{os.path.basename(img)}\n")
320
+
321
+ return desc_Board
@@ -0,0 +1,83 @@
1
+ import os
2
+ from datetime import date
3
+
4
+ from pixBoards.config_loader import config
5
+ from pixBoards.log_utils import setup_logger
6
+
7
+ # set up logger
8
+ today = date.today()
9
+ logger = setup_logger(__name__)
10
+
11
+ # masterDir = config["masterDir"]
12
+
13
+ padding = config["padding"]
14
+ imgs_per_page = config["page_size"]
15
+ # print(f'imgs per page are {imgs_per_page}' )
16
+
17
+
18
+ class page:
19
+ def __init__(self, page_number, total_pages, images, file_location, bname):
20
+ self.page_number = page_number # Current page number
21
+ self.images = images # image list for the page
22
+ self.total_pages = total_pages
23
+ self.file_location = file_location
24
+ self.bname = bname
25
+
26
+
27
+ from math import ceil
28
+
29
+
30
+ class board:
31
+ def __init__(
32
+ self,
33
+ name,
34
+ output_file_loc,
35
+ image_paths,
36
+ # no_of_imgs,
37
+ img_filenames=[],
38
+ paginate=True,
39
+ upload=False,
40
+ dummy_status=False,
41
+ img_list_status=False,
42
+ ):
43
+ self.name = name
44
+ self.image_paths = image_paths
45
+ self.img_filenames = img_filenames
46
+ self.pages = [] # will be storing a list of instances of class, page.
47
+ self.imgs_per_page = imgs_per_page
48
+ self.output_file_loc = output_file_loc
49
+ self.upload_status = upload
50
+ self.paginate_status = paginate
51
+ self.link_hash_map = {} if self.upload_status else None
52
+ self.no_of_imgs = len(image_paths)
53
+ self.nested_boards = []
54
+ self.dummy_status = dummy_status
55
+ self.img_list_status = img_list_status
56
+ parts = self.name.split("_~")
57
+ self.clean_name = parts[-1]
58
+ self.parent = "_~".join(parts[:-1])
59
+
60
+ def paginate_board(self):
61
+ total_images = len(self.image_paths)
62
+ # logger.info(f'total images = {total_images}')
63
+ total_pages = ceil(total_images / self.imgs_per_page)
64
+ output_base = self.output_file_loc
65
+ for i in range(total_pages):
66
+
67
+ start = i * self.imgs_per_page
68
+ end = start + self.imgs_per_page
69
+ page_images = self.image_paths[start:end]
70
+ file_loc = (
71
+ os.path.join(output_base, self.name) + f"_{(i+1):0{padding}}.html"
72
+ )
73
+ Page = page(
74
+ page_number=i + 1,
75
+ total_pages=total_pages,
76
+ images=page_images,
77
+ file_location=file_loc,
78
+ bname=self,
79
+ )
80
+ self.pages.append(Page)
81
+ logger.debug(
82
+ f"Finished with - Board: {self.name}, page {i + 1} of {total_pages}"
83
+ )
@@ -0,0 +1,112 @@
1
+ import time
2
+ from datetime import date
3
+
4
+ from pixBoards.arguments import args
5
+ from pixBoards.boardmakers import (
6
+ boardsForImglist,
7
+ randomBoard,
8
+ descBoard,
9
+ standardBoards,
10
+ uploadBoards,
11
+ )
12
+ from pixBoards.log_utils import setup_logger
13
+
14
+ logger = setup_logger(__name__)
15
+
16
+
17
+ from pixBoards.config_loader import config, outputDir
18
+ from pixBoards.db import create_boards_table, create_conn
19
+
20
+
21
+ def main():
22
+
23
+ start_time = time.time()
24
+ today = date.today()
25
+ logger.info(f"Today is {today}, Starting ...")
26
+
27
+ conn = None
28
+ if args.upload or args.saveBoards:
29
+ conn = create_conn()
30
+
31
+ if args.saveBoards:
32
+ create_boards_table(conn)
33
+
34
+ paginate = config.get("paginate", True) is True
35
+ boards = []
36
+
37
+ # Handle imagelist mode
38
+ if args.useLists or args.imageLists:
39
+ usingLists = True
40
+ imgList_List = (
41
+ args.imageLists if args.imageLists else config.get("imageLists", [])
42
+ )
43
+ boards.extend(boardsForImglist(imgList_List, outputDir, paginate))
44
+
45
+ if args.includeLocal:
46
+ usingLists = False
47
+ else:
48
+ usingLists = False
49
+
50
+ # Handle upload
51
+ if args.upload:
52
+ logger.info("Upload case")
53
+ upload = True
54
+ else:
55
+ upload = False
56
+
57
+ if args.dir:
58
+ directories = [args.dir]
59
+ logger.debug("Using --dir → %s", directories)
60
+ elif config.get("directories"):
61
+ directories = config["directories"]
62
+ logger.debug(f"Using config.directories → %s", directories)
63
+ else:
64
+ directories = []
65
+
66
+ # board generation standar case
67
+ if directories and not usingLists:
68
+ if upload:
69
+ boards.extend(uploadBoards(directories, outputDir, paginate, upload=True))
70
+ else:
71
+ boards.extend(
72
+ standardBoards(directories, outputDir, paginate, upload=False)
73
+ )
74
+
75
+ # for random case
76
+ if args.random:
77
+ rancount = args.random
78
+ boards.append(randomBoard(boards, rancount, outputDir, paginate, upload))
79
+
80
+ if args.recent:
81
+ desc_count = args.recent
82
+ boards.append(descBoard(boards, desc_count, outputDir, paginate, upload))
83
+
84
+ from pixBoards.nest_boards import assign_nested_boards
85
+
86
+ root_boards = assign_nested_boards(boards)
87
+ logger.debug(root_boards)
88
+
89
+ # Group boards by output directory and create output
90
+ logger.info(f"Total boards to generate HTML for: {len(boards)}")
91
+ from pixBoards.filemaking import create_output_files
92
+
93
+ create_output_files(root_boards, boards, conn)
94
+
95
+ # Print nested board tree
96
+ def print_board_tree(boards, depth=0):
97
+ for b in boards:
98
+ print(" " * depth + f"- {b.clean_name}")
99
+ print_board_tree(b.nested_boards, depth + 1)
100
+
101
+ print("Boards structure - ")
102
+ print_board_tree(root_boards)
103
+
104
+ logger.debug(root_boards)
105
+ print(f"browse boards at - {outputDir}")
106
+
107
+ elapsed_time = time.time() - start_time
108
+ logger.info(f"Finished in {elapsed_time:.2f} seconds.")
109
+
110
+
111
+ if __name__ == "__main__":
112
+ main()