Browse Source

first commit

pull/2/head
asiekierka 6 years ago
commit
f9e7e62714

+ 3
- 0
.gitignore View File

@@ -0,0 +1,3 @@
1
+img
2
+node_modules
3
+private

+ 128
- 0
app.js View File

@@ -0,0 +1,128 @@
1
+var express = require('express')
2
+  , mkdirp = require('mkdirp')
3
+  , _ = require('underscore')
4
+  , fs = require('fs')
5
+  , JSON = require('JSON2')
6
+  , imageDB = require('./imagedb.js').ImageDB
7
+  , im = require('imagemagick')
8
+  , program = require('commander')
9
+  , path = require('path')
10
+  , qs = require('querystring');
11
+
12
+var app = express()
13
+  , config = require('./config.json')
14
+  , templates = {};
15
+
16
+var defaultImage = { author: "Unknown", source: "/", uploader: "Computer" };
17
+
18
+_.each(fs.readdirSync("templates/"),function(filename) {
19
+  var name = filename.split(".")[0];
20
+  console.log("[Template] Loading template "+name);
21
+  templates[name] = fs.readFileSync("templates/"+filename,"utf8");    
22
+});
23
+
24
+function fileExt(name) {
25
+  var ext = path.extname(name).split(".");
26
+  return ext[ext.length-1];
27
+}
28
+
29
+var thumbW = 300, thumbH = 300;
30
+
31
+function resize(src,dest,w,h) {
32
+  var cnf = { srcPath: src, dstPath: dest,
33
+              width: w, height: h+"^",
34
+              customArgs: [ "-gravity", "center", "-extent", w+"x"+h ] };
35
+  im.resize(cnf,null);
36
+}
37
+
38
+function thumbnail(src,dest,dest2x) {
39
+  resize(src,dest,thumbW,thumbH);
40
+  if(_.isString(dest2x))
41
+    resize(src,dest2x,thumbW*2,thumbH*2);
42
+}
43
+
44
+function addImage(rawdata,format,info) {
45
+  imageDB.count("imageId",function(err,id) {
46
+    var path = id+"."+format;
47
+    fs.writeFile("img/src/"+path,rawdata,"utf8",function() {
48
+      im.identify("img/src/"+path, function(err,features) {
49
+        if(err) throw err;
50
+        var data = { id: id, format: format, filename: path, originalName: info.filename,
51
+                     width: features.width, height: features.height,
52
+                     tags: info.tags, uploader: info.uploader, author: info.author};
53
+        imageDB.set(id,_.defaults(data,defaultImage));
54
+      });
55
+      thumbnail("img/src/"+path,"img/thumb/"+path,"img/thumb2x/"+path);
56
+    });
57
+  });  
58
+}
59
+
60
+function makeRawTemplate(name,conf,noHeader) {
61
+  var conf2 = _.defaults(conf,config);
62
+  var body = _.template(templates[name],conf2);
63
+  if(!noHeader)
64
+    body = _.template(templates["header"],conf2) + body;
65
+  return body;
66
+}
67
+function makeTemplate(name,conf,raw,noHeader) {
68
+  if(raw=="raw") return makeRawTemplate(name,conf,noHeader);
69
+  var conf2 = _.defaults(conf,config);
70
+  return _.template(templates["main"],_.defaults(conf2,{page: makeRawTemplate(name,conf,noHeader)}));
71
+}
72
+
73
+// Create missing directories (just in case)
74
+mkdirp.sync("img/src");
75
+mkdirp.sync("img/thumb");
76
+mkdirp.sync("img/thumb2x");
77
+
78
+// Load directory dependencies
79
+app.use("/static/",express.static("bootstrap"));
80
+app.use("/static/",express.static("static"));
81
+app.use("/img/",express.static("img"));
82
+app.use("/img/thumb/", function(req,res) { res.redirect("/static/img/thumbnotfound.png"); });
83
+app.use("/img/thumb2x/", function(req,res) { res.redirect("/static/img/thumbnotfound.png"); });
84
+app.use("/upload/",express.basicAuth("test","test"));
85
+app.use("/upload/",function(req,res) {
86
+  var p = qs.unescape(req.path).split("/");
87
+  res.send(makeTemplate("upload",{title: "Boorushy Upload"},p[1]));
88
+});
89
+app.use("/image/",function(req,res) {
90
+  var p = qs.unescape(req.path).split("/");
91
+  if(!p[1]) res.send(500);
92
+  imageDB.get(p[1],function(data) {
93
+    res.send(makeTemplate("view",{image: _.defaults(data, defaultImage), title: "Boorushy v.2"},p[2]));
94
+  });
95
+});
96
+function listImages(res,images1,p,p2) {
97
+  var start = parseInt(p) || 0;
98
+  var isRaw = p2 || false;
99
+  var noHeader = false;
100
+  if(parseInt(p)==NaN) { start = 0; isRaw = p; }
101
+  console.log("listImages: " + start + " " + isRaw);
102
+  imageDB.range(images1,start,config.pageSize,function(images2) {
103
+    var conf = {images: images2, position: start, maxpos: images1.length, title: "Boorushy v.2"};
104
+    var imagesLi = makeRawTemplate("images-li",conf,"raw",true);
105
+    conf.imagesLi = imagesLi;
106
+    if(isRaw == "append") res.send(conf.imagesLi);
107
+    else res.send(makeTemplate("images",conf,isRaw,noHeader));
108
+  });
109
+}
110
+app.use("/",function(req,res) {
111
+  var p = qs.unescape(req.path).split("/");
112
+  console.log("Request: " + JSON.stringify(p)); 
113
+  if(p.length>2 && (p[1] == "tag" || p[1] == "author" || p[1] == "uploader")) imageDB.imagesBy(p[1],p[2],function(images) { listImages(res,images,p[3],p[4]); });
114
+  else imageDB.images(function(images) { listImages(res,images,p[1],p[2]); });
115
+});
116
+
117
+imageDB.connect();
118
+app.listen(config.port);
119
+console.log("Working on port " + config.port);
120
+
121
+program.version("0.0.1");
122
+program.command("add [file]")
123
+       .description("add file to db")
124
+       .action(function(filename){
125
+         addImage(fs.readFileSync(filename),fileExt(filename),{tags: ["test","less tests"],filename: filename});
126
+       });
127
+
128
+program.parse(process.argv);

