summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/birka-cli.rs119
-rw-r--r--src/main.rs133
2 files changed, 166 insertions, 86 deletions
diff --git a/src/birka-cli.rs b/src/birka-cli.rs
new file mode 100644
index 0000000..d2caba3
--- /dev/null
+++ b/src/birka-cli.rs
@@ -0,0 +1,119 @@
+// Copyright © 2020 Jakob L. Kreuze <zerodaysfordays@sdf.org>
+//
+// This file is part of бирка-тян.
+//
+// бирка-тян is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// бирка-тян is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public
+// License along with бирка-тян. If not, see <http://www.gnu.org/licenses/>.
+
+#[macro_use]
+extern crate anyhow;
+extern crate dirs;
+
+mod database;
+
+use anyhow::Result;
+use blake2::{Blake2b, Digest};
+use database::TagDatabase;
+use std::env;
+use std::io;
+use std::path::Path;
+
+/// Return a base64-encoded BLAKE2b hash identifying the file at `path`.
+fn hash_file(path: &Path) -> Result<String> {
+ let mut file = std::fs::File::open(path)?;
+ let mut hasher = Blake2b::new();
+ io::copy(&mut file, &mut hasher)?;
+ Ok(base64::encode(&hasher.result()))
+}
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ if args.len() < 2 {
+ eprintln!("usage: {} ACTION [ARGS ...]", args[0]);
+ std::process::exit(1);
+ }
+
+ let tb = if let Ok(val) = env::var("TB_PATH") {
+ TagDatabase::new(&val)
+ } else if let Some(dir) = dirs::config_dir() {
+ TagDatabase::new(dir.join("birka.db").to_str().unwrap())
+ } else {
+ TagDatabase::new(Path::new("/tmp").join("pometka.db").to_str().unwrap())
+ }
+ .unwrap();
+
+ let action = &args[1];
+ match action.to_lowercase().as_str() {
+ "add" => {
+ if args.len() < 3 {
+ eprintln!("usage: {} add PATH [TAGS ...]", args[0]);
+ std::process::exit(1);
+ }
+ let path = Path::new(&args[2]).canonicalize().unwrap();
+ let hash = hash_file(&path).unwrap();
+ let id = tb.import_image(&path, &hash).unwrap();
+ for arg in args[3..].iter() {
+ tb.add_tag(arg).unwrap();
+ tb.tag_image(id, arg).unwrap();
+ }
+ }
+ "id_for" => {
+ if args.len() < 3 {
+ eprintln!("usage: {} id_for PATH ", args[0]);
+ std::process::exit(1);
+ }
+ let path = Path::new(&args[2]).canonicalize().unwrap();
+ println!("{}", tb.image_id(&path).unwrap());
+ }
+ "add_tags" => {
+ if args.len() < 3 {
+ eprintln!("usage: {} add_tags ID [TAGS ...]", args[0]);
+ std::process::exit(1);
+ }
+ let id = args[2].parse::<i64>().unwrap();
+ for arg in args[3..].iter() {
+ tb.add_tag(arg).unwrap();
+ tb.tag_image(id, arg).unwrap();
+ }
+ }
+ "remove_tags" => {
+ if args.len() < 3 {
+ eprintln!("usage: {} remove_tags ID [TAGS ...]", args[0]);
+ std::process::exit(1);
+ }
+ let id = args[2].parse::<i64>().unwrap();
+ for arg in args[3..].iter() {
+ tb.untag_image(id, arg).unwrap();
+ }
+ }
+ "query" => {
+ let tags = args[2..].iter().map(|s| s.as_str()).collect::<Vec<&str>>();
+ for tag in tags.iter() {
+ if tb.tag_id(tag).is_err() {
+ eprintln!("unknown tag: {}", tag);
+ std::process::exit(1);
+ }
+ }
+ for image in tb.images_by_tags(&tags[..]).unwrap() {
+ println!(
+ "{},{},{}{}",
+ image.id, image.blake2, image.orig_dir, image.filename
+ );
+ }
+ }
+ _ => {
+ eprintln!("Unknown action '{}'", action);
+ std::process::exit(1);
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index d2caba3..b5665b9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,105 +15,66 @@
// You should have received a copy of the GNU Affero General Public
// License along with бирка-тян. If not, see <http://www.gnu.org/licenses/>.
+#![feature(proc_macro_hygiene, decl_macro)]
+
#[macro_use]
extern crate anyhow;
-extern crate dirs;
+extern crate image;
+#[macro_use]
+extern crate rocket;
+#[macro_use]
+extern crate rocket_contrib;
mod database;
-use anyhow::Result;
-use blake2::{Blake2b, Digest};
use database::TagDatabase;
+use image::{GenericImageView, ImageFormat};
+use rocket_contrib::json::{Json, JsonValue};
use std::env;
-use std::io;
+use std::fs;
+use std::fs::File;
+use std::os::unix::fs::symlink;
use std::path::Path;
-/// Return a base64-encoded BLAKE2b hash identifying the file at `path`.
-fn hash_file(path: &Path) -> Result<String> {
- let mut file = std::fs::File::open(path)?;
- let mut hasher = Blake2b::new();
- io::copy(&mut file, &mut hasher)?;
- Ok(base64::encode(&hasher.result()))
+#[get("/")]
+fn index() -> &'static str {
+ "Hello, world!"
}
-fn main() {
- let args: Vec<String> = env::args().collect();
- if args.len() < 2 {
- eprintln!("usage: {} ACTION [ARGS ...]", args[0]);
- std::process::exit(1);
- }
+#[get("/posts?<tags>")]
+fn posts(tags: String) -> Json<Vec<String>> {
+ let tags: Vec<String> = tags.split(",").map(|s| s.into()).collect();
+ Json(tags)
+}
- let tb = if let Ok(val) = env::var("TB_PATH") {
- TagDatabase::new(&val)
- } else if let Some(dir) = dirs::config_dir() {
- TagDatabase::new(dir.join("birka.db").to_str().unwrap())
- } else {
- TagDatabase::new(Path::new("/tmp").join("pometka.db").to_str().unwrap())
- }
- .unwrap();
+fn create_image_directory() {
+ let bin = env::current_exe().unwrap();
+ let image_dir = bin.parent().unwrap().join("image/");
+ fs::create_dir(&image_dir).ok();
- let action = &args[1];
- match action.to_lowercase().as_str() {
- "add" => {
- if args.len() < 3 {
- eprintln!("usage: {} add PATH [TAGS ...]", args[0]);
- std::process::exit(1);
- }
- let path = Path::new(&args[2]).canonicalize().unwrap();
- let hash = hash_file(&path).unwrap();
- let id = tb.import_image(&path, &hash).unwrap();
- for arg in args[3..].iter() {
- tb.add_tag(arg).unwrap();
- tb.tag_image(id, arg).unwrap();
- }
- }
- "id_for" => {
- if args.len() < 3 {
- eprintln!("usage: {} id_for PATH ", args[0]);
- std::process::exit(1);
- }
- let path = Path::new(&args[2]).canonicalize().unwrap();
- println!("{}", tb.image_id(&path).unwrap());
- }
- "add_tags" => {
- if args.len() < 3 {
- eprintln!("usage: {} add_tags ID [TAGS ...]", args[0]);
- std::process::exit(1);
- }
- let id = args[2].parse::<i64>().unwrap();
- for arg in args[3..].iter() {
- tb.add_tag(arg).unwrap();
- tb.tag_image(id, arg).unwrap();
- }
- }
- "remove_tags" => {
- if args.len() < 3 {
- eprintln!("usage: {} remove_tags ID [TAGS ...]", args[0]);
- std::process::exit(1);
- }
- let id = args[2].parse::<i64>().unwrap();
- for arg in args[3..].iter() {
- tb.untag_image(id, arg).unwrap();
- }
- }
- "query" => {
- let tags = args[2..].iter().map(|s| s.as_str()).collect::<Vec<&str>>();
- for tag in tags.iter() {
- if tb.tag_id(tag).is_err() {
- eprintln!("unknown tag: {}", tag);
- std::process::exit(1);
- }
- }
- for image in tb.images_by_tags(&tags[..]).unwrap() {
- println!(
- "{},{},{}{}",
- image.id, image.blake2, image.orig_dir, image.filename
- );
- }
- }
- _ => {
- eprintln!("Unknown action '{}'", action);
- std::process::exit(1);
+ let tb_path = bin.parent().unwrap().join("birka.db");
+ let tb = TagDatabase::new(tb_path.to_str().unwrap()).unwrap();
+
+ for image in tb.images_by_tags(&vec![][..]).unwrap() {
+ let src = format!("{}/{}", image.orig_dir, image.filename);
+ let dst = format!("{}/{}", image_dir.to_str().unwrap(), image.filename);
+ symlink(&src, &dst).ok();
+
+ let stem = Path::new(&dst).file_stem().unwrap().to_str().unwrap();
+ let thumb_path = format!("{}_thumb.png", stem);
+ let thumb_path = Path::new(&thumb_path);
+
+ if !thumb_path.exists() {
+ let im = image::open(&Path::new(&src)).unwrap();
+ let fout = &mut File::create(&thumb_path).unwrap();
+ im.thumbnail(100, 100)
+ .write_to(fout, ImageFormat::Png)
+ .unwrap();
}
}
}
+
+fn main() {
+ create_image_directory();
+ rocket::ignite().mount("/", routes![index, posts]).launch();
+}