kamishibai 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/LICENSE +29 -0
- data/README.md +91 -0
- data/bin/kamishibai +59 -0
- data/changelogs.txt +6 -0
- data/images/reading.jpg +0 -0
- data/images/settings.jpg +0 -0
- data/images/view_browse.jpg +0 -0
- data/images/view_dir.jpg +0 -0
- data/kamishibai.gemspec +31 -0
- data/lib/kamishibai.rb +35 -0
- data/lib/kamishibai/book.rb +97 -0
- data/lib/kamishibai/config.rb +90 -0
- data/lib/kamishibai/database.rb +330 -0
- data/lib/kamishibai/functions.rb +332 -0
- data/lib/kamishibai/patches.rb +58 -0
- data/lib/kamishibai/version.rb +7 -0
- data/lib/kamishibai/webserver.rb +502 -0
- data/lib/kamishibai/webserver_cmds.rb +26 -0
- data/lib/kamishibai/webserver_config.rb +91 -0
- data/lib/kamishibai/webserver_filemanager.rb +29 -0
- data/lib/kamishibai/webserver_tablet.rb +259 -0
- data/lib/kamishibai/workers.rb +39 -0
- data/public/css/browse.css +390 -0
- data/public/css/config.css +3 -0
- data/public/css/reader.css +119 -0
- data/public/css/styles.css +30 -0
- data/public/css/tablet_browse.css +247 -0
- data/public/css/tablet_reader.css +323 -0
- data/public/css/tablet_reader_input.css +191 -0
- data/public/images/ajax-loader.gif +0 -0
- data/public/images/delete.png +0 -0
- data/public/images/folder-mini-up.png +0 -0
- data/public/images/folder-mini.png +0 -0
- data/public/images/spinner.gif +0 -0
- data/public/images/trash-empty-mini.png +0 -0
- data/public/images/trash-full-mini.png +0 -0
- data/public/js/browse.js +391 -0
- data/public/js/config.js +190 -0
- data/public/js/reader.js +497 -0
- data/public/js/swipeview-k.js +478 -0
- data/public/js/tablet3.js +241 -0
- data/public/js/tablet3_browse.js +173 -0
- data/public/js/tablet3_reader.js +534 -0
- data/public/js/utilities.js +170 -0
- data/public/lang/k-cn.json +82 -0
- data/public/lang/k-en.json +82 -0
- data/public/lang/k-ja.json +82 -0
- data/public/vendor/css/bootstrap-slider.css +252 -0
- data/public/vendor/css/bootstrap-theme.css +476 -0
- data/public/vendor/css/bootstrap-theme.css.map +1 -0
- data/public/vendor/css/bootstrap-theme.min.css +5 -0
- data/public/vendor/css/bootstrap.css +6584 -0
- data/public/vendor/css/bootstrap.css.map +1 -0
- data/public/vendor/css/bootstrap.min.css +5 -0
- data/public/vendor/css/jquery-ui-1.10.0.custom.css +1614 -0
- data/public/vendor/css/jquery.mobile-1.3.1.min.css +3 -0
- data/public/vendor/css/jqueryFileTree.css +91 -0
- data/public/vendor/fonts/glyphicons-halflings-regular.eot +0 -0
- data/public/vendor/fonts/glyphicons-halflings-regular.svg +288 -0
- data/public/vendor/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/public/vendor/fonts/glyphicons-halflings-regular.woff +0 -0
- data/public/vendor/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/public/vendor/images/application.png +0 -0
- data/public/vendor/images/code.png +0 -0
- data/public/vendor/images/css.png +0 -0
- data/public/vendor/images/db.png +0 -0
- data/public/vendor/images/dim.png +0 -0
- data/public/vendor/images/directory.png +0 -0
- data/public/vendor/images/doc.png +0 -0
- data/public/vendor/images/file.png +0 -0
- data/public/vendor/images/film.png +0 -0
- data/public/vendor/images/flash.png +0 -0
- data/public/vendor/images/folder_open.png +0 -0
- data/public/vendor/images/grey.png +0 -0
- data/public/vendor/images/html.png +0 -0
- data/public/vendor/images/icons-18-black.png +0 -0
- data/public/vendor/images/icons-18-white.png +0 -0
- data/public/vendor/images/icons-36-black.png +0 -0
- data/public/vendor/images/icons-36-white.png +0 -0
- data/public/vendor/images/java.png +0 -0
- data/public/vendor/images/linux.png +0 -0
- data/public/vendor/images/music.png +0 -0
- data/public/vendor/images/pdf.png +0 -0
- data/public/vendor/images/php.png +0 -0
- data/public/vendor/images/picture.png +0 -0
- data/public/vendor/images/ppt.png +0 -0
- data/public/vendor/images/psd.png +0 -0
- data/public/vendor/images/ruby.png +0 -0
- data/public/vendor/images/script.png +0 -0
- data/public/vendor/images/spinner.gif +0 -0
- data/public/vendor/images/txt.png +0 -0
- data/public/vendor/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- data/public/vendor/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- data/public/vendor/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/public/vendor/images/ui-bg_flat_10_000000_40x100.png +0 -0
- data/public/vendor/images/ui-bg_flat_30_cccccc_40x100.png +0 -0
- data/public/vendor/images/ui-bg_flat_50_5c5c5c_40x100.png +0 -0
- data/public/vendor/images/ui-bg_flat_55_fbec88_40x100.png +0 -0
- data/public/vendor/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/public/vendor/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- data/public/vendor/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- data/public/vendor/images/ui-bg_glass_20_555555_1x400.png +0 -0
- data/public/vendor/images/ui-bg_glass_40_0078a3_1x400.png +0 -0
- data/public/vendor/images/ui-bg_glass_40_ffc73d_1x400.png +0 -0
- data/public/vendor/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/public/vendor/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/public/vendor/images/ui-bg_glass_75_d0e5f5_1x400.png +0 -0
- data/public/vendor/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/public/vendor/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/public/vendor/images/ui-bg_glass_85_dfeffc_1x400.png +0 -0
- data/public/vendor/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/public/vendor/images/ui-bg_gloss-wave_25_333333_500x100.png +0 -0
- data/public/vendor/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- data/public/vendor/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png +0 -0
- data/public/vendor/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- data/public/vendor/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/public/vendor/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- data/public/vendor/images/ui-bg_highlight-soft_80_eeeeee_1x100.png +0 -0
- data/public/vendor/images/ui-bg_inset-hard_100_f5f8f9_1x100.png +0 -0
- data/public/vendor/images/ui-bg_inset-hard_100_fcfdfd_1x100.png +0 -0
- data/public/vendor/images/ui-bg_inset-soft_25_000000_1x100.png +0 -0
- data/public/vendor/images/ui-bg_inset-soft_30_f58400_1x100.png +0 -0
- data/public/vendor/images/ui-icons_217bc0_256x240.png +0 -0
- data/public/vendor/images/ui-icons_222222_256x240.png +0 -0
- data/public/vendor/images/ui-icons_228ef1_256x240.png +0 -0
- data/public/vendor/images/ui-icons_2e83ff_256x240.png +0 -0
- data/public/vendor/images/ui-icons_454545_256x240.png +0 -0
- data/public/vendor/images/ui-icons_469bdd_256x240.png +0 -0
- data/public/vendor/images/ui-icons_4b8e0b_256x240.png +0 -0
- data/public/vendor/images/ui-icons_6da8d5_256x240.png +0 -0
- data/public/vendor/images/ui-icons_888888_256x240.png +0 -0
- data/public/vendor/images/ui-icons_a83300_256x240.png +0 -0
- data/public/vendor/images/ui-icons_cccccc_256x240.png +0 -0
- data/public/vendor/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/public/vendor/images/ui-icons_d8e7f3_256x240.png +0 -0
- data/public/vendor/images/ui-icons_ef8c08_256x240.png +0 -0
- data/public/vendor/images/ui-icons_f9bd01_256x240.png +0 -0
- data/public/vendor/images/ui-icons_ffd27a_256x240.png +0 -0
- data/public/vendor/images/ui-icons_ffffff_256x240.png +0 -0
- data/public/vendor/images/xls.png +0 -0
- data/public/vendor/images/zip.png +0 -0
- data/public/vendor/js/bootstrap-slider.js +1550 -0
- data/public/vendor/js/bootstrap.js +2317 -0
- data/public/vendor/js/bootstrap.min.js +7 -0
- data/public/vendor/js/jquery-2.1.4.js +9210 -0
- data/public/vendor/js/jquery-2.1.4.min.js +4 -0
- data/public/vendor/js/jquery-2.1.4.min.map +1 -0
- data/public/vendor/js/jquery-ui-1.10.2.custom.min.js +7 -0
- data/public/vendor/js/jquery.cookie.js +72 -0
- data/public/vendor/js/jquery.hammer.min.js +7 -0
- data/public/vendor/js/jquery.lazyload.min.js +15 -0
- data/public/vendor/js/jquery.localize.js +180 -0
- data/public/vendor/js/jquery.mobile-1.3.1.min.js +7 -0
- data/public/vendor/js/jquery.scrollTo-1.4.3.1.js +218 -0
- data/public/vendor/js/jqueryFileTree.js +95 -0
- data/public/vendor/js/swipeview.js +471 -0
- data/views/browse.haml +97 -0
- data/views/config.haml +115 -0
- data/views/layout.haml +12 -0
- data/views/login.haml +51 -0
- data/views/reader.haml +70 -0
- data/views/statistics.haml +108 -0
- data/views/tablet3.haml +80 -0
- metadata +334 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# License: refer to LICENSE file
|
|
4
|
+
|
|
5
|
+
require 'addressable/uri' #using addressable because default ruby uri is badly implemented, causing InvalidURIError on many situations, especially unicode string
|
|
6
|
+
|
|
7
|
+
#
|
|
8
|
+
# bug fix
|
|
9
|
+
# the addressable/uri has a bug that is not escaping the '
|
|
10
|
+
#
|
|
11
|
+
class Addressable::URI
|
|
12
|
+
def self.escape2(str)
|
|
13
|
+
s = Addressable::URI.escape(str)
|
|
14
|
+
s = s.gsub("#",'%23')
|
|
15
|
+
s = s.gsub("'",'%27')
|
|
16
|
+
s = s.gsub('+','%2B')
|
|
17
|
+
s
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Addressable::URI
|
|
22
|
+
def self.unescape2(str)
|
|
23
|
+
s = str.gsub('%2B','+')
|
|
24
|
+
s = s.gsub('%27',"'")
|
|
25
|
+
s = s.gsub('%23',"#")
|
|
26
|
+
s = Addressable::URI.unescape(s)
|
|
27
|
+
s
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
# bug fix
|
|
34
|
+
# fixing bug when client post to server it get 405 "Method Not Allowed" Error
|
|
35
|
+
# https://github.com/bachue/rack-contrib/commit/f5f4ffebc20277903f6013adfb0429d12b4a3050
|
|
36
|
+
#
|
|
37
|
+
module Rack
|
|
38
|
+
class TryStatic
|
|
39
|
+
|
|
40
|
+
def initialize(app, options)
|
|
41
|
+
@app = app
|
|
42
|
+
@try = ['', *options[:try]]
|
|
43
|
+
@static = ::Rack::Static.new(
|
|
44
|
+
lambda { |_| [404, {}, []] },
|
|
45
|
+
options)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def call(env)
|
|
49
|
+
orig_path = env['PATH_INFO']
|
|
50
|
+
found = nil
|
|
51
|
+
@try.each do |path|
|
|
52
|
+
resp = @static.call(env.merge!({'PATH_INFO' => orig_path + path}))
|
|
53
|
+
break if !(403..405).include?(resp[0]) && found = resp
|
|
54
|
+
end
|
|
55
|
+
found or @app.call(env.merge!('PATH_INFO' => orig_path))
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# License: refer to LICENSE file
|
|
4
|
+
|
|
5
|
+
require 'haml'
|
|
6
|
+
require 'pp' if $debug
|
|
7
|
+
require 'sinatra'
|
|
8
|
+
require 'sinatra/base'
|
|
9
|
+
require 'sinatra/reloader' if development? and Gem::Specification::find_all_by_name('sinatra-reloader').any?
|
|
10
|
+
#require 'rack/contrib/try_static'
|
|
11
|
+
require 'rbconfig'
|
|
12
|
+
|
|
13
|
+
#
|
|
14
|
+
# Kamishibai
|
|
15
|
+
# A manga reading webapp
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
module Kamishibai
|
|
19
|
+
class Webserver < Sinatra::Base
|
|
20
|
+
# shutdown hook, save database and bookmarks when exiting
|
|
21
|
+
at_exit do
|
|
22
|
+
$db.save
|
|
23
|
+
$db.save_bookmarks
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# smaller, quicker web server
|
|
27
|
+
set :server, 'thin' unless RUBY_PLATFORM == 'java'
|
|
28
|
+
|
|
29
|
+
if $debug
|
|
30
|
+
set :environment, :development
|
|
31
|
+
else
|
|
32
|
+
set :environment, :production
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
configure :development do
|
|
36
|
+
enable :logging
|
|
37
|
+
if Gem::Specification::find_all_by_name('sinatra-reloader').any?
|
|
38
|
+
register Sinatra::Reloader
|
|
39
|
+
|
|
40
|
+
also_reload 'kamishibai/functions'
|
|
41
|
+
also_reload 'kamishibai/patches'
|
|
42
|
+
also_reload 'kamishibai/book'
|
|
43
|
+
also_reload 'kamishibai/database'
|
|
44
|
+
|
|
45
|
+
# reload webserver plug-ins
|
|
46
|
+
Dir.glob( settings.root + '/../**/webserver_*.rb' ) { |f|
|
|
47
|
+
also_reload f.gsub('.rb','')
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# enable caching for public directory
|
|
52
|
+
set :static_cache_control, [:public, :max_age => 1]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
configure :production do
|
|
56
|
+
disable :logging
|
|
57
|
+
disable :raise_errors
|
|
58
|
+
|
|
59
|
+
# enable caching for public directory
|
|
60
|
+
set :static_cache_control, [:public, :max_age => 1] # 300
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
configure do
|
|
64
|
+
# listen to all interface
|
|
65
|
+
set :bind, $settings.bind
|
|
66
|
+
|
|
67
|
+
# setup port
|
|
68
|
+
set :port, $settings.port
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# enable session support
|
|
72
|
+
enable :sessions
|
|
73
|
+
use Rack::Session::Pool, :expire_after => 60*60*24*365
|
|
74
|
+
|
|
75
|
+
# enable http gzip
|
|
76
|
+
use Rack::Deflater
|
|
77
|
+
|
|
78
|
+
# setup template location
|
|
79
|
+
set :views, File.expand_path( settings.root + '/../../views' )
|
|
80
|
+
|
|
81
|
+
# setup public location
|
|
82
|
+
set :public_folder, File.expand_path(settings.views + '/../public')
|
|
83
|
+
|
|
84
|
+
# setup 2nd public location for vendor libraries
|
|
85
|
+
# use Rack::TryStatic,
|
|
86
|
+
# :root => File.expand_path(settings.views + '/../public/vendor'),
|
|
87
|
+
# :urls => %w[/], try: ['.html', 'index.html', '/index.html']
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# authentication
|
|
91
|
+
use Rack::Auth::Basic, "Restricted Area" do |username, password|
|
|
92
|
+
[username, password] == [$settings.username, $settings.password]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# register mime type for static file
|
|
96
|
+
mime_type :jpeg, 'image/jpeg'
|
|
97
|
+
mime_type :png, 'image/png'
|
|
98
|
+
mime_type :gif, 'image/gif'
|
|
99
|
+
mime_type :css, 'text/css'
|
|
100
|
+
mime_type :javascript, 'application/javascript'
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# setup instance variable
|
|
104
|
+
before do
|
|
105
|
+
# global instance var
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# helper functions
|
|
109
|
+
helpers do
|
|
110
|
+
# precheck the input from url
|
|
111
|
+
def input_check( bookcode, page )
|
|
112
|
+
page = page.to_i
|
|
113
|
+
|
|
114
|
+
if $db.has_bookcode?( bookcode )
|
|
115
|
+
@book = $db.get_book( bookcode )
|
|
116
|
+
else
|
|
117
|
+
not_found "No such book code. #{ bookcode }"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
unless @book.pages
|
|
121
|
+
not_found "Book contain no images. #{ bookcode } #{ @book.fullpath }"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
if page < 1 or page > @book.pages
|
|
125
|
+
not_found "No such page. #{ page } #{ bookcode } #{ @book.fullpath }"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
if ! FileTest.exists?( @book.fullpath )
|
|
129
|
+
not_found "File don't exists. #{ bookcode } #{ @book.fullpath }"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
if ! FileTest.file?( @book.fullpath )
|
|
133
|
+
not_found "Not a file. #{ bookcode } #{ @book.fullpath }"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# regular expression from POST keyword search
|
|
138
|
+
def pregex
|
|
139
|
+
keyword = request['keyword'].untaint
|
|
140
|
+
keyword = keyword.gsub(' ','.+')
|
|
141
|
+
return Regexp.new( keyword, Regexp::IGNORECASE )
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# detect screen dimension
|
|
147
|
+
post '/screen' do
|
|
148
|
+
session[:width] = params[:width].to_i
|
|
149
|
+
session[:height] = params[:height].to_i
|
|
150
|
+
|
|
151
|
+
puts "screen dimension. #{session[:width]} x #{session[:height]}" if $debug
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# redirect index page
|
|
155
|
+
get '/' do
|
|
156
|
+
redirect '/browse/'
|
|
157
|
+
# if request.user_agent =~ /(android|tablet|iphone|ipad)/i
|
|
158
|
+
# redirect '/browse_tablet/'
|
|
159
|
+
# else
|
|
160
|
+
# redirect '/browse/'
|
|
161
|
+
# end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
get '/statistics' do
|
|
165
|
+
haml :statistics, :layout => false
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# browse page with folder/file navigation
|
|
169
|
+
get '/browse/' do
|
|
170
|
+
haml :browse, :layout => false
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
get '/bookinfo/*' do |bookcode|
|
|
174
|
+
input_check( bookcode, 1)
|
|
175
|
+
|
|
176
|
+
content_type :javascript
|
|
177
|
+
|
|
178
|
+
page = @book.page ? @book.page : 'null'
|
|
179
|
+
|
|
180
|
+
"var book = {
|
|
181
|
+
bookcode: '#{@book.bookcode}',
|
|
182
|
+
basename: '#{File.basename( @book.fullpath ).gsub(/\.cbz$/i,'').escape_html}',
|
|
183
|
+
title: '#{@book.title.to_s.escape_html}',
|
|
184
|
+
author: '#{@book.author.to_s.escape_html}',
|
|
185
|
+
page: #{page},
|
|
186
|
+
pages: #{@book.pages}
|
|
187
|
+
};
|
|
188
|
+
"
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
get '/setbookmark/*/*' do |bookcode, page|
|
|
192
|
+
page = page.to_i
|
|
193
|
+
input_check( bookcode, page )
|
|
194
|
+
|
|
195
|
+
$db.set_bookmark(bookcode, page)
|
|
196
|
+
|
|
197
|
+
"bookmarked"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def self.get_or_post(path, opts={}, &block)
|
|
201
|
+
get(path, opts, &block)
|
|
202
|
+
post(path, opts, &block)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# reader page
|
|
206
|
+
get '/reader/' do
|
|
207
|
+
cache_control :public, :must_revalidate, :max_age => 1
|
|
208
|
+
|
|
209
|
+
haml :reader, :layout => false
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# list sources
|
|
213
|
+
get '/list_sources' do
|
|
214
|
+
content_type :javascript
|
|
215
|
+
|
|
216
|
+
%Q{
|
|
217
|
+
sources = [
|
|
218
|
+
#{$settings.srcs.collect{ |x| " \"#{x}\"" }.join(",\n")}
|
|
219
|
+
]
|
|
220
|
+
}
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# directory browse page
|
|
224
|
+
get_or_post '/lists_dir' do
|
|
225
|
+
content_type :text
|
|
226
|
+
path = File.expand_path( request['dir'].untaint )
|
|
227
|
+
order_by = request['order_by'].untaint
|
|
228
|
+
|
|
229
|
+
unless FileTest.exists?(path)
|
|
230
|
+
errmsg = "Error. No such path. #{path}"
|
|
231
|
+
puts errmsg if $debug
|
|
232
|
+
# not_found errmsg
|
|
233
|
+
|
|
234
|
+
return errmsg
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
unless File.stat(path).readable_real?
|
|
238
|
+
errmsg = "Error. Not readable path. #{path}"
|
|
239
|
+
puts errmsg if $debug
|
|
240
|
+
# not_found errmsg
|
|
241
|
+
|
|
242
|
+
return errmsg
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# check and add new books, existing books will not be added
|
|
246
|
+
$db.add_books( [ path ], false)
|
|
247
|
+
# refresh db, make sure book filepath is valid
|
|
248
|
+
$db.refresh_bookcodes
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
html = "<ul id=\"ul-lists\" class=\"ul-lists\">\n"
|
|
252
|
+
|
|
253
|
+
html << "\t<li class=\"directory collapsed updir\"><a href=\"#dir=#{File.dirname(path)}\" rel=\"#{File.dirname(path)}/\"><img src=\"/images/folder-mini-up.png\" /><span>..</span></a></li>\n"
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
# poulate the lists with files(books) and directory
|
|
258
|
+
lists = []
|
|
259
|
+
Dir.glob(path.escape_glob + '/*').entries.sort.each { |fp|
|
|
260
|
+
next unless File.stat(fp).readable_real?
|
|
261
|
+
|
|
262
|
+
dir = File.dirname(fp)
|
|
263
|
+
f = File.basename(fp)
|
|
264
|
+
ext = File.extname(fp)[1..-1]
|
|
265
|
+
|
|
266
|
+
next unless pregex.match( f ) # skip unless file/dir name match the searchbox's keyword
|
|
267
|
+
|
|
268
|
+
if FileTest.directory?(fp) and File.stat(fp).executable_real?
|
|
269
|
+
# a directory
|
|
270
|
+
lists << fp
|
|
271
|
+
|
|
272
|
+
elsif ext == 'cbz' and File.stat(fp).readable_real?
|
|
273
|
+
# a file
|
|
274
|
+
|
|
275
|
+
bookcode = $db.get_bookcode_byfilename( fp )
|
|
276
|
+
unless bookcode
|
|
277
|
+
puts "ERROR: bookcode #{bookcode} not found! skipping to next book..."
|
|
278
|
+
next
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
book = $db.get_book( bookcode )
|
|
282
|
+
|
|
283
|
+
lists << book
|
|
284
|
+
end
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
# sort by order
|
|
288
|
+
lists2 = {}
|
|
289
|
+
case order_by
|
|
290
|
+
when 'size'
|
|
291
|
+
lists.each { |x|
|
|
292
|
+
|
|
293
|
+
if x.class == Book
|
|
294
|
+
lists2[x] = x.size
|
|
295
|
+
else
|
|
296
|
+
# x == full path of file or directory
|
|
297
|
+
lists2[x] = 0
|
|
298
|
+
end
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
lists2 = lists2.sort { |a, b| b[1] <=> a[1] }
|
|
302
|
+
|
|
303
|
+
when 'date'
|
|
304
|
+
lists.each { |x|
|
|
305
|
+
if x.class == Book
|
|
306
|
+
lists2[x] = x.mtime
|
|
307
|
+
else
|
|
308
|
+
# x == full path of file or directory
|
|
309
|
+
lists2[x] = File.stat(x).mtime.to_i
|
|
310
|
+
end
|
|
311
|
+
}
|
|
312
|
+
lists2 = lists2.sort { |a, b| b[1] <=> a[1] }
|
|
313
|
+
|
|
314
|
+
else
|
|
315
|
+
# by name, default
|
|
316
|
+
lists.each { |x|
|
|
317
|
+
if x.class == Book
|
|
318
|
+
lists2[x] = File.basename( x.fullpath )
|
|
319
|
+
else
|
|
320
|
+
# x == full path of file or directory
|
|
321
|
+
lists2[x] = File.basename( x )
|
|
322
|
+
end
|
|
323
|
+
}
|
|
324
|
+
lists2 = lists2.sort { |a, b| a[1] <=> b[1] }
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# create html from lists(2)
|
|
328
|
+
lists2.each { |item, dat|
|
|
329
|
+
|
|
330
|
+
if item.class == String
|
|
331
|
+
# a directory
|
|
332
|
+
|
|
333
|
+
li_classes = ['directory', 'collapsed']
|
|
334
|
+
|
|
335
|
+
if item == 'Trash'
|
|
336
|
+
el_id = 'id="trash"'
|
|
337
|
+
li_classes << 'trash'
|
|
338
|
+
if Dir.glob(item.escape_glob + '/*.cbz').entries.length > 0
|
|
339
|
+
icon = 'trash-full-mini.png'
|
|
340
|
+
else
|
|
341
|
+
icon = 'trash-empty-mini.png'
|
|
342
|
+
end
|
|
343
|
+
else
|
|
344
|
+
icon = 'folder-mini.png'
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
html << "\t<li class=\"" + li_classes.join(' ') + "\" #{el_id}><a href=\"#dir=#{item}\" rel=\"#{item}/\"><img src=\"/images/" + icon + "\" /><span>#{File.basename(item)}</span></a></li>\n"
|
|
348
|
+
|
|
349
|
+
elsif item.class == Book
|
|
350
|
+
# a file
|
|
351
|
+
|
|
352
|
+
book = item
|
|
353
|
+
bookcode = book.bookcode
|
|
354
|
+
fp = book.fullpath
|
|
355
|
+
f = File.basename(fp)
|
|
356
|
+
ext = File.extname(fp)[1..-1]
|
|
357
|
+
|
|
358
|
+
img = "<img class='lazy fadeIn fadeIn-1s fadeIn-Delay-Xs' data-original='/thumbnail/#{bookcode}' alt='Loading...' />"
|
|
359
|
+
|
|
360
|
+
if book.page
|
|
361
|
+
# prepare the value for the visual read progress
|
|
362
|
+
page = book.page
|
|
363
|
+
pages = book.pages
|
|
364
|
+
|
|
365
|
+
bn = (1.0*page/pages)*100
|
|
366
|
+
pc = bn - bn % 10
|
|
367
|
+
|
|
368
|
+
# read percentage css class
|
|
369
|
+
if pc > 0
|
|
370
|
+
readstate = 'read' + pc.to_i.to_s
|
|
371
|
+
else
|
|
372
|
+
readstate = 'read5'
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
href = '/tablet#book=' + bookcode + '&page=' + page.to_s
|
|
376
|
+
else
|
|
377
|
+
readstate = 'read0'
|
|
378
|
+
href = '/tablet#book=' + bookcode
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
html << "\t<li class=\"file ext_#{ext}\"><a href=\"#{href}\" bookcode=\"#{bookcode}\" rel=\"#{fp}\">#{img}<span class=\"#{readstate}\">#{f.escape_html}</span><span class=\"badge badge-info bookpages\">#{book.pages}</span></a></li>\n"
|
|
382
|
+
end
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return html
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# directory browse page
|
|
389
|
+
post '/jqueryFileTree' do
|
|
390
|
+
content_type :text
|
|
391
|
+
path = request['dir'].untaint
|
|
392
|
+
|
|
393
|
+
html = "<ul class=\"jqueryFileTree\" style=\"display: none;\">\n"
|
|
394
|
+
|
|
395
|
+
if FileTest.exists?(File.expand_path(path))
|
|
396
|
+
|
|
397
|
+
# chdir() to user requested dir (root + "/" + dir)
|
|
398
|
+
Dir.chdir(File.expand_path(path).untaint);
|
|
399
|
+
|
|
400
|
+
#loop through all directories
|
|
401
|
+
Dir.glob("*") { |x|
|
|
402
|
+
next unless File.directory?(x.untaint)
|
|
403
|
+
next unless File.stat(x.untaint).readable_real? and File.stat(x.untaint).executable_real?
|
|
404
|
+
|
|
405
|
+
fp = path + x
|
|
406
|
+
html << "\t<li class=\"directory collapsed\"><a href=\"#\" rel=\"#{fp}/\" onclick=\"selected_dir('#{fp}');\">#{x.escape_html}</a></li>\n";
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
html << "</ul>\n"
|
|
412
|
+
|
|
413
|
+
return html
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
# cbz thumbnail
|
|
417
|
+
get '/thumbnail/*' do |bookcode|
|
|
418
|
+
cache_control :public, :must_revalidate, :max_age => 3600
|
|
419
|
+
|
|
420
|
+
# check and setup the variable
|
|
421
|
+
input_check( bookcode, 1 )
|
|
422
|
+
|
|
423
|
+
content_type :jpeg
|
|
424
|
+
|
|
425
|
+
# generate thumbnail
|
|
426
|
+
image = mk_thumb( @book.fullpath )
|
|
427
|
+
|
|
428
|
+
return image
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
# cbz file loader
|
|
432
|
+
get '/cbz/*/*' do |bookcode, page|
|
|
433
|
+
# # fake delay
|
|
434
|
+
# if $imgNum
|
|
435
|
+
# $imgNum += 1
|
|
436
|
+
# else
|
|
437
|
+
# $imgNum = 1
|
|
438
|
+
# end
|
|
439
|
+
# pp $imgNum
|
|
440
|
+
|
|
441
|
+
page = page.to_i
|
|
442
|
+
cache_control :public, :must_revalidate, :max_age => 3600
|
|
443
|
+
|
|
444
|
+
input_check( bookcode, page )
|
|
445
|
+
|
|
446
|
+
# width/height
|
|
447
|
+
quality = $settings.default_image_quality
|
|
448
|
+
width = session[:width].to_i
|
|
449
|
+
height = session[:height].to_i
|
|
450
|
+
# hard set to hd
|
|
451
|
+
# width = 1080
|
|
452
|
+
# height = 1920
|
|
453
|
+
|
|
454
|
+
# fix/prevent invalid input
|
|
455
|
+
quality = 0 if quality < 0
|
|
456
|
+
quality = 100 if quality > 100
|
|
457
|
+
width = 0 if width < 0 # 0 will be treated as do not resize
|
|
458
|
+
height = 0 if height < 0
|
|
459
|
+
|
|
460
|
+
# image type, image data
|
|
461
|
+
image = open_cbz( @book.fullpath, page)
|
|
462
|
+
|
|
463
|
+
# set content type, png/jpeg/png/gif/etc
|
|
464
|
+
itype = image_type( image )
|
|
465
|
+
content_type itype
|
|
466
|
+
|
|
467
|
+
# # fake delay
|
|
468
|
+
# Thread.new {
|
|
469
|
+
# sleep 7
|
|
470
|
+
# $imgNum = 0
|
|
471
|
+
# sleep 7
|
|
472
|
+
# $imgNum = 0
|
|
473
|
+
# }
|
|
474
|
+
# sleep 1.5 * $imgNum
|
|
475
|
+
# $imgNum -= 1
|
|
476
|
+
|
|
477
|
+
if width > 0 and height > 0 and $settings.image_resize
|
|
478
|
+
# resize image
|
|
479
|
+
img_resize( image, width, height, { :quality => quality })
|
|
480
|
+
else
|
|
481
|
+
# give raw
|
|
482
|
+
image
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
get '/list_db' do
|
|
487
|
+
html = "<html><body>\n"
|
|
488
|
+
p $db.books.length
|
|
489
|
+
$db.books.each { |bookcode, book|
|
|
490
|
+
html << "<pre>#{bookcode} #{book.page.to_s.rjust(3)}/#{book.pages} #{book.fullpath}</pre>\n"
|
|
491
|
+
}
|
|
492
|
+
html << "</body></html>"
|
|
493
|
+
html
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
# load webserver plug-ins
|
|
500
|
+
Dir.glob( settings.root + '/../**/webserver_*.rb' ) { |f|
|
|
501
|
+
require f.gsub('.rb','')
|
|
502
|
+
}
|