MaterialXWeb 0.0.2
Utilities for using MaterialX Packages with Web clients
Loading...
Searching...
No Matches
JsAmbientCGLoader.js
1const fs = require('fs');
2const { Writable } = require('stream');
3const { createGunzip } = require('zlib');
4const { parse } = require('csv-parse/sync');
5
14 if (AmbientCGLoader.instance) {
15 return AmbientCGLoader.instance;
16 }
17
18 this.logger = console;
19 this.database = {};
20 this.assets = {};
21 this.materials = null;
22 this.materialNames = [];
23 this.csvMaterials = null;
24 this.downloadMaterial = null;
25 this.downloadMaterialFileName = '';
26
27 // Cache the instance
28 AmbientCGLoader.instance = this;
29 }
30
31 setDebugging(debug = true) {
36 this.logger.level = debug ? 'debug' : 'info';
37 }
38
39 getMaterialNames(key = 'assetId') {
45 this.materialNames = [];
46 const uniqueNames = new Set();
47 if (this.materials) {
48 this.materials.forEach(item => uniqueNames.add(item[key]));
49 }
50 this.materialNames = Array.from(uniqueNames).sort();
51 return this.materialNames;
52 }
53
54 writeMaterialList(materialList, filename) {
60 this.logger.info(`Writing material list to file: ${filename}`);
61 fs.writeFileSync(filename, JSON.stringify(materialList, null, 4));
62 }
63
64 buildDownloadAttribute(imageFormat = 'PNG', imageResolution = '1') {
71 return `${imageResolution}K-${imageFormat}`;
72 }
73
74 splitDownloadAttribute(downloadAttribute) {
81 const parts = downloadAttribute.split('-');
82 }
83
89 return {
90 filename: this.downloadMaterialFileName,
91 content: this.downloadMaterial
92 };
93 }
94
99 if (this.downloadMaterial) {
100 this.downloadMaterial = null;
101 }
102 this.downloadMaterialFileName = '';
103 }
104
110 const haveDownload = this.downloadMaterialFileName && this.downloadMaterial;
111 if (!haveDownload) {
112 this.logger.warning('No current material downloaded');
113 return;
114 }
115
116 const filename = `${path}/${this.downloadMaterialFileName}`;
117 fs.writeFileSync(filename, this.downloadMaterial);
118 this.logger.info(`Saved downloaded material to: ${filename}`);
119 }
120
121 async downloadMaterialAsset(assetId, imageFormat = 'PNG', imageResolution = '1', downloadAttributeKey = 'downloadAttribute', downloadLinkKey = 'downloadLink') {
132
133 const items = this.findMaterial(assetId);
134 const target = this.buildDownloadAttribute(imageFormat, imageResolution);
135 let url = '';
136 let downloadAttribute = '';
137
138 items.forEach(item => {
139 downloadAttribute = item[downloadAttributeKey];
140 if (downloadAttribute === target) {
141 url = item[downloadLinkKey];
142 this.logger.info(`Found Asset: ${assetId}. Download Attribute: ${downloadAttribute} -> ${url}`);
143 }
144 });
145
146 if (!url) {
147 this.logger.error(`No download link found for asset: ${assetId}, attribute: ${target}`);
148 return '';
149 }
150
151 this.downloadMaterialFileName = url.split('file=')[1];
152 console.log('>>>> URL:', url, 'Filename:', this.downloadMaterialFileName);
153
154 try {
155 const response = await fetch(url);
156 if (!response.ok) {
157 throw new Error(`HTTP error! Status: ${response.status}`);
158 }
159
160 // Get the response as an ArrayBuffer
161 const arrayBuffer = await response.arrayBuffer();
162
163 // Convert ArrayBuffer to Buffer
164 this.downloadMaterial = Buffer.from(arrayBuffer);
165 this.logger.info(`Material file downloaded: ${this.downloadMaterialFileName}`);
166
167 } catch (error) {
168 this.downloadMaterialFileName = '';
169 this.logger.error(`Error occurred while downloading the file: ${error}`);
170 }
171
172 return this.downloadMaterialFileName;
173 }
174
175 findMaterial(assetId, key = 'assetId') {
182 if (this.materials) {
183 return this.materials.filter(item => item[key] === assetId);
184 }
185 return [];
186 }
187
194 this.materials = JSON.parse(fs.readFileSync(fileName, 'utf8'));
195 this.logger.info(`Loaded materials list from: ${fileName}`);
196 return this.materials;
197 }
198
204 //const url = 'https://ambientCG.com/api/v2/downloads_csv';
205 const headers = { Accept: 'application/csv' };
206 const params = {
207 method: 'PBRPhotogrammetry',
208 type: 'Material',
209 sort: 'Alphabet',
210 };
211
212 const url = new URL('https://ambientCG.com/api/v2/downloads_csv');
213 url.searchParams.append('method', 'PBRPhotogrammetry');
214 url.searchParams.append('type', 'Material');
215 url.searchParams.append('sort', 'Alphabet');
216
217 this.logger.info('Downloading materials CSV list...');
218 try {
219 const response = await fetch(url, { headers });
220 if (response.status === 200) {
221 const csvContent = await response.text(); // Extract CSV content as text
222 this.csvMaterials = csvContent;
223 this.materials = parse(csvContent, { columns: true });
224 this.logger.info('Downloaded CSV material list as JSON.');
225 } else {
226 this.materials = null;
227 this.logger.warning(`Failed to fetch the CSV material content. HTTP status code: ${response.status}`);
228 }
229 } catch (error) {
230 this.materials = null;
231 this.logger.error(`Error downloading materials list: ${error}`);
232 }
233
234 return this.materials;
235 }
236
242 return this.database;
243 }
244
250 return this.assets;
251 }
252
258 this.database = {};
259 this.assets = null;
260
261 const url = 'https://ambientcg.com/api/v2/full_json';
262 const headers = { Accept: 'application/json' };
263 const params = {
264 method: 'PBRPhotogrammetry',
265 type: 'Material',
266 sort: 'Alphabet',
267 };
268
269 try {
270 const response = await axios.get(url, { headers, params });
271 if (response.status === 200) {
272 this.database = response.data;
273 this.assets = this.database.foundAssets;
274 } else {
275 this.logger.error(`Status: ${response.status}, ${response.data}`);
276 }
277 } catch (error) {
278 this.logger.error(`Error downloading asset database: ${error}`);
279 }
280
281 return this.database;
282 }
283
290 if (!this.database) {
291 this.logger.warning('No database to write');
292 return false;
293 }
294
295 fs.writeFileSync(filename, JSON.stringify(this.database, null, 4));
296 return true;
297 }
298
305 if (!this.mx) {
306 this.logger.error('MaterialX module is required');
307 return [false, ''];
308 }
309
310 if (!doc) {
311 this.logger.warning('MaterialX document is required');
312 return [false, ''];
313 }
314
315 const valid = doc.validate();
316 return [valid, valid ? '' : 'Validation failed'];
317 }
318
319 addComment(doc, commentString) {
325 const comment = doc.addChildOfCategory('comment');
326 comment.setDocString(commentString);
327 }
328
335 if (!this.mx) {
336 this.logger.error('MaterialX module is required');
337 return;
338 }
339
340 const writeOptions = this.mx.XmlWriteOptions();
341 writeOptions.writeXIncludeEnable = false;
342 writeOptions.elementPredicate = this.skipLibraryElement;
343 return this.mx.writeToXmlString(doc, writeOptions);
344 }
345}
346
347module.exports = new AmbientCGLoader();
buildDownloadAttribute(imageFormat='PNG', imageResolution='1')
setDebugging(debug=true)
constructor()
Class to load materials from the AmbientCG site.
async downloadMaterialAsset(assetId, imageFormat='PNG', imageResolution='1', downloadAttributeKey='downloadAttribute', downloadLinkKey='downloadLink')
writeDownloadedMaterialToFile(path='')
addComment(doc, commentString)
findMaterial(assetId, key='assetId')
getMaterialNames(key='assetId')
writeDatabaseToFile(filename)
splitDownloadAttribute(downloadAttribute)
writeMaterialList(materialList, filename)