Browse Source

added danbooru2 api emulation; PLEASE REGENERATE

pull/2/head
asiekierka 6 years ago
parent
commit
3812c30a07
4 changed files with 177 additions and 30 deletions
  1. 53
    29
      app.js
  2. 2
    0
      config-default.json
  3. 10
    1
      imagedb.js
  4. 112
    0
      module-danbooru.js

+ 53
- 29
app.js View File

@@ -44,6 +44,7 @@ function error(req,res,text,codeO) {
44 44
 }
45 45
 
46 46
 function parse(req,res,next) { if(req.params[0]) req.params = req.params[0].split("/"); else req.params = [""]; next(); }
47
+function logConnection(req, res, next) { console.log(req.path); next(); }
47 48
 
48 49
 // Configure
49 50
 var config = fs.existsSync("./config.json") ? require('./config.json') : defaultConfig;
@@ -172,6 +173,14 @@ function handleQuery(entry,images,allImages) {
172 173
   return images;
173 174
 }
174 175
 function handleSearch(req, res, query) {
176
+  getSearchTable(req, query, function(table) {
177
+    getImageTable(req,table,req.query,function(images) {
178
+      var mlen = Math.min(config.maxSearchLength,images.length);
179
+      listImages(req,res,images,req.query,mlen,{ajaxFetching: false, isSearch: true, subtitle: mlen+" results found."});
180
+    }, config.maxSearchLength);
181
+  });
182
+}
183
+function getSearchTable(req, query, callback) {
175 184
   var stack = [];
176 185
   cacheDB.exists("search:"+query,function(err,exists) {
177 186
     if(!exists)
@@ -195,13 +204,13 @@ function handleSearch(req, res, query) {
195 204
           if(stack.length > 1) { error(req,res,"Something quite bad happened! "+JSON.stringify(stack)); return; }
196 205
           var result = stack.pop();
197 206
           cacheDB.set("search:"+query,result,60,null);
198
-          listImages(req,res,result,req.query,{ajaxFetching: false, isSearch: true, subtitle: Math.min(1000,result.length)+" results found."},1000);
207
+          callback(result);
199 208
         });
200 209
       });
201 210
     else { // Found cached!
202 211
       console.log("Loading from cache!");
203 212
       cacheDB.get("search:"+query,function(err,result) {
204
-        listImages(req,res,result,req.query,{ajaxFetching: false, isSearch: true, subtitle: Math.min(1000,result.length)+" results found."},1000);
213
+        callback(result);
205 214
       });
206 215
     }
207 216
   });
@@ -292,10 +301,8 @@ app.get("/random*", parse, function(req,res) {
292 301
 });
293 302
 
294 303
 // Image listing
295
-function listImages(req,res,images1,options,defConfig,maxVal) {
304
+function getImageTable(req,images1,options,callback,maxVal) {
296 305
   var start = parseInt(options["start"]) || 0;
297
-  var mode = options["mode"] || "";
298
-  var noHeader = false;
299 306
   var images1a, data;
300 307
   var maxValue = options["length"] || maxVal || config.pageSize;
301 308
   if(maxValue > config.maxPageSize) maxValue = config.maxPageSize;
@@ -303,32 +310,43 @@ function listImages(req,res,images1,options,defConfig,maxVal) {
303 310
     if(!_(req.cookies.showHidden).isUndefined() || req.query["hidden"] == true) images1a = images1;
304 311
     else images1a = _.difference(images1,hiddenImages);
305 312
     imageDB.range(images1a,start,maxValue,function(images2) {
306
-      var conf = _.defaults({images: images2, position: start, maxpos: images1.length, req: req}, defConfig || {isSearch: false});
307
-      console.log(options);
308
-      if(options["mobile"] == 'true') conf.mobile = true;
309
-      if(mode=="json") {
310
-        if(config.api.json == false) { error(req, res, "JSON not allowed!", 403); return; }
311
-        res.json({position: start, length: images2.length, results: images2});
312
-      } else {
313
-        if(_(options).has("subtitle2"))
314
-          conf.subtitle = _.capitalize(options["subtitle1"])+": "+options["subtitle2"];
315
-        else if(!_.isString(conf.subtitle)) { // Create custom subtitle
316
-          if(start > 0 && (start % config.pageSize) == 0) { // page 2+
317
-            conf.subtitle = "Page " + ((start / config.pageSize)+1);
318
-          } else { // page 1
319
-            conf.subtitle = "Now with " + conf.maxpos + " images!";        
320
-          }
321
-        }
322
-        var imagesLi = makeRawTemplate("images-li",conf,"raw",true);
323
-        conf.imagesLi = imagesLi;
324
-        if(mode == "append") data = conf.imagesLi;
325
-        else data = makeTemplate("images",conf,mode,noHeader);
326
-        res.send(data);
327
-      }
313
+      callback(images2);
328 314
     });
329 315
   });
330 316
 }
