reef-beet-plugin 1.0.0b1__py3-none-any.whl

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.
reef/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ __version__ = "1.0.0-beta1"
2
+
3
+ __all__ = [
4
+ "reef"
5
+ ]
6
+
7
+ from .plugin import *
reef/gslides.py ADDED
File without changes
reef/options.py ADDED
@@ -0,0 +1,11 @@
1
+ from beet import PluginOptions
2
+ from pydantic import ConfigDict
3
+
4
+ class ReefPluginOptions(PluginOptions):
5
+ model_config = ConfigDict(extra="ignore")
6
+
7
+ tint: int | None = None
8
+ cache_timeout_hours: int = 24
9
+
10
+ class PdfPluginOptions(PluginOptions):
11
+ poppler_path: str | None = None
reef/pdf.py ADDED
@@ -0,0 +1,191 @@
1
+ import pdf2image
2
+ from PIL import Image
3
+ from pathlib import Path
4
+ from typing import ClassVar, List, Any
5
+ from beet import (
6
+ Context,
7
+ configurable,
8
+ PluginOptions,
9
+ File,
10
+ NamespaceFileScope,
11
+ Drop,
12
+ ResourcePack,
13
+ Model,
14
+ ItemModel,
15
+ Texture
16
+ )
17
+ from .options import ReefPluginOptions, PdfPluginOptions
18
+ from tempfile import TemporaryDirectory
19
+ import shutil
20
+ import logging
21
+
22
+ __all__ = ["pdf"]
23
+
24
+ PDF_NAMESPACE = "reef/pdf"
25
+ logger = logging.getLogger(PDF_NAMESPACE)
26
+
27
+ # TODO: add poppler path detection
28
+
29
+
30
+ def create_reef_pdf_namespace(ctx: Context):
31
+ class ReefPdf(File):
32
+ """Class representing a Reef PDF file."""
33
+
34
+ scope: ClassVar[NamespaceFileScope] = ("reef",)
35
+ extension: ClassVar[str] = ".pdf"
36
+
37
+ reef_opts = ctx.validate("reef", ReefPluginOptions)
38
+ pdf_opts = ctx.validate("reef.pdf", PdfPluginOptions)
39
+
40
+ def bind(self, pack: ResourcePack, path: str):
41
+ super().bind(pack, path)
42
+
43
+ # Variables -----------
44
+
45
+ namespace, _, path = path.partition(":")
46
+ pdf_path = Path(self.ensure_source_path())
47
+ poppler_path: dict[str, Any] = {"poppler_path": self.pdf_opts.poppler_path} if self.pdf_opts.poppler_path is not None else {}
48
+
49
+ # ---------------------
50
+
51
+ # Start to build the file
52
+ logger.debug(f"Building: {pdf_path}")
53
+
54
+ # Cache the original PDF
55
+ ctx.cache[PDF_NAMESPACE].download(pdf_path.as_uri())
56
+ logger.debug("Cached pdf %s (%s)", f"{namespace}:{path}", pdf_path)
57
+
58
+ # Cache the images if we didn't hit the cache
59
+ if ctx.cache[PDF_NAMESPACE].has_changed(pdf_path):
60
+ logger.debug("Recaching image files...")
61
+ with TemporaryDirectory() as temp_dir:
62
+ # Convert the PDF to a list of Images
63
+
64
+ uncached_images: List[str] = pdf2image.convert_from_path(
65
+ pdf_path=pdf_path,
66
+ fmt="png",
67
+ output_folder=temp_dir,
68
+ thread_count=4,
69
+ paths_only=True,
70
+ **poppler_path
71
+ ) # type: ignore
72
+
73
+ # Cache the images
74
+ with ctx.cache[PDF_NAMESPACE] as cache:
75
+ cache.timeout(hours=self.reef_opts.cache_timeout_hours)
76
+
77
+ for i in range(0, len(uncached_images)):
78
+ image_path = uncached_images[i]
79
+
80
+ cache_path = cache.get_path(f"{namespace}:{path}/{i}.png")
81
+
82
+ shutil.copyfile(image_path, cache_path)
83
+
84
+ logger.debug("Cached %s (%s)", f"{namespace}:{path}/{i}.png", cache_path)
85
+
86
+ logger.debug("Done caching!")
87
+
88
+ # Get PDF debug
89
+ # NOTE: oh my god why is pdf2image typed so horribly
90
+ pdf_info = pdf2image.pdfinfo_from_path(
91
+ pdf_path=str(pdf_path),
92
+ **poppler_path
93
+ )
94
+
95
+ # Put the cached images into a list
96
+ images: List[Image.Image] = []
97
+
98
+ with ctx.cache[PDF_NAMESPACE] as cache:
99
+ logger.debug("Loading images from cache...")
100
+ for i in range(0, pdf_info["Pages"]):
101
+ cache_path = cache.get_path(f"{namespace}:{path}/{i}.png")
102
+
103
+ with Image.open(cache_path) as img:
104
+ images.append(img.copy())
105
+ logger.debug("Copied %s (%s)", f"{namespace}:{path}/{i}.png", cache_path)
106
+
107
+ # Generate the resource pack assets
108
+ self.generate_assets(pack, namespace, path, images)
109
+
110
+ # Prevent the PDF itself from getting put into the resource pack
111
+ raise Drop()
112
+
113
+ def generate_assets(
114
+ self,
115
+ pack: ResourcePack,
116
+ namespace: str,
117
+ path: str,
118
+ images: List[Image.Image]
119
+ ) -> None:
120
+ resource_location_path = f"reef/mini/{path}"
121
+
122
+ # Calculate the transformation matrix
123
+ image_size = images[0].size
124
+ offset = (
125
+ 0.5 - image_size[0] / 16,
126
+ 0.5 - image_size[1] / 16
127
+ )
128
+ transformation_matrix = [
129
+ image_size[0], 0, 0, offset[0],
130
+ 0, image_size[1], 0, offset[1],
131
+ 0, 0, 1, 0.5,
132
+ 0, 0, 0, 1
133
+ ]
134
+
135
+ # File generation
136
+ logger.debug("Building resource pack files...")
137
+
138
+ item_model_entries = []
139
+
140
+ for i in range(0, len(images)):
141
+ logger.debug("Bulding %s", f"{resource_location_path}/{i}")
142
+ image = images[i]
143
+
144
+ # Texture at `assets/<ns>/textures/item/reef/mini/<pdf_name>/<page>`
145
+ pack[namespace].textures[f"item/{resource_location_path}/{i}"] = Texture(image)
146
+
147
+ # Model at `assets/<ns>/models/item/reef/mini/<pdf_name>/<page>`
148
+ pack[namespace].models[f"item/{resource_location_path}/{i}"] = Model({
149
+ "credit": "Generated with Reef",
150
+ "parent": "reef:item/element_base",
151
+ "textures": {
152
+ "image": f"{namespace}:{resource_location_path}/{i}",
153
+ }
154
+ })
155
+
156
+ # Build the item model entries
157
+ tints_field = {
158
+ "tints": [{
159
+ "type": "minecraft:constant",
160
+ "value": self.reef_opts.tint
161
+ }]
162
+ } if self.reef_opts.tint is not None else {}
163
+ item_model_entries.append({
164
+ "threshold": i,
165
+ "model": {
166
+ "type": "minecraft:model",
167
+ "model": f"{namespace}:{resource_location_path}/{i}",
168
+ **tints_field
169
+ }
170
+ })
171
+
172
+ # Item Model at `assets/<ns>/items/reef/mini/<pdf_name>`
173
+ pack[namespace].item_models[f"{resource_location_path}"] = ItemModel({
174
+ "model": {
175
+ "type": "minecraft:range_dispatch",
176
+ "property": "minecraft:custom_model_data",
177
+ "index": 0,
178
+ "entries": item_model_entries,
179
+ "transformation": transformation_matrix
180
+ }
181
+ })
182
+
183
+ logger.debug("Done building resource pack files!")
184
+
185
+
186
+ return ReefPdf
187
+
188
+ def pdf(ctx: Context):
189
+ """Adds support for Reef PDF asset files to generate Reef Mini compatible assets."""
190
+
191
+ ctx.assets.extend_namespace.append(create_reef_pdf_namespace(ctx))
reef/plugin.py ADDED
@@ -0,0 +1,38 @@
1
+ from beet import Context, Model, PluginOptions
2
+ import logging
3
+
4
+ from .pdf import pdf
5
+
6
+ __all__ = [
7
+ "reef",
8
+ "beet_default"
9
+ ]
10
+
11
+ logger = logging.getLogger("reef")
12
+
13
+ def beet_default(ctx: Context):
14
+ ctx.require(reef)
15
+ ctx.require(pdf)
16
+
17
+ def reef(ctx: Context):
18
+ """Initializes the Reef plugin system"""
19
+ logger.debug("Creating base assets...")
20
+
21
+ ctx.assets["reef"].models["item/element_base"] = Model({
22
+ "credit": "Generated with Reef",
23
+ "ambientocclusion": False,
24
+ "elements": [
25
+ {
26
+ "from": [0, 0, 0],
27
+ "to": [1, 1, 0],
28
+ "shade": False,
29
+ "light_emission": 15,
30
+ "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0]},
31
+ "faces": {
32
+ "north": {"uv": [0, 0, 16, 16], "texture": "#image", "tintindex": 0}
33
+ }
34
+ }
35
+ ]
36
+ })
37
+
38
+ logger.debug("Created reef:item/element_base")
@@ -0,0 +1,19 @@
1
+ Metadata-Version: 2.4
2
+ Name: reef-beet-plugin
3
+ Version: 1.0.0b1
4
+ Summary: Beet plugin to autogenerate Reef compatible data packs and resource packs from PDF and Google Slides presentations.
5
+ Keywords: beet,minecraft,datapack,resource_pack,presentation,reef
6
+ Author: Trplnr
7
+ Author-email: Trplnr <triopane30@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Requires-Dist: beet>=0.115.0
11
+ Requires-Dist: pdf2image>=1.17.0
12
+ Requires-Python: >=3.14
13
+ Project-URL: Homepage, https://github.com/Trioplane/reef
14
+ Project-URL: Issues, https://github.com/Trioplane/reef/issues
15
+ Project-URL: Repository, https://github.com/Trioplane/reef/blob/main/packages/reef
16
+ Description-Content-Type: text/markdown
17
+
18
+ # Reef Beet Plugin
19
+ > Beet plugin to autogenerate Reef compatible data packs and resource packs from PDF and Google Slides presentations.
@@ -0,0 +1,9 @@
1
+ reef/__init__.py,sha256=45sG9-60c5g67pa6p2w0JqU7jQNlepSuXOzVFVDBLgA,82
2
+ reef/gslides.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ reef/options.py,sha256=sVwpC9CqKkMCrB2Nb9xgB_-ysqPOMsC5qiMyB1_sE74,298
4
+ reef/pdf.py,sha256=lqQ7JZRpuPn3rHZy4Pa7OzImbQDV1c7CuZ9bZTkHeSI,7119
5
+ reef/plugin.py,sha256=4qfF2zz_HToZyuroODyLJtBA6Od096QI-AwdZZV1bPc,908
6
+ reef_beet_plugin-1.0.0b1.dist-info/licenses/LICENSE,sha256=b8M9UbMguBmohcWXAcKjoOjSmohcUSFdBwx76yrKbc0,1083
7
+ reef_beet_plugin-1.0.0b1.dist-info/WHEEL,sha256=wXwAVsgVaOZ_pwDFqQm5Rd6PID-Fc74nkLc8X8gHiDo,81
8
+ reef_beet_plugin-1.0.0b1.dist-info/METADATA,sha256=zPl7BoKPvaVQOwgQ7yNbKqRMdbxA--d0iYZ37S90efY,824
9
+ reef_beet_plugin-1.0.0b1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.11.19
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Trplnr
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.