From 63564921e5400ae007af0aeac3dd4984c6779b71 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 15 Aug 2011 11:30:14 -0400 Subject: [PATCH 01/40] js work --- app/assets/javascripts/favorites.js | 30 +++ app/assets/javascripts/post_mode_menu.js | 85 +++++++ app/assets/javascripts/posts.js | 231 ++++++-------------- app/assets/javascripts/tag_script.js | 56 +++++ app/assets/javascripts/utility.js | 4 + app/assets/stylesheets/application.css.scss | 66 ++++++ app/helpers/application_helper.rb | 2 +- 7 files changed, 305 insertions(+), 169 deletions(-) create mode 100644 app/assets/javascripts/post_mode_menu.js create mode 100644 app/assets/javascripts/tag_script.js diff --git a/app/assets/javascripts/favorites.js b/app/assets/javascripts/favorites.js index 3a88f0860..6441ff5cf 100644 --- a/app/assets/javascripts/favorites.js +++ b/app/assets/javascripts/favorites.js @@ -20,6 +20,36 @@ $("a#remove-from-favorites").hide(); } } + + Danbooru.Favorite.create = function(post_id) { + Danbooru.Post.notice_update("inc"); + + $.ajax({ + type: "POST", + url: "/favorites", + data: { + post_id: post_id + }, + complete: function() { + Danbooru.Post.notice_update("dec"); + }, + error: function(data, status, xhr) { + Danbooru.j_alert("Error: " + data.reason); + } + }); + } + + Danbooru.Favorite.destroy = function(post_id) { + Danbooru.Post.notice_update("inc"); + + $.ajax({ + type: "DELETE", + url: "/favorites/" + post_id, + complete: function() { + Danbooru.Post.notice_update("dec"); + } + }); + } })(); $(document).ready(function() { diff --git a/app/assets/javascripts/post_mode_menu.js b/app/assets/javascripts/post_mode_menu.js new file mode 100644 index 000000000..881eefb43 --- /dev/null +++ b/app/assets/javascripts/post_mode_menu.js @@ -0,0 +1,85 @@ +(function() { + Danbooru.PostModeMenu = {}; + + Danbooru.PostModeMenu.initialize = function() { + this.initialize_selector(); + this.initialize_preview_link(); + } + + Danbooru.PostModeMenu.initialize_selector = function() { + if (Danbooru.Cookie.get("mode") === "") { + Danbooru.Cookie.put("mode", "view"); + $("#mode-box select").val("view"); + } else { + $("#mode-box select").val(Danbooru.Cookie.get("mode")); + } + + $("#mode-box select").click(Danbooru.PostModeMenu.change); + } + + Danbooru.PostModeMenu.initialize_preview_link = function() { + $(".post-preview a").click(Danbooru.PostModeMenu.click); + } + + Danbooru.PostModeMenu.change = function() { + var s = $("#mode-box select").val(); + var $body = $(document.body); + $body.removeClass(); + $body.addClass("mode-" + s); + Danbooru.Cookie.put("mode", s, 7); + + if (s === "edit-tag-script") { + var script = Danbooru.Cookie.get("tag-script"); + script = prompt("Enter a tag script", script); + + if (script) { + Cookie.put("tag-script", script); + $("#mode-box select").val("apply-tag-script"); + } else { + $("#mode-box select").val("view"); + } + + this.change(); + } + } + + Danbooru.PostModeMenu.click = function(e) { + var s = $("#mode-box select").val(); + var post_id = $(e.target).closest("article").data("id"); + + if (s === "view") { + return; + } else if (s === "add-fav") { + Danbooru.Favorite.create(post_id); + } else if (s === "remove-fav") { + Danbooru.Favorite.destroy(post_id); + } else if (s === "edit") { + // TODO + } else if (s === 'vote-down') { + Danbooru.Post.vote("down", post_id); + } else if (s === 'vote-up') { + Danbooru.Post.vote("up", post_id); + } else if (s === 'rating-q') { + Danbooru.Post.update(post_id, {"post[rating]": "q"}); + } else if (s === 'rating-s') { + Danbooru.Post.update(post_id, {"post[rating]": "s"}); + } else if (s === 'rating-e') { + Danbooru.Post.update(post_id, {"post[rating]": "e"}); + } else if (s === 'lock-rating') { + Danbooru.Post.update(post_id, {"post[is_rating_locked]": "1"}); + } else if (s === 'lock-note') { + Danbooru.Post.update(post_id, {"post[is_note_locked]": "1"}); + } else if (s === 'add-to-pool') { + Pool.add_post(post_id, 0); + } else if (s === "apply-tag-script") { + var tag_script = Cookie.get("tag-script"); + TagScript.run(post_id, tag_script); + } + + e.preventDefault(); + } +})(); + +$(function() { + Danbooru.PostModeMenu.initialize(); +}); diff --git a/app/assets/javascripts/posts.js b/app/assets/javascripts/posts.js index a7235bafa..2f05527b5 100644 --- a/app/assets/javascripts/posts.js +++ b/app/assets/javascripts/posts.js @@ -1,170 +1,8 @@ -// PostModeMenu = { -// init: function() { -// this.original_background_color = $(document.body).css("background-color") -// -// if (Cookie.get("mode") == "") { -// Cookie.put("mode", "view"); -// $("#mode-box select").val("view"); -// } else { -// $("#mode-box select").val(Cookie.get("mode")); -// } -// -// // this.change(); -// }, -// -// change: function() { -// var s = $("#mode-box select").val(); -// Cookie.put("mode", s, 7); -// -// if (s == "view") { -// $(document.body).css({"background-color": this.original_background_color}); -// } else if (s == "edit") { -// $(document.body).css({"background-color": "#3A3"}); -// } else if (s == "add-fav") { -// $(document.body).css({"background-color": "#FFA"}); -// } else if (s == "remove-fav") { -// $(document.body).css({"background-color": "#FFA"}); -// } else if (s == "rating-q") { -// $(document.body).css({"background-color": "#AAA"}); -// } else if (s == "rating-s") { -// $(document.body).css({"background-color": "#6F6"}); -// } else if (s == "rating-e") { -// $(document.body).css({"background-color": "#F66"}); -// } else if (s == "vote-down") { -// $(document.body).css({"background-color": "#FAA"}); -// } else if (s == "vote-up") { -// $(document.body).css({"background-color": "#AFA"}); -// } else if (s == "lock-rating") { -// $(document.body).css({"background-color": "#AA3"}); -// } else if (s == "lock-note") { -// $(document.body).css({"background-color": "#3AA"}); -// } else if (s == "approve") { -// $(document.body).css({"background-color": "#26A"}); -// } else if (s == "unapprove") { -// $(document.body).css({"background-color": "#F66"}); -// } else if (s == "add-to-pool") { -// $(document.body).css({"background-color": "#26A"}); -// } else if (s == "apply-tag-script") { -// $(document.body).css({"background-color": "#A3A"}); -// } else if (s == "edit-tag-script") { -// $(document.body).css({"background-color": "#FFF"}); -// -// var script = Cookie.get("tag-script"); -// script = prompt("Enter a tag script", script); -// -// if (script) { -// Cookie.put("tag-script", script); -// $("#mode-box select").val("apply-tag-script"); -// } else { -// $("#mode-box select").val("view"); -// } -// -// this.change(); -// } else { -// $(document.body).css({"background-color": "#AFA"}); -// } -// }, -// -// click: function(post_id) { -// var s = $("#mode-box select").val(); -// -// if (s.value == "view") { -// return true; -// } else if (s.value == "add-fav") { -// Favorite.create(post_id); -// } else if (s.value == "remove-fav") { -// Favorite.destroy(post_id); -// } else if (s.value == "edit") { -// // TODO -// } else if (s.value == 'vote-down') { -// PostVote.create("down", post_id); -// } else if (s.value == 'vote-up') { -// PostVote.create("up", post_id); -// } else if (s.value == 'rating-q') { -// Post.update(post_id, {"post[rating]": "questionable"}); -// } else if (s.value == 'rating-s') { -// Post.update(post_id, {"post[rating]": "safe"}); -// } else if (s.value == 'rating-e') { -// Post.update(post_id, {"post[rating]": "explicit"}); -// } else if (s.value == 'lock-rating') { -// Post.update(post_id, {"post[is_rating_locked]": "1"}); -// } else if (s.value == 'lock-note') { -// Post.update(post_id, {"post[is_note_locked]": "1"}); -// } else if (s.value == 'unapprove') { -// Unapproval.create(post_id); -// } else if (s.value == "approve") { -// Post.update(post_id, {"post[is_pending]": "0"}); -// } else if (s.value == 'add-to-pool') { -// Pool.add_post(post_id, 0); -// } else if (s.value == "apply-tag-script") { -// var tag_script = Cookie.get("tag-script"); -// TagScript.run(post_id, tag_script); -// } -// -// return false; -// } -// } -// -// TagScript = { -// parse: function(script) { -// return script.match(/\[.+?\]|\S+/g); -// }, -// -// test: function(tags, predicate) { -// var split_pred = predicate.match(/\S+/g); -// var is_true = true; -// -// split_pred.each(function(x) { -// if (x[0] == "-") { -// if (tags.include(x.substr(1, 100))) { -// is_true = false; -// throw $break; -// } -// } else { -// if (!tags.include(x)) { -// is_true = false; -// throw $break; -// } -// } -// }) -// -// return is_true -// }, -// -// process: function(tags, command) { -// if (command.match(/^\[if/)) { -// var match = command.match(/\[if\s+(.+?)\s*,\s*(.+?)\]/) -// if (TagScript.test(tags, match[1])) { -// return TagScript.process(tags, match[2]); -// } else { -// return tags; -// } -// } else if (command == "[reset]") { -// return []; -// } else if (command[0] == "-") { -// return tags.reject(function(x) {return x == command.substr(1, 100)}) -// } else { -// tags.push(command) -// return tags; -// } -// }, -// -// run: function(post_id, tag_script) { -// var commands = TagScript.parse(tag_script); -// var post = Post.posts.get(post_id); -// var old_tags = post.tags.join(" "); -// -// commands.each(function(x) { -// post.tags = TagScript.process(post.tags, x); -// }) -// -// Post.update(post_id, {"post[old_tags]": old_tags, "post[tags]": post.tags.join(" ")}); -// } -// } - (function() { Danbooru.Post = {}; + Danbooru.Post.pending_update_count = 0; + Danbooru.Post.initialize_all = function() { this.initialize_post_sections(); this.initialize_wiki_page_excerpt(); @@ -192,7 +30,7 @@ Danbooru.Cookie.put("hide-wiki-page-excerpt", "0"); }); } - + Danbooru.Post.initialize_post_sections = function() { $("#post-sections li a").click(function(e) { $("#comments").hide(); @@ -209,11 +47,68 @@ $("#notes").hide(); $("#edit").hide(); } + + Danbooru.Post.notice_update = function(x) { + if (x === "inc") { + Danbooru.Post.pending_update_count += 1; + Danbooru.notice("Updating posts (" + Danbooru.Post.pending_update_count + " pending)..."); + } else { + Danbooru.Post.pending_update_count -= 1; + + if (Danbooru.Post.pending_update_count < 1) { + Danbooru.notice("Posts updated"); + } else { + Danbooru.notice("Updating posts (" + Post.pending_update_count + " pending)..."); + } + } + } + + Danbooru.Post.update_data = function(data) { + var $post = $("#post_" + data.id); + $post.data("tags", data.tags); + } + + Danbooru.Post.vote = function(score, id) { + Danbooru.Post.notice_update("inc"); + + $.ajax({ + type: "POST", + url: "/posts/" + id + "/votes", + data: { + score: score + }, + complete: function() { + Danbooru.Post.notice_update("dec"); + }, + success: function(data, status, xhr) { + $("post-score-" + data.post_id).html(data.score); + }, + error: function(data, status, xhr) { + Danbooru.notice("Error: " + data.reason); + } + }); + } + + Danbooru.Post.update = function(post_id, params) { + Danbooru.Post.notice_update("inc"); + + $.ajax({ + type: "PUT", + url: "/posts/" + post_id + ".json", + data: params, + complete: function() { + Danbooru.Post.notice_update("dec"); + }, + success: function(data, status, xhr) { + Danbooru.Post.update_data(data); + }, + error: function(data, status, xhr) { + Danbooru.j_alert("Error: " + data.reason); + } + }); + } })(); $(document).ready(function() { - // $("#mode-box select").click(PostModeMenu.change); - // PostModeMenu.init(); - Danbooru.Post.initialize_all(); }); diff --git a/app/assets/javascripts/tag_script.js b/app/assets/javascripts/tag_script.js new file mode 100644 index 000000000..20e8ffa46 --- /dev/null +++ b/app/assets/javascripts/tag_script.js @@ -0,0 +1,56 @@ +TagScript = { + parse: function(script) { + return script.match(/\[.+?\]|\S+/g); + }, + + test: function(tags, predicate) { + var split_pred = predicate.match(/\S+/g); + var is_true = true; + + split_pred.each(function(x) { + if (x[0] == "-") { + if (tags.include(x.substr(1, 100))) { + is_true = false; + throw $break; + } + } else { + if (!tags.include(x)) { + is_true = false; + throw $break; + } + } + }) + + return is_true + }, + + process: function(tags, command) { + if (command.match(/^\[if/)) { + var match = command.match(/\[if\s+(.+?)\s*,\s*(.+?)\]/) + if (TagScript.test(tags, match[1])) { + return TagScript.process(tags, match[2]); + } else { + return tags; + } + } else if (command == "[reset]") { + return []; + } else if (command[0] == "-") { + return tags.reject(function(x) {return x == command.substr(1, 100)}) + } else { + tags.push(command) + return tags; + } + }, + + run: function(post_id, tag_script) { + var commands = TagScript.parse(tag_script); + var post = Post.posts.get(post_id); + var old_tags = post.tags.join(" "); + + commands.each(function(x) { + post.tags = TagScript.process(post.tags, x); + }) + + Post.update(post_id, {"post[old_tags]": old_tags, "post[tags]": post.tags.join(" ")}); + } +} \ No newline at end of file diff --git a/app/assets/javascripts/utility.js b/app/assets/javascripts/utility.js index bae2db7cf..712f58bbc 100644 --- a/app/assets/javascripts/utility.js +++ b/app/assets/javascripts/utility.js @@ -3,6 +3,10 @@ return $("meta[name=" + key + "]").attr("content"); } + Danbooru.notice = function(msg) { + $('#notice').html(msg).show(); + } + Danbooru.j_alert = function(title, msg) { $('
').html(msg).dialog(); } diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index 098fea73d..9a805d5ab 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -1108,3 +1108,69 @@ div#news-ticker { float: right; } } + + +/*** post mode menus ***/ +body#mode-view { + background-color: "#FFF"; +} + +body#mode-edit { + background-color: "#3A3"; +} + +body#mode-add-fav { + background-color: "#FFA"; +} + +body#mode-remove-fav { + background-color: "#FFA"; +} + +body#mode-rating-q { + background-color: "#AAA"; +} + +body#mode-rating-s { + background-color: "#6F6"; +} + +body#mode-rating-e { + background-color: "#F66"; +} + +body#mode-vote-down { + background-color: "#FAA"; +} + +body#mode-vote-up { + background-color: "#AFA"; +} + +body#mode-lock-rating { + background-color: "#AA3"; +} + +body#mode-lock-note { + background-color: "#3AA"; +} + +body#mode-approve { + background-color: "#26A"; +} + +body#mode-unapprove { + background-color: "#F66"; +} + +body#mode-add-to-pool { + background-color: "#26A"; +} + +body#mode-apply-tag-script { + background-color: "#A3A"; +} + +body#mode-edit-tag-script { + background-color: "#FFF"; +} diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 7c3425f44..95304d0cc 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -62,7 +62,7 @@ protected when "uploads" /^\/post/ - when "post_versions" + when "post_versions", "explore/posts" /^\/post/ when "pool_versions" From dafe322b776a45c83a913482eceb75ec16407cb0 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 15 Aug 2011 12:14:57 -0400 Subject: [PATCH 02/40] js work --- app/assets/javascripts/post_mode_menu.js | 6 +-- app/assets/javascripts/tag_script.js | 48 ++++++++++++------------ 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/app/assets/javascripts/post_mode_menu.js b/app/assets/javascripts/post_mode_menu.js index 881eefb43..526e74f6b 100644 --- a/app/assets/javascripts/post_mode_menu.js +++ b/app/assets/javascripts/post_mode_menu.js @@ -69,11 +69,9 @@ Danbooru.Post.update(post_id, {"post[is_rating_locked]": "1"}); } else if (s === 'lock-note') { Danbooru.Post.update(post_id, {"post[is_note_locked]": "1"}); - } else if (s === 'add-to-pool') { - Pool.add_post(post_id, 0); } else if (s === "apply-tag-script") { - var tag_script = Cookie.get("tag-script"); - TagScript.run(post_id, tag_script); + var tag_script = Danbooru.Cookie.get("tag-script"); + Danbooru.TagScript.run(post_id, tag_script); } e.preventDefault(); diff --git a/app/assets/javascripts/tag_script.js b/app/assets/javascripts/tag_script.js index 20e8ffa46..0cca5fff5 100644 --- a/app/assets/javascripts/tag_script.js +++ b/app/assets/javascripts/tag_script.js @@ -1,56 +1,56 @@ -TagScript = { - parse: function(script) { - return script.match(/\[.+?\]|\S+/g); - }, +(function() { + Danbooru.TagScript = {}; - test: function(tags, predicate) { + Danbooru.TagScript.parse = function(script) { + return script.match(/\[.+?\]|\S+/g); + } + + Danbooru.TagScript.test = function(tags, predicate) { var split_pred = predicate.match(/\S+/g); var is_true = true; - split_pred.each(function(x) { - if (x[0] == "-") { + $.each(split_pred, function(i, x) { + if (x[0] === "-") { if (tags.include(x.substr(1, 100))) { is_true = false; - throw $break; } } else { if (!tags.include(x)) { is_true = false; - throw $break; } } - }) + }); - return is_true - }, + return is_true; + } - process: function(tags, command) { + Danbooru.TagScript.process = function(tags, command) { if (command.match(/^\[if/)) { var match = command.match(/\[if\s+(.+?)\s*,\s*(.+?)\]/) - if (TagScript.test(tags, match[1])) { - return TagScript.process(tags, match[2]); + if (this.test(tags, match[1])) { + return this.process(tags, match[2]); } else { return tags; } - } else if (command == "[reset]") { + } else if (command === "[reset]") { return []; - } else if (command[0] == "-") { + } else if (command[0] === "-") { return tags.reject(function(x) {return x == command.substr(1, 100)}) } else { tags.push(command) return tags; } - }, + } - run: function(post_id, tag_script) { - var commands = TagScript.parse(tag_script); + Danbooru.TagScript.run = function(post_id, tag_script) { + var commands = this.parse(tag_script); var post = Post.posts.get(post_id); var old_tags = post.tags.join(" "); - commands.each(function(x) { - post.tags = TagScript.process(post.tags, x); + $.each(commands, function(i, x) { + post.tags = Danbooru.TagScript.process(post.tags, x); }) - Post.update(post_id, {"post[old_tags]": old_tags, "post[tags]": post.tags.join(" ")}); + Danbooru.Post.update(post_id, {"post[old_tags]": old_tags, "post[tags]": post.tags.join(" ")}); } -} \ No newline at end of file +})(); From c6b1778145a29baf91adcec29f0c33c93d3e6ddf Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 15 Aug 2011 12:19:09 -0400 Subject: [PATCH 03/40] better range text for explore popular --- app/presenters/post_set_presenters/popular.rb | 12 +++++++++++- app/views/explore/posts/popular.html.erb | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/presenters/post_set_presenters/popular.rb b/app/presenters/post_set_presenters/popular.rb index 0d58f5e19..18f6c6973 100644 --- a/app/presenters/post_set_presenters/popular.rb +++ b/app/presenters/post_set_presenters/popular.rb @@ -1,7 +1,7 @@ module PostSetPresenters class Popular < Base attr_accessor :post_set, :tag_set_presenter - delegate :posts, :date, :to => :post_set + delegate :posts, :date, :min_date, :max_date, :to => :post_set def initialize(post_set) @post_set = post_set @@ -30,5 +30,15 @@ module PostSetPresenters def next_month 1.month.since(date) end + + def range_text + if min_date == max_date + date.strftime("%B %d, %Y") + elsif max_date - min_date == 6 + min_date.strftime("Week of %B %d, %Y") + else + date.strftime("Month of %B %Y") + end + end end end diff --git a/app/views/explore/posts/popular.html.erb b/app/views/explore/posts/popular.html.erb index 28440a27f..3a8cf905d 100644 --- a/app/views/explore/posts/popular.html.erb +++ b/app/views/explore/posts/popular.html.erb @@ -1,6 +1,6 @@
-

Explore: <%= @post_set.min_date %> – <%= @post_set.max_date %>

+

Explore: <%= @post_set.presenter.range_text %>

<%= render "date_explore", :post_set => @post_set %> From d32a839aa135dcb2dc4b8e9993d25a55729adec4 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 15 Aug 2011 17:10:35 -0400 Subject: [PATCH 04/40] view fixes, updated uesr profile --- app/controllers/users_controller.rb | 1 + app/models/user.rb | 2 +- app/presenters/user_presenter.rb | 20 +++++-- app/views/advertisements/edit.html.erb | 10 +++- app/views/advertisements/index.html.erb | 42 ++++++++------- app/views/advertisements/new.html.erb | 10 +++- app/views/advertisements/show.html.erb | 15 ++++-- app/views/artists/index.html.erb | 2 + app/views/bans/index.html.erb | 2 + app/views/comments/index_by_comment.html.erb | 2 + app/views/comments/search.html.erb | 1 + app/views/dmails/edit.html.erb | 9 +++- app/views/dmails/index.html.erb | 3 ++ .../posts/partials/index/_mode_menu.html.erb | 3 -- app/views/users/show.html.erb | 53 ++++++++++++++++++- 15 files changed, 138 insertions(+), 37 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index c7a319709..18350bee4 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -22,6 +22,7 @@ class UsersController < ApplicationController def show @user = User.find(params[:id]) + @presenter = UserPresenter.new(@user) respond_with(@user) end diff --git a/app/models/user.rb b/app/models/user.rb index 6d114b7ea..f496aaed8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -30,7 +30,7 @@ class User < ActiveRecord::Base has_many :feedback, :class_name => "UserFeedback", :dependent => :destroy has_many :posts, :foreign_key => "uploader_id" has_one :ban - has_many :subscriptions, :class_name => "TagSubscription" + has_many :subscriptions, :class_name => "TagSubscription", :foreign_key => "creator_id" has_many :note_versions, :foreign_key => "updater_id" belongs_to :inviter, :class_name => "User" scope :named, lambda {|name| where(["lower(name) = ?", name])} diff --git a/app/presenters/user_presenter.rb b/app/presenters/user_presenter.rb index 9b3fb0e64..8776e9e57 100644 --- a/app/presenters/user_presenter.rb +++ b/app/presenters/user_presenter.rb @@ -5,6 +5,10 @@ class UserPresenter @user = user end + def join_date + user.created_at.strftime("%Y-%m-%d") + end + def level user.level_string end @@ -26,7 +30,7 @@ class UserPresenter def upload_limit deleted_count = Post.for_user(user.id).deleted.count pending_count = Post.for_user(user.id).pending.count - approved_count = Post.where("is_flagged = false and is_pending = false and user_id = ?", user.id).count + approved_count = Post.where("is_flagged = false and is_pending = false and uploader_id = ?", user.id).count if user.base_upload_limit limit = user.base_upload_limit - pending_count @@ -89,7 +93,7 @@ class UserPresenter if user.inviter_id template.link_to(user.inviter.name, template.user_path(user.inviter_id)) else - nil + "None" end end @@ -102,6 +106,16 @@ class UserPresenter neutral = UserFeedback.for_user(user.id).neutral.count negative = UserFeedback.for_user(user.id).negative.count - template.link_to("positive:#{positive} neutral:#{neutral} negative:#{negative}", user_feedbacks_path(:search => {:user_id_rq => user.id})) + template.link_to("positive:#{positive} neutral:#{neutral} negative:#{negative}", template.user_feedbacks_path(:search => {:user_id_rq => user.id})) + end + + def subscriptions(template) + if user.subscriptions.any? + user.subscriptions.map do |subscription| + template.link_to(subscription.name, template.posts_path(:tags => "sub:#{user.name}:#{subscription.name}")) + end.join(", ").html_safe + else + "None" + end end end diff --git a/app/views/advertisements/edit.html.erb b/app/views/advertisements/edit.html.erb index ca4e7466b..61a745a01 100644 --- a/app/views/advertisements/edit.html.erb +++ b/app/views/advertisements/edit.html.erb @@ -1,3 +1,9 @@ -<%= image_tag(@advertisement.image_url) %> -<%= render "form" %> +
+
+

Edit Advertisement

+ <%= image_tag(@advertisement.image_url) %> + <%= render "form" %> +
+
+ <%= render "secondary_links" %> diff --git a/app/views/advertisements/index.html.erb b/app/views/advertisements/index.html.erb index 17a5381db..3ee38a416 100644 --- a/app/views/advertisements/index.html.erb +++ b/app/views/advertisements/index.html.erb @@ -1,22 +1,26 @@ -

Advertisements

+
+
+

Advertisements

- - - - - - - - - - <% @advertisements.each do |advertisement| %> - - - - - - <% end %> - -
Hits
<%= image_tag(advertisement.image_url, :width => advertisement.preview_width, :height => advertisement.preview_height) %><%= advertisement.hits.between(@start_date, @end_date).count %><%= link_to "Edit", edit_advertisement_path(advertisement) %>
+ + + + + + + + + + <% @advertisements.each do |advertisement| %> + + + + + + <% end %> + +
Hits
<%= image_tag(advertisement.image_url, :width => advertisement.preview_width, :height => advertisement.preview_height) %><%= advertisement.hits.between(@start_date, @end_date).count %><%= link_to "Edit", edit_advertisement_path(advertisement) %>
+
+
<%= render "secondary_links" %> diff --git a/app/views/advertisements/new.html.erb b/app/views/advertisements/new.html.erb index 319fd8451..0bf018729 100644 --- a/app/views/advertisements/new.html.erb +++ b/app/views/advertisements/new.html.erb @@ -1,3 +1,9 @@ -<%= error_messages_for :advertisement %> -<%= render "form" %> +
+
+

New Advertisement

+ <%= error_messages_for :advertisement %> + <%= render "form" %> +
+
+ <%= render "secondary_links" %> diff --git a/app/views/advertisements/show.html.erb b/app/views/advertisements/show.html.erb index 302d08888..0248fc5ca 100644 --- a/app/views/advertisements/show.html.erb +++ b/app/views/advertisements/show.html.erb @@ -1,7 +1,14 @@ -
<%= image_tag(@advertisement.image_url, :width => @advertisement.preview_width, :height => @advertisement.preview_height) %>
+
+
+

Show Advertisement

+ + <%= image_tag(@advertisement.image_url, :width => @advertisement.preview_width, :height => @advertisement.preview_height) %> + +
    +
  • Hits: <%= @advertisement.hits.between(@start_date, @end_date).count %>
  • +
+
+
-
    -
  • Hits: <%= @advertisement.hits.between(@start_date, @end_date).count %>
  • -
<%= render "secondary_links" %> diff --git a/app/views/artists/index.html.erb b/app/views/artists/index.html.erb index 9de28e6bc..003ef1a7d 100644 --- a/app/views/artists/index.html.erb +++ b/app/views/artists/index.html.erb @@ -1,5 +1,7 @@
+

Artists

+ diff --git a/app/views/bans/index.html.erb b/app/views/bans/index.html.erb index 11f8196fa..6f15f1670 100644 --- a/app/views/bans/index.html.erb +++ b/app/views/bans/index.html.erb @@ -1,5 +1,7 @@
+

Bans

+
diff --git a/app/views/comments/index_by_comment.html.erb b/app/views/comments/index_by_comment.html.erb index 1360609df..b91a566ac 100644 --- a/app/views/comments/index_by_comment.html.erb +++ b/app/views/comments/index_by_comment.html.erb @@ -1,5 +1,7 @@
+

Comments

+
<% @comments.each do |comment| %> diff --git a/app/views/comments/search.html.erb b/app/views/comments/search.html.erb index f287ed913..9b514fca1 100644 --- a/app/views/comments/search.html.erb +++ b/app/views/comments/search.html.erb @@ -1,6 +1,7 @@
-<%= render "comments/secondary_links" %> \ No newline at end of file +<%= render "comments/secondary_links" %> diff --git a/app/views/comments/partials/index/_list.html.erb b/app/views/comments/partials/index/_list.html.erb index f80b48599..6cf5d0a19 100644 --- a/app/views/comments/partials/index/_list.html.erb +++ b/app/views/comments/partials/index/_list.html.erb @@ -1,6 +1,6 @@
<% if show_header %> - <%= render :partial => "comments/partials/index/header", :locals => {:post => post} %> + <%= render "comments/partials/index/header", :post => post %> <% end %>
@@ -15,6 +15,6 @@

<%= link_to "Post comment", new_comment_path, :class => "expand-comment-response" %>

- <%= render :partial => "comments/partials/new/form", :locals => {:post => post} %> + <%= render "comments/partials/new/form", :post => post %>
diff --git a/app/views/dmails/index.html.erb b/app/views/dmails/index.html.erb index 9c52b92ee..084a8e3a6 100644 --- a/app/views/dmails/index.html.erb +++ b/app/views/dmails/index.html.erb @@ -1,18 +1,19 @@
- +
+

Messages

+ + <%= render "search" %> + +
+ + <% @dmails.each do |dmail| %> + <% if params[:folder] == "sent" %> + <%= render "sent", :dmail => dmail %> + <% else %> + <%= render "received", :dmail => dmail %> + <% end %> + <% end %> + +
+
-

Messages

- -<%= render "search" %> - - - - <% @dmails.each do |dmail| %> - <% if params[:folder] == "sent" %> - <%= render :partial => "sent", :locals => {:dmail => dmail} %> - <% else %> - <%= render :partial => "received", :locals => {:dmail => dmail} %> - <% end %> - <% end %> - -
diff --git a/app/views/dmails/new.html.erb b/app/views/dmails/new.html.erb index afb9d2004..2105c426e 100644 --- a/app/views/dmails/new.html.erb +++ b/app/views/dmails/new.html.erb @@ -1,2 +1,7 @@ -

New Message

-<%= render :partial => "form", :locals => {:dmail => @dmail} %> +
+
+

New Message

+ <%= render "form", :dmail => @dmail %> +
+
+ diff --git a/app/views/dmails/show.html.erb b/app/views/dmails/show.html.erb index d4b5f2e80..7fcf4306b 100644 --- a/app/views/dmails/show.html.erb +++ b/app/views/dmails/show.html.erb @@ -1,8 +1,9 @@ -
-
+
+

<%= @dmail.title %>

<%= format_text(@dmail.body) %> +

<%= link_to "Respond", new_dmail_path(:respond_to_id => @dmail) %> | <%= link_to "Forward", new_dmail_path(:respond_to_id => @dmail, :forward => true) %> diff --git a/app/views/favorites/index.html.erb b/app/views/favorites/index.html.erb index 26c97dbcf..007c0b56c 100644 --- a/app/views/favorites/index.html.erb +++ b/app/views/favorites/index.html.erb @@ -1,11 +1,11 @@

diff --git a/app/views/forum_posts/_listing.html.erb b/app/views/forum_posts/_listing.html.erb index f297c0f7f..9ccfcf307 100644 --- a/app/views/forum_posts/_listing.html.erb +++ b/app/views/forum_posts/_listing.html.erb @@ -1,6 +1,6 @@
<% forum_posts.each do |forum_post| %> - <%= render :partial => "forum_posts/forum_post", :locals => {:forum_post => forum_post} %> + <%= render "forum_posts/forum_post", :forum_post => forum_post %> <% end %>
diff --git a/app/views/forum_posts/show.html.erb b/app/views/forum_posts/show.html.erb index 7240c2d1b..a64619f91 100644 --- a/app/views/forum_posts/show.html.erb +++ b/app/views/forum_posts/show.html.erb @@ -1,6 +1,6 @@
- <%= render :partial => "forum_post", :locals => {:forum_post => @forum_post} %> + <%= render "forum_post", :forum_post => @forum_post %>
diff --git a/app/views/forum_topics/index.html.erb b/app/views/forum_topics/index.html.erb index c03170149..f1ed11ebc 100644 --- a/app/views/forum_topics/index.html.erb +++ b/app/views/forum_topics/index.html.erb @@ -1,24 +1,28 @@ -

Forum

+
+
+

Forum

- - - - - - - - - - - <% @forum_topics.each do |topic| %> - - - - - - - <% end %> - -
TitleCreatorUpdated byUpdated at
<% if topic.is_sticky? %>Sticky: <% end %><%= link_to topic.title, forum_topic_path(topic) %><%= topic.creator.name %><%= topic.updater.name %><%= compact_time topic.updated_at %>
+ + + + + + + + + + + <% @forum_topics.each do |topic| %> + + + + + + + <% end %> + +
TitleCreatorUpdated byUpdated at
<% if topic.is_sticky? %>Sticky: <% end %><%= link_to topic.title, forum_topic_path(topic) %><%= topic.creator.name %><%= topic.updater.name %><%= compact_time topic.updated_at %>
+
+
<%= render "secondary_links" %> \ No newline at end of file diff --git a/app/views/forum_topics/show.html.erb b/app/views/forum_topics/show.html.erb index 457f897fe..41a8d4a96 100644 --- a/app/views/forum_topics/show.html.erb +++ b/app/views/forum_topics/show.html.erb @@ -6,7 +6,7 @@
<% end %> - <%= render :partial => "forum_posts/listing", :locals => {:forum_posts => @forum_posts} %> + <%= render "forum_posts/listing", :forum_posts => @forum_posts %> <%= render "paginator" %>
@@ -14,5 +14,5 @@ <%= render "secondary_links" %> <%= content_for(:page_title) do %> -forum/<%= @forum_topic.title %> + forum/<%= @forum_topic.title %> <% end %> \ No newline at end of file diff --git a/app/views/ip_bans/index.html.erb b/app/views/ip_bans/index.html.erb index 693cf2c79..1dde3dd6a 100644 --- a/app/views/ip_bans/index.html.erb +++ b/app/views/ip_bans/index.html.erb @@ -1,22 +1,27 @@ -

IP Bans

+
+
+

IP Bans

+ + + + + + + + + + + + <% @ip_bans.each do |ip_ban| %> + + + + + + + <% end %> + +
IP AddressBannerReason
<%= ip_ban.ip_addr %><%= ip_ban.creator.name %><%= ip_ban.reason %><%= link_to "Unban", ip_ban_path(ip_ban), :remote => true, :method => :delete, :confirm => "Do your really want to unban #{ip_ban.creator.name}?" %>
+
+
- - - - - - - - - - - <% @ip_bans.each do |ip_ban| %> - - - - - - - <% end %> - -
IP AddressBannerReason
<%= ip_ban.ip_addr %><%= ip_ban.creator.name %><%= ip_ban.reason %><%= link_to "Unban", ip_ban_path(ip_ban), :remote => true, :method => :delete, :confirm => "Do your really want to unban #{ip_ban.creator.name}?" %>
diff --git a/app/views/ip_bans/new.html.erb b/app/views/ip_bans/new.html.erb index e1a05b1a8..24831b118 100644 --- a/app/views/ip_bans/new.html.erb +++ b/app/views/ip_bans/new.html.erb @@ -1,7 +1,11 @@ -

New IP Ban

+
+
+

New IP Ban

-<%= simple_form_for(@ip_ban) do |f| %> - <%= f.input :ip_addr %> - <%= f.input :reason %> - <%= f.button :submit %> -<% end %> + <%= simple_form_for(@ip_ban) do |f| %> + <%= f.input :ip_addr %> + <%= f.input :reason %> + <%= f.button :submit %> + <% end %> +
+
diff --git a/app/views/janitor_trials/index.html.erb b/app/views/janitor_trials/index.html.erb index e33cd33ae..cc5949421 100644 --- a/app/views/janitor_trials/index.html.erb +++ b/app/views/janitor_trials/index.html.erb @@ -1,23 +1,27 @@ -

Janitor Trials

+
+
+

Janitor Trials

- - - - - - - - - - <% @janitor_trials.each do |janitor_trial| %> - - - - - - <% end %> - -
UserDuration
<%= janitor_trial.user.name %><%= janitor_trial.created_at %> - <%= link_to "Promote", promote_janitor_trial_path(janitor_trial), :remote => true, :method => :put %> - | <%= link_to "Demote", demote_janitor_trial_path(janitor_trial), :remote => true, :method => :put %> -
+ + + + + + + + + + <% @janitor_trials.each do |janitor_trial| %> + + + + + + <% end %> + +
UserDuration
<%= janitor_trial.user.name %><%= janitor_trial.created_at %> + <%= link_to "Promote", promote_janitor_trial_path(janitor_trial), :remote => true, :method => :put %> + | <%= link_to "Demote", demote_janitor_trial_path(janitor_trial), :remote => true, :method => :put %> +
+
+
diff --git a/app/views/janitor_trials/new.html.erb b/app/views/janitor_trials/new.html.erb index e4e4edf3e..c23737be5 100644 --- a/app/views/janitor_trials/new.html.erb +++ b/app/views/janitor_trials/new.html.erb @@ -1,6 +1,10 @@ -

New Janitor Trial

+
+
+

New Janitor Trial

-<%= simple_form_for(@janitor_trial) do |f| %> - <%= f.input :user_id %> - <%= f.button :submit %> -<% end %> + <%= simple_form_for(@janitor_trial) do |f| %> + <%= f.input :user_id %> + <%= f.button :submit %> + <% end %> +
+
diff --git a/app/views/moderator/post/dashboards/show.html.erb b/app/views/moderator/post/dashboards/show.html.erb index e42286898..0e660fb6b 100644 --- a/app/views/moderator/post/dashboards/show.html.erb +++ b/app/views/moderator/post/dashboards/show.html.erb @@ -38,4 +38,4 @@
-<%= render :partial => "posts/partials/common/secondary_links" %> \ No newline at end of file +<%= render "posts/partials/common/secondary_links" %> \ No newline at end of file diff --git a/app/views/news/_listing.html.erb b/app/views/news/_listing.html.erb index 82572c6db..6ffdf89f9 100644 --- a/app/views/news/_listing.html.erb +++ b/app/views/news/_listing.html.erb @@ -1,4 +1,4 @@ -
+
diff --git a/app/views/note_versions/index.html.erb b/app/views/note_versions/index.html.erb index a8cac5001..8b10fdfa6 100644 --- a/app/views/note_versions/index.html.erb +++ b/app/views/note_versions/index.html.erb @@ -35,7 +35,7 @@ <%= sequential_paginator(@note_versions) %> - <%= render :partial => "notes/secondary_links" %> + <%= render "notes/secondary_links" %>
diff --git a/app/views/pool_orders/edit.html.erb b/app/views/pool_orders/edit.html.erb index 0d2bb7a5b..978e3c2bc 100644 --- a/app/views/pool_orders/edit.html.erb +++ b/app/views/pool_orders/edit.html.erb @@ -17,4 +17,4 @@
-<%= render :partial => "pools/secondary_links" %> +<%= render "pools/secondary_links" %> diff --git a/app/views/pool_versions/index.html.erb b/app/views/pool_versions/index.html.erb index 67e6ffe38..b6c4c0e09 100644 --- a/app/views/pool_versions/index.html.erb +++ b/app/views/pool_versions/index.html.erb @@ -37,4 +37,4 @@ -<%= render :partial => "pools/secondary_links" %> +<%= render "pools/secondary_links" %> diff --git a/app/views/post_appeals/new.html.erb b/app/views/post_appeals/new.html.erb index 178aa543c..9f19935e1 100644 --- a/app/views/post_appeals/new.html.erb +++ b/app/views/post_appeals/new.html.erb @@ -1,17 +1,21 @@ -

If this post was automatically deleted, then it means at least ten janitors all thought it didn't belong on the site. If you still believe this image was wrongfully deleted, then you can appeal its deletion.

+
+
+

If this post was automatically deleted, then it means at least ten janitors all thought it didn't belong on the site. If you still believe this image was wrongfully deleted, then you can appeal its deletion.

-

Some valid reasons for appealing include:

+

Some valid reasons for appealing include:

-
    -
  • Funny
  • -
  • Weird
  • -
  • Translated
  • -
  • Part of a pool
  • -
+
    +
  • Funny
  • +
  • Weird
  • +
  • Translated
  • +
  • Part of a pool
  • +
-

All users are limited to 5 appeals a day. For more details, please read the <%= link_to "wiki", wiki_pages_path(:title => "help:deletion_appeals") %>.

+

All users are limited to 5 appeals a day. For more details, please read the <%= link_to "wiki", wiki_pages_path(:title => "help:deletion_appeals") %>.

-<%= simple_form_for(@post_appeal, :remote => true, :format => :js) do |f| %> - <%= hidden_field_tag "post_appeal[post_id]", @post_appeal.post_id %> - <%= f.text_field :reason, :size => "40x5" %> -<% end %> + <%= simple_form_for(@post_appeal, :remote => true, :format => :js) do |f| %> + <%= hidden_field_tag "post_appeal[post_id]", @post_appeal.post_id %> + <%= f.text_field :reason, :size => "40x5" %> + <% end %> +
+
diff --git a/app/views/post_flags/new.html.erb b/app/views/post_flags/new.html.erb index 6a588637b..726bcb351 100644 --- a/app/views/post_flags/new.html.erb +++ b/app/views/post_flags/new.html.erb @@ -1,25 +1,29 @@ -

If you believe a post does not belong on this site, you can flag for its deletion. As a reminder, the following are some common reasons for flagging a post:

+
+
+

If you believe a post does not belong on this site, you can flag for its deletion. As a reminder, the following are some common reasons for flagging a post:

-
    -
  • Not anime-related
  • -
  • Furry: a character has body fur or an animal face
  • -
  • Watermark: text or logo inserted by someone besides the original artist
  • -
  • Poor compression: JPEG artifacts
  • -
  • Guro: mutilation, extreme bodily distension
  • -
  • Bad proportions: extremely large breasts or penises
  • -
  • Manga: Multiple pages of a manga, doujinshi, or comic that don't stand up to individual scrutiny
  • -
  • Fake translations: Made up translations are banned
  • -
+
    +
  • Not anime-related
  • +
  • Furry: a character has body fur or an animal face
  • +
  • Watermark: text or logo inserted by someone besides the original artist
  • +
  • Poor compression: JPEG artifacts
  • +
  • Guro: mutilation, extreme bodily distension
  • +
  • Bad proportions: extremely large breasts or penises
  • +
  • Manga: Multiple pages of a manga, doujinshi, or comic that don't stand up to individual scrutiny
  • +
  • Fake translations: Made up translations are banned
  • +
-

The following are NOT valid reasons for flagging a post:

+

The following are NOT valid reasons for flagging a post:

-
    -
  • Duplicate: just parent to the original
  • -
+
    +
  • Duplicate: just parent to the original
  • +
-

Enter a reason:

+

Enter a reason:

-<%= simple_form_for(@post_flag, :remote => true, :format => :js) do |f| %> - <%= f.input :post_id, :as => :hidden %> - <%= f.text_field :reason %> -<% end %> + <%= simple_form_for(@post_flag, :remote => true, :format => :js) do |f| %> + <%= f.input :post_id, :as => :hidden %> + <%= f.text_field :reason %> + <% end %> +
+
diff --git a/app/views/post_versions/index.html.erb b/app/views/post_versions/index.html.erb index a3f4e69f0..54f0a56fa 100644 --- a/app/views/post_versions/index.html.erb +++ b/app/views/post_versions/index.html.erb @@ -11,7 +11,7 @@ <% if @post_versions.empty? %> <%= render "post_sets/blank" %> <% else %> - <%= render :partial => "listing", :locals => {:post_versions => @post_versions} %> + <%= render"listing", :post_versions => @post_versions %> <% end %> diff --git a/app/views/posts/index.html.erb b/app/views/posts/index.html.erb index dcfb18e8a..1fd067734 100644 --- a/app/views/posts/index.html.erb +++ b/app/views/posts/index.html.erb @@ -1,28 +1,28 @@
- <%= render :partial => "wiki_pages/excerpt", :locals => {:post_set => @post_set} %> - <%= render :partial => "posts/partials/index/posts", :locals => {:post_set => @post_set} %> + <%= render "wiki_pages/excerpt", :post_set => @post_set %> + <%= render "posts/partials/index/posts", :post_set => @post_set %>
<% content_for(:page_title) do %> /<%= @post_set.tag_string %> <% end %> - <%= render :partial => "posts/partials/common/secondary_links" %> + <%= render "posts/partials/common/secondary_links" %>
diff --git a/app/views/posts/show.html.erb b/app/views/posts/show.html.erb index 487bb8009..708c0f54f 100644 --- a/app/views/posts/show.html.erb +++ b/app/views/posts/show.html.erb @@ -1,12 +1,12 @@
- <%= render :partial => "posts/partials/show/notices", :locals => {:post => @post} %> + <%= render "posts/partials/show/notices", :post => @post %>
@@ -50,7 +50,7 @@
- <%= render :partial => "comments/partials/index/list", :locals => {:comments => @post.comments, :post => @post, :show_header => false} %> + <%= render "comments/partials/index/list", :comments => @post.comments, :post => @post, :show_header => false %>
@@ -62,7 +62,7 @@
- <%= render :partial => "posts/partials/show/edit", :locals => {:post => @post} %> + <%= render "posts/partials/show/edit", :post => @post %>
@@ -93,4 +93,4 @@ <% end %> -<%= render :partial => "posts/partials/common/secondary_links" %> +<%= render "posts/partials/common/secondary_links" %> diff --git a/app/views/report/common.html.erb b/app/views/report/common.html.erb deleted file mode 100644 index fe7889d59..000000000 --- a/app/views/report/common.html.erb +++ /dev/null @@ -1,66 +0,0 @@ -

Report: <%= @report_title %>

- -
-
- <% form_tag({:action => params[:action]}, :method => :get) do %> - - - - - - - - - - - - - - - - - - - - - - - - -
<%= submit_tag "Search" %>
<%= text_field_tag "start_date", @start_date, :size => 10 %>
<%= text_field_tag "end_date", @end_date, :size => 10 %>
<%= text_field_tag "limit", @limit, :size => 5 %>
<%= user_level_select_tag "level", :include_blank => true %>
- <% end %> -
- -
- - - - - - - - - - - - - - - <% @users.each do |user| %> - - - - - - <% end %> - -
UserChangesPercentage
Total<%= @users[0]["sum"].to_i %>
<%= link_to_unless user["id"].nil?, h(user["name"]), :controller => "user", :action => "show", :id => user["id"] %><%= link_to_unless user["id"].nil?, user["change_count"], @change_params.call(user["id"]) %><%= number_to_percentage 100 * user["change_count"] / user["sum"], :precision => 1 %>
-
-
- -<% content_for("subnavbar") do %> -
  • <%= link_to "Tags", :action => "tag_updates", :start_date => @start_date, :end_date => @end_date %>
  • -
  • <%= link_to "Notes", :action => "note_updates", :start_date => @start_date, :end_date => @end_date %>
  • -
  • <%= link_to "Wiki", :action => "wiki_updates", :start_date => @start_date, :end_date => @end_date %>
  • -
  • <%= link_to "Uploads", :action => "post_uploads", :start_date => @start_date, :end_date => @end_date %>
  • -<% end %> diff --git a/app/views/report/tag_history.html.erb b/app/views/report/tag_history.html.erb deleted file mode 100644 index 6fe89e644..000000000 --- a/app/views/report/tag_history.html.erb +++ /dev/null @@ -1,40 +0,0 @@ - - -<% form_tag({:action => "tag_history"}, :method => :get) do %> - - - - - - - - - - - - - - - - - - -
    Tags<%= text_field_tag "tag", params[:tag], :size => 50 %>
    Start Date<%= text_field_tag "start_date", @start_date %>
    End Date<%= text_field_tag "end_date", @end_date %>
    <%= submit_tag "Search" %>
    -<% end %> - -
    - -<% if @counts %> - -<% end %> \ No newline at end of file diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb index 078a0a7e4..01dac73fe 100644 --- a/app/views/sessions/new.html.erb +++ b/app/views/sessions/new.html.erb @@ -1,5 +1,5 @@ -
    -
    +
    +

    Login

    <%= form_tag(session_path, :class => "simple_form") do %> diff --git a/app/views/tag_subscriptions/posts.html.erb b/app/views/tag_subscriptions/posts.html.erb index f9bb2133b..83d2cc802 100644 --- a/app/views/tag_subscriptions/posts.html.erb +++ b/app/views/tag_subscriptions/posts.html.erb @@ -1,11 +1,11 @@
    @@ -20,7 +20,7 @@ /fav:<%= CurrentUser.name %> <% end %> - <%= render :partial => "posts/partials/common/secondary_links" %> + <%= render "posts/partials/common/secondary_links" %>
    diff --git a/app/views/uploads/index.html.erb b/app/views/uploads/index.html.erb index 4e69ab83e..6d5f4b727 100644 --- a/app/views/uploads/index.html.erb +++ b/app/views/uploads/index.html.erb @@ -27,4 +27,4 @@
    -<%= render :partial => "posts/partials/common/secondary_links" %> \ No newline at end of file +<%= render "posts/partials/common/secondary_links" %> \ No newline at end of file diff --git a/app/views/uploads/new.html.erb b/app/views/uploads/new.html.erb index a0d898bac..a32419019 100644 --- a/app/views/uploads/new.html.erb +++ b/app/views/uploads/new.html.erb @@ -59,4 +59,4 @@ / Upload <% end %> -<%= render :partial => "posts/partials/common/secondary_links" %> +<%= render "posts/partials/common/secondary_links" %> diff --git a/app/views/uploads/show.html.erb b/app/views/uploads/show.html.erb index 97a0ee0ea..589fad3f1 100644 --- a/app/views/uploads/show.html.erb +++ b/app/views/uploads/show.html.erb @@ -21,4 +21,4 @@ <% end %>

    -<%= render :partial => "posts/partials/common/secondary_links" %> +<%= render "posts/partials/common/secondary_links" %> diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index b043d0852..08902ef97 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -51,4 +51,4 @@
    -<%= render :partial => "secondary_links" %> \ No newline at end of file +<%= render "secondary_links" %> \ No newline at end of file diff --git a/app/views/wiki_page_versions/index.html.erb b/app/views/wiki_page_versions/index.html.erb index 13706c24d..633788e5f 100644 --- a/app/views/wiki_page_versions/index.html.erb +++ b/app/views/wiki_page_versions/index.html.erb @@ -1,6 +1,6 @@
    - <%= render :partial => "wiki_pages/sidebar" %> + <%= render "wiki_pages/sidebar" %>

    Wiki Pages

    @@ -37,4 +37,4 @@
    -<%= render :partial => "wiki_pages/secondary_links" %> +<%= render "wiki_pages/secondary_links" %> diff --git a/app/views/wiki_pages/index.html.erb b/app/views/wiki_pages/index.html.erb index 5444615bc..6b003f441 100644 --- a/app/views/wiki_pages/index.html.erb +++ b/app/views/wiki_pages/index.html.erb @@ -1,6 +1,6 @@
    - <%= render :partial => "sidebar" %> + <%= render "sidebar" %>

    Wiki Pages

    diff --git a/script/delayed_job b/script/delayed_job new file mode 100755 index 000000000..edf195985 --- /dev/null +++ b/script/delayed_job @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby + +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) +require 'delayed/command' +Delayed::Command.new(ARGV).daemonize From 2b7a8f2d67d9b25fd0a2ec68ac4fa1acdeca76c3 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 22 Aug 2011 16:28:31 -0400 Subject: [PATCH 08/40] view changes --- Gemfile | 3 ++- Gemfile.lock | 4 ++++ app/assets/javascripts/tag_script.js | 10 +++++----- app/assets/javascripts/uploads.js | 4 ++-- app/assets/javascripts/utility.js | 10 ++++++++++ app/assets/stylesheets/application.css.scss | 1 + app/controllers/artists_controller.rb | 5 +++++ app/models/artist.rb | 4 ++++ app/views/artists/banned.html.erb | 13 +++++++++++++ config/routes.rb | 1 + 10 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 app/views/artists/banned.html.erb diff --git a/Gemfile b/Gemfile index ce006c104..f140d19f0 100644 --- a/Gemfile +++ b/Gemfile @@ -24,4 +24,5 @@ gem "mechanize" gem "nokogiri" gem "meta_search", :git => "git://github.com/ernie/meta_search.git" gem "silent-postgres" -gem "whenever", :require => false \ No newline at end of file +gem "whenever", :require => false +gem "bourbon" diff --git a/Gemfile.lock b/Gemfile.lock index 352b3e780..b482da19f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -48,6 +48,8 @@ GEM multi_json (~> 1.0) arel (2.1.4) bcrypt-ruby (2.1.4) + bourbon (0.1.5) + sass (>= 3.1) builder (3.0.0) daemons (1.1.4) delayed_job (2.1.4) @@ -103,6 +105,7 @@ GEM thor (~> 0.14.6) rake (0.9.2) rdoc (3.9.1) + sass (3.1.7) shoulda (2.11.3) silent-postgres (0.0.8) simple_form (1.4.2) @@ -134,6 +137,7 @@ PLATFORMS ruby DEPENDENCIES + bourbon delayed_job factory_girl ffaker! diff --git a/app/assets/javascripts/tag_script.js b/app/assets/javascripts/tag_script.js index 0cca5fff5..7efe2be24 100644 --- a/app/assets/javascripts/tag_script.js +++ b/app/assets/javascripts/tag_script.js @@ -35,7 +35,7 @@ } else if (command === "[reset]") { return []; } else if (command[0] === "-") { - return tags.reject(function(x) {return x == command.substr(1, 100)}) + return Danbooru.reject(tags, function(x) {return x === command.substr(1, 100)}); } else { tags.push(command) return tags; @@ -44,13 +44,13 @@ Danbooru.TagScript.run = function(post_id, tag_script) { var commands = this.parse(tag_script); - var post = Post.posts.get(post_id); - var old_tags = post.tags.join(" "); + var post = $("#p_" + post_id); + var old_tags = post.data("tags"); $.each(commands, function(i, x) { - post.tags = Danbooru.TagScript.process(post.tags, x); + post.data("tags", Danbooru.TagScript.process(post.data("tags"), x)); }) - Danbooru.Post.update(post_id, {"post[old_tags]": old_tags, "post[tags]": post.tags.join(" ")}); + Danbooru.Post.update(post_id, {"post[old_tags]": old_tags, "post[tags]": post.data("tags")}); } })(); diff --git a/app/assets/javascripts/uploads.js b/app/assets/javascripts/uploads.js index 4713e536d..2614604d1 100644 --- a/app/assets/javascripts/uploads.js +++ b/app/assets/javascripts/uploads.js @@ -1,4 +1,4 @@ -$(document).ready(function() { +$(function() { var img = $("#image-preview img"); if (img) { var height = img.attr("height"); @@ -7,7 +7,7 @@ $(document).ready(function() { var ratio = 400.0 / height; img.attr("height", height * ratio); img.attr("width", width * ratio); - $("#scale").val("Scaled " + parseInt(100 * ratio) + "%"); + $("#scale").html("Scaled " + parseInt(100 * ratio) + "%"); } } }); diff --git a/app/assets/javascripts/utility.js b/app/assets/javascripts/utility.js index 712f58bbc..d93a858d0 100644 --- a/app/assets/javascripts/utility.js +++ b/app/assets/javascripts/utility.js @@ -34,4 +34,14 @@ return all; } + + Danbooru.reject = function(array, f) { + var filtered = []; + $.each(array, function(i, x) { + if (!f(x)) { + filtered.push(x); + } + }); + return filtered; + } })(); diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index 9310643d5..164835f74 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -1,4 +1,5 @@ /*= require "smoothness/jquery-ui-1.8.5.custom.css" */ +@import 'bourbon'; $link_color: #006FFA; $link_hover_color: #9093FF; diff --git a/app/controllers/artists_controller.rb b/app/controllers/artists_controller.rb index 33f226937..2f21c92ac 100644 --- a/app/controllers/artists_controller.rb +++ b/app/controllers/artists_controller.rb @@ -12,6 +12,11 @@ class ArtistsController < ApplicationController respond_with(@artist) end + def banned + @artists = Artist.where("is_banned = ?", true).order("name") + respond_with(@artists) + end + def index @search = Artist.search(params[:search]) @artists = @search.paginate(params[:page]) diff --git a/app/models/artist.rb b/app/models/artist.rb index c405f18d7..0990a30fe 100644 --- a/app/models/artist.rb +++ b/app/models/artist.rb @@ -166,6 +166,10 @@ class Artist < ActiveRecord::Base include NoteMethods include TagMethods + def ban! + + end + def initialize_creator self.creator_id = CurrentUser.user.id end diff --git a/app/views/artists/banned.html.erb b/app/views/artists/banned.html.erb new file mode 100644 index 000000000..abf9ca387 --- /dev/null +++ b/app/views/artists/banned.html.erb @@ -0,0 +1,13 @@ +
    +
    +

    Banned Artists

    + +

    The following artists have requested they be removed from the site. Please do not upload any works from these artists. These artists all have implications pointing to the banned_artist tag.

    + +
      + <% @artists.each do |artist| %> +
    • <%= link_to artist.name, artist_path(artist) %>
    • + <% end %> +
    +
    +
    \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 868fdb2a2..547d46765 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -38,6 +38,7 @@ Danbooru::Application.routes.draw do end collection do get :search + get :banned end end resources :artist_versions, :only => [:index] From 6b01c886795c0ef7ee17ae2fb245b713afb00294 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 22 Aug 2011 17:19:25 -0400 Subject: [PATCH 09/40] added capistrano scripts --- Capfile | 4 ++++ config/deploy.rb | 39 +++++++++++++++++++++++++++++++++++++ config/deploy/production.rb | 2 ++ config/deploy/staging.rb | 1 + config/schedule.rb | 6 ++++-- 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 Capfile create mode 100644 config/deploy.rb create mode 100644 config/deploy/production.rb create mode 100644 config/deploy/staging.rb diff --git a/Capfile b/Capfile new file mode 100644 index 000000000..d04de115b --- /dev/null +++ b/Capfile @@ -0,0 +1,4 @@ +load 'deploy' if respond_to?(:namespace) # cap2 differentiator +Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) } + +load 'config/deploy' # remove this line to skip loading any of the default tasks \ No newline at end of file diff --git a/config/deploy.rb b/config/deploy.rb new file mode 100644 index 000000000..bbf7e66c9 --- /dev/null +++ b/config/deploy.rb @@ -0,0 +1,39 @@ +$:.unshift(File.expand_path("./lib", ENV["rvm_path"])) +set :rvm_ruby_string, "ruby-1.9.2" +require 'rvm/capistrano' + +set :stages, %w(production staging) +set :default_stage, "staging" +require 'capistrano/ext/multistage' + +require 'bundler/capistrano' + +set :whenever_command, "bundle exec whenever" +set :whenever_environment, defer {stage} +require 'whenever/capistrano' + +set :application, "danbooru" +set :repository, "git://github.com/r888888888/danbooru.git" +set :scm, :git +set :deploy_to, "/var/www/#{application}" + +namespace :delayed_job do + desc "Start delayed_job process" + task :start, :roles => :app do + run "cd #{current_path}; script/delayed_job start #{rails_env}" + end + + desc "Stop delayed_job process" + task :stop, :roles => :app do + run "cd #{current_path}; script/delayed_job stop #{rails_env}" + end + + desc "Restart delayed_job process" + task :restart, :roles => :app do + run "cd #{current_path}; script/delayed_job restart #{rails_env}" + end +end + +after "deploy:start", "delayed_job:start" +after "deploy:stop", "delayed_job:stop" +after "deploy:restart", "delayed_job:restart" diff --git a/config/deploy/production.rb b/config/deploy/production.rb new file mode 100644 index 000000000..0a59a8671 --- /dev/null +++ b/config/deploy/production.rb @@ -0,0 +1,2 @@ +server "sonohara.donmai.us", :web, :app, :primary => true +server "hijiribe.donmai.us", :web, :app \ No newline at end of file diff --git a/config/deploy/staging.rb b/config/deploy/staging.rb new file mode 100644 index 000000000..5ace5b5d1 --- /dev/null +++ b/config/deploy/staging.rb @@ -0,0 +1 @@ +server "testbooru.donmai.us", :web, :app, :primary => true diff --git a/config/schedule.rb b/config/schedule.rb index 054359354..411d6af5c 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -4,6 +4,8 @@ every 1.hour do TagSubscription.process_all end -every 1.hour do - AmazonBackup.execute +if fetch(:whenever_environment) == "production" + every 1.hour do + AmazonBackup.execute + end end From 97134c3268ffd31999924b237f7d4ae98e25351d Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 22 Aug 2011 17:46:20 -0400 Subject: [PATCH 10/40] updated resizer --- lib/danbooru_image_resizer/ConvertToRGB.cpp | 66 ++++ lib/danbooru_image_resizer/ConvertToRGB.h | 27 ++ lib/danbooru_image_resizer/Filter.h | 16 + lib/danbooru_image_resizer/GIFReader.cpp | 32 +- lib/danbooru_image_resizer/GIFReader.h | 3 +- lib/danbooru_image_resizer/Histogram.cpp | 48 +++ lib/danbooru_image_resizer/Histogram.h | 29 ++ lib/danbooru_image_resizer/JPEGReader.cpp | 77 ++-- lib/danbooru_image_resizer/JPEGReader.h | 13 +- lib/danbooru_image_resizer/Makefile | 43 +-- lib/danbooru_image_resizer/PNGReader.cpp | 17 +- lib/danbooru_image_resizer/PNGReader.h | 7 +- lib/danbooru_image_resizer/Reader.h | 4 +- lib/danbooru_image_resizer/Resize.cpp | 352 +++++++++++------- lib/danbooru_image_resizer/Resize.h | 43 ++- lib/danbooru_image_resizer/RowBuffer.cpp | 81 ---- lib/danbooru_image_resizer/RowBuffer.h | 111 +++++- .../danbooru_image_resizer.cpp | 141 +++++-- .../danbooru_image_resizer.rb | 31 +- lib/danbooru_image_resizer/extconf.rb | 2 +- lib/danbooru_image_resizer/test.rb | 5 + 21 files changed, 792 insertions(+), 356 deletions(-) create mode 100644 lib/danbooru_image_resizer/ConvertToRGB.cpp create mode 100644 lib/danbooru_image_resizer/ConvertToRGB.h create mode 100644 lib/danbooru_image_resizer/Filter.h create mode 100644 lib/danbooru_image_resizer/Histogram.cpp create mode 100644 lib/danbooru_image_resizer/Histogram.h delete mode 100644 lib/danbooru_image_resizer/RowBuffer.cpp create mode 100644 lib/danbooru_image_resizer/test.rb diff --git a/lib/danbooru_image_resizer/ConvertToRGB.cpp b/lib/danbooru_image_resizer/ConvertToRGB.cpp new file mode 100644 index 000000000..eb1e950d3 --- /dev/null +++ b/lib/danbooru_image_resizer/ConvertToRGB.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include "ConvertToRGB.h" +#include "Filter.h" +#include +using namespace std; + +ConvertToRGB::ConvertToRGB(auto_ptr pCompressor): + m_pCompressor(pCompressor) +{ + m_pBuffer = NULL; +} + +ConvertToRGB::~ConvertToRGB() +{ + delete[] m_pBuffer; +} + +bool ConvertToRGB::Init(int iSourceWidth, int iSourceHeight, int iBPP) +{ + m_iSourceWidth = iSourceWidth; + // m_iSourceHeight = iSourceHeight; + m_iBPP = iBPP; + m_pBuffer = new uint8_t[iSourceWidth * 3]; + assert(m_iBPP == 1 || m_iBPP == 3 || m_iBPP == 4); // greyscale, RGB or RGBA + + return m_pCompressor->Init(iSourceWidth, iSourceHeight, 3); +} + +bool ConvertToRGB::WriteRow(uint8_t *pNewRow) +{ + if(m_iBPP == 3) + return m_pCompressor->WriteRow(pNewRow); + if(m_iBPP == 1) + { + uint8_t *pBuffer = m_pBuffer; + for(int i = 0; i < m_iSourceWidth; ++i) + { + *pBuffer++ = *pNewRow; + *pBuffer++ = *pNewRow; + *pBuffer++ = *pNewRow; + ++pNewRow; + } + } + else if(m_iBPP == 4) + { + uint8_t *pBuffer = m_pBuffer; + for(int i = 0; i < m_iSourceWidth; ++i) + { + uint8_t iR = *pNewRow++; + uint8_t iG = *pNewRow++; + uint8_t iB = *pNewRow++; + uint8_t iA = *pNewRow++; + iR = uint8_t((iR * iA) / 255.0f); + iG = uint8_t((iG * iA) / 255.0f); + iB = uint8_t((iB * iA) / 255.0f); + *pBuffer++ = iR; + *pBuffer++ = iG; + *pBuffer++ = iB; + } + } + + return m_pCompressor->WriteRow(m_pBuffer); +} + diff --git a/lib/danbooru_image_resizer/ConvertToRGB.h b/lib/danbooru_image_resizer/ConvertToRGB.h new file mode 100644 index 000000000..be117c90f --- /dev/null +++ b/lib/danbooru_image_resizer/ConvertToRGB.h @@ -0,0 +1,27 @@ +#ifndef CONVERT_TO_RGB_H +#define CONVERT_TO_RGB_H + +#include "Filter.h" +#include +using namespace std; + +class ConvertToRGB: public Filter +{ +public: + ConvertToRGB(auto_ptr pCompressor); + ~ConvertToRGB(); + + bool Init(int iSourceWidth, int iSourceHeight, int BPP); + bool WriteRow(uint8_t *pNewRow); + bool Finish() { return true; } + + const char *GetError() const { return NULL; } + +private: + uint8_t *m_pBuffer; + auto_ptr m_pCompressor; + int m_iSourceWidth; + int m_iBPP; +}; + +#endif diff --git a/lib/danbooru_image_resizer/Filter.h b/lib/danbooru_image_resizer/Filter.h new file mode 100644 index 000000000..03b1093e6 --- /dev/null +++ b/lib/danbooru_image_resizer/Filter.h @@ -0,0 +1,16 @@ +#ifndef FILTER_H +#define FILTER_H + +#include + +class Filter +{ +public: + virtual ~Filter() { } + virtual bool Init(int iSourceWidth, int iSourceHeight, int iSourceBPP) = 0; + virtual bool WriteRow(uint8_t *row) = 0; + virtual bool Finish() = 0; + virtual const char *GetError() const = 0; +}; + +#endif diff --git a/lib/danbooru_image_resizer/GIFReader.cpp b/lib/danbooru_image_resizer/GIFReader.cpp index f02744e78..b4bbc9eb4 100644 --- a/lib/danbooru_image_resizer/GIFReader.cpp +++ b/lib/danbooru_image_resizer/GIFReader.cpp @@ -1,12 +1,11 @@ +#include #include #include #include "GIFReader.h" -#include "RowBuffer.h" #include "Resize.h" -bool GIF::Read(FILE *f, Resizer *resizer, char error[1024]) +bool GIF::Read(FILE *f, Filter *pOutput, char error[1024]) { - RowBuffer Rows; bool Ret = false; gdImage *image = gdImageCreateFromGif(f); @@ -16,21 +15,18 @@ bool GIF::Read(FILE *f, Resizer *resizer, char error[1024]) return false; } - if(!Rows.Init(image->sx, image->sy, 3)) + uint8_t *pBuf = NULL; + pBuf = (uint8_t *) malloc(image->sx * 3); + if(pBuf == NULL) { strcpy(error, "out of memory"); goto cleanup; } - resizer->SetSource(image->sx, image->sy, 3); + pOutput->Init(image->sx, image->sy, 3); for(int y = 0; y < image->sy; ++y) { - uint8_t *p = Rows.GetRow(y); - if(p == NULL) - { - strcpy(error, "out of memory"); - goto cleanup; - } + uint8_t *p = pBuf; for(int x = 0; x < image->sx; ++x) { @@ -40,19 +36,25 @@ bool GIF::Read(FILE *f, Resizer *resizer, char error[1024]) (*p++) = gdTrueColorGetBlue(c); } - int DiscardRow; - if(!resizer->Run(Rows.GetRows(), Rows.GetStartRow(), Rows.GetEndRow(), DiscardRow)) + if(!pOutput->WriteRow(pBuf)) { - strcpy(error, resizer->GetError()); + strcpy(error, pOutput->GetError()); goto cleanup; } + } - Rows.DiscardRows(DiscardRow); + if(!pOutput->Finish()) + { + strcpy(error, pOutput->GetError()); + goto cleanup; } Ret = true; cleanup: + if(pBuf != NULL) + free(pBuf); + gdImageDestroy(image); return Ret; } diff --git a/lib/danbooru_image_resizer/GIFReader.h b/lib/danbooru_image_resizer/GIFReader.h index 61c200fa5..42488c1b1 100644 --- a/lib/danbooru_image_resizer/GIFReader.h +++ b/lib/danbooru_image_resizer/GIFReader.h @@ -2,10 +2,11 @@ #define GIF_READER_H #include "Reader.h" +class Filter; class GIF: public Reader { public: - bool Read(FILE *f, Resizer *resizer, char error[1024]); + bool Read(FILE *f, Filter *pOutput, char error[1024]); }; #endif diff --git a/lib/danbooru_image_resizer/Histogram.cpp b/lib/danbooru_image_resizer/Histogram.cpp new file mode 100644 index 000000000..49da2e107 --- /dev/null +++ b/lib/danbooru_image_resizer/Histogram.cpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include "Histogram.h" +#include "Filter.h" +#include +using namespace std; + +Histogram::Histogram() +{ + memset(m_Histogram, 0, sizeof(m_Histogram)); +} + +bool Histogram::Init(int iSourceWidth, int iSourceHeight, int iBPP) +{ + assert(iBPP >= 3); + m_SourceWidth = iSourceWidth; + m_SourceBPP = iBPP; + + return true; +} +int Histogram::GetChannels() const +{ + return min(m_SourceBPP, 3); +} + +bool Histogram::WriteRow(uint8_t *pNewRow) +{ + uint8_t *pInput = pNewRow; + int channels = GetChannels(); + for(int x = 0; x < m_SourceWidth; ++x) + { + for(int c = 0; c < channels; ++c) + { + int color = pInput[c]; + if(m_SourceBPP == 3) + color = (color * pInput[3]) / 255; + ++m_Histogram[c][color]; + } + + pInput += m_SourceBPP; + } + + return true; +} + diff --git a/lib/danbooru_image_resizer/Histogram.h b/lib/danbooru_image_resizer/Histogram.h new file mode 100644 index 000000000..dbbef1ea5 --- /dev/null +++ b/lib/danbooru_image_resizer/Histogram.h @@ -0,0 +1,29 @@ +#ifndef HISTOGRAM_H +#define HISTOGRAM_H + +#include "Filter.h" +#include +using namespace std; +#include + +class Histogram: public Filter +{ +public: + Histogram(); + + bool Init(int iSourceWidth, int iSourceHeight, int BPP); + bool WriteRow(uint8_t *pNewRow); + bool Finish() { return true; } + + const char *GetError() const { return NULL; } + int GetChannels() const; + const unsigned *GetHistogram(int iChannel) const { return m_Histogram[iChannel]; } + +private: + unsigned m_Histogram[3][256]; + + int m_SourceWidth; + int m_SourceBPP; +}; + +#endif diff --git a/lib/danbooru_image_resizer/JPEGReader.cpp b/lib/danbooru_image_resizer/JPEGReader.cpp index e3d61eab9..d235940b9 100644 --- a/lib/danbooru_image_resizer/JPEGReader.cpp +++ b/lib/danbooru_image_resizer/JPEGReader.cpp @@ -1,6 +1,6 @@ #include +#include #include "JPEGReader.h" -#include "RowBuffer.h" #include "Resize.h" #include using namespace std; @@ -32,9 +32,14 @@ const char *JPEGCompressor::GetError() const return m_JErr.buffer; } - -bool JPEGCompressor::Init(int width, int height, int quality) +void JPEGCompressor::SetQuality(int quality) { + m_iQuality = quality; +} + +bool JPEGCompressor::Init(int width, int height, int bpp) +{ + assert(bpp == 3); m_CInfo.err = jpeg_std_error(&m_JErr.pub); m_JErr.pub.error_exit = jpeg_error_exit; @@ -53,8 +58,18 @@ bool JPEGCompressor::Init(int width, int height, int quality) m_CInfo.in_color_space = JCS_RGB; /* colorspace of input image */ jpeg_set_defaults(&m_CInfo); - jpeg_simple_progression(&m_CInfo); - jpeg_set_quality(&m_CInfo, quality, TRUE); // limit to baseline-JPEG values + jpeg_set_quality(&m_CInfo, m_iQuality, TRUE); // limit to baseline-JPEG values + + /* For high-quality compression, disable color subsampling. */ + if(m_iQuality >= 95) + { + m_CInfo.comp_info[0].h_samp_factor = 1; + m_CInfo.comp_info[0].v_samp_factor = 1; + m_CInfo.comp_info[1].h_samp_factor = 1; + m_CInfo.comp_info[1].v_samp_factor = 1; + m_CInfo.comp_info[2].h_samp_factor = 1; + m_CInfo.comp_info[2].v_samp_factor = 1; + } jpeg_start_compress(&m_CInfo, TRUE); @@ -89,13 +104,10 @@ bool JPEGCompressor::Finish() return true; } -bool JPEG::Read(FILE *f, Resizer *resizer, char error[1024]) +bool JPEG::Read(FILE *f, Filter *pOutput, char error[1024]) { // JMSG_LENGTH_MAX <= sizeof(error) - m_JErr.buffer = error; - RowBuffer Rows; - - m_Resizer = resizer; + m_pOutputFilter = pOutput; struct jpeg_decompress_struct CInfo; CInfo.err = jpeg_std_error(&m_JErr.pub); @@ -103,44 +115,55 @@ bool JPEG::Read(FILE *f, Resizer *resizer, char error[1024]) m_JErr.pub.emit_message = jpeg_warning; bool Ret = false; + uint8_t *pBuf = NULL; if(setjmp(m_JErr.setjmp_buffer)) + { + memcpy(error, m_JErr.buffer, JMSG_LENGTH_MAX); goto cleanup; + } jpeg_create_decompress(&CInfo); jpeg_stdio_src(&CInfo, f); jpeg_read_header(&CInfo, TRUE); CInfo.out_color_space = JCS_RGB; + if(CInfo.jpeg_color_space == JCS_CMYK || CInfo.jpeg_color_space == JCS_YCCK) + { + strcpy(error, "CMYK JPEGs are not supported; please convert to RGB"); + goto cleanup; + } jpeg_start_decompress(&CInfo); - if(!Rows.Init(CInfo.output_width, CInfo.output_height, 3)) + if(!m_pOutputFilter->Init(CInfo.output_width, CInfo.output_height, 3)) + { + strncpy(error, m_pOutputFilter->GetError(), sizeof(error)); + error[sizeof(error)-1] = 0; + goto cleanup; + } + + pBuf = (uint8_t *) malloc(CInfo.output_width * 3); + if(pBuf == NULL) { strcpy(error, "out of memory"); goto cleanup; } - m_Resizer->SetSource(CInfo.output_width, CInfo.output_height, 3); - while(CInfo.output_scanline < CInfo.output_height) { - uint8_t *p = Rows.GetRow(CInfo.output_scanline); - if(p == NULL) + jpeg_read_scanlines(&CInfo, &pBuf, 1); + + if(!m_pOutputFilter->WriteRow(pBuf)) { - strcpy(error, "out of memory"); + strcpy(error, m_pOutputFilter->GetError()); goto cleanup; } + } - jpeg_read_scanlines(&CInfo, &p, 1); - - int DiscardRow; - if(!m_Resizer->Run(Rows.GetRows(), Rows.GetStartRow(), min(Rows.GetEndRow(), (int) CInfo.output_scanline+1), DiscardRow)) - { - strcpy(error, m_Resizer->GetError()); - goto cleanup; - } - - Rows.DiscardRows(DiscardRow); + if(!m_pOutputFilter->Finish()) + { + strcpy(error, m_pOutputFilter->GetError()); + goto cleanup; } jpeg_finish_decompress(&CInfo); @@ -148,6 +171,8 @@ bool JPEG::Read(FILE *f, Resizer *resizer, char error[1024]) Ret = true; cleanup: + if(pBuf != NULL) + free(pBuf); jpeg_destroy_decompress(&CInfo); return Ret; diff --git a/lib/danbooru_image_resizer/JPEGReader.h b/lib/danbooru_image_resizer/JPEGReader.h index 14479979e..06c8625c6 100644 --- a/lib/danbooru_image_resizer/JPEGReader.h +++ b/lib/danbooru_image_resizer/JPEGReader.h @@ -6,31 +6,33 @@ #include #include "jpeglib-extern.h" #include "Reader.h" +#include "Filter.h" struct jpeg_error { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; - char *buffer; + char buffer[JMSG_LENGTH_MAX]; }; class JPEG: public Reader { public: - bool Read(FILE *f, Resizer *resizer, char error[1024]); + bool Read(FILE *f, Filter *pOutput, char error[1024]); private: - Resizer *m_Resizer; + Filter *m_pOutputFilter; struct jpeg_error m_JErr; }; -class JPEGCompressor +class JPEGCompressor: public Filter { public: JPEGCompressor(FILE *f); ~JPEGCompressor(); - bool Init(int width, int height, int quality); + bool Init(int iSourceWidth, int iSourceHeight, int iBPP); + void SetQuality(int quality); bool WriteRow(uint8_t *row); bool Finish(); @@ -40,6 +42,7 @@ public: private: FILE *m_File; + int m_iQuality; struct jpeg_compress_struct m_CInfo; struct jpeg_error m_JErr; }; diff --git a/lib/danbooru_image_resizer/Makefile b/lib/danbooru_image_resizer/Makefile index 88a6fd1ac..b4690b847 100644 --- a/lib/danbooru_image_resizer/Makefile +++ b/lib/danbooru_image_resizer/Makefile @@ -4,11 +4,11 @@ SHELL = /bin/sh #### Start of system configuration section. #### srcdir = . -topdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-preview1/include/ruby-1.9.1 -hdrdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-preview1/include/ruby-1.9.1 -arch_hdrdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-preview1/include/ruby-1.9.1/$(arch) +topdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1 +hdrdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1 +arch_hdrdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1/$(arch) VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby -prefix = $(DESTDIR)/Users/ayi/.rvm/rubies/ruby-1.9.2-preview1 +prefix = $(DESTDIR)/Users/ayi/.rvm/rubies/ruby-1.9.2-p0 rubylibprefix = $(libdir)/$(RUBY_BASE_NAME) exec_prefix = $(prefix) vendorhdrdir = $(rubyhdrdir)/vendor_ruby @@ -45,7 +45,7 @@ vendorarchdir = $(vendorlibdir)/$(sitearch) CC = g++ CXX = g++ -LIBRUBY = $(LIBRUBY_A) +LIBRUBY = $(LIBRUBY_SO) LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static @@ -55,29 +55,29 @@ COUTFLAG = -o RUBY_EXTCONF_H = cflags = $(optflags) $(debugflags) $(warnflags) optflags = -O3 -debugflags = -g -warnflags = -Wall -Wno-unused-parameter -Wno-parentheses -Wno-missing-field-initializers -Wshorten-64-to-32 -Wpointer-arith -Wwrite-strings -CFLAGS = -fno-common -O2 -fno-exceptions -Wall +debugflags = -ggdb +warnflags = -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long +CFLAGS = -fno-common -O2 -Wall INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) DEFS = CPPFLAGS = -DHAVE_GD_H -DHAVE_GDIMAGECREATEFROMGIF -DHAVE_GDIMAGEJPEG -DHAVE_JPEG_SET_QUALITY -DHAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8 -I/opt/local/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $(DEFS) $(cppflags) CXXFLAGS = $(CFLAGS) $(cxxflags) ldflags = -L. -dldflags = -archflag = -DLDFLAGS = $(ldflags) $(dldflags) $(archflag) -LDSHARED = $(CC) -dynamic -bundle -undefined suppress -flat_namespace -LDSHAREDXX = $(CXX) -dynamic -bundle -undefined suppress -flat_namespace +dldflags = -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -Wl,-flat_namespace +ARCH_FLAG = +DLDFLAGS = $(ldflags) $(dldflags) +LDSHARED = $(CC) -dynamic -bundle +LDSHAREDXX = $(CXX) -dynamic -bundle AR = ar EXEEXT = RUBY_BASE_NAME = ruby RUBY_INSTALL_NAME = ruby -RUBY_SO_NAME = ruby -arch = i386-darwin10.4.0 +RUBY_SO_NAME = ruby.1.9.1 +arch = x86_64-darwin10.4.0 sitearch = $(arch) ruby_version = 1.9.1 -ruby = /Users/ayi/.rvm/rubies/ruby-1.9.2-preview1/bin/ruby +ruby = /Users/ayi/.rvm/rubies/ruby-1.9.2-p0/bin/ruby RUBY = $(ruby) RM = rm -f RM_RF = $(RUBY) -run -e rm -- -rf @@ -104,9 +104,9 @@ extout = extout_prefix = target_prefix = LOCAL_LIBS = -LIBS = -lpng -ljpeg -lgd -lpthread -ldl -lobjc -SRCS = danbooru_image_resizer.cpp GIFReader.cpp JPEGReader.cpp PNGReader.cpp Resize.cpp RowBuffer.cpp -OBJS = danbooru_image_resizer.o GIFReader.o JPEGReader.o PNGReader.o Resize.o RowBuffer.o +LIBS = $(LIBRUBYARG_SHARED) -lpng -ljpeg -lgd -lpthread -ldl -lobjc +SRCS = ConvertToRGB.cpp danbooru_image_resizer.cpp GIFReader.cpp Histogram.cpp JPEGReader.cpp PNGReader.cpp Resize.cpp +OBJS = ConvertToRGB.o danbooru_image_resizer.o GIFReader.o Histogram.o JPEGReader.o PNGReader.o Resize.o TARGET = danbooru_image_resizer DLLIB = $(TARGET).bundle EXTSTATIC = @@ -147,8 +147,9 @@ install: install-so install-rb install-so: $(RUBYARCHDIR) install-so: $(RUBYARCHDIR)/$(DLLIB) -$(RUBYARCHDIR)/$(DLLIB): $(RUBYARCHDIR) $(DLLIB) - $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) +$(RUBYARCHDIR)/$(DLLIB): $(DLLIB) + @-$(MAKEDIRS) $(@D) + $(INSTALL_PROG) $(DLLIB) $(@D) install-rb: pre-install-rb install-rb-default install-rb-default: pre-install-rb-default pre-install-rb: Makefile diff --git a/lib/danbooru_image_resizer/PNGReader.cpp b/lib/danbooru_image_resizer/PNGReader.cpp index d65886f19..7fa1bd7a7 100644 --- a/lib/danbooru_image_resizer/PNGReader.cpp +++ b/lib/danbooru_image_resizer/PNGReader.cpp @@ -44,7 +44,7 @@ void PNG::InfoCallback(png_struct *png, png_info *info_ptr) png_read_update_info(png, info_ptr); - data->m_Resizer->SetSource(width, height, 4); + data->m_pOutputFilter->Init(width, height, 4); } void PNG::RowCallback(png_struct *png, png_byte *new_row, png_uint_32 row_num, int pass) @@ -62,14 +62,12 @@ void PNG::RowCallback(png_struct *png, png_byte *new_row, png_uint_32 row_num, i /* We've allocated data->m_RowsAllocated, but if we're doing multiple passes, only * rows 0 to row_num will actually have usable data. */ - int DiscardRow; - int LastRow = min(data->m_Rows.GetEndRow(), (int) row_num+1); - if(!data->m_Resizer->Run(data->m_Rows.GetRows(), data->m_Rows.GetStartRow(), LastRow, DiscardRow)) - Error(png, data->m_Resizer->GetError()); + if(!data->m_pOutputFilter->WriteRow(p)) + Error(png, data->m_pOutputFilter->GetError()); /* If we're interlaced, never discard rows. */ if(data->m_Passes == 1) - data->m_Rows.DiscardRows(DiscardRow); + data->m_Rows.DiscardRows(row_num+1); } void PNG::EndCallback(png_struct *png, png_info *info) @@ -79,9 +77,9 @@ void PNG::EndCallback(png_struct *png, png_info *info) } -bool PNG::Read(FILE *f, Resizer *resizer, char error[1024]) +bool PNG::Read(FILE *f, Filter *pOutput, char error[1024]) { - m_Resizer = resizer; + m_pOutputFilter = pOutput; png_error_info err; err.err = error; @@ -125,6 +123,9 @@ bool PNG::Read(FILE *f, Resizer *resizer, char error[1024]) png_process_data(png, info_ptr, buf, ret); } + if(!m_pOutputFilter->Finish()) + Error(png, m_pOutputFilter->GetError()); + if(!m_Done) { strcpy(error, "incomplete file"); diff --git a/lib/danbooru_image_resizer/PNGReader.h b/lib/danbooru_image_resizer/PNGReader.h index 5eeabc847..a065152d3 100644 --- a/lib/danbooru_image_resizer/PNGReader.h +++ b/lib/danbooru_image_resizer/PNGReader.h @@ -3,6 +3,7 @@ #include #include "Reader.h" +#include "Filter.h" #include "RowBuffer.h" struct png_error_info @@ -18,11 +19,11 @@ public: m_Done = false; } - bool Read(FILE *f, Resizer *resizer, char error[1024]); + bool Read(FILE *f, Filter *pOutput, char error[1024]); private: - RowBuffer m_Rows; - Resizer *m_Resizer; + RowBuffer m_Rows; + Filter *m_pOutputFilter; bool m_Done; int m_Passes; diff --git a/lib/danbooru_image_resizer/Reader.h b/lib/danbooru_image_resizer/Reader.h index c7b6892f6..eb217ccfd 100644 --- a/lib/danbooru_image_resizer/Reader.h +++ b/lib/danbooru_image_resizer/Reader.h @@ -3,12 +3,12 @@ #include -class Resizer; +class Filter; class Reader { public: virtual ~Reader() { } - virtual bool Read(FILE *f, Resizer *rp, char errorbuf[1024]) = 0; + virtual bool Read(FILE *f, Filter *rp, char errorbuf[1024]) = 0; }; #endif diff --git a/lib/danbooru_image_resizer/Resize.cpp b/lib/danbooru_image_resizer/Resize.cpp index a6ad03fef..353f0b8ae 100644 --- a/lib/danbooru_image_resizer/Resize.cpp +++ b/lib/danbooru_image_resizer/Resize.cpp @@ -1,17 +1,101 @@ #include #include #include +#include #include #include "Resize.h" -#include "JPEGReader.h" +#include "Filter.h" #include using namespace std; -Resizer::Resizer(JPEGCompressor *Compressor) +namespace { - m_Compressor = Compressor; + inline float sincf(float x) + { + if(fabsf(x) < 1e-9) + return 1.0; + + return sinf(x) / x; + } + + inline double fract(double f) + { + return f - floor(f); + } +} + +static const int KERNEL_SIZE = 3; + +LanczosFilter::LanczosFilter() +{ + m_pFilters = NULL; +} + +LanczosFilter::~LanczosFilter() +{ + delete[] m_pFilters; +} + +void LanczosFilter::Init(float fFactor) +{ + /* If we're reducing the image, each output pixel samples each input pixel in the + * range once, so we step one pixel. If we're enlarging it by 2x, each output pixel + * samples each input pixel twice, so we step half a pixel. */ + m_fStep = 1; + if(fFactor > 1.0) + m_fStep = 1.0 / fFactor; + + /* If we're sampling each pixel twice (m_fStep is .5), then we need twice as many taps + * to sample KERNEL_SIZE pixels. */ + m_iTaps = (int) ceil(KERNEL_SIZE / m_fStep) * 2; + + delete[] m_pFilters; + m_pFilters = NULL; // in case of exception + m_pFilters = new float[m_iTaps * 256]; + + float *pOutput = m_pFilters; + for(int i=0; i < 256; ++i) + { + float fOffset = i / 256.0f; + + float fSum = 0; + for(int i = 0; i < m_iTaps; ++i) + { + float fPos = -(m_iTaps/2-1) - fOffset + i; + fPos *= m_fStep; + + float fValue = 0; + if(fabs(fPos) < KERNEL_SIZE) + fValue = sincf(M_PI*fPos) * sincf(M_PI / KERNEL_SIZE * fPos); + + pOutput[i] = fValue; + fSum += fValue; + } + + /* Scale the filter so it sums to 1. */ + for(int i = 0; i pOutput): + m_pCompressor(pOutput) +{ + m_DestWidth = -1; + m_DestHeight = -1; m_CurrentY = 0; m_OutBuf = NULL; + m_szError = NULL; + m_iInputY = 0; } Resizer::~Resizer() @@ -22,160 +106,178 @@ Resizer::~Resizer() const char *Resizer::GetError() const { - return m_Compressor->GetError(); + if(m_szError != NULL) + return m_szError; + return m_pCompressor->GetError(); } -void Resizer::SetSource(int Width, int Height, int BPP) +bool Resizer::Init(int iSourceWidth, int iSourceHeight, int iBPP) { - m_SourceWidth = Width; - m_SourceHeight = Height; - m_SourceBPP = BPP; -} + assert(m_DestWidth != -1); + assert(m_DestHeight != -1); + assert(iBPP == 3); + m_SourceWidth = iSourceWidth; + m_SourceHeight = iSourceHeight; + m_SourceBPP = iBPP; -bool Resizer::SetDest(int Width, int Height, int Quality) -{ - m_DestWidth = Width; - m_DestHeight = Height; - m_OutBuf = (uint8_t *) malloc(Width*3); + float fXFactor = float(m_SourceWidth) / m_DestWidth; + m_XFilter.Init(fXFactor); - return m_Compressor->Init(Width, Height, Quality); -} + float fYFactor = float(m_SourceHeight) / m_DestHeight; + m_YFilter.Init(fYFactor); -#define scale(x, l1, h1, l2, h2) (((x)-(l1))*((h2)-(l2))/((h1)-(l1))+(l2)) - -static void Average(const uint8_t *const *src, float Colors[3], float SourceXStart, float SourceXEnd, float SourceYStart, float SourceYEnd, int SourceBPP) -{ - float Total = 0.0f; - for(float y = SourceYStart; y < SourceYEnd; ++y) + if(!m_Rows.Init(m_DestWidth, m_SourceHeight, m_SourceBPP, m_YFilter.m_iTaps)) { - float YCoverage = 1.0f; - if(int(y) == int(SourceYStart)) - YCoverage -= y - int(y); - if(int(y) == int(SourceYEnd)) - YCoverage -= 1.0f - (SourceYEnd - int(SourceYEnd)); - - const uint8_t *xsrc=src[(int) y]+(int)SourceXStart*SourceBPP; - - /* The two conditionals can only be true on the first and last iteration of the loop, - * so unfold those iterations and pull the conditionals out of the inner loop. */ -/* while(x < SourceXEnd) - { - float XCoverage = 1.0f; - if(int(x) == int(SourceXStart)) - XCoverage -= x - int(x); - if(int(x) == int(SourceXEnd)) - XCoverage -= 1.0f - (SourceXEnd - int(SourceXEnd)); - - Colors[0] += xsrc[0] * XCoverage * YCoverage; - Colors[1] += xsrc[1] * XCoverage * YCoverage; - Colors[2] += xsrc[2] * XCoverage * YCoverage; - if(SourceBPP == 4) - Colors[3] += xsrc[3] * XCoverage * YCoverage; - xsrc += SourceBPP; - - Total += XCoverage * YCoverage; - ++x; - } -*/ - float x = int(SourceXStart); - if(x < SourceXEnd) - { - float XCoverage = 1.0f; - if(int(x) == int(SourceXStart)) - XCoverage -= x - int(x); - if(int(x) == int(SourceXEnd)) - XCoverage -= 1.0f - (SourceXEnd - int(SourceXEnd)); - - Colors[0] += xsrc[0] * XCoverage * YCoverage; - Colors[1] += xsrc[1] * XCoverage * YCoverage; - Colors[2] += xsrc[2] * XCoverage * YCoverage; - if(SourceBPP == 4) - Colors[3] += xsrc[3] * XCoverage * YCoverage; - xsrc += SourceBPP; - - Total += XCoverage * YCoverage; - ++x; - } - - while(x < SourceXEnd-1) - { - Colors[0] += xsrc[0] * YCoverage; - Colors[1] += xsrc[1] * YCoverage; - Colors[2] += xsrc[2] * YCoverage; - if(SourceBPP == 4) - Colors[3] += xsrc[3] * YCoverage; - xsrc += SourceBPP; - - Total += YCoverage; - ++x; - } - - if(x < SourceXEnd) - { - float XCoverage = 1.0f; - if(int(x) == int(SourceXStart)) - XCoverage -= x - int(x); - if(int(x) == int(SourceXEnd)) - XCoverage -= 1.0f - (SourceXEnd - int(SourceXEnd)); - - Colors[0] += xsrc[0] * XCoverage * YCoverage; - Colors[1] += xsrc[1] * XCoverage * YCoverage; - Colors[2] += xsrc[2] * XCoverage * YCoverage; - if(SourceBPP == 4) - Colors[3] += xsrc[3] * XCoverage * YCoverage; - xsrc += SourceBPP; - - Total += XCoverage * YCoverage; - } + m_szError = "out of memory"; + return false; } - if(Total != 0.0f) - for(int i = 0; i < 4; ++i) - Colors[i] /= Total; + m_OutBuf = (uint8_t *) malloc(m_DestWidth * m_SourceBPP); + if(m_OutBuf == NULL) + { + m_szError = "out of memory"; + return false; + } + + return m_pCompressor->Init(m_DestWidth, m_DestHeight, m_SourceBPP); } -bool Resizer::Run(const uint8_t *const *Source, int StartRow, int EndRow, int &DiscardRow) +void Resizer::SetDest(int iDestWidth, int iDestHeight) { - while(m_CurrentY < m_DestHeight) + m_DestWidth = iDestWidth; + m_DestHeight = iDestHeight; +} + +static uint8_t *PadRow(const uint8_t *pSourceRow, int iWidth, int iBPP, int iPadding) +{ + uint8_t *pRow = new uint8_t[(iWidth + iPadding*2) * iBPP]; + uint8_t *pDest = pRow; + for(int x = 0; x < iPadding; ++x) { - float SourceYStart = scale((float) m_CurrentY, 0.0f, (float) m_DestHeight, 0.0f, (float) m_SourceHeight); - float SourceYEnd = scale((float) m_CurrentY + 1, 0.0f, (float) m_DestHeight, 0.0f, (float) m_SourceHeight); - DiscardRow = int(SourceYStart)-1; + for(int i = 0; i < iBPP; ++i) + pDest[i] = pSourceRow[i]; + pDest += iBPP; + } - if(EndRow != m_SourceHeight && int(SourceYEnd)+1 > EndRow-1) + memcpy(pDest, pSourceRow, iWidth*iBPP*sizeof(uint8_t)); + pDest += iWidth*iBPP; + + for(int x = 0; x < iPadding; ++x) + { + for(int i = 0; i < iBPP; ++i) + pDest[i] = pSourceRow[i]; + pDest += iBPP; + } + + return pRow; +} + +bool Resizer::WriteRow(uint8_t *pNewRow) +{ + if(m_SourceWidth == m_DestWidth && m_SourceHeight == m_DestHeight) + { + ++m_CurrentY; + + /* We don't actually have any resizing to do, so short-circuit. */ + if(!m_pCompressor->WriteRow((uint8_t *) pNewRow)) + return false; + + if(m_CurrentY != m_DestHeight) return true; - assert(SourceYStart>=StartRow); - uint8_t *Output = m_OutBuf; + return m_pCompressor->Finish(); + } + + /* Make a copy of pNewRow with the first and last pixel duplicated, so we don't have to do + * bounds checking in the inner loop below. */ + uint8_t *pActualPaddedRow = PadRow(pNewRow, m_SourceWidth, m_SourceBPP, m_XFilter.m_iTaps/2); + const uint8_t *pPaddedRow = pActualPaddedRow + (m_XFilter.m_iTaps/2)*m_SourceBPP; + + const float fXFactor = float(m_SourceWidth) / m_DestWidth; + const float fYFactor = float(m_SourceHeight) / m_DestHeight; + + /* Run the horizontal filter on the incoming row, and drop the result into m_Rows. */ + { + float *pRow = m_Rows.GetRow(m_iInputY); + ++m_iInputY; + + float *pOutput = pRow; for(int x = 0; x < m_DestWidth; ++x) { - float SourceXStart = scale((float) x, 0.0f, (float) m_DestWidth, 0.0f, (float) m_SourceWidth); - float SourceXEnd = scale((float) x + 1, 0.0f, (float) m_DestWidth, 0.0f, (float) m_SourceWidth); + const double fSourceX = (x + 0.5f) * fXFactor; + const double fOffset = fract(fSourceX + 0.5); + const float *pFilter = m_XFilter.GetFilter(fOffset); + const int iStartX = lrint(fSourceX - m_XFilter.m_iTaps/2 + 1e-6); - float Colors[4] = { 0.0 }; - Average(Source, Colors, SourceXStart, SourceXEnd, SourceYStart, SourceYEnd, m_SourceBPP); + const uint8_t *pSource = pPaddedRow + iStartX*3; - if(m_SourceBPP == 4) + float fR = 0, fG = 0, fB = 0; + for(int i = 0; i < m_XFilter.m_iTaps; ++i) { - for(int i = 0; i < 3; ++i) - Colors[i] *= Colors[3]/255.0f; + float fWeight = *pFilter++; + + fR += pSource[0] * fWeight; + fG += pSource[1] * fWeight; + fB += pSource[2] * fWeight; + pSource += 3; } - Output[0] = (uint8_t) min(255, int(Colors[0])); - Output[1] = (uint8_t) min(255, int(Colors[1])); - Output[2] = (uint8_t) min(255, int(Colors[2])); + pOutput[0] = fR; + pOutput[1] = fG; + pOutput[2] = fB; - Output += 3; + pOutput += m_SourceBPP; + } + } + delete[] pActualPaddedRow; + + const float *const *pSourceRows = m_Rows.GetRows(); + while(m_CurrentY < m_DestHeight) + { + const double fSourceY = (m_CurrentY + 0.5) * fYFactor; + const double fOffset = fract(fSourceY + 0.5); + const int iStartY = lrint(fSourceY - m_YFilter.m_iTaps/2 + 1e-6); + + /* iStartY is the first row we'll need, and we never move backwards. Discard rows + * before it to save memory. */ + m_Rows.DiscardRows(iStartY); + + if(m_iInputY != m_SourceHeight && iStartY+m_YFilter.m_iTaps >= m_iInputY) + return true; + + /* Process the next output row. */ + uint8_t *pOutput = m_OutBuf; + for(int x = 0; x < m_DestWidth; ++x) + { + const float *pFilter = m_YFilter.GetFilter(fOffset); + + float fR = 0, fG = 0, fB = 0; + for(int i = 0; i < m_YFilter.m_iTaps; ++i) + { + const float *pSource = pSourceRows[iStartY+i]; + pSource += x * m_SourceBPP; + + float fWeight = *pFilter++; + fR += pSource[0] * fWeight; + fG += pSource[1] * fWeight; + fB += pSource[2] * fWeight; + } + + pOutput[0] = (uint8_t) max(0, min(255, (int) lrintf(fR))); + pOutput[1] = (uint8_t) max(0, min(255, (int) lrintf(fG))); + pOutput[2] = (uint8_t) max(0, min(255, (int) lrintf(fB))); + + pOutput += 3; } - if(!m_Compressor->WriteRow((JSAMPLE *) m_OutBuf)) + if(!m_pCompressor->WriteRow((uint8_t *) m_OutBuf)) return false; ++m_CurrentY; } if(m_CurrentY == m_DestHeight) { - if(!m_Compressor->Finish()) + if(!m_pCompressor->Finish()) return false; } diff --git a/lib/danbooru_image_resizer/Resize.h b/lib/danbooru_image_resizer/Resize.h index fb1090a8e..946daada9 100644 --- a/lib/danbooru_image_resizer/Resize.h +++ b/lib/danbooru_image_resizer/Resize.h @@ -1,32 +1,43 @@ #ifndef RESIZE_H #define RESIZE_H +#include "RowBuffer.h" +#include "Filter.h" +#include +using namespace std; #include -class JPEGCompressor; +struct LanczosFilter +{ + LanczosFilter(); + ~LanczosFilter(); + void Init(float fFactor); + const float *GetFilter(float fOffset) const; -class Resizer + float m_fStep; + int m_iTaps; + float *m_pFilters; +}; + +class Resizer: public Filter { public: - Resizer(JPEGCompressor *Compressor); + Resizer(auto_ptr pCompressor); ~Resizer(); // BPP is 3 or 4, indicating RGB or RGBA. - void SetSource(int Width, int Height, int BPP); - bool SetDest(int Width, int Height, int Quality); + bool Init(int iSourceWidth, int iSourceHeight, int BPP); + void SetDest(int iDestWidth, int iDestHeight); + bool WriteRow(uint8_t *pNewRow); + bool Finish() { return true; } - /* - * Resize part of an image. - * - * [FirstRow,LastRow) is a range indicating which elements in src[] are available. - * On return, any rows in [0,DiscardRow) are no longer needed and can be deleted. - */ - bool Run(const uint8_t *const *src, int FirstRow, int LastRow, int &DiscardRow); const char *GetError() const; private: - JPEGCompressor *m_Compressor; + auto_ptr m_pCompressor; uint8_t *m_OutBuf; + RowBuffer m_Rows; + const char *m_szError; int m_SourceWidth; int m_SourceHeight; @@ -35,7 +46,11 @@ private: int m_DestWidth; int m_DestHeight; - float m_CurrentY; + LanczosFilter m_XFilter; + LanczosFilter m_YFilter; + + int m_iInputY; + int m_CurrentY; }; #endif diff --git a/lib/danbooru_image_resizer/RowBuffer.cpp b/lib/danbooru_image_resizer/RowBuffer.cpp deleted file mode 100644 index e09179990..000000000 --- a/lib/danbooru_image_resizer/RowBuffer.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include -#include "RowBuffer.h" -#include -using namespace std; - -RowBuffer::RowBuffer() -{ - m_Rows = NULL; - m_StartRow = 0; - m_EndRow = 0; - m_BPP = 0; - m_Height = 0; -} - -RowBuffer::~RowBuffer() -{ - for(int i = 0; i < m_Height; ++i) - delete [] m_Rows[i]; - - delete [] m_Rows; -} - -bool RowBuffer::Init(int Width, int Height, int BPP) -{ - m_Width = Width; - m_Height = Height; - m_BPP = BPP; - - m_Rows = new uint8_t *[Height]; - if(m_Rows == NULL) - return false; - memset(m_Rows, 0, sizeof(uint8_t *) * Height); - - return true; -} - -uint8_t *RowBuffer::GetRow(int Row) -{ - assert(m_BPP > 0); - - if(m_Rows[Row] == NULL) - { - m_Rows[Row] = new uint8_t[m_Width*m_BPP]; - if(m_Rows[Row] == NULL) - return NULL; - if(m_StartRow == m_EndRow) - { - m_StartRow = Row; - m_EndRow = m_StartRow + 1; - } - } - - if(int(Row) == m_StartRow+1) - { - while(m_StartRow != 0 && m_Rows[m_StartRow-1]) - --m_StartRow; - } - - if(int(Row) == m_EndRow) - { - while(m_EndRow < m_Height && m_Rows[m_EndRow]) - ++m_EndRow; - } - return m_Rows[Row]; -} - -void RowBuffer::DiscardRows(int DiscardRow) -{ - assert(m_BPP > 0); - - for(int i = m_StartRow; i < DiscardRow; ++i) - { - delete [] m_Rows[i]; - m_Rows[i] = NULL; - } - - m_StartRow = max(m_StartRow, DiscardRow); - m_EndRow = max(m_EndRow, DiscardRow); -} diff --git a/lib/danbooru_image_resizer/RowBuffer.h b/lib/danbooru_image_resizer/RowBuffer.h index 2c792236f..2c9618302 100644 --- a/lib/danbooru_image_resizer/RowBuffer.h +++ b/lib/danbooru_image_resizer/RowBuffer.h @@ -2,30 +2,126 @@ #define ROW_BUFFER_H #include +#include +#include +#include +#include "RowBuffer.h" +#include +using namespace std; +template class RowBuffer { public: - RowBuffer(); - ~RowBuffer(); + RowBuffer() + { + m_Rows = NULL; + m_ActualRows = NULL; + m_StartRow = 0; + m_EndRow = 0; + m_BPP = 0; + m_Height = 0; + } - bool Init(int Width, int Height, int BPP); + ~RowBuffer() + { + for(int i = 0; i < m_Height; ++i) + delete [] m_Rows[i]; + + delete [] m_ActualRows; + } + + /* + * If iVertPadding is non-zero, simulate padding on the top and bottom of the image. After + * row 0 is written, rows [-1 ... -iVertPadding] will point to the same row. After the bottom + * row is written, the following iVertPadding will also point to the last row. These rows + * are discarded when the row they refer to is discarded. + */ + bool Init(int iWidth, int iHeight, int iBPP, int iVertPadding = 0) + { + m_Width = iWidth; + m_Height = iHeight; + m_BPP = iBPP; + m_iVertPadding = iVertPadding; + + m_ActualRows = new T *[iHeight + iVertPadding*2]; + m_Rows = m_ActualRows + iVertPadding; + memset(m_ActualRows, 0, sizeof(T *) * (iHeight + iVertPadding*2)); + + return true; + } /* Return row, allocating if necessary. */ - uint8_t *GetRow(int row); + T *GetRow(int Row) + { + assert(m_BPP > 0); + + if(m_Rows[Row] == NULL) + { + m_Rows[Row] = new T[m_Width*m_BPP]; + if(Row == 0) + { + for(int i = -m_iVertPadding; i < 0; ++i) + m_Rows[i] = m_Rows[0]; + } + if(Row == m_Height - 1) + { + for(int i = m_Height; i < m_Height + m_iVertPadding; ++i) + m_Rows[i] = m_Rows[m_Height - 1]; + } + if(m_Rows[Row] == NULL) + return NULL; + if(m_StartRow == m_EndRow) + { + m_StartRow = Row; + m_EndRow = m_StartRow + 1; + } + } + + if(int(Row) == m_StartRow+1) + { + while(m_StartRow != 0 && m_Rows[m_StartRow-1]) + --m_StartRow; + } + + if(int(Row) == m_EndRow) + { + while(m_EndRow < m_Height && m_Rows[m_EndRow]) + ++m_EndRow; + } + return m_Rows[Row]; + } // Free rows [0,DiscardRow). - void DiscardRows(int DiscardRow); + void DiscardRows(int DiscardRow) + { + assert(m_BPP > 0); + if(DiscardRow > m_Height) + DiscardRow = m_Height; + + for(int i = m_StartRow; i < DiscardRow; ++i) + { + delete [] m_Rows[i]; + m_Rows[i] = NULL; + } + + m_StartRow = max(m_StartRow, DiscardRow); + m_EndRow = max(m_EndRow, DiscardRow); + } /* Get a range of rows allocated in m_Rows: [m_StartRow,m_EndRow). If * more than one allocated range exists, which range is returned is undefined. */ int GetStartRow() const { return m_StartRow; } int GetEndRow() const { return m_EndRow; } - const uint8_t *const *GetRows() const { return m_Rows; } + const T *const *GetRows() const { return m_Rows; } private: /* Array of image rows. These are allocated as needed. */ - uint8_t **m_Rows; + T **m_Rows; + + /* The actual pointer m_Rows is contained in. m_Rows may be offset from this to + * implement padding. */ + T **m_ActualRows; /* in m_Rows is allocated: */ int m_StartRow; @@ -34,6 +130,7 @@ private: int m_Width; int m_Height; int m_BPP; + int m_iVertPadding; }; #endif diff --git a/lib/danbooru_image_resizer/danbooru_image_resizer.cpp b/lib/danbooru_image_resizer/danbooru_image_resizer.cpp index 8c502450a..cca12b6e0 100644 --- a/lib/danbooru_image_resizer/danbooru_image_resizer.cpp +++ b/lib/danbooru_image_resizer/danbooru_image_resizer.cpp @@ -1,15 +1,31 @@ #include #include #include - +#include +using namespace std; #include "PNGReader.h" #include "GIFReader.h" #include "JPEGReader.h" #include "Resize.h" +#include "Histogram.h" +#include "ConvertToRGB.h" static VALUE danbooru_module; -static VALUE danbooru_resize_image(VALUE module, VALUE file_ext_val, VALUE read_path_val, VALUE write_path_val, VALUE output_width_val, VALUE output_height_val, VALUE output_quality_val) +static Reader *GetReader(const char *file_ext) +{ + if (!strcmp(file_ext, "jpg") || !strcmp(file_ext, "jpeg")) + return new JPEG; + if (!strcmp(file_ext, "gif")) + return new GIF; + if (!strcmp(file_ext, "png")) + return new PNG; + return NULL; +} + +static VALUE danbooru_resize_image(VALUE module, VALUE file_ext_val, VALUE read_path_val, VALUE write_path_val, + VALUE output_width_val, VALUE output_height_val, + VALUE output_quality_val) { const char * file_ext = StringValueCStr(file_ext_val); const char * read_path = StringValueCStr(read_path_val); @@ -31,44 +47,44 @@ static VALUE danbooru_resize_image(VALUE module, VALUE file_ext_val, VALUE read_ bool ret = false; char error[1024]; - JPEGCompressor *Compressor = NULL; - Resizer *resizer = NULL; - Reader *Reader = NULL; - if (!strcmp(file_ext, "jpg") || !strcmp(file_ext, "jpeg")) - Reader = new JPEG; - else if (!strcmp(file_ext, "gif")) - Reader = new GIF; - else if (!strcmp(file_ext, "png")) - Reader = new PNG; - else + try { - strcpy(error, "unknown filetype"); - goto cleanup; - } + auto_ptr pReader(GetReader(file_ext)); + if(pReader.get() == NULL) + { + strcpy(error, "unknown filetype"); + goto cleanup; + } - Compressor = new JPEGCompressor(write_file); - if(Compressor == NULL) + auto_ptr pFilter(NULL); + + { + auto_ptr pCompressor(new JPEGCompressor(write_file)); + pCompressor->SetQuality(output_quality); + pFilter.reset(pCompressor.release()); + } + + { + auto_ptr pResizer(new Resizer(pFilter)); + pResizer->SetDest(output_width, output_height); + pFilter.reset(pResizer.release()); + } + + + { + auto_ptr pConverter(new ConvertToRGB(pFilter)); + pFilter.reset(pConverter.release()); + } + + ret = pReader->Read(read_file, pFilter.get(), error); + } + catch(const std::bad_alloc &e) { strcpy(error, "out of memory"); - goto cleanup; } - resizer = new Resizer(Compressor); - if(resizer == NULL || Reader == NULL) - { - strcpy(error, "out of memory"); - goto cleanup; - } - - resizer->SetDest(output_width, output_height, output_quality); - ret = Reader->Read(read_file, resizer, error); - cleanup: - delete Reader; - delete resizer; - delete Compressor; - fclose(read_file); fclose(write_file); @@ -78,7 +94,68 @@ cleanup: return INT2FIX(0); } +static VALUE danbooru_histogram(VALUE module, VALUE file_ext_val, VALUE read_path_val) +{ + const char * file_ext = StringValueCStr(file_ext_val); + const char * read_path = StringValueCStr(read_path_val); + + FILE *read_file = fopen(read_path, "rb"); + if(read_file == NULL) + rb_raise(rb_eIOError, "can't open %s\n", read_path); + + bool ret = false; + char error[1024]; + VALUE results = Qnil; + + try + { + auto_ptr pReader(GetReader(file_ext)); + if(pReader.get() == NULL) + { + strcpy(error, "unknown filetype"); + goto cleanup; + } + + auto_ptr pFilter(NULL); + + Histogram *pHistogram = new Histogram(); + pFilter.reset(pHistogram); + + { + auto_ptr pConverter(new ConvertToRGB(pFilter)); + pFilter.reset(pConverter.release()); + } + + ret = pReader->Read(read_file, pFilter.get(), error); + + results = rb_ary_new(); + int channels = pHistogram->GetChannels(); + for(int channel = 0; channel < channels; ++channel) + { + const unsigned *pChannelData = pHistogram->GetHistogram(channel); + VALUE channel_array = rb_ary_new(); + rb_ary_push(results, channel_array); + + for(int i = 0; i < 256; ++i) + rb_ary_push(channel_array, INT2NUM(pChannelData[i])); + } + } + catch(const std::bad_alloc &e) + { + strcpy(error, "out of memory"); + } + +cleanup: + fclose(read_file); + + if(!ret) + rb_raise(rb_eException, "%s", error); + + return results; +} + extern "C" void Init_danbooru_image_resizer() { danbooru_module = rb_define_module("Danbooru"); rb_define_module_function(danbooru_module, "resize_image", (VALUE(*)(...))danbooru_resize_image, 6); + rb_define_module_function(danbooru_module, "histogram", (VALUE(*)(...))danbooru_histogram, 2); } diff --git a/lib/danbooru_image_resizer/danbooru_image_resizer.rb b/lib/danbooru_image_resizer/danbooru_image_resizer.rb index 68f718ee2..0f4c8f628 100644 --- a/lib/danbooru_image_resizer/danbooru_image_resizer.rb +++ b/lib/danbooru_image_resizer/danbooru_image_resizer.rb @@ -5,23 +5,24 @@ module Danbooru Danbooru.resize_image(file_ext, read_path, write_path, output_size[:width], output_size[:height], output_quality) end - def reduce_to(size, max_size) - size.dup.tap do |new_size| - if new_size[:width] > max_size[:width] - scale = max_size[:width].to_f / new_size[:width].to_f - new_size[:width] = new_size[:width] * scale - new_size[:height] = new_size[:height] * scale - end - - if max_size[:height] && (new_size[:height] > max_size[:height]) - scale = max_size[:height].to_f / new_size[:height].to_f - new_size[:width] = new_size[:width] * scale - new_size[:height] = new_size[:height] * scale - end + def reduce_to(size, max_size, ratio = 1) + ret = size.dup - new_size[:width] = new_size[:width].to_i - new_size[:height] = new_size[:height].to_i + if ret[:width] > ratio * max_size[:width] + scale = max_size[:width].to_f / ret[:width].to_f + ret[:width] = ret[:width] * scale + ret[:height] = ret[:height] * scale end + + if max_size[:height] && (ret[:height] > ratio * max_size[:height]) + scale = max_size[:height].to_f / ret[:height].to_f + ret[:width] = ret[:width] * scale + ret[:height] = ret[:height] * scale + end + + ret[:width] = ret[:width].to_i + ret[:height] = ret[:height].to_i + ret end module_function :resize diff --git a/lib/danbooru_image_resizer/extconf.rb b/lib/danbooru_image_resizer/extconf.rb index 5ffbbfea3..a690b9141 100644 --- a/lib/danbooru_image_resizer/extconf.rb +++ b/lib/danbooru_image_resizer/extconf.rb @@ -20,7 +20,7 @@ have_func("gdImageJpeg", "gd.h") have_func("jpeg_set_quality", ["stdlib.h", "stdio.h", "jpeglib-extern.h"]) have_func("png_set_expand_gray_1_2_4_to_8", "png.h") -with_cflags("-O2 -fno-exceptions -Wall") {true} +with_cflags("-O2 -Wall") {true} #with_cflags("-O0 -g -fno-exceptions -Wall") {true} create_makefile("danbooru_image_resizer") diff --git a/lib/danbooru_image_resizer/test.rb b/lib/danbooru_image_resizer/test.rb new file mode 100644 index 000000000..c0d41cf66 --- /dev/null +++ b/lib/danbooru_image_resizer/test.rb @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby + +require 'danbooru_image_resizer' +Danbooru.resize_image("jpg", "test.jpg", "test-out.jpg", 2490, 3500, 95) + From f63a69ae6e1ed9da2fbfa5fb8a744f298a271bcd Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 22 Aug 2011 17:47:26 -0400 Subject: [PATCH 11/40] removed jpgcrush --- lib/jpgcrush.tar.gz | Bin 3156 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lib/jpgcrush.tar.gz diff --git a/lib/jpgcrush.tar.gz b/lib/jpgcrush.tar.gz deleted file mode 100644 index 4205b24b3a0db4f38749c705cfb973a4cc7bc7dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3156 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 L=iXxoU|;|M0y!&# From e3a9614930827e8ac3bcf3529a7d567fdbc62cd6 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 23 Aug 2011 16:15:29 -0400 Subject: [PATCH 12/40] fixes to whenever scripts --- app/models/post.rb | 23 ++++++++++++++++++++--- config/danbooru_default_config.rb | 5 +++++ config/schedule.rb | 6 +++--- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index d9e82f357..fb52bed3b 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -65,7 +65,8 @@ class Post < ActiveRecord::Base FileUtils.rm_f(file_path) FileUtils.rm_f(medium_file_path) FileUtils.rm_f(large_file_path) - FileUtils.rm_f(preview_file_path) + FileUtils.rm_f(ssd_preview_file_path) if Danbooru.config.ssd_path + FileUtils.rm_f(real_preview_file_path) end def file_path_prefix @@ -91,9 +92,21 @@ class Post < ActiveRecord::Base file_path end end + + def real_preview_file_path + "#{Rails.root}/public/data/preview/#{file_path_prefix}#{md5}.jpg" + end + + def ssd_preview_file_path + "#{Danbooru.config.ssd_path}/public/data/preview/#{file_path_preview}#{md5}.jpg" + end def preview_file_path - "#{Rails.root}/public/data/preview/#{file_path_prefix}#{md5}.jpg" + if Danbooru.config.ssd_path + ssd_preview_file_path + else + real_preview_file_path + end end def file_url @@ -117,7 +130,11 @@ class Post < ActiveRecord::Base end def preview_file_url - "/data/preview/#{file_path_prefix}#{md5}.jpg" + if Danbooru.config.ssd_path + "/ssd/data/preview/#{file_path_prefix}#{md5}.jpg" + else + "/data/preview/#{file_path_prefix}#{md5}.jpg" + end end def file_url_for(user) diff --git a/config/danbooru_default_config.rb b/config/danbooru_default_config.rb index f4698b164..3e659bc9c 100644 --- a/config/danbooru_default_config.rb +++ b/config/danbooru_default_config.rb @@ -72,6 +72,11 @@ module Danbooru 300 end + # If a solid state drive is availble, cache the thumbnails on the SSD to reduce disk seek times. + def ssd_path + nil + end + # List of memcached servers def memcached_servers %w(localhost:11211) diff --git a/config/schedule.rb b/config/schedule.rb index 411d6af5c..6bf986368 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -1,11 +1,11 @@ set :output, "/var/log/whenever.log" every 1.hour do - TagSubscription.process_all + runner "TagSubscription.process_all" end -if fetch(:whenever_environment) == "production" +if environment == "production" every 1.hour do - AmazonBackup.execute + runner "AmazonBackup.execute" end end From 124403a9216a455f79372468a7a86614dd3922f7 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 23 Aug 2011 17:11:21 -0400 Subject: [PATCH 13/40] implemented last-forum-read-at --- Gemfile | 1 - Gemfile.lock | 4 ---- app/assets/javascripts/forum_posts.js | 13 +++++++++++++ app/assets/stylesheets/application.css.scss | 5 ++++- app/controllers/forum_topics_controller.rb | 7 +++++++ app/controllers/sessions_controller.rb | 1 + app/helpers/application_helper.rb | 13 ++++++++++--- app/logical/anonymous_user.rb | 7 +++++++ app/presenters/forum_topic_presenter.rb | 4 ---- app/views/forum_topics/_paginator.html.erb | 1 - app/views/forum_topics/index.html.erb | 8 +++++++- app/views/forum_topics/show.html.erb | 3 ++- 12 files changed, 51 insertions(+), 16 deletions(-) delete mode 100644 app/views/forum_topics/_paginator.html.erb diff --git a/Gemfile b/Gemfile index f140d19f0..c79bcabcd 100644 --- a/Gemfile +++ b/Gemfile @@ -25,4 +25,3 @@ gem "nokogiri" gem "meta_search", :git => "git://github.com/ernie/meta_search.git" gem "silent-postgres" gem "whenever", :require => false -gem "bourbon" diff --git a/Gemfile.lock b/Gemfile.lock index b482da19f..352b3e780 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -48,8 +48,6 @@ GEM multi_json (~> 1.0) arel (2.1.4) bcrypt-ruby (2.1.4) - bourbon (0.1.5) - sass (>= 3.1) builder (3.0.0) daemons (1.1.4) delayed_job (2.1.4) @@ -105,7 +103,6 @@ GEM thor (~> 0.14.6) rake (0.9.2) rdoc (3.9.1) - sass (3.1.7) shoulda (2.11.3) silent-postgres (0.0.8) simple_form (1.4.2) @@ -137,7 +134,6 @@ PLATFORMS ruby DEPENDENCIES - bourbon delayed_job factory_girl ffaker! diff --git a/app/assets/javascripts/forum_posts.js b/app/assets/javascripts/forum_posts.js index 6caf4e4f2..0ec5b9a10 100644 --- a/app/assets/javascripts/forum_posts.js +++ b/app/assets/javascripts/forum_posts.js @@ -5,6 +5,19 @@ $("#c-forum-topics #preview").hide(); this.initialize_preview_link(); + this.initialize_last_forum_read_at(); + } + + Danbooru.ForumPost.initialize_last_forum_read_at = function() { + var last_forum_read_at = Date.parse(Danbooru.meta("last-forum-read-at")); + + $("#c-forum-topics #a-index time").each(function(i, x) { + var $x = $(x); + var $date = Date.parse($x.attr("datetime")); + if (Date.parse($x.attr("datetime")) > last_forum_read_at) { + $x.closest("tr").addClass("new-topic"); + } + }); } Danbooru.ForumPost.initialize_preview_link = function() { diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index 164835f74..229215959 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -1,5 +1,4 @@ /*= require "smoothness/jquery-ui-1.8.5.custom.css" */ -@import 'bourbon'; $link_color: #006FFA; $link_hover_color: #9093FF; @@ -897,6 +896,10 @@ div#c-forum-topics { color: #AAA; } + tr.new-topic { + font-weight: bold; + } + div#form-content { float: left; width: 450px; diff --git a/app/controllers/forum_topics_controller.rb b/app/controllers/forum_topics_controller.rb index 5668dfdad..7f2f7b335 100644 --- a/app/controllers/forum_topics_controller.rb +++ b/app/controllers/forum_topics_controller.rb @@ -2,6 +2,7 @@ class ForumTopicsController < ApplicationController respond_to :html, :xml, :json before_filter :member_only, :except => [:index, :show] before_filter :normalize_search, :only => :index + before_filter :update_last_forum_read_at, :only => [:index, :show] rescue_from User::PrivilegeError, :with => "static/access_denied" def new @@ -56,6 +57,12 @@ private forum_topic.is_sticky = params[:forum_topic][:is_sticky] end + def update_last_forum_read_at + return if CurrentUser.last_forum_read_at.present? && CurrentUser.last_forum_read_at > 1.day.ago + + CurrentUser.update_column(:last_forum_read_at, Time.now) + end + def normalize_search if params[:title_matches] params[:search] ||= {} diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index de0478d9d..310758350 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -6,6 +6,7 @@ class SessionsController < ApplicationController def create if User.authenticate(params[:name], params[:password]) @user = User.find_by_name(params[:name]) + @user.update_column(:last_logged_in_at, Time.now) session[:user_id] = @user.id redirect_to(params[:url] || session[:previous_uri] || posts_path, :notice => "You are now logged in.") else diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 95304d0cc..254503f97 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -23,13 +23,20 @@ module ApplicationHelper end end + def time_tag(content = nil, time) + zone = time.strftime("%z") + datetime = time.strftime("%Y-%m-%dT%H:%M" + zone[0, 3] + ":" + zone[3, 2]) + + content_tag(:time, content || datetime, :datetime => datetime) + end + def compact_time(time) if time > Time.now.beginning_of_day - time.strftime("%H:%M") + time_tag(time.strftime("%H:%M"), time) elsif time > Time.now.beginning_of_year - time.strftime("%b %e") + time_tag(time.strftime("%b %e"), time) else - time.strftime("%b %e, %Y") + time_tag(time.strftime("%b %e, %Y"), time) end end diff --git a/app/logical/anonymous_user.rb b/app/logical/anonymous_user.rb index eb352dac4..1faf5b95e 100644 --- a/app/logical/anonymous_user.rb +++ b/app/logical/anonymous_user.rb @@ -112,6 +112,13 @@ class AnonymousUser [] end + def last_forum_read_at + Time.now + end + + def update_column(*params) + end + %w(member banned privileged contributor janitor moderator admin).each do |name| define_method("is_#{name}?") do false diff --git a/app/presenters/forum_topic_presenter.rb b/app/presenters/forum_topic_presenter.rb index 538a0a751..a10593cbc 100644 --- a/app/presenters/forum_topic_presenter.rb +++ b/app/presenters/forum_topic_presenter.rb @@ -5,8 +5,4 @@ class ForumTopicPresenter < Presenter @forum_posts = forum_posts @forum_topic = forum_topic end - - def pagination_html(template) - Paginators::ForumTopic.new(forum_topic, forum_posts).numbered_pagination_html(template) - end end diff --git a/app/views/forum_topics/_paginator.html.erb b/app/views/forum_topics/_paginator.html.erb deleted file mode 100644 index 67bc366e6..000000000 --- a/app/views/forum_topics/_paginator.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= @forum_topic.presenter(@forum_posts).pagination_html(self) %> diff --git a/app/views/forum_topics/index.html.erb b/app/views/forum_topics/index.html.erb index f1ed11ebc..131270f18 100644 --- a/app/views/forum_topics/index.html.erb +++ b/app/views/forum_topics/index.html.erb @@ -22,7 +22,13 @@ <% end %> + + <%= numbered_paginator(@forum_topics) %>
    -<%= render "secondary_links" %> \ No newline at end of file +<%= render "secondary_links" %> + +<%= content_for(:html_header) do %> + +<% end %> diff --git a/app/views/forum_topics/show.html.erb b/app/views/forum_topics/show.html.erb index 41a8d4a96..8eca7f10b 100644 --- a/app/views/forum_topics/show.html.erb +++ b/app/views/forum_topics/show.html.erb @@ -7,7 +7,8 @@ <% end %> <%= render "forum_posts/listing", :forum_posts => @forum_posts %> - <%= render "paginator" %> + + <%= numbered_paginator(@forum_posts) %>
    From 42654085817210eb98534ec50de597e416ff2cc7 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 23 Aug 2011 17:22:38 -0400 Subject: [PATCH 14/40] fix tests --- db/development_structure.sql | 54 ++++++++++++++++++++++++++++++++++-- test/unit/upload_test.rb | 6 ++-- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/db/development_structure.sql b/db/development_structure.sql index 3317975ee..8309e1645 100644 --- a/db/development_structure.sql +++ b/db/development_structure.sql @@ -463,6 +463,37 @@ CREATE SEQUENCE advertisements_id_seq ALTER SEQUENCE advertisements_id_seq OWNED BY advertisements.id; +-- +-- Name: amazon_backups; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE amazon_backups ( + id integer NOT NULL, + last_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: amazon_backups_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE amazon_backups_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: amazon_backups_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE amazon_backups_id_seq OWNED BY amazon_backups.id; + + -- -- Name: artist_urls; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -2252,7 +2283,7 @@ CREATE TABLE tag_aliases ( creator_id integer NOT NULL, creator_ip_addr inet NOT NULL, forum_topic_id integer, - status character varying(255) DEFAULT 'pending'::character varying NOT NULL, + status text DEFAULT 'pending'::text NOT NULL, created_at timestamp without time zone, updated_at timestamp without time zone ); @@ -2289,7 +2320,7 @@ CREATE TABLE tag_implications ( creator_id integer NOT NULL, creator_ip_addr inet NOT NULL, forum_topic_id integer, - status character varying(255) DEFAULT 'pending'::character varying NOT NULL, + status text DEFAULT 'pending'::text NOT NULL, created_at timestamp without time zone, updated_at timestamp without time zone ); @@ -2623,6 +2654,13 @@ ALTER TABLE advertisement_hits ALTER COLUMN id SET DEFAULT nextval('advertisemen ALTER TABLE advertisements ALTER COLUMN id SET DEFAULT nextval('advertisements_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE amazon_backups ALTER COLUMN id SET DEFAULT nextval('amazon_backups_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -2877,6 +2915,14 @@ ALTER TABLE ONLY advertisements ADD CONSTRAINT advertisements_pkey PRIMARY KEY (id); +-- +-- Name: amazon_backups_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY amazon_backups + ADD CONSTRAINT amazon_backups_pkey PRIMARY KEY (id); + + -- -- Name: artist_urls_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -5224,4 +5270,6 @@ INSERT INTO schema_migrations (version) VALUES ('20110607194023'); INSERT INTO schema_migrations (version) VALUES ('20110717010705'); -INSERT INTO schema_migrations (version) VALUES ('20110722211855'); \ No newline at end of file +INSERT INTO schema_migrations (version) VALUES ('20110722211855'); + +INSERT INTO schema_migrations (version) VALUES ('20110815233456'); \ No newline at end of file diff --git a/test/unit/upload_test.rb b/test/unit/upload_test.rb index 68a3bfe3b..554b9024d 100644 --- a/test/unit/upload_test.rb +++ b/test/unit/upload_test.rb @@ -111,11 +111,11 @@ class UploadTest < ActiveSupport::TestCase @upload.calculate_dimensions(@upload.file_path) assert_nothing_raised {@upload.generate_resizes(@upload.file_path)} assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.small_image_width))) - assert_equal(6556, File.size(@upload.resized_file_path_for(Danbooru.config.small_image_width))) + assert_equal(7265, File.size(@upload.resized_file_path_for(Danbooru.config.small_image_width))) assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.medium_image_width))) - assert_equal(39411, File.size(@upload.resized_file_path_for(Danbooru.config.medium_image_width))) + assert_equal(43474, File.size(@upload.resized_file_path_for(Danbooru.config.medium_image_width))) assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.large_image_width))) - assert_equal(179324, File.size(@upload.resized_file_path_for(Danbooru.config.large_image_width))) + assert_equal(198583, File.size(@upload.resized_file_path_for(Danbooru.config.large_image_width))) end end From ebee1eb665103263e0838b03521ce9d9f117fdd0 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 23 Aug 2011 18:33:27 -0400 Subject: [PATCH 15/40] fixed upload tests --- app/models/upload.rb | 2 +- test/functional/uploads_controller_test.rb | 4 +++- test/test_helper.rb | 2 +- tmp/test.jpg | Bin 28086 -> 0 bytes 4 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 tmp/test.jpg diff --git a/app/models/upload.rb b/app/models/upload.rb index 3611e98e4..53f35f403 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -260,7 +260,7 @@ class Upload < ActiveRecord::Base self.file_path = temp_file_path - if file.tempfile + if file.respond_to?(:tempfile) && file.tempfile FileUtils.cp(file.tempfile.path, file_path) else File.open(file_path, 'wb') do |out| diff --git a/test/functional/uploads_controller_test.rb b/test/functional/uploads_controller_test.rb index dba826462..5e9197c7d 100644 --- a/test/functional/uploads_controller_test.rb +++ b/test/functional/uploads_controller_test.rb @@ -64,7 +64,9 @@ class UploadsControllerTest < ActionController::TestCase context "create action" do should "create a new upload" do assert_difference("Upload.count", 1) do - post :create, {:upload => {:file => upload_jpeg("#{Rails.root}/test/files/test.jpg"), :tag_string => "aaa", :rating => "q", :source => "aaa"}}, {:user_id => @user.id} + file = Rack::Test::UploadedFile.new("#{Rails.root}/test/files/test.jpg", "image/jpeg") + file.stubs(:tempfile).returns(file) + post :create, {:upload => {:file => file, :tag_string => "aaa", :rating => "q", :source => "aaa"}}, {:user_id => @user.id} end end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 66e7adb60..e64bc3780 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -18,7 +18,7 @@ module UploadTestMethods define_method(:original_filename) {filename} define_method(:content_type) {content_type} end - + tempfile end diff --git a/tmp/test.jpg b/tmp/test.jpg deleted file mode 100644 index 253c508d9c84cee6433f57c5c756f06dc25534a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28086 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 PaJbDXdPt*R{r^n>pWW2} From 6d022d308aa486244b64d95d732ed3ae27046f77 Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 24 Aug 2011 16:56:30 -0400 Subject: [PATCH 16/40] updated INSTALL script --- INSTALL.debian | 171 ++++++++++------------------- script/install/nginx.conf | 31 ++++++ script/install/nginx.danbooru.conf | 43 ++++++++ 3 files changed, 131 insertions(+), 114 deletions(-) create mode 100644 script/install/nginx.conf create mode 100644 script/install/nginx.danbooru.conf diff --git a/INSTALL.debian b/INSTALL.debian index 6bf1c8cd5..677e65499 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -1,131 +1,74 @@ #!/bin/bash -echo "This script is out of date; please read the INSTALL document" -exit 1 - -if [ $USER != root ] ; then +if [[ "$(whoami)" != "root" ] ; then echo "You must run this script as root" exit 1 fi -echo "Danbooru Install" -echo "This script will install Ruby, Rails, PostgreSQL, and Nginx. By the end," -echo "you should be able to connect to the server and create an account." -echo -echo "It will create a new user called danbooru which will run the Danbooru" -echo "processes. It will download the latest trunk copy and install it in" -echo "/var/www/danbooru. It will run three Mongrel processes, starting on port" -echo "8050." -echo -echo -n "Enter the hostname for this server (ex: danbooru.donmai.us): " -read hostname - -if [ -z $hostname ] ; then - echo "Must enter a hostname" - exit 1 -fi - -echo -n "Enter a name for the site (default: Danbooru): " -read sitename - -if [ -z $sitename ] ; then - sitename=Danbooru -fi +# echo "Danbooru Install" +# echo "This script will install Ruby, Rails, PostgreSQL, and Nginx. By the end," +# echo "you should be able to connect to the server and create an account." +# echo +# echo "It will create a new user called danbooru which will run the Danbooru" +# echo "processes. It will download the latest copy and install it in" +# echo "/var/www/danbooru." +# echo +# echo -n "Enter the hostname for this server (ex: danbooru.donmai.us): " +# read hostname +# +# if [[ -z "$hostname" ]] ; then +# echo "Must enter a hostname" +# exit 1 +# fi +# +# echo -n "Enter a name for the site (default: Danbooru): " +# read sitename +# +# if [[ -z "$sitename" ]] ; then +# sitename=Danbooru +# fi # Install packages -apt-get -y install sudo gcc g++ make libreadline5-dev zlib1g-dev flex bison libgd2-noxpm libgd2-noxpm-dev bzip2 postgresql-8.3 postgresql-contrib-8.3 libpq-dev ruby ruby1.8-dev ri irb rdoc rubygems ragel memcached libmemcache-dev subversion nginx rake libopenssl-ruby mongrel +echo "Installing packages..." +apt-get -y install build-essential automake openssl libssl-dev libyaml-dev libxml2-dev libxslt-dev autoconf ncurses-dev sudo gcc g++ libreadline-dev zlib1g-dev flex bison libgd2-noxpm libgd2-noxpm-dev bzip2 ragel memcached libmemcache-dev git curl libcurl4-openssl-dev -# Install Ruby gems -for i in postgres diff-lcs html5 mongrel mongrel_cluster memcache-client aws-s3 json ; do gem install $i ; done -gem install rails --version=2.1.0 -gem install acts_as_versioned +# Install PostgreSQL 9.1 +apt-get -y install python-software-properties +add-apt-repository ppa:pitti/postgresql +apt-get update +apt-get install postgresql-9.1 libpq-dev + +# Install RVM +echo "Installing RVM..." +bash < <(curl -s https://rvm.beginrescueend.com/install/rvm) +echo "source /usr/local/rvm/scripts/rvm" >> /etc/bash.bashrc +source /usr/local/rvm/scripts/rvm +rvm install ruby-1.9.2-p290 --with-openssl-dir=/usr/local +rvm 1.9.2 --default + +# Install gems +gem install --no-ri --no-rdoc capistrano + +# Install Passenger +gem install --no-ri --no-rdoc -v 3.0.8 passenger +rvm exec passenger-install-nginx-module + +# Setup nginx +curl -s https://raw.github.com/ascarter/nginx-ubuntu-rvm/master/nginx > /etc/init.d/nginx +chmod +x,g-w /etc/init.d/nginx +update-rc.d -f nginx defaults +mkdir -p /opt/nginx/sites +curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.conf > /opt/nginx/conf/nginx.conf +curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.danbooru.conf > /opt/nginx/conf/sites/danbooru.conf +/etc/init.d/nginx start # Create user account -useradd -m danbooru -PG_HBA_FILE="/etc/postgresql/8.3/main/pg_hba.conf" +# useradd -m danbooru +PG_HBA_FILE="/etc/postgresql/9.1/main/pg_hba.conf" echo "local all postgres,danbooru trust" > $PG_HBA_FILE echo "host all postgres,danbooru 127.0.0.1/32 trust" >> $PG_HBA_FILE -/etc/init.d/postgresql-8.3 restart - -# Install Danbooru -cd /var/www -svn export svn://donmai.us/danbooru/trunk danbooru -chown -R danbooru:danbooru danbooru -cd danbooru -mkdir -p public/data/sample -cd config -cp database.yml.example database.yml -cp local_config.rb.example local_config.rb -sed -i -e "s/DAN_HOSTNAME/$hostname/g" local_config.rb -sed -i -e "s/DAN_SITENAME/$sitename/g" local_config.rb -echo "--- " > mongrel_cluster.yml -echo "cwd: /var/www/danbooru" >> mongrel_cluster.yml -echo "port: \"8050\"" >> mongrel_cluster.yml -echo "environment: production" >> mongrel_cluster.yml -echo "address: 127.0.0.1" >> mongrel_cluster.yml -echo "servers: 3" >> mongrel_cluster.yml -echo "num_processors: 10" >> mongrel_cluster.yml -cd ../lib/danbooru_image_resizer -ruby extconf.rb -make -cd ../.. +/etc/init.d/postgresql-9.1 restart sudo -u postgres createuser -s danbooru -sudo -u danbooru createdb danbooru -sudo -u danbooru psql danbooru < db/postgres.sql -sudo -u danbooru rake db:migrate RAILS_ENV=production -script/donmai/upbooru - -# Set up nginx -DANBOORU_CONF_FILE="/etc/nginx/sites-enabled/danbooru.conf" -echo "upstream mongrel {" > $DANBOORU_CONF_FILE -echo " server 127.0.0.1:8050;" >> $DANBOORU_CONF_FILE -echo " server 127.0.0.1:8051;" >> $DANBOORU_CONF_FILE -echo " server 127.0.0.1:8052;" >> $DANBOORU_CONF_FILE -echo "}" >> $DANBOORU_CONF_FILE -echo "server {" >> $DANBOORU_CONF_FILE -echo " listen 80;" >> $DANBOORU_CONF_FILE -echo " server_name $hostname;" >> $DANBOORU_CONF_FILE -echo " root /var/www/danbooru/public;" >> $DANBOORU_CONF_FILE -echo " index index.html;" >> $DANBOORU_CONF_FILE -echo " access_log /var/www/danbooru/log/server.access.log;" >> $DANBOORU_CONF_FILE -echo " error_log /var/www/danbooru/log/server.error.log;" >> $DANBOORU_CONF_FILE -echo " client_max_body_size 30m;" >> $DANBOORU_CONF_FILE -echo " location /stylesheets {" >> $DANBOORU_CONF_FILE -echo " expires max;" >> $DANBOORU_CONF_FILE -echo " break;" >> $DANBOORU_CONF_FILE -echo " }" >> $DANBOORU_CONF_FILE -echo " location /javascripts {" >> $DANBOORU_CONF_FILE -echo " expires max;" >> $DANBOORU_CONF_FILE -echo " break;" >> $DANBOORU_CONF_FILE -echo " }" >> $DANBOORU_CONF_FILE -echo " location /data {" >> $DANBOORU_CONF_FILE -echo " valid_referers none $hostname;" >> $DANBOORU_CONF_FILE -echo " if (\$invalid_referer) {" >> $DANBOORU_CONF_FILE -echo " return 403;" >> $DANBOORU_CONF_FILE -echo " }" >> $DANBOORU_CONF_FILE -echo " expires max;" >> $DANBOORU_CONF_FILE -echo " break;" >> $DANBOORU_CONF_FILE -echo " }" >> $DANBOORU_CONF_FILE -echo " location /maintenance.html {" >> $DANBOORU_CONF_FILE -echo " expires 10;" >> $DANBOORU_CONF_FILE -echo " }" >> $DANBOORU_CONF_FILE -echo " if (-f \$document_root/maintenance.html) {" >> $DANBOORU_CONF_FILE -echo " rewrite ^(.*)\$ /maintenance.html last;" >> $DANBOORU_CONF_FILE -echo " break;" >> $DANBOORU_CONF_FILE -echo " }" >> $DANBOORU_CONF_FILE -echo " location / {" >> $DANBOORU_CONF_FILE -echo " proxy_set_header X-Real-IP \$remote_addr;" >> $DANBOORU_CONF_FILE -echo " proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;" >> $DANBOORU_CONF_FILE -echo " proxy_set_header Host \$http_host;" >> $DANBOORU_CONF_FILE -echo " proxy_redirect false;" >> $DANBOORU_CONF_FILE -echo " if (!-f \$request_filename) {" >> $DANBOORU_CONF_FILE -echo " proxy_pass http://mongrel;" >> $DANBOORU_CONF_FILE -echo " }" >> $DANBOORU_CONF_FILE -echo " }" >> $DANBOORU_CONF_FILE -echo " error_page 404 /404.html;" >> $DANBOORU_CONF_FILE -echo " error_page 500 502 503 504 /500.html;" >> $DANBOORU_CONF_FILE -echo "}" >> $DANBOORU_CONF_FILE -/etc/init.d/nginx restart echo echo "I'm done!" diff --git a/script/install/nginx.conf b/script/install/nginx.conf new file mode 100644 index 000000000..ac3f8e5ad --- /dev/null +++ b/script/install/nginx.conf @@ -0,0 +1,31 @@ +pid /var/run/nginx.pid; + +events { + use epoll; + worker_connections 1024; +} + +http { + passenger_root /usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.8; + passenger_ruby /usr/local/rvm/wrappers/default/ruby; + passenger_enabled on; + passenger_user_switching on; + passenger_default_user danbooru; + rails_spawn_method smart; + passenger_max_pool_size 3; + + include mime.types; + default_type application/octet-stream; + + sendfile on; + + gzip on; + gzip_http_version 1.1; + gzip_vary off; + gzip_comp_level 6; + gzip_proxied any; + gzip_types text/plain text/html text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; + gzip_buffers 16 8k; + + include /opt/nginx/conf/sites/*.conf; +} diff --git a/script/install/nginx.danbooru.conf b/script/install/nginx.danbooru.conf new file mode 100644 index 000000000..df756ff36 --- /dev/null +++ b/script/install/nginx.danbooru.conf @@ -0,0 +1,43 @@ +server { + listen 80; + server_name $hostname; + root /var/www/danbooru/public; + index index.html; + access_log /var/www/danbooru/log/server.access.log; + error_log /var/www/danbooru/log/server.error.log; + client_max_body_size 30m; + location /stylesheets { + expires max; + break; + } + location /javascripts { + expires max; + break; + } + location /data { + valid_referers none $hostname; + if ($invalid_referer) { + return 403; + } + expires max; + break; + } + location /maintenance.html { + expires 10; + } + if (-f $document_root/maintenance.html) { + rewrite ^(.*)$ /maintenance.html last; + break; + } + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_redirect false; + if (!-f $request_filename) { + proxy_pass http://mongrel; + } + } + error_page 404 /404.html; + error_page 500 502 503 504 /500.html; +} \ No newline at end of file From 43db02b7d0c2f57086fa22cbeaac4e178a6fa36b Mon Sep 17 00:00:00 2001 From: albert Date: Wed, 24 Aug 2011 17:04:26 -0400 Subject: [PATCH 17/40] script fixes --- INSTALL.debian | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/INSTALL.debian b/INSTALL.debian index 677e65499..e015cc11c 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -1,6 +1,6 @@ #!/bin/bash -if [[ "$(whoami)" != "root" ] ; then +if [[ "$(whoami)" != "root" ]] ; then echo "You must run this script as root" exit 1 fi @@ -36,7 +36,8 @@ apt-get -y install build-essential automake openssl libssl-dev libyaml-dev libxm apt-get -y install python-software-properties add-apt-repository ppa:pitti/postgresql apt-get update -apt-get install postgresql-9.1 libpq-dev +apt-get install -y postgresql-9.1 libpq-dev +POSTGRESQL_EXIT=$? # Install RVM echo "Installing RVM..." @@ -52,6 +53,7 @@ gem install --no-ri --no-rdoc capistrano # Install Passenger gem install --no-ri --no-rdoc -v 3.0.8 passenger rvm exec passenger-install-nginx-module +RVM_EXIT=$? # Setup nginx curl -s https://raw.github.com/ascarter/nginx-ubuntu-rvm/master/nginx > /etc/init.d/nginx @@ -60,15 +62,25 @@ update-rc.d -f nginx defaults mkdir -p /opt/nginx/sites curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.conf > /opt/nginx/conf/nginx.conf curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.danbooru.conf > /opt/nginx/conf/sites/danbooru.conf -/etc/init.d/nginx start + +if [ $RVM_EXIT -ne 0 ] ; then + echo "Passenger installation failed; not starting nginx" +else + /etc/init.d/nginx start +fi # Create user account # useradd -m danbooru PG_HBA_FILE="/etc/postgresql/9.1/main/pg_hba.conf" echo "local all postgres,danbooru trust" > $PG_HBA_FILE echo "host all postgres,danbooru 127.0.0.1/32 trust" >> $PG_HBA_FILE -/etc/init.d/postgresql-9.1 restart -sudo -u postgres createuser -s danbooru + +if [ $POSTGRESQL_EXIT -ne 0 ]; then + echo "PostgreSQL installation failed; not starting server" +else + /etc/init.d/postgresql-9.1 restart + sudo -u postgres createuser -s danbooru +fi echo echo "I'm done!" From 659f79ace592f841600c561e7179d141b5071cc8 Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 26 Aug 2011 17:06:54 -0400 Subject: [PATCH 18/40] install script fixes --- INSTALL.debian | 27 ++++---- INSTALL.freebsd | 138 -------------------------------------- script/install/nginx.conf | 1 - 3 files changed, 12 insertions(+), 154 deletions(-) delete mode 100644 INSTALL.freebsd diff --git a/INSTALL.debian b/INSTALL.debian index e015cc11c..d11913857 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -37,7 +37,10 @@ apt-get -y install python-software-properties add-apt-repository ppa:pitti/postgresql apt-get update apt-get install -y postgresql-9.1 libpq-dev -POSTGRESQL_EXIT=$? + +if [ $? -ne 0 ]; then + exit 1 +fi # Install RVM echo "Installing RVM..." @@ -53,7 +56,10 @@ gem install --no-ri --no-rdoc capistrano # Install Passenger gem install --no-ri --no-rdoc -v 3.0.8 passenger rvm exec passenger-install-nginx-module -RVM_EXIT=$? + +if [ $? -ne 0 ]; then + exit 1 +fi # Setup nginx curl -s https://raw.github.com/ascarter/nginx-ubuntu-rvm/master/nginx > /etc/init.d/nginx @@ -62,25 +68,16 @@ update-rc.d -f nginx defaults mkdir -p /opt/nginx/sites curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.conf > /opt/nginx/conf/nginx.conf curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.danbooru.conf > /opt/nginx/conf/sites/danbooru.conf - -if [ $RVM_EXIT -ne 0 ] ; then - echo "Passenger installation failed; not starting nginx" -else - /etc/init.d/nginx start -fi +/etc/init.d/nginx start # Create user account -# useradd -m danbooru +useradd -m danbooru PG_HBA_FILE="/etc/postgresql/9.1/main/pg_hba.conf" echo "local all postgres,danbooru trust" > $PG_HBA_FILE echo "host all postgres,danbooru 127.0.0.1/32 trust" >> $PG_HBA_FILE -if [ $POSTGRESQL_EXIT -ne 0 ]; then - echo "PostgreSQL installation failed; not starting server" -else - /etc/init.d/postgresql-9.1 restart - sudo -u postgres createuser -s danbooru -fi +/etc/init.d/postgresql-9.1 restart +sudo -u postgres createuser -s danbooru echo echo "I'm done!" diff --git a/INSTALL.freebsd b/INSTALL.freebsd deleted file mode 100644 index 44bb59039..000000000 --- a/INSTALL.freebsd +++ /dev/null @@ -1,138 +0,0 @@ -Danbooru Installation guide on FreeBSD (6.2) -Provided by Shuugo -Cleanup of dovac's guide: http://uruchai.com/2007/12/24/in-depth-guide-on-installing-danbooru-on-freebsd - -A minimal FreeBSD profile installation is encouraged. You can use VMWare to test how things work before trying on an actual machine. - -1)) Updating ports: -You can find how fully work here: http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ports-using.html but basically you will only need: - -1. portsnap fetch -2. portsnap extract - -2)) Install the following things through ports - -1. cd /usr/ports/devel/mkmf/ && make install clean -2. cd /usr/ports/ftp/wget/ && make install clean -3. cd /usr/ports/editors/nano/ && make install clean -4. cd /usr/ports/devel/subversion/ && make install clean (May ask for configuration: Choose "libiconv", "python25", enable "huge stack size", and disable "ipv6" -5. cd /usr/ports/databases/memcached/ && make install clean -6. cd /usr/ports/graphics/gd/ && make install clean (Make sure you enable iconv support) -7. cd /usr/ports/databases/postgresql83-client/ && make install clean (config defaults are ok) -8. cd /usr/ports/databases/postgresql83-server/ && make install clean (config defaults are ok) - -3)) Editing rc.conf for starting postgres and memcached at boot. - -1. nano /etc/rc.conf -2. Add the following at the end of the file: - -postgresql_enable="YES" -memcached_enable="yes" -memacached_flags="-l 127.0.0.1 -d m 100" - -3. Press Control + X to save. - -4. We run "/usr/local/etc/rc.d/postgresql initdb" to get ready to initialize postgres for first time. - -5. Use "/usr/local/etc/rc.d/postgresql start", to start the postgresql server. - -4)) Ruby on rails installation - -1. cd /usr/ports/lang/ruby18/ && make install clean (Disable ipv6) -2. rubygem-rails port is broken, download it from rubyforge -2a wget http://rubyforge.org/frs/download.php/29548/rubygems-1.0.1.tgz -2b tar xvf rubygems-1.0.1.tgz -2c cd rubygems-1.0.1 -2d ruby setup.rb -3. cd /usr/ports/www/rubygem-rails/ && make install clean (Be sure it's rubygem-rails-1.2.6. Rails 2.0 isn't compatible yet) -4. cd /usr/ports/www/rubygem-redcloth/ && make install clean -5. cd /usr/ports/www/rubygem-mongrel/ && make install clean - -Some gems are not available through ports - -6a wget http://rubyforge.org/frs/download.php/29624/postgres-0.7.9.2007.12.22.gem -6b /usr/bin/gem18 install --no-ri --install-dir /usr/local/lib/ruby/gems/1.8 ./postgres-0.7.9.2007.12.22.gem (There's a chance that it's not gem18, but gem I'll assume it's the correct path, if not, replace it on the following steps too) - -7. /usr/bin/gem18 aws-s3 diff-lcs acts_as_versioned html5 (Accept all dependencies) - -5)) Danbooru installation - -1. Create the danbooru user, -> adduser (danbooru, and choose a password) -2. cd /home/danbooru -3. svn co svn://danbooru.donmai.us/danbooru/trunk (This will get you the latest trunk) -4. cd trunk/ -5. mv * .. -6. cd .. -7. rm -r trunk/ - -8. Database creation: -8a su pgsql -8b CREATE DATABASE danbooru; -8c \q -8d psql -d danbooru -f /home/danbooru/db/postgres.sql -8e exit - -6)) Danbooru configuration - -1. cd /home/danbooru/config -2. mv database.yml.example database.yml -3. nano database.yml -3a Change all users to pgsql (Control+X to save and exit) -4. mv local_config.rb.example local_config.rb -5. nano local_config.rb -NOTE: You can check for additional configuration parameters and a brief explanation in default_config.rb -5a. Change the parameters needed an add these parameters -CONFIG["password_salt"] = “choujin-steinerr” (replace the salt with something else) -CONFIG["image_store"] = :local_flat (replace with :local_hierarchy if you want scaled folders for example /01/23/fullhash.ext, leave :local_falt to leave all the images in one same folder) -CONFIG["enable_caching"] = false (change to true to enable memcache, this will speed up things) -CONFIG["memcache_servers"] = ["localhost:4000"] (change to "localhost:11211") -5b Control + X to save and exit. - -6. Compiling the resizer -6a You can rather choose between using "ruby extconf.rb" or "ruby extconf.rb --with-gd-dir=/usr/local/gd", if you are using this last option you can ignore the 6b 6c and 6d steps. Using the first method will give you always the same gd version while the second command, the gd version will be updated when you update it through ports. -6b cp /usr/local/include/gd.h gd.h -6c cp /usr/local/include/gd_io.h gd_io.h -6d cp /usr/local/include/gdfx.h gdfx.h -6e make -6f make install - -7. cd /home/danbooru -7b /usr/local/bin/rake db:migrate - -7)) Basic webserver - -- Now you can run "mongrel_rails start", this will make danbooru public on your hostname:3000. You will see debug information in the console - -- For running it with mongrel and serving it "normally" you can use "mongrel_rails start -p 80 -d" This will tell mongrel to run on port 80 and as a daemon (not displaying anything in the console) - -8)) Advanced webserver - -Is encouraged that you rather configure Apache or lighttpd to proxy (or vhosting) the rails app. However this last method requries advanced configuration files and server modules. - -If you plan only on running danbooru here's a good configuration for lighttpd usage (you can install it through ports) -Mongrel running as a daemon (4 threads) You might want to add this to the rc.conf if you want to start it automatically - -1. cd /home/danbooru -2a mongrel_rails start -d -p 8001 -e production -P log/mongrel-1.pid -2b mongrel_rails start -d -p 8002 -e production -P log/mongrel-2.pid -2c mongrel_rails start -d -p 8003 -e production -P log/mongrel-3.pid -2d mongrel_rails start -d -p 8004 -e production -P log/mongrel-4.pid - -Then on lighttpd.conf be sure to have the following mods enabled (Remove # before its names if not): --mod_rewrite --mod_redirect --mod_access --mod_accesslog --mod_compress --mod_proxy - -3. Add this to your lighttpd.conf: - -proxy.balance = "fair" -proxy.server = ( "/" => - ( ( "host" => "127.0.0.1", "port" => 8001 ), - ( "host" => "127.0.0.1", "port" => 8002 ), - ( "host" => "127.0.0.1", "port" => 8003 ), - ( "host" => "127.0.0.1", "port" => 8004 ) ) ) - -4. Restart lighttpd: "/usr/local/etc/rc.d/lighttpd restart" \ No newline at end of file diff --git a/script/install/nginx.conf b/script/install/nginx.conf index ac3f8e5ad..91626ec5c 100644 --- a/script/install/nginx.conf +++ b/script/install/nginx.conf @@ -8,7 +8,6 @@ events { http { passenger_root /usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.8; passenger_ruby /usr/local/rvm/wrappers/default/ruby; - passenger_enabled on; passenger_user_switching on; passenger_default_user danbooru; rails_spawn_method smart; From 8031893ea7a51edd63b990a2a1c7b645237a342d Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 26 Aug 2011 17:13:05 -0400 Subject: [PATCH 19/40] install script fixes --- INSTALL.debian | 1 + script/install/nginx.danbooru.conf | 13 ++----------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/INSTALL.debian b/INSTALL.debian index d11913857..581dadf15 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -68,6 +68,7 @@ update-rc.d -f nginx defaults mkdir -p /opt/nginx/sites curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.conf > /opt/nginx/conf/nginx.conf curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.danbooru.conf > /opt/nginx/conf/sites/danbooru.conf +sed -i -e 's/HOSTNAME/$hostname/g' /opt/nginx/conf/sites/danbooru.conf /etc/init.d/nginx start # Create user account diff --git a/script/install/nginx.danbooru.conf b/script/install/nginx.danbooru.conf index df756ff36..4457d6751 100644 --- a/script/install/nginx.danbooru.conf +++ b/script/install/nginx.danbooru.conf @@ -1,6 +1,6 @@ server { listen 80; - server_name $hostname; + server_name HOSTNAME; root /var/www/danbooru/public; index index.html; access_log /var/www/danbooru/log/server.access.log; @@ -15,7 +15,7 @@ server { break; } location /data { - valid_referers none $hostname; + valid_referers none HOSTNAME; if ($invalid_referer) { return 403; } @@ -29,15 +29,6 @@ server { rewrite ^(.*)$ /maintenance.html last; break; } - location / { - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $http_host; - proxy_redirect false; - if (!-f $request_filename) { - proxy_pass http://mongrel; - } - } error_page 404 /404.html; error_page 500 502 503 504 /500.html; } \ No newline at end of file From d7ccb94a5e32c10943aba47c24d52e2b4a46eea9 Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 26 Aug 2011 17:24:07 -0400 Subject: [PATCH 20/40] install script fixes --- INSTALL.debian | 62 +++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/INSTALL.debian b/INSTALL.debian index 581dadf15..1fe042503 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -5,28 +5,28 @@ if [[ "$(whoami)" != "root" ]] ; then exit 1 fi -# echo "Danbooru Install" -# echo "This script will install Ruby, Rails, PostgreSQL, and Nginx. By the end," -# echo "you should be able to connect to the server and create an account." -# echo -# echo "It will create a new user called danbooru which will run the Danbooru" -# echo "processes. It will download the latest copy and install it in" -# echo "/var/www/danbooru." -# echo -# echo -n "Enter the hostname for this server (ex: danbooru.donmai.us): " -# read hostname -# -# if [[ -z "$hostname" ]] ; then -# echo "Must enter a hostname" -# exit 1 -# fi -# -# echo -n "Enter a name for the site (default: Danbooru): " -# read sitename -# -# if [[ -z "$sitename" ]] ; then -# sitename=Danbooru -# fi +echo "Danbooru Install" +echo "This script will install Ruby, Rails, PostgreSQL, and Nginx. By the end," +echo "you should be able to connect to the server and create an account." +echo +echo "It will create a new user called danbooru which will run the Danbooru" +echo "processes. It will download the latest copy and install it in" +echo "/var/www/danbooru." +echo +echo -n "Enter the hostname for this server (ex: danbooru.donmai.us): " +read hostname + +if [[ -z "$hostname" ]] ; then + echo "Must enter a hostname" + exit 1 +fi + +echo -n "Enter a name for the site (default: Danbooru): " +read sitename + +if [[ -z "$sitename" ]] ; then + sitename=Danbooru +fi # Install packages echo "Installing packages..." @@ -61,6 +61,15 @@ if [ $? -ne 0 ]; then exit 1 fi +# Create user account +useradd -m danbooru +PG_HBA_FILE="/etc/postgresql/9.1/main/pg_hba.conf" +echo "local all postgres,danbooru trust" > $PG_HBA_FILE +echo "host all postgres,danbooru 127.0.0.1/32 trust" >> $PG_HBA_FILE + +/etc/init.d/postgresql restart +sudo -u postgres createuser -s danbooru + # Setup nginx curl -s https://raw.github.com/ascarter/nginx-ubuntu-rvm/master/nginx > /etc/init.d/nginx chmod +x,g-w /etc/init.d/nginx @@ -71,15 +80,6 @@ curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.d sed -i -e 's/HOSTNAME/$hostname/g' /opt/nginx/conf/sites/danbooru.conf /etc/init.d/nginx start -# Create user account -useradd -m danbooru -PG_HBA_FILE="/etc/postgresql/9.1/main/pg_hba.conf" -echo "local all postgres,danbooru trust" > $PG_HBA_FILE -echo "host all postgres,danbooru 127.0.0.1/32 trust" >> $PG_HBA_FILE - -/etc/init.d/postgresql-9.1 restart -sudo -u postgres createuser -s danbooru - echo echo "I'm done!" echo "You should probably set the password for the danbooru account (run passwd danbooru)." From 8b0ff52ede41e3b76c7d4f65301c4b450ffe2cc6 Mon Sep 17 00:00:00 2001 From: albert Date: Sun, 28 Aug 2011 11:11:58 -0400 Subject: [PATCH 21/40] updated install script --- INSTALL.debian | 11 ++++++++++- app/models/post.rb | 17 +++++++++++++++++ app/models/upload.rb | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/INSTALL.debian b/INSTALL.debian index 1fe042503..3154c3dc3 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -13,6 +13,9 @@ echo "It will create a new user called danbooru which will run the Danbooru" echo "processes. It will download the latest copy and install it in" echo "/var/www/danbooru." echo +echo "It is mostly automated but you will receive some prompts when installing" +echo "Passenger towards the end of the script." +echo echo -n "Enter the hostname for this server (ex: danbooru.donmai.us): " read hostname @@ -76,10 +79,16 @@ chmod +x,g-w /etc/init.d/nginx update-rc.d -f nginx defaults mkdir -p /opt/nginx/sites curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.conf > /opt/nginx/conf/nginx.conf +mkdir -p /opt/nginx/conf/sites curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.danbooru.conf > /opt/nginx/conf/sites/danbooru.conf sed -i -e 's/HOSTNAME/$hostname/g' /opt/nginx/conf/sites/danbooru.conf /etc/init.d/nginx start +# Setup danbooru account +echo "*************************************************" +echo "* Enter a new password for the danbooru account *" +echo "*************************************************" +passwd danbooru + echo echo "I'm done!" -echo "You should probably set the password for the danbooru account (run passwd danbooru)." diff --git a/app/models/post.rb b/app/models/post.rb index fb52bed3b..72edda4b2 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -5,6 +5,7 @@ class Post < ActiveRecord::Base attr_accessor :old_tag_string, :old_parent_id after_destroy :delete_files + after_destroy :delete_remote_files after_save :create_version after_save :update_parent_on_save before_save :merge_old_tags @@ -61,6 +62,22 @@ class Post < ActiveRecord::Base } module FileMethods + def distribute_files + RemoteFileManager.new(file_path).distribute + RemoteFileManager.new(real_preview_path).distribute + RemoteFileManager.new(ssd_preview_path).distribute if Danbooru.config.ssd_path + RemoteFileManager.new(medium_file_path).distribute if has_medium? + RemoteFileManager.new(large_file_path).distribute if has_large? + end + + def delete_remote_files + RemoteFileManager.new(file_path).delete + RemoteFileManager.new(real_preview_path).delete + RemoteFileManager.new(ssd_preview_path).delete if Danbooru.config.ssd_path + RemoteFileManager.new(medium_file_path).delete if has_medium? + RemoteFileManager.new(large_file_path).delete if has_large? + end + def delete_files FileUtils.rm_f(file_path) FileUtils.rm_f(medium_file_path) diff --git a/app/models/upload.rb b/app/models/upload.rb index 53f35f403..0d8de2062 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -66,6 +66,7 @@ class Upload < ActiveRecord::Base generate_resizes(file_path) move_file post = convert_to_post + post.distribute_files if post.save update_attributes(:status => "completed", :post_id => post.id) else From 6e54f257afe40f20d210d96cee6387ba1e9a4541 Mon Sep 17 00:00:00 2001 From: albert Date: Sun, 28 Aug 2011 13:17:38 -0400 Subject: [PATCH 22/40] install script fixes --- INSTALL.debian | 16 ++++++++++++++-- script/install/nginx.danbooru.conf | 4 ++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/INSTALL.debian b/INSTALL.debian index 3154c3dc3..7f6907dad 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -73,17 +73,29 @@ echo "host all postgres,danbooru 127.0.0.1/32 trust" /etc/init.d/postgresql restart sudo -u postgres createuser -s danbooru +mkdir -p /var/log/www + # Setup nginx curl -s https://raw.github.com/ascarter/nginx-ubuntu-rvm/master/nginx > /etc/init.d/nginx chmod +x,g-w /etc/init.d/nginx update-rc.d -f nginx defaults -mkdir -p /opt/nginx/sites -curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.conf > /opt/nginx/conf/nginx.conf mkdir -p /opt/nginx/conf/sites +curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.conf > /opt/nginx/conf/nginx.conf curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.danbooru.conf > /opt/nginx/conf/sites/danbooru.conf sed -i -e 's/HOSTNAME/$hostname/g' /opt/nginx/conf/sites/danbooru.conf /etc/init.d/nginx start +# Setup logrotate +LOGROTATE_CONF_FILE="/etc/logrotate.conf" +echo >> $LOGROTATE_CONF_FILE +echo "/var/log/www/danbooru.access.log" >> $LOGROTATE_CONF_FILE +echo "/var/log/www/danbooru.error.log">> $LOGROTATE_CONF_FILE +echo "/var/www/danbooru/current/log/production.log {" >> $LOGROTATE_CONF_FILE +echo " daily" >> $LOGROTATE_CONF_FILE +echo " rotate 3" >> $LOGROTATE_CONF_FILE +echo " copytruncate" >> $LOGROTATE_CONF_FILE +echo "}" >> $LOGROTATE_CONF_FILE + # Setup danbooru account echo "*************************************************" echo "* Enter a new password for the danbooru account *" diff --git a/script/install/nginx.danbooru.conf b/script/install/nginx.danbooru.conf index 4457d6751..53de37ac5 100644 --- a/script/install/nginx.danbooru.conf +++ b/script/install/nginx.danbooru.conf @@ -3,8 +3,8 @@ server { server_name HOSTNAME; root /var/www/danbooru/public; index index.html; - access_log /var/www/danbooru/log/server.access.log; - error_log /var/www/danbooru/log/server.error.log; + access_log /var/log/www/danbooru.access.log; + error_log /var/log/www/danbooru.error.log; client_max_body_size 30m; location /stylesheets { expires max; From 03a5fff2196bbae17166720f7ef1382a0a8b4e86 Mon Sep 17 00:00:00 2001 From: albert Date: Sun, 28 Aug 2011 13:28:53 -0400 Subject: [PATCH 23/40] install script --- INSTALL.debian | 2 ++ 1 file changed, 2 insertions(+) diff --git a/INSTALL.debian b/INSTALL.debian index 7f6907dad..932168487 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -1,5 +1,7 @@ #!/bin/bash +# Run: bash < <(curl -s https://raw.github.com/r888888888/danbooru/master/INSTALL.debian) + if [[ "$(whoami)" != "root" ]] ; then echo "You must run this script as root" exit 1 From 51e8b57a3dcb5113c76e2794d3072d96390a6627 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 29 Aug 2011 14:49:34 -0400 Subject: [PATCH 24/40] fixes --- INSTALL.debian | 18 ++++++++++++++++-- app/logical/remote_file_manager.rb | 23 +++++++++++++++++++++++ config/deploy.rb | 25 +++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 app/logical/remote_file_manager.rb diff --git a/INSTALL.debian b/INSTALL.debian index 932168487..7d2784669 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -1,6 +1,6 @@ #!/bin/bash -# Run: bash < <(curl -s https://raw.github.com/r888888888/danbooru/master/INSTALL.debian) +# Run: curl -s https://raw.github.com/r888888888/danbooru/master/INSTALL.debian > install.sh ; chmod +x install.sh ; ./install.sh if [[ "$(whoami)" != "root" ]] ; then echo "You must run this script as root" @@ -35,7 +35,7 @@ fi # Install packages echo "Installing packages..." -apt-get -y install build-essential automake openssl libssl-dev libyaml-dev libxml2-dev libxslt-dev autoconf ncurses-dev sudo gcc g++ libreadline-dev zlib1g-dev flex bison libgd2-noxpm libgd2-noxpm-dev bzip2 ragel memcached libmemcache-dev git curl libcurl4-openssl-dev +apt-get -y install build-essential automake openssl libssl-dev libyaml-dev libxml2-dev libxslt-dev autoconf ncurses-dev sudo gcc g++ libreadline-dev zlib1g-dev flex bison libgd2-noxpm libgd2-noxpm-dev bzip2 ragel memcached libmemcache-dev git curl libcurl4-openssl-dev emacs-nox # Install PostgreSQL 9.1 apt-get -y install python-software-properties @@ -51,12 +51,14 @@ fi echo "Installing RVM..." bash < <(curl -s https://rvm.beginrescueend.com/install/rvm) echo "source /usr/local/rvm/scripts/rvm" >> /etc/bash.bashrc +echo "source /usr/local/rvm/scripts/rvm" >> /etc/profile source /usr/local/rvm/scripts/rvm rvm install ruby-1.9.2-p290 --with-openssl-dir=/usr/local rvm 1.9.2 --default # Install gems gem install --no-ri --no-rdoc capistrano +gem install --no-ri --no-rdoc capistrano-ext # Install Passenger gem install --no-ri --no-rdoc -v 3.0.8 passenger @@ -68,6 +70,16 @@ fi # Create user account useradd -m danbooru +chsh -s /bin/bash danbooru +echo "source /usr/local/rvm/scripts/rvm" > /home/danbooru/.bashrc +chmod g-wx,o-wx /home/danbooru/.bashrc +chown danbooru:danbooru /home/danbooru/.bashrc +echo "export rvm_path=/usr/local/rvm" > /etc/rvmrc +addgroup wheel +usermod -G root,wheel root +usermod -G danbooru,wheel danbooru + +# Update PostgreSQL PG_HBA_FILE="/etc/postgresql/9.1/main/pg_hba.conf" echo "local all postgres,danbooru trust" > $PG_HBA_FILE echo "host all postgres,danbooru 127.0.0.1/32 trust" >> $PG_HBA_FILE @@ -87,6 +99,8 @@ curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.d sed -i -e 's/HOSTNAME/$hostname/g' /opt/nginx/conf/sites/danbooru.conf /etc/init.d/nginx start +echo "%wheel ALL=(ALL) ALL" >> /etc/sudoers + # Setup logrotate LOGROTATE_CONF_FILE="/etc/logrotate.conf" echo >> $LOGROTATE_CONF_FILE diff --git a/app/logical/remote_file_manager.rb b/app/logical/remote_file_manager.rb new file mode 100644 index 000000000..beb2c7af5 --- /dev/null +++ b/app/logical/remote_file_manager.rb @@ -0,0 +1,23 @@ +class RemoteFileManager + attr_reader :path + + def initialize(path) + @path = path + end + + def distribute + Danbooru.config.other_server_hosts.each do |hostname| + Net::SFTP.start(hostname, Danbooru.config.remote_server_login) do |ftp| + ftp.upload!(path, path) + end + end + end + + def delete + Danbooru.config.other_server_hosts.each do |hostname| + Net::SFTP.start(hostname, Danbooru.config.remote_server_login) do |ftp| + ftp.remove(path) + end + end + end +end diff --git a/config/deploy.rb b/config/deploy.rb index bbf7e66c9..e70a241d0 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -1,5 +1,6 @@ $:.unshift(File.expand_path("./lib", ENV["rvm_path"])) set :rvm_ruby_string, "ruby-1.9.2" +set :rvm_bin_path, "/usr/local/rvm/bin" require 'rvm/capistrano' set :stages, %w(production staging) @@ -15,8 +16,30 @@ require 'whenever/capistrano' set :application, "danbooru" set :repository, "git://github.com/r888888888/danbooru.git" set :scm, :git +set :user, "danbooru" set :deploy_to, "/var/www/#{application}" +default_run_options[:pty] = true + +desc "Change ownership of common directory to user" +task :reset_ownership_of_common_directory do + sudo "chown -R #{user}:#{user} /var/www/danbooru" +end + +namespace :deploy do + namespace :web do + desc "Present a maintenance page to visitors." + task :disable do + run "mv #{current_path}/public/maintenance2.html #{current_path}/public/maintenance.html" + end + + desc "Makes the application web-accessible again." + task :enable do + run "mv #{current_path}/public/maintenance.html #{current_path}/public/maintenance2.html" + end + end +end + namespace :delayed_job do desc "Start delayed_job process" task :start, :roles => :app do @@ -34,6 +57,8 @@ namespace :delayed_job do end end +after "deploy:setup", "reset_ownership_of_common_directory" after "deploy:start", "delayed_job:start" after "deploy:stop", "delayed_job:stop" after "deploy:restart", "delayed_job:restart" + From fc007fccf8859efc01f1b75bd34d8e203ac64763 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 29 Aug 2011 15:21:24 -0400 Subject: [PATCH 25/40] install script fixes --- INSTALL.debian | 1 + config/deploy/staging.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/INSTALL.debian b/INSTALL.debian index 7d2784669..8ee5e85cf 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -59,6 +59,7 @@ rvm 1.9.2 --default # Install gems gem install --no-ri --no-rdoc capistrano gem install --no-ri --no-rdoc capistrano-ext +gem install --no-ri --no-rdoc bundler # Install Passenger gem install --no-ri --no-rdoc -v 3.0.8 passenger diff --git a/config/deploy/staging.rb b/config/deploy/staging.rb index 5ace5b5d1..1fa48f7ad 100644 --- a/config/deploy/staging.rb +++ b/config/deploy/staging.rb @@ -1 +1 @@ -server "testbooru.donmai.us", :web, :app, :primary => true +server "testbooru.donmai.us", :web, :app, :db, :primary => true From 476f210615d7385c5d93e80278d133cbed71e861 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 29 Aug 2011 16:54:39 -0400 Subject: [PATCH 26/40] deploy script fixes --- config/deploy.rb | 24 ++++++++++++++++++- script/install/danbooru_local_config.rb.templ | 5 ++++ .../install/database.yml.templ | 0 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 script/install/danbooru_local_config.rb.templ rename config/database.yml.template => script/install/database.yml.templ (100%) diff --git a/config/deploy.rb b/config/deploy.rb index e70a241d0..b4aec7f0b 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -21,6 +21,25 @@ set :deploy_to, "/var/www/#{application}" default_run_options[:pty] = true +namespace :local_config do + desc "Create the shared config directory" + task :setup_shared_directory do + run "mkdir -p #{deploy_to}/shared/config" + end + + desc "Initialize local config files" + task :setup_local_files do + run "cp #{current_path}/script/install/danbooru_local_config.rb.templ #{deploy_to}/shared/config/danbooru_local_config.rb" + run "cp #{current_path}/script/install/database.yml.templ #{deploy_to}/shared/config/database.yml" + end + + desc "Link the local config files" + task :link_local_files do + run "ln -s #{deploy_to}/shared/config/danbooru_local_config.rb #{current_path}/config/danbooru_local_config.rb" + run "ln -s #{deploy_to}/shared/config/database.yml #{current_path}/config/database.yml" + end +end + desc "Change ownership of common directory to user" task :reset_ownership_of_common_directory do sudo "chown -R #{user}:#{user} /var/www/danbooru" @@ -50,7 +69,7 @@ namespace :delayed_job do task :stop, :roles => :app do run "cd #{current_path}; script/delayed_job stop #{rails_env}" end - + desc "Restart delayed_job process" task :restart, :roles => :app do run "cd #{current_path}; script/delayed_job restart #{rails_env}" @@ -58,6 +77,9 @@ namespace :delayed_job do end after "deploy:setup", "reset_ownership_of_common_directory" +after "deploy:setup", "local_config:setup_shared_directory" +after "deploy:setup", "local_config:setup_local_files" +after "deploy:update_code", "local_config:link_local_files" after "deploy:start", "delayed_job:start" after "deploy:stop", "delayed_job:stop" after "deploy:restart", "delayed_job:restart" diff --git a/script/install/danbooru_local_config.rb.templ b/script/install/danbooru_local_config.rb.templ new file mode 100644 index 000000000..64bc3dced --- /dev/null +++ b/script/install/danbooru_local_config.rb.templ @@ -0,0 +1,5 @@ +module Danbooru + class CustomConfiguration < Configuration + # Define your custom overloads here + end +end diff --git a/config/database.yml.template b/script/install/database.yml.templ similarity index 100% rename from config/database.yml.template rename to script/install/database.yml.templ From 9727d1e8fa995557bd2436a936e4f12763e94e71 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 29 Aug 2011 17:26:09 -0400 Subject: [PATCH 27/40] fix deploy script --- config/deploy.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/deploy.rb b/config/deploy.rb index b4aec7f0b..e0112eea2 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -29,14 +29,14 @@ namespace :local_config do desc "Initialize local config files" task :setup_local_files do - run "cp #{current_path}/script/install/danbooru_local_config.rb.templ #{deploy_to}/shared/config/danbooru_local_config.rb" - run "cp #{current_path}/script/install/database.yml.templ #{deploy_to}/shared/config/database.yml" + run "curl -s https://raw.github.com/r888888888/danbooru/master/script/install/danbooru_local_config.rb.templ > #{deploy_to}/shared/config/danbooru_local_config.rb" + run "curl -s https://raw.github.com/r888888888/danbooru/master/script/install/database.yml.templ > #{deploy_to}/shared/config/database.yml" end desc "Link the local config files" task :link_local_files do - run "ln -s #{deploy_to}/shared/config/danbooru_local_config.rb #{current_path}/config/danbooru_local_config.rb" - run "ln -s #{deploy_to}/shared/config/database.yml #{current_path}/config/database.yml" + run "ln -s #{deploy_to}/shared/config/danbooru_local_config.rb #{release_path}/config/danbooru_local_config.rb" + run "ln -s #{deploy_to}/shared/config/database.yml #{release_path}/config/database.yml" end end From b3335ce8c288acfea2f198c48289e2ee873eceae Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 29 Aug 2011 17:48:54 -0400 Subject: [PATCH 28/40] removed local config --- config/danbooru_local_config.rb | 39 --------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 config/danbooru_local_config.rb diff --git a/config/danbooru_local_config.rb b/config/danbooru_local_config.rb deleted file mode 100644 index 283e02225..000000000 --- a/config/danbooru_local_config.rb +++ /dev/null @@ -1,39 +0,0 @@ -module Danbooru - class CustomConfiguration < Configuration - # Define your custom overloads here - def app_name - "Lorem" - end - - def posts_per_page - 3 - end - - def is_user_restricted?(user) - !user.is_privileged? || user.name == "ppayne" - end - - def is_post_restricted?(post) - post.has_tag?("loli") || post.has_tag?("shota") - end - - def custom_html_header_content - %{ - - - }.html_safe - end - - def is_user_advertiser?(user) - user.is_admin? || user.name == "ppayne" - end - end -end From 79e2ed236bcdd32376101e97bf26b3b7720b0d8b Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 30 Aug 2011 10:11:53 -0400 Subject: [PATCH 29/40] added misc html files --- INSTALL.debian | 22 ++++++++++++++++++++-- config/deploy.rb | 24 +++++++++++++++++++++--- public/404.html | 6 +++++- public/422.html | 6 +++++- public/500.html | 6 +++++- public/503-redirect.html | 22 ++++++++++++++++++++++ public/503.html | 25 +++++++++++++++++++++++++ 7 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 public/503-redirect.html create mode 100644 public/503.html diff --git a/INSTALL.debian b/INSTALL.debian index 8ee5e85cf..4e5a329f9 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -41,7 +41,7 @@ apt-get -y install build-essential automake openssl libssl-dev libyaml-dev libxm apt-get -y install python-software-properties add-apt-repository ppa:pitti/postgresql apt-get update -apt-get install -y postgresql-9.1 libpq-dev +apt-get install -y postgresql-9.1 postgresql-contrib-9.1 libpq-dev if [ $? -ne 0 ]; then exit 1 @@ -119,5 +119,23 @@ echo "* Enter a new password for the danbooru account *" echo "*************************************************" passwd danbooru +sudo -u danbooru createdb danbooru2 +cd /home/danbooru +sudo -u danbooru mkdir /home/danbooru/apps +git clone git://github.com/r888888888/danbooru.git danbooru +chown -R danbooru:danbooru danbooru +cap deploy:setup +cap deploy:update_code +cap deploy:migrate +chown danbooru:danbooru /var/www/danbooru/shared/log/development.log + echo -echo "I'm done!" +echo +echo "**************************************************************" +echo "* Danbooru has now been setup on this computer and should be *" +echo "* accessible from the web. Go ahead and create an account. *" +echo "* The first account will automatically be made an admin.You *" +echo "* can edit the configuration files by editing *" +echo "* /var/www/danbooru/shared/config/local_config and *" +echo "* /var/www/danbooru/shared/config/database.yml *" +echo "**************************************************************" diff --git a/config/deploy.rb b/config/deploy.rb index e0112eea2..fd1f13541 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -40,6 +40,21 @@ namespace :local_config do end end +namespace :data do + task :setup_directories do + run "mkdir -p #{deploy_to}/shared/data" + run "mkdir #{deploy_to}/shared/data/preview" + run "mkdir #{deploy_to}/shared/data/small" + run "mkdir #{deploy_to}/shared/data/large" + run "mkdir #{deploy_to}/shared/data/original" + end + + task :link_directories do + run "rm -f #{release_path}/public/data" + run "ln -s #{deploy_to}/shared/data #{release_path}/public/data" + end +end + desc "Change ownership of common directory to user" task :reset_ownership_of_common_directory do sudo "chown -R #{user}:#{user} /var/www/danbooru" @@ -49,12 +64,12 @@ namespace :deploy do namespace :web do desc "Present a maintenance page to visitors." task :disable do - run "mv #{current_path}/public/maintenance2.html #{current_path}/public/maintenance.html" + run "mv #{current_path}/public/maintenance.html.bak #{current_path}/public/maintenance.html" end desc "Makes the application web-accessible again." task :enable do - run "mv #{current_path}/public/maintenance.html #{current_path}/public/maintenance2.html" + run "mv #{current_path}/public/maintenance.html #{current_path}/public/maintenance.html.bak" end end end @@ -79,8 +94,11 @@ end after "deploy:setup", "reset_ownership_of_common_directory" after "deploy:setup", "local_config:setup_shared_directory" after "deploy:setup", "local_config:setup_local_files" +after "deploy:setup", "data:setup_directories" after "deploy:update_code", "local_config:link_local_files" +after "deploy:update_code", "data:link_directories" after "deploy:start", "delayed_job:start" after "deploy:stop", "delayed_job:stop" after "deploy:restart", "delayed_job:restart" - +before "deploy:update", "deploy:web:disable" +after "deploy:restart", "deploy:web:enable" diff --git a/public/404.html b/public/404.html index 9a48320a5..be5c82b42 100644 --- a/public/404.html +++ b/public/404.html @@ -2,7 +2,11 @@ The page you were looking for doesn't exist (404) - + + +

    The site is down for maintenance.

    +

    Check Twitter for updates.

    + + From 80c142dc1df576b60fae9152c6edef6320123b87 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 30 Aug 2011 12:17:25 -0400 Subject: [PATCH 31/40] fix for nginx init script --- INSTALL.debian | 4 ++-- script/install/nginx.danbooru.conf | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/INSTALL.debian b/INSTALL.debian index 4e5a329f9..c26f9a765 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -91,7 +91,7 @@ sudo -u postgres createuser -s danbooru mkdir -p /var/log/www # Setup nginx -curl -s https://raw.github.com/ascarter/nginx-ubuntu-rvm/master/nginx > /etc/init.d/nginx +curl -s https://raw.github.com/r888888888/danbooru/master/script/install/init_d.templ > /etc/init.d/nginx chmod +x,g-w /etc/init.d/nginx update-rc.d -f nginx defaults mkdir -p /opt/nginx/conf/sites @@ -134,7 +134,7 @@ echo echo "**************************************************************" echo "* Danbooru has now been setup on this computer and should be *" echo "* accessible from the web. Go ahead and create an account. *" -echo "* The first account will automatically be made an admin.You *" +echo "* The first account will automatically be made an admin. You *" echo "* can edit the configuration files by editing *" echo "* /var/www/danbooru/shared/config/local_config and *" echo "* /var/www/danbooru/shared/config/database.yml *" diff --git a/script/install/nginx.danbooru.conf b/script/install/nginx.danbooru.conf index 53de37ac5..729414667 100644 --- a/script/install/nginx.danbooru.conf +++ b/script/install/nginx.danbooru.conf @@ -1,7 +1,7 @@ server { listen 80; server_name HOSTNAME; - root /var/www/danbooru/public; + root /var/www/danbooru/current/public; index index.html; access_log /var/log/www/danbooru.access.log; error_log /var/log/www/danbooru.error.log; From d8e4f51f604b71101ca7c70707744e1dc5f373a1 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 30 Aug 2011 13:17:32 -0400 Subject: [PATCH 32/40] updated versions --- Gemfile | 4 +- Gemfile.lock | 96 +++---- INSTALL.debian | 13 +- config/deploy.rb | 6 + script/install/init_d.templ | 399 +++++++++++++++++++++++++++++ script/install/nginx.danbooru.conf | 1 + 6 files changed, 466 insertions(+), 53 deletions(-) create mode 100644 script/install/init_d.templ diff --git a/Gemfile b/Gemfile index c79bcabcd..2cc9865b8 100644 --- a/Gemfile +++ b/Gemfile @@ -9,10 +9,10 @@ group :test do end group :assets do - + gem "uglifier" end -gem "rails", "3.1.0.rc5" +gem "rails", "3.1.0.rc8" gem "pg" gem "memcache-client", :require => "memcache" gem "imagesize", :require => "image_size" diff --git a/Gemfile.lock b/Gemfile.lock index 352b3e780..fdf0efe5b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -17,46 +17,48 @@ GEM remote: http://gemcutter.org/ specs: aaronh-chronic (0.3.9) - actionmailer (3.1.0.rc5) - actionpack (= 3.1.0.rc5) + actionmailer (3.1.0.rc8) + actionpack (= 3.1.0.rc8) mail (~> 2.3.0) - actionpack (3.1.0.rc5) - activemodel (= 3.1.0.rc5) - activesupport (= 3.1.0.rc5) + actionpack (3.1.0.rc8) + activemodel (= 3.1.0.rc8) + activesupport (= 3.1.0.rc8) builder (~> 3.0.0) erubis (~> 2.7.0) i18n (~> 0.6) - rack (~> 1.3.1) - rack-cache (~> 1.0.2) - rack-mount (~> 0.8.1) - rack-test (~> 0.6.0) - sprockets (~> 2.0.0.beta.12) - activemodel (3.1.0.rc5) - activesupport (= 3.1.0.rc5) - bcrypt-ruby (~> 2.1.4) + rack (~> 1.3.2) + rack-cache (~> 1.0.3) + rack-mount (~> 0.8.2) + rack-test (~> 0.6.1) + sprockets (~> 2.0.0.beta.15) + activemodel (3.1.0.rc8) + activesupport (= 3.1.0.rc8) + bcrypt-ruby (~> 3.0.0) builder (~> 3.0.0) i18n (~> 0.6) - activerecord (3.1.0.rc5) - activemodel (= 3.1.0.rc5) - activesupport (= 3.1.0.rc5) - arel (~> 2.1.4) + activerecord (3.1.0.rc8) + activemodel (= 3.1.0.rc8) + activesupport (= 3.1.0.rc8) + arel (~> 2.2.1) tzinfo (~> 0.3.29) - activeresource (3.1.0.rc5) - activemodel (= 3.1.0.rc5) - activesupport (= 3.1.0.rc5) - activesupport (3.1.0.rc5) + activeresource (3.1.0.rc8) + activemodel (= 3.1.0.rc8) + activesupport (= 3.1.0.rc8) + activesupport (3.1.0.rc8) multi_json (~> 1.0) - arel (2.1.4) - bcrypt-ruby (2.1.4) + arel (2.2.1) + bcrypt-ruby (3.0.0) builder (3.0.0) daemons (1.1.4) delayed_job (2.1.4) activesupport (~> 3.0) daemons erubis (2.7.0) - factory_girl (2.0.3) + execjs (1.2.4) + multi_json (~> 1.0) + factory_girl (2.0.5) haml (3.1.2) - hike (1.2.0) + hike (1.2.1) i18n (0.6.0) imagesize (0.1.1) mail (2.3.0) @@ -73,58 +75,61 @@ GEM mocha (0.9.12) multi_json (1.0.3) net-http-digest_auth (1.1.1) - net-http-persistent (1.8) + net-http-persistent (1.9) nokogiri (1.5.0) pg (0.11.0) polyglot (0.3.2) rack (1.3.2) - rack-cache (1.0.2) + rack-cache (1.0.3) rack (>= 0.4) - rack-mount (0.8.1) + rack-mount (0.8.2) rack (>= 1.0.0) rack-ssl (1.3.2) rack rack-test (0.6.1) rack (>= 1.0) - rails (3.1.0.rc5) - actionmailer (= 3.1.0.rc5) - actionpack (= 3.1.0.rc5) - activerecord (= 3.1.0.rc5) - activeresource (= 3.1.0.rc5) - activesupport (= 3.1.0.rc5) + rails (3.1.0.rc8) + actionmailer (= 3.1.0.rc8) + actionpack (= 3.1.0.rc8) + activerecord (= 3.1.0.rc8) + activeresource (= 3.1.0.rc8) + activesupport (= 3.1.0.rc8) bundler (~> 1.0) - railties (= 3.1.0.rc5) - railties (3.1.0.rc5) - actionpack (= 3.1.0.rc5) - activesupport (= 3.1.0.rc5) + railties (= 3.1.0.rc8) + railties (3.1.0.rc8) + actionpack (= 3.1.0.rc8) + activesupport (= 3.1.0.rc8) rack-ssl (~> 1.3.2) rake (>= 0.8.7) rdoc (~> 3.4) thor (~> 0.14.6) rake (0.9.2) - rdoc (3.9.1) + rdoc (3.9.4) shoulda (2.11.3) - silent-postgres (0.0.8) + silent-postgres (0.1.1) simple_form (1.4.2) actionpack (~> 3.0) activemodel (~> 3.0) simplecov (0.4.2) simplecov-html (~> 0.4.4) simplecov-html (0.4.5) - sprockets (2.0.0.beta.13) + sprockets (2.0.0) hike (~> 1.2) rack (~> 1.0) - tilt (!= 1.3.0, ~> 1.1) + tilt (~> 1.1, != 1.3.0) super_exception_notifier (3.0.13) actionmailer rake thor (0.14.6) - tilt (1.3.2) + tilt (1.3.3) treetop (1.4.10) polyglot polyglot (>= 0.3.1) tzinfo (0.3.29) - webrobots (0.0.10) + uglifier (1.0.2) + execjs (>= 0.3.0) + multi_json (>= 1.0.2) + webrobots (0.0.11) nokogiri (>= 1.4.4) whenever (0.6.8) aaronh-chronic (>= 0.3.9) @@ -145,10 +150,11 @@ DEPENDENCIES mocha nokogiri pg - rails (= 3.1.0.rc5) + rails (= 3.1.0.rc8) shoulda silent-postgres simple_form simplecov super_exception_notifier + uglifier whenever diff --git a/INSTALL.debian b/INSTALL.debian index c26f9a765..4fb2ac5f3 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -19,18 +19,18 @@ echo "It is mostly automated but you will receive some prompts when installing" echo "Passenger towards the end of the script." echo echo -n "Enter the hostname for this server (ex: danbooru.donmai.us): " -read hostname +read HOSTNAME -if [[ -z "$hostname" ]] ; then +if [[ -z "$HOSTNAME" ]] ; then echo "Must enter a hostname" exit 1 fi echo -n "Enter a name for the site (default: Danbooru): " -read sitename +read SITENAME -if [[ -z "$sitename" ]] ; then - sitename=Danbooru +if [[ -z "$SITENAME" ]] ; then + SITENAME=Danbooru fi # Install packages @@ -64,6 +64,7 @@ gem install --no-ri --no-rdoc bundler # Install Passenger gem install --no-ri --no-rdoc -v 3.0.8 passenger rvm exec passenger-install-nginx-module +rm /opt/nginx/conf/*.default if [ $? -ne 0 ]; then exit 1 @@ -97,7 +98,7 @@ update-rc.d -f nginx defaults mkdir -p /opt/nginx/conf/sites curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.conf > /opt/nginx/conf/nginx.conf curl -s https://raw.github.com/r888888888/danbooru/master/script/install/nginx.danbooru.conf > /opt/nginx/conf/sites/danbooru.conf -sed -i -e 's/HOSTNAME/$hostname/g' /opt/nginx/conf/sites/danbooru.conf +sed -i -e 's/\$hostname/$HOSTNAME/g' /opt/nginx/conf/sites/danbooru.conf /etc/init.d/nginx start echo "%wheel ALL=(ALL) ALL" >> /etc/sudoers diff --git a/config/deploy.rb b/config/deploy.rb index 44a0574ff..bee059e83 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -74,6 +74,11 @@ namespace :deploy do run "if [ -e #{maintenance_html_path} ] ; then mv #{maintenance_html_path} #{current_path}/public/maintenance.html.bak ; fi" end end + + desc "Compile the image resizer" + task :compile_image_resizer do + run "cd #{current_path}/lib/danbooru_image_resize ; ruby extconf.rb ; make" + end end namespace :delayed_job do @@ -99,6 +104,7 @@ after "deploy:setup", "local_config:setup_local_files" after "deploy:setup", "data:setup_directories" after "deploy:update_code", "local_config:link_local_files" after "deploy:update_code", "data:link_directories" +after "deploy:update_code", "deploy:compile_image_resizer" after "deploy:start", "delayed_job:start" after "deploy:stop", "delayed_job:stop" after "deploy:restart", "delayed_job:restart" diff --git a/script/install/init_d.templ b/script/install/init_d.templ new file mode 100644 index 000000000..ff46f3518 --- /dev/null +++ b/script/install/init_d.templ @@ -0,0 +1,399 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: nginx +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: nginx init.d dash script for Ubuntu <=9.10. +# Description: nginx init.d dash script for Ubuntu <=9.10. +### END INIT INFO +#------------------------------------------------------------------------------ +# nginx - this Debian Almquist shell (dash) script, starts and stops the nginx +# daemon for ubuntu 9.10 and lesser version numbered releases. +# +# description: Nginx is an HTTP(S) server, HTTP(S) reverse \ +# proxy and IMAP/POP3 proxy server. This \ +# script will manage the initiation of the \ +# server and it's process state. +# +# processname: nginx +# config: /opt/nginx/conf/nginx.conf +# pidfile: /opt/nginx/logs/nginx.pid +# Provides: nginx +# +# Authoer: Andrew Carter +# +# +# Version: 0.1 27-DEC-2010 ascarter@gmail.com +# Notes: Forked from original script to support default Passenger nginx +# install via RVM. +# +#------------------------------------------------------------------------------ +# MIT X11 License +#------------------------------------------------------------------------------ +# +# Copyright (c) 2010 Andrew Carter +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +#------------------------------------------------------------------------------ +# +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# ORIGINAL SCRIPT: +# +# Author: Jason Giedymin +# . +# +# Version: 2.0 02-NOV-2009 jason.giedymin AT gmail.com +# URL: http://code.google.com/p/nginx-init-ubuntu/ +# +#------------------------------------------------------------------------------ +# MIT X11 License +#------------------------------------------------------------------------------ +# +# Copyright (c) 2009 Jason Giedymin, http://Amuxbit.com formerly +# http://AcronymLabs.com +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# Functions +#------------------------------------------------------------------------------ +. /lib/lsb/init-functions + +#------------------------------------------------------------------------------ +# Consts +#------------------------------------------------------------------------------ +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/opt/nginx/sbin/nginx + +PS="nginx" +PIDNAME="nginx" #lets you do $PS-slave +PIDFILE=$PIDNAME.pid #pid file +PIDSPATH=/var/run + +DESCRIPTION="Nginx Server..." + +RUNAS=root #user to run as + +SCRIPT_OK=0 #ala error codes +SCRIPT_ERROR=1 #ala error codes +TRUE=1 #boolean +FALSE=0 #boolean + +lockfile=/var/lock/subsys/nginx +NGINX_CONF_FILE="/opt/nginx/conf/nginx.conf" + +#------------------------------------------------------------------------------ +# Simple Tests +#------------------------------------------------------------------------------ + +#test if nginx is a file and executable +test -x $DAEMON || exit 0 + +# Include nginx defaults if available +if [ -f /etc/default/nginx ] ; then + . /etc/default/nginx +fi + +#set exit condition +#set -e + +#------------------------------------------------------------------------------ +# Functions +#------------------------------------------------------------------------------ + +setFilePerms(){ + + if [ -f $PIDSPATH/$PIDFILE ]; then + chmod 400 $PIDSPATH/$PIDFILE + fi +} + +configtest() { + $DAEMON -t -c $NGINX_CONF_FILE +} + +getPSCount() { + return `pgrep -f $PS | wc -l` +} + +isRunning() { + if [ $1 ]; then + pidof_daemon $1 + PID=$? + + if [ $PID -gt 0 ]; then + return 1 + else + return 0 + fi + else + pidof_daemon + PID=$? + + if [ $PID -gt 0 ]; then + return 1 + else + return 0 + fi + fi +} + +#courtesy of php-fpm +wait_for_pid () { + try=0 + + while test $try -lt 35 ; do + + case "$1" in + 'created') + if [ -f "$2" ] ; then + try='' + break + fi + ;; + + 'removed') + if [ ! -f "$2" ] ; then + try='' + break + fi + ;; + esac + + #echo -n . + try=`expr $try + 1` + sleep 1 + done +} + +status(){ + isRunning + isAlive=$? + + if [ "${isAlive}" -eq $TRUE ]; then + echo "$PIDNAME found running with processes: `pidof $PS`" + else + echo "$PIDNAME is NOT running." + fi + + +} + +removePIDFile(){ + if [ $1 ]; then + if [ -f $1 ]; then + rm -f $1 + fi + else + #Do default removal + if [ -f $PIDSPATH/$PIDFILE ]; then + rm -f $PIDSPATH/$PIDFILE + fi + fi +} + +start() { + log_daemon_msg "Starting $DESCRIPTION" + + isRunning + isAlive=$? + + if [ "${isAlive}" -eq $TRUE ]; then + log_end_msg $SCRIPT_ERROR + else + start-stop-daemon --start --quiet --chuid $RUNAS --pidfile $PIDSPATH/$PIDFILE --exec $DAEMON \ + -- -c $NGINX_CONF_FILE + setFilePerms + log_end_msg $SCRIPT_OK + fi +} + +stop() { + log_daemon_msg "Stopping $DESCRIPTION" + + isRunning + isAlive=$? + if [ "${isAlive}" -eq $TRUE ]; then + start-stop-daemon --stop --quiet --pidfile $PIDSPATH/$PIDFILE + + wait_for_pid 'removed' $PIDSPATH/$PIDFILE + + if [ -n "$try" ] ; then + log_end_msg $SCRIPT_ERROR + else + removePIDFile + log_end_msg $SCRIPT_OK + fi + + else + log_end_msg $SCRIPT_ERROR + fi +} + +reload() { + configtest || return $? + + log_daemon_msg "Reloading (via HUP) $DESCRIPTION" + + isRunning + if [ $? -eq $TRUE ]; then + kill -HUP `cat $PIDSPATH/$PIDFILE` + + log_end_msg $SCRIPT_OK + else + log_end_msg $SCRIPT_ERROR + fi +} + +quietupgrade() { + log_daemon_msg "Peforming Quiet Upgrade $DESCRIPTION" + + isRunning + isAlive=$? + if [ "${isAlive}" -eq $TRUE ]; then + kill -USR2 `cat $PIDSPATH/$PIDFILE` + kill -WINCH `cat $PIDSPATH/$PIDFILE.oldbin` + + isRunning + isAlive=$? + if [ "${isAlive}" -eq $TRUE ]; then + kill -QUIT `cat $PIDSPATH/$PIDFILE.oldbin` + wait_for_pid 'removed' $PIDSPATH/$PIDFILE.oldbin + removePIDFile $PIDSPATH/$PIDFILE.oldbin + + log_end_msg $SCRIPT_OK + else + log_end_msg $SCRIPT_ERROR + + log_daemon_msg "ERROR! Reverting back to original $DESCRIPTION" + + kill -HUP `cat $PIDSPATH/$PIDFILE` + kill -TERM `cat $PIDSPATH/$PIDFILE.oldbin` + kill -QUIT `cat $PIDSPATH/$PIDFILE.oldbin` + + wait_for_pid 'removed' $PIDSPATH/$PIDFILE.oldbin + removePIDFile $PIDSPATH/$PIDFILE.oldbin + + log_end_msg $SCRIPT_ok + fi + else + log_end_msg $SCRIPT_ERROR + fi +} + +terminate() { + log_daemon_msg "Force terminating (via KILL) $DESCRIPTION" + + PIDS=`pidof $PS` || true + + [ -e $PIDSPATH/$PIDFILE ] && PIDS2=`cat $PIDSPATH/$PIDFILE` + + for i in $PIDS; do + if [ "$i" = "$PIDS2" ]; then + kill $i + wait_for_pid 'removed' $PIDSPATH/$PIDFILE + removePIDFile + fi + done + + log_end_msg $SCRIPT_OK +} + +destroy() { + log_daemon_msg "Force terminating and may include self (via KILLALL) $DESCRIPTION" + killall $PS -q >> /dev/null 2>&1 + log_end_msg $SCRIPT_OK +} + +pidof_daemon() { + PIDS=`pidof $PS` || true + + [ -e $PIDSPATH/$PIDFILE ] && PIDS2=`cat $PIDSPATH/$PIDFILE` + + for i in $PIDS; do + if [ "$i" = "$PIDS2" ]; then + return 1 + fi + done + return 0 +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart|force-reload) + stop + sleep 1 + start + ;; + reload) + $1 + ;; + status) + status + ;; + configtest) + $1 + ;; + quietupgrade) + $1 + ;; + terminate) + $1 + ;; + destroy) + $1 + ;; + *) + FULLPATH=/etc/init.d/$PS + echo "Usage: $FULLPATH {start|stop|restart|force-reload|status|configtest|quietupgrade|terminate|destroy}" + echo " The 'destroy' command should only be used as a last resort." + exit 1 + ;; +esac + +exit 0 diff --git a/script/install/nginx.danbooru.conf b/script/install/nginx.danbooru.conf index 729414667..feffce17b 100644 --- a/script/install/nginx.danbooru.conf +++ b/script/install/nginx.danbooru.conf @@ -1,4 +1,5 @@ server { + passenger_enabled on; listen 80; server_name HOSTNAME; root /var/www/danbooru/current/public; From 1d950ff63aeb0a02c5cd3a6a1c91d526b3fec1c6 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 30 Aug 2011 13:19:31 -0400 Subject: [PATCH 33/40] deploy fix --- config/deploy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/deploy.rb b/config/deploy.rb index bee059e83..c069cd038 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -77,7 +77,7 @@ namespace :deploy do desc "Compile the image resizer" task :compile_image_resizer do - run "cd #{current_path}/lib/danbooru_image_resize ; ruby extconf.rb ; make" + run "cd #{current_path}/lib/danbooru_image_resizer ; ruby extconf.rb ; make" end end From 781100f2d982034dcdac17307ffd3aaaa257878f Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 30 Aug 2011 13:42:09 -0400 Subject: [PATCH 34/40] added uglifier-rails --- Gemfile | 3 ++- Gemfile.lock | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 2cc9865b8..b6156d7ad 100644 --- a/Gemfile +++ b/Gemfile @@ -10,8 +10,9 @@ end group :assets do gem "uglifier" + gem "uglifier-rails" end - + gem "rails", "3.1.0.rc8" gem "pg" gem "memcache-client", :require => "memcache" diff --git a/Gemfile.lock b/Gemfile.lock index fdf0efe5b..d2ccf4ff6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -129,6 +129,9 @@ GEM uglifier (1.0.2) execjs (>= 0.3.0) multi_json (>= 1.0.2) + uglifier-rails (3.1.0.rc.2) + railties (~> 3.1.0.rc1) + uglifier (>= 1.0.0) webrobots (0.0.11) nokogiri (>= 1.4.4) whenever (0.6.8) @@ -157,4 +160,5 @@ DEPENDENCIES simplecov super_exception_notifier uglifier + uglifier-rails whenever From 434d686bfd815c67c389bf71fda1701360c2e5b6 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 30 Aug 2011 13:49:57 -0400 Subject: [PATCH 35/40] added therubyracer gem --- Gemfile | 1 + Gemfile.lock | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/Gemfile b/Gemfile index b6156d7ad..3db971454 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ end group :assets do gem "uglifier" gem "uglifier-rails" + gem "therubyracer" end gem "rails", "3.1.0.rc8" diff --git a/Gemfile.lock b/Gemfile.lock index d2ccf4ff6..867dd2dfc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -61,6 +61,7 @@ GEM hike (1.2.1) i18n (0.6.0) imagesize (0.1.1) + libv8 (3.3.10.2) mail (2.3.0) i18n (>= 0.4.0) mime-types (~> 1.16) @@ -120,6 +121,8 @@ GEM super_exception_notifier (3.0.13) actionmailer rake + therubyracer (0.9.4) + libv8 (~> 3.3.10) thor (0.14.6) tilt (1.3.3) treetop (1.4.10) @@ -159,6 +162,7 @@ DEPENDENCIES simple_form simplecov super_exception_notifier + therubyracer uglifier uglifier-rails whenever From c0a352a499d8ee69c26e11ad6ce608de7dacf749 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 30 Aug 2011 14:11:32 -0400 Subject: [PATCH 36/40] deploy script fixes --- config/deploy.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config/deploy.rb b/config/deploy.rb index c069cd038..03576f4ea 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -64,37 +64,37 @@ namespace :deploy do namespace :web do desc "Present a maintenance page to visitors." task :disable do - maintenance_html_path = "#{current_path}/public/maintenance.html.bak" - run "if [ -e #{maintenance_html_path} ] ; then mv #{maintenance_html_path} #{current_path}/public/maintenance.html ; fi" + maintenance_html_path = "#{release_path}/public/maintenance.html.bak" + run "if [ -e #{maintenance_html_path} ] ; then mv #{maintenance_html_path} #{release_path}/public/maintenance.html ; fi" end desc "Makes the application web-accessible again." task :enable do - maintenance_html_path = "#{current_path}/public/maintenance.html" - run "if [ -e #{maintenance_html_path} ] ; then mv #{maintenance_html_path} #{current_path}/public/maintenance.html.bak ; fi" + maintenance_html_path = "#{release_path}/public/maintenance.html" + run "if [ -e #{maintenance_html_path} ] ; then mv #{maintenance_html_path} #{release_path}/public/maintenance.html.bak ; fi" end end desc "Compile the image resizer" task :compile_image_resizer do - run "cd #{current_path}/lib/danbooru_image_resizer ; ruby extconf.rb ; make" + run "cd #{release_path}/lib/danbooru_image_resizer ; ruby extconf.rb ; make" end end namespace :delayed_job do desc "Start delayed_job process" task :start, :roles => :app do - run "cd #{current_path}; script/delayed_job start #{rails_env}" + run "cd #{release_path}; script/delayed_job start #{rails_env}" end desc "Stop delayed_job process" task :stop, :roles => :app do - run "cd #{current_path}; script/delayed_job stop #{rails_env}" + run "cd #{release_path}; script/delayed_job stop #{rails_env}" end desc "Restart delayed_job process" task :restart, :roles => :app do - run "cd #{current_path}; script/delayed_job restart #{rails_env}" + run "cd #{release_path}; script/delayed_job restart #{rails_env}" end end From 7caa905a15dde46ee95b513cc4414f8633e48fd4 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 30 Aug 2011 14:51:19 -0400 Subject: [PATCH 37/40] fixed process id --- app/models/upload.rb | 3 ++- config/deploy.rb | 25 +++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/models/upload.rb b/app/models/upload.rb index 0d8de2062..f84e23e4a 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -1,5 +1,6 @@ require "danbooru_image_resizer/danbooru_image_resizer" require "tmpdir" +require "process" class Upload < ActiveRecord::Base class Error < Exception ; end @@ -234,7 +235,7 @@ class Upload < ActiveRecord::Base end def temp_file_path - @temp_file_path ||= File.join(Rails.root, "tmp", "upload_#{Time.now.to_f}.#{$PROCESS_ID}") + @temp_file_path ||= File.join(Rails.root, "tmp", "upload_#{Time.now.to_f}.#{Process.pid}") end end diff --git a/config/deploy.rb b/config/deploy.rb index 03576f4ea..e275f7737 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -64,17 +64,22 @@ namespace :deploy do namespace :web do desc "Present a maintenance page to visitors." task :disable do - maintenance_html_path = "#{release_path}/public/maintenance.html.bak" - run "if [ -e #{maintenance_html_path} ] ; then mv #{maintenance_html_path} #{release_path}/public/maintenance.html ; fi" + maintenance_html_path = "#{current_path}/public/maintenance.html.bak" + run "if [ -e #{maintenance_html_path} ] ; then mv #{maintenance_html_path} #{current_path}/public/maintenance.html ; fi" end desc "Makes the application web-accessible again." task :enable do - maintenance_html_path = "#{release_path}/public/maintenance.html" - run "if [ -e #{maintenance_html_path} ] ; then mv #{maintenance_html_path} #{release_path}/public/maintenance.html.bak ; fi" + maintenance_html_path = "#{current_path}/public/maintenance.html" + run "if [ -e #{maintenance_html_path} ] ; then mv #{maintenance_html_path} #{current_path}/public/maintenance.html.bak ; fi" end end + desc "Restart the application" + task :restart do + run "touch #{current_path}/tmp/restart.txt" + end + desc "Compile the image resizer" task :compile_image_resizer do run "cd #{release_path}/lib/danbooru_image_resizer ; ruby extconf.rb ; make" @@ -84,17 +89,17 @@ end namespace :delayed_job do desc "Start delayed_job process" task :start, :roles => :app do - run "cd #{release_path}; script/delayed_job start #{rails_env}" + run "cd #{current_path}; script/delayed_job start #{rails_env}" end desc "Stop delayed_job process" task :stop, :roles => :app do - run "cd #{release_path}; script/delayed_job stop #{rails_env}" + run "cd #{current_path}; script/delayed_job stop #{rails_env}" end desc "Restart delayed_job process" task :restart, :roles => :app do - run "cd #{release_path}; script/delayed_job restart #{rails_env}" + run "cd #{current_path}; script/delayed_job restart #{rails_env}" end end @@ -102,9 +107,9 @@ after "deploy:setup", "reset_ownership_of_common_directory" after "deploy:setup", "local_config:setup_shared_directory" after "deploy:setup", "local_config:setup_local_files" after "deploy:setup", "data:setup_directories" -after "deploy:update_code", "local_config:link_local_files" -after "deploy:update_code", "data:link_directories" -after "deploy:update_code", "deploy:compile_image_resizer" +after "deploy:symlink", "local_config:link_local_files" +after "deploy:symlink", "data:link_directories" +after "deploy:symlink", "deploy:compile_image_resizer" after "deploy:start", "delayed_job:start" after "deploy:stop", "delayed_job:stop" after "deploy:restart", "delayed_job:restart" From 5823ba8e5d978b5869fff303493a8f03a0c6e2ff Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 30 Aug 2011 14:53:17 -0400 Subject: [PATCH 38/40] typo fix --- app/models/upload.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/upload.rb b/app/models/upload.rb index f84e23e4a..e76e74003 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -1,6 +1,5 @@ require "danbooru_image_resizer/danbooru_image_resizer" require "tmpdir" -require "process" class Upload < ActiveRecord::Base class Error < Exception ; end From ce720dab6c9936b106891697b01d787f8c23270b Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 30 Aug 2011 15:05:30 -0400 Subject: [PATCH 39/40] fix for preview path --- app/models/post.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index 72edda4b2..5d50bf923 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -64,16 +64,16 @@ class Post < ActiveRecord::Base module FileMethods def distribute_files RemoteFileManager.new(file_path).distribute - RemoteFileManager.new(real_preview_path).distribute - RemoteFileManager.new(ssd_preview_path).distribute if Danbooru.config.ssd_path + RemoteFileManager.new(real_preview_file_path).distribute + RemoteFileManager.new(ssd_preview_file_path).distribute if Danbooru.config.ssd_path RemoteFileManager.new(medium_file_path).distribute if has_medium? RemoteFileManager.new(large_file_path).distribute if has_large? end def delete_remote_files RemoteFileManager.new(file_path).delete - RemoteFileManager.new(real_preview_path).delete - RemoteFileManager.new(ssd_preview_path).delete if Danbooru.config.ssd_path + RemoteFileManager.new(real_preview_file_path).delete + RemoteFileManager.new(ssd_preview_file_path).delete if Danbooru.config.ssd_path RemoteFileManager.new(medium_file_path).delete if has_medium? RemoteFileManager.new(large_file_path).delete if has_large? end From 60abc867ca81548fce8ab25e8a8d4fd0487e699d Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 30 Aug 2011 20:10:38 -0400 Subject: [PATCH 40/40] js fixes --- app/assets/javascripts/post_mode_menu.js | 6 +++--- app/models/upload.rb | 4 ++++ app/views/uploads/show.html.erb | 2 ++ config/deploy.rb | 7 ++++--- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/post_mode_menu.js b/app/assets/javascripts/post_mode_menu.js index 526e74f6b..e10b9037f 100644 --- a/app/assets/javascripts/post_mode_menu.js +++ b/app/assets/javascripts/post_mode_menu.js @@ -47,9 +47,7 @@ var s = $("#mode-box select").val(); var post_id = $(e.target).closest("article").data("id"); - if (s === "view") { - return; - } else if (s === "add-fav") { + if (s === "add-fav") { Danbooru.Favorite.create(post_id); } else if (s === "remove-fav") { Danbooru.Favorite.destroy(post_id); @@ -72,6 +70,8 @@ } else if (s === "apply-tag-script") { var tag_script = Danbooru.Cookie.get("tag-script"); Danbooru.TagScript.run(post_id, tag_script); + } else { + return; } e.preventDefault(); diff --git a/app/models/upload.rb b/app/models/upload.rb index e76e74003..bf5e8004a 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -282,6 +282,10 @@ class Upload < ActiveRecord::Base status == "pending" end + def is_processing? + status == "processing" + end + def is_completed? status == "completed" end diff --git a/app/views/uploads/show.html.erb b/app/views/uploads/show.html.erb index 589fad3f1..e761d92e2 100644 --- a/app/views/uploads/show.html.erb +++ b/app/views/uploads/show.html.erb @@ -10,6 +10,8 @@

    This upload has finished processing. <%= link_to "View the post", post_path(@upload.post_id) %>.

    <% elsif @upload.is_pending? %>

    This upload is waiting to be processed. Please wait a few seconds.

    +<% elsif @upload.is_processing? %> +

    This upload is being processed. Please wait a few seconds.

    <% else %>

    An error occurred: <%= @upload.status %>

    <% end %> diff --git a/config/deploy.rb b/config/deploy.rb index e275f7737..7dc205399 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -89,17 +89,17 @@ end namespace :delayed_job do desc "Start delayed_job process" task :start, :roles => :app do - run "cd #{current_path}; script/delayed_job start #{rails_env}" + run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job start" end desc "Stop delayed_job process" task :stop, :roles => :app do - run "cd #{current_path}; script/delayed_job stop #{rails_env}" + run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job stop" end desc "Restart delayed_job process" task :restart, :roles => :app do - run "cd #{current_path}; script/delayed_job restart #{rails_env}" + run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job restart" end end @@ -115,3 +115,4 @@ after "deploy:stop", "delayed_job:stop" after "deploy:restart", "delayed_job:restart" before "deploy:update", "deploy:web:disable" after "deploy:restart", "deploy:web:enable" +