Bläddra i källkod

Add the thumbnail & README generator

Daniel Quinn 7 år sedan
förälder
incheckning
25ccd2ea7e
1 ändrade filer med 184 tillägg och 0 borttagningar
  1. 184
    0
      scripts/generate-readmes

+ 184
- 0
scripts/generate-readmes Visa fil

@@ -0,0 +1,184 @@
1
+#!/usr/bin/env python3
2
+
3
+import json
4
+import os
5
+import shutil
6
+import subprocess
7
+import tempfile
8
+from multiprocessing.pool import Pool
9
+
10
+from PIL import Image as PillowImage
11
+
12
+
13
+class Image:
14
+
15
+    @classmethod
16
+    def thumbnail(cls, args):
17
+
18
+        source, target, size = args
19
+
20
+        if os.path.exists(target):
21
+            return
22
+
23
+        print(f"Generating thumbnail for {source}")
24
+
25
+        scratch = tempfile.mkdtemp(prefix="lnxpcs-")
26
+        resized = os.path.join(scratch, "resized.png")
27
+
28
+        cls._resize(source, resized, size)
29
+        cls._optimise(resized, target)
30
+
31
+        shutil.rmtree(scratch)
32
+
33
+    @classmethod
34
+    def _resize(cls, source, target, size):
35
+        try:
36
+            im = PillowImage.open(source)
37
+            im.thumbnail(size)
38
+            im.save(target, "PNG")
39
+        except IOError:
40
+            print(f"Thumbnail creation failed for {source}")
41
+
42
+    @classmethod
43
+    def _optimise(cls, source, target):
44
+        subprocess.Popen(
45
+            ["optipng", "-o7", source, "-out", target],
46
+            stdout=subprocess.DEVNULL,
47
+            stderr=subprocess.DEVNULL
48
+        ).wait()
49
+
50
+
51
+class Prettifier:
52
+
53
+    ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
54
+    THUMB_SIZE = (256, 256)
55
+
56
+    def __init__(self, columns, threads=None):
57
+
58
+        self.columns = columns
59
+
60
+        self.threads = threads or int(
61
+            subprocess.check_output(["nproc"]).strip())
62
+
63
+    def _generate_headers(self):
64
+        return "| {} |\n| {} |\n".format(
65
+            " | ".join(["" for _ in range(self.columns)]),
66
+            " | ".join([":---:" for _ in range(self.columns)])
67
+        )
68
+
69
+    def _generate_image_cell(self, path, base):
70
+        return "![{name}]({path})".format(
71
+            name=path.replace(".png", ""),
72
+            path=os.path.join(".meta", "thumbnails", path)
73
+        )
74
+
75
+    def _generate_text_cell(self, path, base):
76
+        """
77
+        Look for a file called ``support.json`` in the ``.meta`` subdirectory
78
+        if it's there, it should have the following format:
79
+
80
+        {
81
+          image-name: {
82
+            "shirt": "https://url.to/shirt",
83
+            "mug": "https://hurl.to/mug",
84
+            ...
85
+          },
86
+        }
87
+
88
+        Using this file as a guide, we generate the relevant text bits.
89
+        """
90
+
91
+        name = path.replace(".png", "")
92
+        r = "[{name}]({path})".format(
93
+            name=name.replace("-", " "),
94
+            path=os.path.join(base, path)
95
+        )
96
+
97
+        support = {}
98
+        try:
99
+            support_path = os.path.join(
100
+                self.ROOT,
101
+                base,
102
+                ".meta",
103
+                "support.json"
104
+            )
105
+            with open(support_path) as f:
106
+                support = json.load(f)[name]
107
+        except (FileNotFoundError, KeyError):
108
+            pass
109
+
110
+        for key, value in support.items():
111
+            r += f" ([{key}]({value}))"
112
+
113
+        return r
114
+
115
+    def _generate_thumbnails(self, sources):
116
+        args = []
117
+        for source in sources:
118
+            args.append((
119
+                source,
120
+                os.path.join(
121
+                    os.path.dirname(source),
122
+                    ".meta",
123
+                    "thumbnails",
124
+                    os.path.basename(source)),
125
+                self.THUMB_SIZE
126
+            ))
127
+        with Pool(processes=self.threads) as pool:
128
+            pool.map(Image.thumbnail, args)
129
+
130
+    def _generate_rows(self, paths, base):
131
+
132
+        this, remainder = paths[:self.columns], paths[self.columns:]
133
+
134
+        r = "| {} |\n| {} |\n".format(
135
+            " | ".join([self._generate_image_cell(p, base) for p in this]),
136
+            " | ".join([self._generate_text_cell(p, base) for p in this])
137
+        )
138
+
139
+        if remainder:
140
+            r += self._generate_rows(remainder, base)
141
+
142
+        return r
143
+
144
+    def generate(self, path):
145
+        return self._generate_headers() + self._generate_rows(
146
+            [_ for _ in os.listdir(path) if ".png" in _],
147
+            path.replace(self.ROOT + "/", "")
148
+        )
149
+
150
+    @classmethod
151
+    def _get_image_dirs(cls, path):
152
+
153
+        r = []
154
+        for path, _, files in os.walk(path):
155
+            if "." in path:
156
+                continue
157
+            for f in files:
158
+                if ".png" in f:
159
+                    r.append(path)
160
+                    break
161
+
162
+        return r
163
+
164
+    @classmethod
165
+    def main(cls, columns):
166
+
167
+        instance = cls(columns)
168
+
169
+        originals = []
170
+        for d in cls._get_image_dirs(cls.ROOT):
171
+
172
+            thumb_dir = os.path.join(d, ".meta", "thumbnails")
173
+            os.makedirs(thumb_dir, exist_ok=True)
174
+
175
+            with open(os.path.join(d, "README.md"), "w") as f:
176
+                f.write(instance.generate(d))
177
+
178
+            originals += [os.path.join(d, _) for _ in os.listdir(d) if ".png" in _]  # NOQA: E501
179
+
180
+        instance._generate_thumbnails(originals)
181
+
182
+
183
+if __name__ == "__main__":
184
+    Prettifier.main(4)