+ 1109
- 0
bootstrap/css/bootstrap-responsive.css
File diff suppressed because it is too large
View File


+ 9
- 0
bootstrap/css/bootstrap-responsive.min.css
File diff suppressed because it is too large
View File


+ 6158
- 0
bootstrap/css/bootstrap.css
File diff suppressed because it is too large
View File


+ 9
- 0
bootstrap/css/bootstrap.min.css
File diff suppressed because it is too large
View File


+ 2268
- 0
bootstrap/js/bootstrap.js
File diff suppressed because it is too large
View File


+ 6
- 0
bootstrap/js/bootstrap.min.js
File diff suppressed because it is too large
View File


+ 1
- 0
config.json View File

@@ -0,0 +1 @@
1
+{ "port": 8080, "pageSize": 8 }

+ 113
- 0
imagedb.js View File

@@ -0,0 +1,113 @@
1
+var ImageDB = {}
2
+  , redis = require("redis")
3
+  , _ = require("underscore")
4
+  , JSON = require("JSON2")
5
+  , async = require("async");
6
+
7
+var client = null;
8
+
9
+ImageDB.connect = function(port,host,options) {
10
+  client = redis.createClient(port || null,host || null,options || {});
11
+}
12
+
13
+ImageDB.get = function(id,callback) {
14
+  client.get("data:"+id,function(err,out) {
15
+    if(err) throw err;
16
+    callback(JSON.parse(out));
17
+  });
18
+}
19
+ImageDB.getWithError = function(id,callback) {
20
+  client.get("data:"+id,function(err,out) {
21
+    callback(err,JSON.parse(out));
22
+  });
23
+}
24
+
25
+ImageDB.exists = function(id,cb) { return client.exists(client,"data:"+id,cb); }
26
+
27
+ImageDB.addField = function(id,key,val) {
28
+  client.sadd(key+"s",val);
29
+  client.sadd(key+":"+val,id);
30
+}
31
+ImageDB.delField = function(id,key,val) {
32
+  client.srem(key+":"+val,id);
33
+  client.scard(key+":"+val, function(err,m) {
34
+    if(err) throw err;
35
+    if(m>0) return;
36
+    client.del(key+":"+val);
37
+    client.srem(key+"s",val);
38
+  });
39
+}
40
+
41
+ImageDB.tags = function(callback) {
42
+  client.smembers("tags", function(err,m) {
43
+    if(err) throw err;
44
+    if(_.isNull(m)) callback(new Array());
45
+    else callback(m.sort());
46
+  });
47
+}
48
+ImageDB.images = function(callback) {
49
+  client.smembers("images", function(err,m){
50
+    if(err) throw err;
51
+    if(_.isNull(m)) callback(new Array());
52
+    else callback(_.sortBy(m,function(num){ return 0-num; }));
53
+  });
54
+}
55
+ImageDB.imagesBy = function(key,val,callback) {
56
+  client.smembers(key+":"+val, function(err,m){
57
+    if(err) throw err;
58
+    if(_.isNull(m)) callback(new Array());
59
+    else callback(_.sortBy(m,function(num){ return 0-num; }));
60
+  });
61
+}
62
+ImageDB.range = function(arr2,s,l,callback) {
63
+  var out = new Array();
64
+  var arr = arr2;
65
+  if(_.isNumber(arr2)) arr = new Array(arr2);
66
+  arr = _.first(_.rest(arr,s),l);
67
+  async.map(arr,this.getWithError,function(err, results) {
68
+    if(err) throw err;
69
+    callback(results);
70
+  });
71
+}
72
+
73
+ImageDB.count = function(name,callback) {
74
+  client.setnx("counter:"+name,0);
75
+  client.incr("counter:"+name,callback);
76
+}
77
+ImageDB.uncount = function(name,callback) {
78
+  client.setnx("counter:"+name,0);
79
+  client.decr("counter:"+name,callback);
80
+}
81
+ImageDB.add = function(data,callback) {
82
+  this.count("imageId",function(count) {
83
+    this.set(count,data);
84
+    if(_.isFunction(callback))
85
+      callback(count);
86
+  });
87
+}
88
+ImageDB.set = function(id,data) {
89
+  data.id = id;
90
+  client.set("data:"+id,JSON.stringify(data));
91
+  client.sadd("images",id);
92
+  var t = this;
93
+  _.each(data.tags,function(tag) { t.addField(id,"tag",tag); });
94
+  if(_.isString(data.author))
95
+    this.addField(id,"author",data.author);
96
+  if(_.isString(data.uploader))
97
+    this.addField(id,"uploader",data.uploader);
98
+}
99
+
100
+ImageDB.unset = function(id) {
101
+  this.get(id,function(data) {
102
+    client.del("data:"+id);
103
+    client.srem("images",id);
104
+    var t = this;
105
+    _.each(data.tags,function(tag) { t.delField(id,"tag",tag); });
106
+    if(_.isString(data.author))
107
+      this.delField(id,"author",data.author);  
108
+    if(_.isString(data.uploader))
109
+      this.delField(id,"uploader",data.uploader);
110
+  });
111
+}
112
+
113
+exports.ImageDB = ImageDB;