331 317
 
318
+function listImages(req,res,images2,options,imageAmount,defConfig) {
319
+  var mode = options["mode"] || "";
320
+  var noHeader = false;
321
+  var conf = _.defaults({images: images2, position: start, maxpos: imageAmount, req: req}, defConfig || {"isSearch": false});
322
+  console.log(options);
323
+  if(options["mobile"] == 'true') conf.mobile = true;
324
+  if(mode=="json") {
325
+    if(config.api.json == false) { error(req, res, "JSON not allowed!", 403); return; }
326
+    res.json({position: start, length: images2.length, results: images2});
327
+  } else {
328
+    if(_(options).has("subtitle2"))
329
+      conf.subtitle = _.capitalize(options["subtitle1"])+": "+options["subtitle2"];
330
+    else if(!_.isString(conf.subtitle)) { // Create custom subtitle
331
+      if(start > 0 && (start % config.pageSize) == 0) { // page 2+
332
+        conf.subtitle = "Page " + ((start / config.pageSize)+1);
333
+      } else { // page 1
334
+        conf.subtitle = "Now with " + conf.maxpos + " images!";        
335
+      }
336
+    }
337
+    var imagesLi = makeRawTemplate("images-li",conf,"raw",true);
338
+    conf.imagesLi = imagesLi;
339
+    if(mode == "append") data = conf.imagesLi;
340
+    else data = makeTemplate("images",conf,mode,noHeader);
341
+    res.send(data);
342
+  }
343
+}
344
+
345
+// Load Danbooru API emulation
346
+if(config.api.danbooru) {
347
+  eval(fs.readFileSync('module-danbooru.js', 'utf-8'));
348
+}
349
+
332 350
 app.get("/cloud/*", parse, function(req,res) {
333 351
   if(req.params.length < 1 || !imageDB.isCloudTag(req.params[0])) { error(req,res,"No tag found!",404); return; }
334 352
   imageDB.getCloud(req.params[0], function(cloudData) {  
@@ -342,9 +360,15 @@ app.get("/*", function(req,res) {
342 360
   var p = qs.unescape(req.path).split("/");
343 361
   console.log("Request: " + JSON.stringify(p)); 
344 362
   if(p.length>0 && (p[1] == "tag" || p[1] == "author" || p[1] == "uploader")) imageDB.imagesBy(p[1],p[2],function(images) {
345
-    listImages(req,res,images,_(req.query).extend({"subtitle1": p[1], "subtitle2": p[2]}));
363
+    getImageTable(req,images,req.query,function(images2) {
364
+      listImages(req,res,images2,_(req.query).extend({"subtitle1": p[1], "subtitle2": p[2]}), images.length);
365
+    });
366
+  });
367
+  else imageDB.images(function(images) {
368
+    getImageTable(req,images,req.query,function(images2) {
369
+      listImages(req,res,images2,req.query,images.length);
370
+    });
346 371
   });
347
-  else imageDB.images(function(images) { listImages(req,res,images,req.query); });
348 372
 });
349 373
 
350 374
 // Personal boost.io code

+ 2
- 0
config-default.json View File

@@ -11,12 +11,14 @@
11 11
   "salt": "",
12 12
   "pageSize": 15,
13 13
   "maxPageSize": 500,
14
+  "maxSearchLength": 500,
14 15
   "title": "New Booru",
15 16
   "htmlTitle": "New Booru",
16 17
   "users": {
17 18
     "admin": {"pass": "admin", "nick": "admin", "type": "admin" }
18 19
   },
19 20
   "api": {
21
+    "danbooru": true,
20 22
     "json": true
21 23
   },
22 24
   "frameworks": {

+ 10
- 1
imagedb.js View File

@@ -33,7 +33,7 @@ ImageDB.updateDatabase = function(callback) {
33 33
         client.set(prefix+"db_version", 2, _.bind(self.updateDatabase, self));
34 34
       });
35 35
     }
36
-    else if(version == CURRENT_VERSION) { self.log("Latest DB version, nothing to do..."); if(_.isFunction(callback)) callback(); }
36
+    if(version == CURRENT_VERSION) { self.log("Latest DB version, nothing to do..."); if(_.isFunction(callback)) callback(false); return; }
37 37
   });
38 38
 }
