# encoding: utf-8 # License: refer to LICENSE file require 'haml' require 'pp' if $debug require 'sinatra' require 'sinatra/base' require 'sinatra/reloader' if development? and Gem::Specification::find_all_by_name('sinatra-reloader').any? #require 'rack/contrib/try_static' require 'rbconfig' # # Kamishibai # A manga reading webapp # module Kamishibai class Webserver < Sinatra::Base # shutdown hook, save database and bookmarks when exiting at_exit do $db.save $db.save_bookmarks end # smaller, quicker web server set :server, 'thin' unless RUBY_PLATFORM == 'java' if $debug set :environment, :development else set :environment, :production end configure :development do enable :logging if Gem::Specification::find_all_by_name('sinatra-reloader').any? register Sinatra::Reloader also_reload 'kamishibai/functions' also_reload 'kamishibai/patches' also_reload 'kamishibai/book' also_reload 'kamishibai/database' # reload webserver plug-ins Dir.glob( settings.root + '/../**/webserver_*.rb' ) { |f| also_reload f.gsub('.rb','') } end # enable caching for public directory set :static_cache_control, [:public, :max_age => 1] end configure :production do disable :logging disable :raise_errors # enable caching for public directory set :static_cache_control, [:public, :max_age => 1] # 300 end configure do # listen to all interface set :bind, $settings.bind # setup port set :port, $settings.port # enable session support enable :sessions use Rack::Session::Pool, :expire_after => 60*60*24*365 # enable http gzip use Rack::Deflater # setup template location set :views, File.expand_path( settings.root + '/../../views' ) # setup public location set :public_folder, File.expand_path(settings.views + '/../public') # setup 2nd public location for vendor libraries # use Rack::TryStatic, # :root => File.expand_path(settings.views + '/../public/vendor'), # :urls => %w[/], try: ['.html', 'index.html', '/index.html'] # authentication use Rack::Auth::Basic, "Restricted Area" do |username, password| [username, password] == [$settings.username, $settings.password] end # register mime type for static file mime_type :jpeg, 'image/jpeg' mime_type :png, 'image/png' mime_type :gif, 'image/gif' mime_type :css, 'text/css' mime_type :javascript, 'application/javascript' end # setup instance variable before do # global instance var end # helper functions helpers do # precheck the input from url def input_check( bookcode, page ) page = page.to_i if $db.has_bookcode?( bookcode ) @book = $db.get_book( bookcode ) else not_found "No such book code. #{ bookcode }" end unless @book.pages not_found "Book contain no images. #{ bookcode } #{ @book.fullpath }" end if page < 1 or page > @book.pages not_found "No such page. #{ page } #{ bookcode } #{ @book.fullpath }" end if ! FileTest.exists?( @book.fullpath ) not_found "File don't exists. #{ bookcode } #{ @book.fullpath }" end if ! FileTest.file?( @book.fullpath ) not_found "Not a file. #{ bookcode } #{ @book.fullpath }" end end # regular expression from POST keyword search def pregex keyword = request['keyword'].untaint keyword = keyword.gsub(' ','.+') return Regexp.new( keyword, Regexp::IGNORECASE ) end end # detect screen dimension post '/screen' do session[:width] = params[:width].to_i session[:height] = params[:height].to_i puts "screen dimension. #{session[:width]} x #{session[:height]}" if $debug end # redirect index page get '/' do redirect '/browse/' # if request.user_agent =~ /(android|tablet|iphone|ipad)/i # redirect '/browse_tablet/' # else # redirect '/browse/' # end end get '/statistics' do haml :statistics, :layout => false end # browse page with folder/file navigation get '/browse/' do haml :browse, :layout => false end get '/bookinfo/*' do |bookcode| input_check( bookcode, 1) content_type :javascript page = @book.page ? @book.page : 'null' "var book = { bookcode: '#{@book.bookcode}', basename: '#{File.basename( @book.fullpath ).gsub(/\.cbz$/i,'').escape_html}', title: '#{@book.title.to_s.escape_html}', author: '#{@book.author.to_s.escape_html}', page: #{page}, pages: #{@book.pages} }; " end get '/setbookmark/*/*' do |bookcode, page| page = page.to_i input_check( bookcode, page ) $db.set_bookmark(bookcode, page) "bookmarked" end def self.get_or_post(path, opts={}, &block) get(path, opts, &block) post(path, opts, &block) end # reader page get '/reader/' do cache_control :public, :must_revalidate, :max_age => 1 haml :reader, :layout => false end # list sources get '/list_sources' do content_type :javascript %Q{ sources = [ #{$settings.srcs.collect{ |x| " \"#{x}\"" }.join(",\n")} ] } end # directory browse page get_or_post '/lists_dir' do content_type :text path = File.expand_path( request['dir'].untaint ) order_by = request['order_by'].untaint unless FileTest.exists?(path) errmsg = "Error. No such path. #{path}" puts errmsg if $debug # not_found errmsg return errmsg end unless File.stat(path).readable_real? errmsg = "Error. Not readable path. #{path}" puts errmsg if $debug # not_found errmsg return errmsg end # check and add new books, existing books will not be added $db.add_books( [ path ], false) # refresh db, make sure book filepath is valid $db.refresh_bookcodes html = "