+ 16
- 0
package.json View File

@@ -0,0 +1,16 @@
1
+{
2
+  "name": "boorushy2",
3
+  "description": "boorushy engine",
4
+  "version": "0.0.1",
5
+  "private": true,
6
+  "dependencies": {
7
+    "express": "3.x",
8
+    "JSON2": "0.1.x",
9
+    "underscore": "1.4.x",
10
+    "mkdirp": "0.3.x",
11
+    "commander": "1.1.x",
12
+    "redis": "0.8.x",
13
+    "imagemagick": "0.1.x",
14
+    "async": ">=0.2.5"
15
+  }
16
+}

+ 5
- 0
static/js/jquery-1.9.1.min.js
File diff suppressed because it is too large
View File


+ 1
- 0
static/js/underscore-min.js
File diff suppressed because it is too large
View File


+ 5
- 0
templates/header.html View File

@@ -0,0 +1,5 @@
1
+<div class="row padded-row">
2
+<div class="span12" style="text-align: center;">
3
+<h1>Boorushy<sub>2</sub></h1>
4
+</div>
5
+</div>

+ 4
- 0
templates/images-li.html View File

@@ -0,0 +1,4 @@
1
+<% _.each(images, function(img) {
2
+  print('<li class="span4"><a href="/image/'+img.id+'/" class="thumbnail">');
3
+  print('<img src="/img/thumb/'+img.filename+'" class="to-retinize"></a></li>');
4
+}); %>

+ 40
- 0
templates/images.html View File