39 39
 
@@ -204,6 +204,7 @@ ImageDB.setSearchData = function(id, data, callback) {
204 204
     _.bind(self.setTags,self,id,data.tags),
205 205
     _.bind(self.addField,self,id,"author",data.author),
206 206
     _.bind(self.addField,self,id,"uploader",data.uploader),
207
+    _.bind(client.hset,client,"hashToImage",data.hash,data.id),
207 208
     _.bind(self.addSize,self,id,"width",data.width),
208 209
     _.bind(self.addSize,self,id,"height",data.height)
209 210
   ], callback);
@@ -216,10 +217,18 @@ ImageDB.unsetSearchData = function(id, data, callback) {
216 217
     function(cb) { cb(); },
217 218
     _.bind(self.delField,self,id,"author",data.author),
218 219
     _.bind(self.delField,self,id,"uploader",data.uploader),
220
+    _.bind(client.hdel,client,"hashToImage",data.hash),
219 221
     _.bind(self.delSize,self,id,"width"),
220 222
     _.bind(self.delSize,self,id,"height")
221 223
   ], callback);
222 224
 }
225
+ImageDB.getByHash = function(hash, callback) {
226
+  var self = this;
227
+  client.hget("hashToImage", hash, function(err, results){
228
+    if(err) callback(err, null);
229
+    else self.getWithError(results, callback); 
230
+  });
231
+}
223 232
 
