diff --git a/public/shu/scenes/index.html b/public/shu/scenes/index.html index 2bd8184e..87f9a04f 100644 --- a/public/shu/scenes/index.html +++ b/public/shu/scenes/index.html @@ -52,7 +52,7 @@ let scene = data[i]; let sid = scene.sid; - let urlCover = (scene.cover)? ATON.PATH_SCENES+sid+"/cover.png" : ATON.PATH_RES+"scenecover.png"; + let urlCover = ATON.PATH_RESTAPI2+"scenes/"+sid+"/cover"; //(scene.cover)? ATON.PATH_SCENES+sid+"/cover.png" : ATON.PATH_RES+"scenecover.png"; //let urlCover = ATON.PATH_RESTAPI+"cover/"+sid; let shtml = ""; diff --git a/public/shu/shu.js b/public/shu/shu.js index 8da62e2f..008c7769 100644 --- a/public/shu/shu.js +++ b/public/shu/shu.js @@ -149,7 +149,7 @@ SHU.createPubScenesGallery = (idcontainer, bSamples, onComplete, opts)=>{ let user = SHU.getUserFromSID(sid); if ( bSamples || user !== "samples" ){ - let urlCover = (scene.cover)? ATON.PATH_SCENES+sid+"/cover.png" : ATON.PATH_RES+"scenecover.png"; + let urlCover = ATON.PATH_RESTAPI2+"scenes/"+sid+"/cover"; // (scene.cover)? ATON.PATH_SCENES+sid+"/cover.png" : ATON.PATH_RES+"scenecover.png"; let title = (scene.title)? scene.title : sid; let terms = title.trim().toLowerCase(); diff --git a/services/API/v1.js b/services/API/v1.js index 3cf4182c..34b1437d 100644 --- a/services/API/v1.js +++ b/services/API/v1.js @@ -240,40 +240,8 @@ app.post("/api/cover/scene/", (req,res,next)=>{ img = img.replace(/^data:image\/png;base64,/, ""); - let scenefolder = Core.getSceneFolder(sid); - let coverfile = path.join(scenefolder, "cover-high.png"); - let coverfileOpt = path.join(scenefolder, "cover.png"); - console.log(coverfile); - - fs.writeFile(coverfile, img, 'base64', (err)=>{ - //if (fs.existsSync(coverfileOpt)) fs.unlinkSync(coverfileOpt); - - // Optimize PNG size - sharp(coverfile) - //.resize({ width: 256, height: 256 }) - .withMetadata() - .png({ - quality: 90, // 0-100 - //compression: 6, // this doesn't need to be set - }) - .toFile(coverfileOpt, (err)=>{ - if (err) console.log(err); - else { - console.log('done'); - res.send(true); - } - }); - -/* - imagemin([coverfile], { - destination: scenefolder, - plugins: [ imageminPNGquant({ quality: [0.1, 0.1] }) ] - }).then(()=>{ - console.log("Cover compressed"); - res.send(true); - }); -*/ - //res.send(true); + Core.generateCoverForScene(sid, img, ()=>{ + res.send(true); }); }); @@ -287,10 +255,13 @@ app.post("/api/cover/scene/", (req,res,next)=>{ app.get(/^\/api\/cover\/(.*)$/, (req,res,next)=>{ let sid = req.params[0]; - let coverfile = path.join(Core.getSceneFolder(sid), "cover.png"); + let coverfile = path.join(Core.getSceneFolder(sid), Core.STD_COVERFILE); + if (!fs.existsSync(coverfile)) coverfile = path.join(Core.getSceneFolder(sid), Core.STD_COVERFILE_HI); + + console.log(coverfile) if (!fs.existsSync(coverfile)){ - return res.sendFile(Core.DIR_RES+"scenecover.png"); + return res.sendFile(Core.STD_COVERFILE_PATH); } res.sendFile(coverfile); diff --git a/services/API/v2.js b/services/API/v2.js index 43a5e0d8..8f24b669 100644 --- a/services/API/v2.js +++ b/services/API/v2.js @@ -223,6 +223,10 @@ API.init = (app)=>{ let sid = U+"/"+S; let coverfile = path.join(Core.getSceneFolder(sid), Core.STD_COVERFILE); + + // To be removed in the future (old PNGs covers) + if (!fs.existsSync(coverfile)) coverfile = path.join(Core.getSceneFolder(sid), Core.STD_COVERFILE_HI); + fs.access(coverfile, (err) => { if (err){ res.sendFile(Core.STD_COVERFILE_PATH); diff --git a/services/Core.js b/services/Core.js index 5501e5a6..f83d4645 100644 --- a/services/Core.js +++ b/services/Core.js @@ -19,6 +19,7 @@ const fsx = require('fs-extra'); //const chokidar = require('chokidar'); const fg = require('fast-glob'); const chalk = require('chalk'); +const sharp = require("sharp"); const { networkInterfaces } = require('os'); @@ -57,7 +58,9 @@ Core.DIR_EXAMPLES = path.join(Core.DIR_PUBLIC,"examples/"); Core.DIR_FLARES = path.join(Core.DIR_CONFIG,"flares/"); //path.join(Core.DIR_PUBLIC,"custom/flares/"); Core.STD_SCENEFILE = "scene.json"; Core.STD_PUBFILE = "pub.txt"; // deprecated -Core.STD_COVERFILE = "cover.png"; +Core.STD_COVERFILE_HI = "cover.png"; +Core.STD_COVERFILE = "cover.jpg"; +Core.STD_COVERSIZE = 256; Core.STD_COVERFILE_PATH = path.join(Core.DIR_RES,"scenecover.png"); // Unused @@ -924,4 +927,38 @@ Core.setupDataRoute = (app)=>{ }); }; +// IMG +Core.generateCoverForScene = (sid, b64img, onComplete)=>{ + if (!sid) return; + + let scenefolder = Core.getSceneFolder(sid); + let coverfile = path.join(scenefolder, Core.STD_COVERFILE_HI); + let coverfileOpt = path.join(scenefolder, Core.STD_COVERFILE); + + fs.writeFile(coverfile, b64img, 'base64', (err)=>{ + //if (fs.existsSync(coverfileOpt)) fs.unlinkSync(coverfileOpt); + + // Optimize PNG size + sharp(coverfile) + .resize({ + width: Core.STD_COVERSIZE, + height: Core.STD_COVERSIZE + }) + .withMetadata() +/* + .png({ + quality: 90, // 0-100 + //compression: 6, // this doesn't need to be set + }) +*/ + .jpeg({ + quality: 60 + }) + .toFile(coverfileOpt, (err)=>{ + if (err) console.log(err); + else if (onComplete) onComplete(); + }); + }); +}; + module.exports = Core; \ No newline at end of file diff --git a/services/maat/Maat.js b/services/maat/Maat.js index 0b6934e0..aadfae28 100644 --- a/services/maat/Maat.js +++ b/services/maat/Maat.js @@ -94,6 +94,15 @@ Maat.init = ()=>{ }); */ //Maat._dUpd = setInterval(Maat.update, Maat.INTERVAL); + + // First global scan + Maat.getUsers(); + Maat.scanApps(); + Maat.scanScenes(); + for (let i in Maat.db.users){ + let u = Maat.db.users[i].username; + Maat.scanCollection(u); + } }; Maat.sortScenes = (entryA, entryB)=>{ @@ -125,110 +134,113 @@ Maat.addSceneKeyword = (k)=>{ Maat.scanScenes = ()=>{ if (Maat.needScan.scenes === false) return; - - Maat.db.scenes = []; // clear - Maat.db.scenesByID = {}; - Maat.db.kwords = {}; // clear global keywords - //Maat.db.users = {}; console.log("Scanning scenes..."); const confSHU = Core.config.shu; - let files = fg.sync("**/"+Core.STD_SCENEFILE, Core.SCENES_GLOB_OPTS); - - for (let f in files){ - let S = {}; + //let files = fg.sync("**/"+Core.STD_SCENEFILE, Core.SCENES_GLOB_OPTS); + fg("**/"+Core.STD_SCENEFILE, Core.SCENES_GLOB_OPTS).then( files => { - let sid = path.dirname(files[f]); - //let pubfile = Core.DIR_SCENES + sid+"/" + Core.STD_PUBFILE; - let coverfile = Core.DIR_SCENES + sid+"/" + Core.STD_COVERFILE; - - //let user = sid.split("/")[0]; - //if (user) Maat.db.users[user] = 1; + Maat.db.scenes = []; // clear + Maat.db.scenesByID = {}; + Maat.db.kwords = {}; // clear global keywords + //Maat.db.users = {}; - S.sid = sid; - S.cover = fs.existsSync(coverfile)? true : false; - //S.public = fs.existsSync(pubfile)? true : false; + for (let f in files){ + let S = {}; - if (confSHU && confSHU.staffpick && confSHU.staffpick[sid]) S.staffpick = 1; + let sid = path.dirname(files[f]); + //let pubfile = Core.DIR_SCENES + sid+"/" + Core.STD_PUBFILE; + let coverfile = Core.DIR_SCENES + sid+"/" + Core.STD_COVERFILE; - let sobj = Core.readSceneJSON(sid); + //let user = sid.split("/")[0]; + //if (user) Maat.db.users[user] = 1; - if (sobj){ - if (sobj.title) S.title = sobj.title; + S.sid = sid; + S.cover = fs.existsSync(coverfile)? true : false; + //S.public = fs.existsSync(pubfile)? true : false; - if (sobj.kwords){ - S.kwords = sobj.kwords; - for (let k in S.kwords) Maat.addSceneKeyword(k); - } + if (confSHU && confSHU.staffpick && confSHU.staffpick[sid]) S.staffpick = 1; + + let sobj = Core.readSceneJSON(sid); - if (sobj.visibility) S.visibility = sobj.visibility; + if (sobj){ + if (sobj.title) S.title = sobj.title; - if (!sobj.creationDate){ - const sstats = fs.statSync(Core.DIR_SCENES + files[f]); - S.creationDate = sstats.birthtime; - } + if (sobj.kwords){ + S.kwords = sobj.kwords; + for (let k in S.kwords) Maat.addSceneKeyword(k); + } - Maat.db.scenes.push(S); + if (sobj.visibility) S.visibility = sobj.visibility; - Maat.db.scenesByID[S.sid] = { - title: S.title, - visibility: S.visibility, - kwords: S.kwords, - cover: S.cover, - creationDate: S.creationDate - }; - } - else { - console.log("ERROR malformed scene: ", sid); + if (!sobj.creationDate){ + const sstats = fs.statSync(Core.DIR_SCENES + files[f]); + S.creationDate = sstats.birthtime; + } + + Maat.db.scenes.push(S); + + Maat.db.scenesByID[S.sid] = { + title: S.title, + visibility: S.visibility, + kwords: S.kwords, + cover: S.cover, + creationDate: S.creationDate + }; + } + else { + console.log("ERROR malformed scene: ", sid); + } + + //Maat.db.scenes.push(S); } - //Maat.db.scenes.push(S); - } - //console.log(Maat.db.scenesByID); - //Maat.db.scenes.sort( Maat.sortScenes ); + //console.log(Maat.db.scenesByID); - Maat.needScan.scenes = false; + //Maat.db.scenes.sort( Maat.sortScenes ); - console.log(Maat.db.kwords); + Maat.needScan.scenes = false; - setTimeout(()=>{ - Maat.needScan.scenes = true; - }, Maat.INTERVAL); + //console.log(Maat.db.kwords); + + setTimeout(()=>{ Maat.needScan.scenes = true; }, Maat.INTERVAL); + }); }; Maat.scanApps = ()=>{ if (Maat.needScan.apps === false) return; - Maat.db.apps = []; - let O = {}; O.cwd = Core.DIR_WAPPS; O.follow = true; console.log("Scanning web-apps..."); - let files = fg.sync("*/app.webmanifest", O); // index.html - for (let f in files){ - let wid = path.dirname(files[f]); - let appicon = path.join(Core.DIR_WAPPS+wid, "/appicon.png"); - let datadir = path.join(Core.DIR_WAPPS+wid, "/data"); - - Maat.db.apps.push({ - wappid: wid, - icon: fs.existsSync(appicon)? true : false, - data: fs.existsSync(datadir)? true : false - }); - } + fg("*/app.webmanifest", O).then(files => { + Maat.db.apps = []; - Maat.needScan.apps = false; + for (let f in files){ + let wid = path.dirname(files[f]); + let appicon = path.join(Core.DIR_WAPPS+wid, "/appicon.png"); + let datadir = path.join(Core.DIR_WAPPS+wid, "/data"); - setTimeout(()=>{ - Maat.needScan.apps = true; - }, Maat.INTERVAL); + Maat.db.apps.push({ + wappid: wid, + icon: fs.existsSync(appicon)? true : false, + data: fs.existsSync(datadir)? true : false + }); + } + + Maat.needScan.apps = false; + + setTimeout(()=>{ + Maat.needScan.apps = true; + }, Maat.INTERVAL); + }); }; @@ -264,16 +276,17 @@ Maat.scanModels = (uid)=>{ globopts.follow = true; */ //let files = fg.sync("**/{*.gltf,*.glb,*.json}", globopts); - let files = fg.sync("{"+uid+",samples}/models/**/{"+Core.mpattern+"}", Core.COLLECTIONS_GLOB_OPTS); + fg("{"+uid+",samples}/models/**/{"+Core.mpattern+"}", Core.COLLECTIONS_GLOB_OPTS).then( files =>{ - CC[uid].models = []; + CC[uid].models = []; - if (files.length < 1) return; + if (files.length < 1) return; - // TODO: improve filtering perf. - //files = Maat.filterTSets(files); + // TODO: improve filtering perf. + //files = Maat.filterTSets(files); - for (let f in files) CC[uid].models.push( /*relpath + */files[f] ); + for (let f in files) CC[uid].models.push( /*relpath + */files[f] ); + }); }; Maat.scanPanoramas = (uid)=>{ @@ -288,12 +301,13 @@ Maat.scanPanoramas = (uid)=>{ globopts.follow = true; */ //let files = fg.sync("**/{*.jpg,*.mp4,*.webm}", globopts); - let files = fg.sync("{"+uid+",samples}/pano/**/{"+Core.panopattern+"}", Core.COLLECTIONS_GLOB_OPTS); + fg("{"+uid+",samples}/pano/**/{"+Core.panopattern+"}", Core.COLLECTIONS_GLOB_OPTS).then(files => { - CC[uid].panos = []; - if (files.length < 1) return; - - for (let f in files) CC[uid].panos.push( /*relpath +*/ files[f] ); + CC[uid].panos = []; + + if (files.length < 1) return; + for (let f in files) CC[uid].panos.push( /*relpath +*/ files[f] ); + }); }; Maat.scanMedia = (uid)=>{ @@ -301,12 +315,13 @@ Maat.scanMedia = (uid)=>{ if (CC[uid] === undefined) CC[uid] = {}; - let files = fg.sync("{"+uid+",samples}/media/**/{"+Core.mediapattern+"}", Core.COLLECTIONS_GLOB_OPTS); + fg("{"+uid+",samples}/media/**/{"+Core.mediapattern+"}", Core.COLLECTIONS_GLOB_OPTS).then(files =>{ - CC[uid].media = []; - if (files.length < 1) return; + CC[uid].media = []; + if (files.length < 1) return; - for (let f in files) CC[uid].media.push( files[f] ); + for (let f in files) CC[uid].media.push( files[f] ); + }); }; // TODO: improve filter alg