@@ -0,0 +1,40 @@
1
+<div class="row padded-row">
2
+<ul class="thumbnails">
3
+<%= imagesLi %>
4
+</ul>
5
+<script type="text/javascript">
6
+// Retinizer!
7
+function retinize() {
8
+  if(window.devicePixelRatio>=1.5)
9
+    $("img.to-retinize").each(function(idx) {
10
+      var mSrc = $(this).attr("src");
11
+      if(mSrc.indexOf("thumb2x")<0)
12
+        $(this).attr("src",mSrc.replace("thumb","thumb2x"));
13
+      $(this).removeClass("to-retinize");
14
+    });
15
+}
16
+function pageLoad() {
17
+  retinize();
18
+  var position = <%= position %>;
19
+  var maxpos = <%= maxpos %>;
20
+  var pageSize = <%= pageSize %>;
21
+  var dwh = $(document).height() - $(window).height() - 300;
22
+  var update = function() {
23
+    if(position+pageSize < maxpos && $(window).scrollTop() >= dwh) {
24
+      position = position + pageSize;
25
+      $.get(position + "/append/",function(data) {
26
+        $("ul.thumbnails").append(data);
27
+        retinize();
28
+        setTimeout(update,50); // In case of huge scrollings
29
+      });
30
+    }
31
+  };
32
+  $(window).scroll(update);
33
+  update();
34
+}
35
+function pageUnload() {
36
+  $(window).unbind("scroll");
37
+  
38
+}
39
+</script>
40
+</div>

+ 59
- 0
templates/main.html View File

@@ -0,0 +1,59 @@
1
+<html>
2
+<head>
3
+<title><%= title %></title>
4
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
5
+<link href="/static/css/bootstrap.min.css" rel="stylesheet" media="screen">
6
+<style>
7
+.padded-row {
8
+  margin-top: 20px;
9
+}
10
+body {
11
+  background-color: #F4F2F0;
12
+}
13
+.thumbnail {
14
+  background-color: #FFF;
15
+}
16
+h1 {
17
+ color: #222;
18
+}
19
+</style>
20
+</head>
21
+<body>
22
+<script src="/static/js/jquery-1.9.1.min.js"></script>
23
+<script src="/static/js/bootstrap.min.js"></script>
24
+<script src="/static/js/underscore-min.js"></script>
25
+<div class="container" id="page-inject"><%= page %></div>
26
+<script>
27
+function redirect(url,noPush) {
28
+  console.log("Redirecting to " + url);
29
+  var url2 = url + "raw/";
30
+  if(url.substr(url.length-1,1)!="/") url2 = url + "/raw/";
31
+  $.get(url2, function(data) {
32
+    history.replaceState({currentUrl: location.pathname}, "", location.pathname);
33
+    if(!noPush) history.pushState({currentUrl: url}, "", url);
34
+    pageUnload();
35
+    $("#page-inject").html(data);
36
+    $("a").click(changeView);
37
+    pageLoad();
38
+  });
39
+}
40
+function changeView(ev) {
41
+  ev.preventDefault();
42
+  redirect($(this).attr("href"));
43
+}
44
+
45
+window.onpopstate = function(event) {
46
+  if(event.state && typeof(event.state.currentUrl) == "string")
47
+    redirect(event.state.currentUrl,true);
48
+}
49
+
50
+// ChangeViewize URLs
51
+$("a").each(function(idx) {
52
+  var href = $(this).attr("href");
53
+  if(href.indexOf("/src/")<0)
54
+    $(this).click(changeView);
55
+});
56
+pageLoad();
57
+</script>
58
+</body>
59
+</html>

+ 1
- 0
templates/upload.html View File

@@ -0,0 +1 @@
1
+Hi!

+ 28
- 0
templates/view.html View File

@@ -0,0 +1,28 @@
1
+<div class="row padded-row">
2
+<div class="span12" style="text-align: center;">
3
+<a href="/img/src/<%= image.filename %>">
4
+<img src="/img/src/<%= image.filename %>" style="max-width: 100%; height: auto;" class="img-polaroid to-resize">
5
+</a><br><br>
6
+Tags: <%
7
+  var t = 0;
8
+  _.each(image.tags,function(v) {
9
+    if(t>0) print(', ');
10
+    print('<a href="/tag/'+v+'/">'+v+'</a>');
11
+    t+=1;
12
+  });
13
+%><br>
14
+Author: <a href="/author/<%= image.author %>/"><%= image.author %></a> (<a href="<%= image.source %>">Source</a>)<br>
15
+Uploaded by <a href="/uploader/<%= image.uploader %>/"><%= image.uploader %></a>
16
+</div>
17
+<script type="text/javascript">
18
+function pageLoad() {
19
+  var winh = $(window).height()*0.8;
20
+  $("img.to-resize").load(function(){
21
+    var h = $(this).height();
22
+    if(h>winh)
23
+      $(this).attr("style","width: auto; max-height: 80%;");
24
+  });
25
+}
26
+function pageUnload() { }
27
+</script>
28
+</div>

Loading…
Cancel
Save