224 233
 ImageDB.regenerate = function(id, callback) {
225 234
   var self = this;

+ 112
- 0
module-danbooru.js View File

@@ -0,0 +1,112 @@
1
+// Danbooru API emulation
2
+// fits inside app.js
3
+
4
+function toDanbooruFormat(item) {
5
+ var isQuestionable = ( _.intersection(item.tags, config.tags.spoiler).length > 0)
6
+   , isExplicit = ( _.intersection(item.tags, config.tags.hidden).length > 0);
7
+
8
+ return{"approver_id": null,
9
+	"created_at": "1970-01-01T00:00:00+00:00",
10
+	"down_score": 0,
11
+	"fav_count": 0,
12
+	"fav_string": "",
13
+	"file_ext": item.format,
14
+	"file_size": util.filesize("./img/src/"+item.filename), // TODO: Index this!
15
+	"has_children": false,
16
+	"id": item.id,
17
+	"image_height": item.height,
18
+	"image_width": item.width,
19
+	"is_banned": false,
20
+	"is_deleted": false,
21
+	"is_flagged": false,
22
+	"is_note_locked": false,
23
+	"is_pending": false,
24
+	"is_rating_locked": isQuestionable || isExplicit,
25
+	"is_status_locked": false,
26
+	"last_commented_at": null,
27
+	"last_noted_at": null,
28
+	"md5": item.hash,
29
+	"parent_id": null,
30
+	"pixiv_id": 0,
31
+	"pool_string":"",
32
+	"rating": (isExplicit ? "e" : (isQuestionable ? "q" : "s")),
33
+	"score": 0,
34
+	"source": item.source,
35
+	"tag_count": item.tags.length,
36
+	"tag_count_artist": ((_.isString(item.author) && item.author != "") ? 1 : 0),
37
+	"tag_count_character": 0,
38
+	"tag_count_copyright": 0,
39
+	"tag_count_general": item.tags.length,
40
+	"tag_string": item.tags.join(" "),
41
+	"up_score": 0,
42
+	"updated_at": "1970-01-01T00:00:00+00:00",
43
+	"uploader_id": 1, // TODO: Make a real uploader ID!
44
+	"uploader_name": item.uploader,
45
+	"has_large": false,
46
+	"tag_string_artist": item.author,
47
+	"tag_string_character": "",
48
+	"tag_string_copyright": "",
49
+	"tag_string_general": item.tags.join(" "),
50
+	"file_url": "/img/src/"+item.filename,
51
+	"large_file_url": "/img/src/"+item.filename,
52
+	"preview_file_url": "/img/thumb/"+item.filename
53
+       };
54
+}
55
+
56
+// Effing Anime boxes on iPad...
57
+app.get("/data/*", parse, function(req,res) {
58
+  if(req.params[0].indexOf(".") > 0) {
59
+    var md5 = req.params[0].split(".")[0];
60
+    imageDB.getByHash(md5, function(err, image) {
61
+      if(image != null) {
62
+        res.redirect("/img/src/"+image.filename);
63
+      } else res.send(404, "Not found!");
64
+    });
65
+  } else res.send(404, "Not found!");
66
+});
67
+app.get("/ssd/data/preview/*", parse, function(req,res) {
68
+  if(req.params[0].indexOf(".") > 0) {
69
+    var md5 = req.params[0].split(".")[0];
70
+    imageDB.getByHash(md5, function(err, image) {
71
+      if(image != null) {
72
+        res.redirect("/img/thumb/"+image.filename);
73
+      } else res.send(404, "Not found!");
74
+    });
75
+  } else res.send(404, "Not found!");
76
+});
77
+
78
+function sendDanbooruTable(req, res, images, options) {
79
+  getImageTable(req,images,options,function(images2) {
80
+    async.map(images2, function(item, callback) {
81
+      callback(null, toDanbooruFormat(item));	
82
+    }, function(err, results) {
83
+      res.json(results);
84
+    });
85
+  });
86
+}
87
+app.get("/posts.json", function(req,res) {
88
+  imageDB.images(function(images) {
89
+    var onePageSize = (_.isNumber(req.query["limit"]) ? Math.min(config.maxPageSize,req.query["limit"]) : config.pageSize);
90
+    var pageNumber = (req.query["page"] || 1)-1;
91
+    var options = {
92
+	"length": onePageSize,
93
+        "start": pageNumber*onePageSize
94
+    };
95
+    var tags = [];
96
+    if(_.isString(req.query["tags"]) && req.query["tags"] != "*" && req.query["tags"] != "") {
97
+      var oldTags = req.query["tags"].split(" ");
98
+      _.each(oldTags, function(tag) {
99
+        if(tag != "" && !(_.startsWith(tag,"rating"))) {
100
+          tags.push(tag);
101
+        }
102
+      });
103
+    }
104
+    if(tags.length > 0) {
105
+      var query = queryParser.parse(tags.join(" "));
106
+      if(options["start"] > 0) res.json([])
107
+      else getSearchTable(req, query, function(result) {
108
+        sendDanbooruTable(req, res, result, {"start": 0, "length": result.length});
109
+      });
110
+    } else sendDanbooruTable(req, res, images, options);
111
+  });
112
+});

Loading…
Cancel
Save