magicshelf 0.2.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1442269b371a6a584ed4a00eede012300e8f48af
4
+ data.tar.gz: e311a0dd3d245eaa42c8a0c2cfa488e9805234db
5
+ SHA512:
6
+ metadata.gz: f61e304a272623e583b13f1fdfd1d83ad62316d0323613479e2fc943eae1d4317100e91a0da7ee6a11e7460c6528a060b1f3b91b80c24115df82b7c1ab6a8948
7
+ data.tar.gz: 04bfca83c4fb273026ba2dfea8484f82f03dac508ea108c8407c986bd2a877fdf2ca866af718a2ff5e4755e00f770e437c3bcc31d8c4bde8dee0f7a991de664c
@@ -0,0 +1,3 @@
1
+ vendor/
2
+ Gemfile.lock
3
+ .bundle/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'gepub', github: 'skoji/gepub' # git: 'https://xxxxxx/yyyy.git'
6
+ #gem 'naturally', github: 'zedalaye/naturally'
@@ -0,0 +1,4 @@
1
+ web: bundle exec shotgun -p 4567 -o 0.0.0.0
2
+ resque: QUEUE=* bundle exec rake resque:work
3
+ redisserver: redis-server
4
+ #resque-web: resque-web --foreground
@@ -0,0 +1,38 @@
1
+ # MagicShelf
2
+
3
+ Access and get your e-book from kindle anywhere.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'magicshelf'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install magicshelf
20
+
21
+ ## Usage
22
+
23
+ ### Console app
24
+ ````
25
+ magicconvert --inputfile comic.rar --outputfile comic.mobi --booktype novel/comic/novelimage --title booktitle
26
+ ````
27
+
28
+
29
+ ### File Server
30
+ ````
31
+ bundle exec foreman start
32
+ ````
33
+
34
+
35
+ ## Contributing
36
+
37
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ompugao/magicshelf.
38
+
@@ -0,0 +1,16 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+ require 'resque/tasks'
4
+
5
+ desc 'Run test_unit based test'
6
+ Rake::TestTask.new do |t|
7
+ # To run test for only one file (or file path pattern)
8
+ # $ bundle exec rake test TEST=test/test_specified_path.rb
9
+ t.libs << "test"
10
+ t.test_files = Dir["test/**/test_*.rb"]
11
+ t.verbose = true
12
+ end
13
+
14
+ task :'resque:setup' do
15
+ Dir["./lib/magicshelf/mobitask.rb"].each {|file| require file}
16
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "magicshelf"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require "pry"
11
+ Pry.start
12
+
13
+ #require "irb"
14
+ #IRB.start
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'magicshelf'
4
+ require 'magicshelf/executionpipe'
5
+ require 'optparse'
6
+
7
+ optparams = ARGV.getopts("", "inputfile:", "title:", "outputfile:", "booktype:comic")
8
+
9
+ MagicShelf::ExecutionPipe.new.enter { |params,&block|
10
+ Dir.mktmpdir("magicshelf") do |dir|
11
+ params[:workdir] = dir
12
+ block.call
13
+ end
14
+ }.pipe(MagicShelf::FileExtractor.new,:workdir => [:destdir]) { |this|
15
+ this.inputfile = File.expand_path(optparams["inputfile"])
16
+ }.enter(:destdir => [:workdir]) {|params, &block|
17
+ Dir.chdir(params[:workdir]) do
18
+ block.call
19
+ end
20
+ }.pipe(MagicShelf::DirRenamer.new, :workdir => [:workdir]) { |this|
21
+ }.pipe(MagicShelf::FileNameValidator.new, :workdir => [:workdir]) { |this|
22
+ }.pipe(MagicShelf::MakeItVertical.new, :workdir => [:workdir]) { |this|
23
+ }.pipe(MagicShelf::EpubGenerator.new, :workdir => [:workdir]) { |this|
24
+ this.title = optparams['title']
25
+ this.book_type = optparams['booktype']
26
+ this.outputfile = 'test.epub'
27
+ }.pipe(MagicShelf::KindleGenWrapper.new, :outputfile => [:inputfile]) { |this|
28
+ this.outputfile = 'test.mobi'
29
+ }.process(:inputfile => [:file,:inputfile], :outputfile => [:outputfile]) { |params|
30
+ FileUtils.remove(params[:file])
31
+ }.pipe(MagicShelf::KindleStripper.new, :outputfile => [:inputfile]) { |this|
32
+ this.outputfile = File.expand_path('test_strip.mobi')
33
+ }.pipe(MagicShelf::FileCleaner.new, :inputfile => [:file], :outputfile => [:outputfile]) { |this|
34
+ }.pipe(MagicShelf::FileMover.new, :outputfile => [:inputfile]) { |this|
35
+ this.outputfile = File.expand_path(optparams["outputfile"])
36
+ }.execute
37
+
38
+ # vim: set ft=ruby ts=22 sw=2:
39
+
40
+
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ require 'sinatra'
3
+ require 'magicshelf'
4
+
5
+ run MagicShelf::FileServer
6
+
7
+
8
+ # vim: set ft=ruby:
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,6 @@
1
+ require './lib/magicshelf/fileserver'
2
+ require 'resque/server'
3
+
4
+ run Rack::URLMap.new \
5
+ "/" => MagicShelf::FileServer,
6
+ "/resque" => Resque::Server.new
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require "magicshelf/version"
3
+
4
+ require "magicshelf/dirchanger"
5
+ require "magicshelf/dirrenamer"
6
+ require "magicshelf/dirstructureflattener"
7
+ require "magicshelf/epubgenerator"
8
+ require "magicshelf/executionpipe"
9
+ require "magicshelf/filecleaner"
10
+ require "magicshelf/fileextractor"
11
+ require "magicshelf/filemover"
12
+ require "magicshelf/filenamevalidator"
13
+ require "magicshelf/fileserver"
14
+ require "magicshelf/kindlegenwrapper"
15
+ require "magicshelf/kindlestripper"
16
+ require "magicshelf/makeitvertical"
17
+ require "magicshelf/tempdiropener"
18
+
19
+
20
+ Dir.glob('monkeypatches/*') do |f|
21
+ require f
22
+ end
23
+
24
+ require 'logger'
25
+
26
+ module MagicShelf
27
+ (class << self; self end).module_eval do
28
+ attr_accessor :logger
29
+ end
30
+ end
31
+
32
+ MagicShelf.logger = Logger.new(STDOUT)
33
+
@@ -0,0 +1,22 @@
1
+ require 'magicshelf/exception'
2
+
3
+ module MagicShelf
4
+ class DirChangerError < Error; end
5
+
6
+ class DirChanger
7
+ attr_accessor :workdir
8
+
9
+ def enter()
10
+ raise MagicShelf::DirChangerError.new("workdir is not set") if @workdir == nil
11
+ Dir.chdir(@workdir) {|dir|
12
+ MagicShelf.logger.debug("DirChanger: chdir to #{dir}")
13
+ yield
14
+ }
15
+ end
16
+
17
+ def process()
18
+ end
19
+
20
+ end
21
+ end
22
+
@@ -0,0 +1,30 @@
1
+ require 'magicshelf/exception'
2
+
3
+ module MagicShelf
4
+ class DirRenamerError < Error; end
5
+
6
+ class DirRenamer
7
+ attr_accessor :workdir
8
+ def enter()
9
+ yield
10
+ end
11
+
12
+ def process()
13
+ @workdir ||= Dir.pwd
14
+ rename_dir_recursively(@workdir)
15
+ end
16
+
17
+ def rename_dir_recursively(path)
18
+ Dir.chdir(path) {
19
+ Dir['./*'].select{|f|File.directory?(f)}.each.with_index { |f,index|
20
+ if File.directory?(f)
21
+ rename_dir_recursively(f)
22
+ FileUtils.mv(f, index.to_s)
23
+ end
24
+ }
25
+ }
26
+ end
27
+ end
28
+ end
29
+
30
+
@@ -0,0 +1,25 @@
1
+ require 'magicshelf/exception'
2
+
3
+ module MagicShelf
4
+ class DirStructureFlattenerError < Error; end
5
+
6
+ class DirStructureFlattener
7
+ attr_accessor :workdir
8
+ def enter()
9
+ yield
10
+ end
11
+
12
+ def process()
13
+ @workdir ||= Dir.pwd
14
+ Dir.glob(File.join(@workdir,'**/*')).select{|f|File.file?(f)}.each do |f|
15
+ begin
16
+ FileUtils.mv f, @workdir
17
+ rescue => e
18
+ MagicShelf.logger.warn(e.message)
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,86 @@
1
+ require 'magicshelf/exception'
2
+ require 'gepub'
3
+ require 'shellwords'
4
+ require 'naturally'
5
+
6
+ module MagicShelf
7
+ class EpubGeneratorError < Error; end
8
+
9
+ # create a epub file with the file under the current directory
10
+ class EpubGenerator
11
+ attr_accessor :book_type, :title, :outputfile, :language, :identifier_url, :creator, :creator_en
12
+
13
+ def enter()
14
+ MagicShelf.logger.debug('enter EpubGenerator')
15
+ # check parameters
16
+ raise MagicShelf::EpubGeneratorError.new("@title is not set") if @title == nil
17
+ raise MagicShelf::EpubGeneratorError.new("@outputfile is not set") if @outputfile == nil
18
+ # default parameters
19
+ @book_type ||= 'comic'
20
+ @language ||= 'ja'
21
+ @identifier_url ||= 'http:/example.jp/bookid_in_url'
22
+
23
+ yield
24
+ end
25
+
26
+ def process()
27
+ epubname = @outputfile
28
+
29
+ book = GEPUB::Book.new
30
+ book.unique_identifier @identifier_url
31
+ book.identifier @identifier_url
32
+ book.language = @language
33
+
34
+
35
+ book.add_title(@title, nil, GEPUB::TITLE_TYPE::MAIN) { |title|
36
+ title.lang = @language
37
+ title.file_as = Shellwords.escape(@title)
38
+ title.display_seq = 1
39
+ }
40
+ if @creator
41
+ book.add_creator(@creator) { |creator|
42
+ creator.display_seq = 1
43
+ creator.add_alternates('en' => @creator_en) if @creator_en
44
+ }
45
+ end
46
+
47
+ if @book_type == "comic"
48
+ book.page_progression_direction = 'rtl'
49
+ metadata = book.instance_eval{@package}.instance_eval{@metadata}
50
+ metacomic = metadata.add_metadata('meta', '')
51
+ metacomic['name'] = 'book-type'
52
+ metacomic['content'] = 'comic'
53
+ metafixedlayout = metadata.add_metadata('meta', '')
54
+ metafixedlayout['name'] = 'fixed-layout'
55
+ metafixedlayout['content'] = 'true'
56
+ elsif @book_type == "novelimage"
57
+ book.page_progression_direction = 'rtl'
58
+ metadata = book.instance_eval{@package}.instance_eval{@metadata}
59
+ metafixedlayout = metadata.add_metadata('meta', '')
60
+ metafixedlayout['name'] = 'fixed-layout'
61
+ metafixedlayout['content'] = 'true'
62
+ elsif @book_type == "novel"
63
+ book.page_progression_direction = 'rtl'
64
+ #nothing to do
65
+ elsif @book_type == "ltr"
66
+ book.page_progression_direction = 'ltr'
67
+ end
68
+
69
+ # within ordered block, add_item will be added to spine.
70
+ book.ordered {
71
+ # to add nav file:
72
+ #navpath = 'nav.xhtml'
73
+ #book.add_item(navpath).add_content(File.open(navpath)).add_property('nav')
74
+ Naturally.sort(Dir.glob('**/*.{jpg,png}')).each_with_index do |filepath,index|
75
+ MagicShelf.logger.info("append image #{filepath}, index: #{index}")
76
+ item = book.add_item(filepath)
77
+ item.add_content(File.open(filepath)).toc_text(index.to_s)
78
+ item.cover_image if index == 0
79
+ end
80
+ }
81
+
82
+ book.generate_epub(epubname)
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,4 @@
1
+
2
+ module MagicShelf
3
+ class Error < StandardError; end
4
+ end
@@ -0,0 +1,105 @@
1
+ require 'magicshelf/exception'
2
+
3
+ module MagicShelf
4
+ class ExecutionPipe
5
+ class Procedure
6
+ attr_accessor :command_obj, :proc, :proc_withblock, :map_params, :params
7
+ def initialize
8
+ @command_obj = nil
9
+ @proc = nil
10
+ @proc_withblock = nil
11
+ @params = nil
12
+ @map_params = nil #from previous procedure
13
+ end
14
+ end
15
+
16
+ def initialize
17
+ @procedures = []
18
+ end
19
+
20
+ def pipe(command_obj, **map_params, &block)
21
+ procedure = Procedure.new()
22
+ block.call(command_obj)
23
+ procedure.command_obj = command_obj
24
+ procedure.map_params = map_params
25
+ @procedures.push(procedure)
26
+ self
27
+ end
28
+
29
+ def enter(**map_params, &block)
30
+ procedure = Procedure.new()
31
+ procedure.proc_withblock = block
32
+ procedure.map_params = map_params
33
+ @procedures.push(procedure)
34
+ self
35
+ end
36
+
37
+ def process(**map_params, &block)
38
+ procedure = Procedure.new()
39
+ procedure.proc = block
40
+ procedure.map_params = map_params
41
+ @procedures.push(procedure)
42
+ self
43
+ end
44
+
45
+ def execute
46
+ self.execute_(0)
47
+ end
48
+
49
+ def execute_(i_proc)
50
+ procedure = @procedures[i_proc]
51
+ previous_procedure = @procedures[i_proc-1]
52
+
53
+ if procedure.nil?
54
+ return
55
+ end
56
+
57
+ if not procedure.command_obj.nil?
58
+ if not previous_procedure.nil?
59
+ if not previous_procedure.command_obj.nil?
60
+ procedure.map_params.each_pair do |param_key_recv, param_keys|
61
+ param_keys.each do |param_key|
62
+ procedure.command_obj.instance_variable_set('@'+param_key.to_s, previous_procedure.command_obj.instance_variable_get('@'+param_key_recv.to_s))
63
+ end
64
+ end
65
+ else
66
+ procedure.map_params.each_pair do |param_key_recv, param_keys|
67
+ param_keys.each do |param_key|
68
+ procedure.command_obj.instance_variable_set('@'+param_key.to_s, previous_procedure.params[param_key_recv])
69
+ end
70
+ end
71
+ end
72
+ end
73
+ procedure.command_obj.enter {
74
+ procedure.command_obj.process
75
+ self.execute_(i_proc+1)
76
+ }
77
+ elsif not procedure.proc.nil? or not procedure.proc_withblock.nil?
78
+
79
+ procedure.params = {}
80
+ if not previous_procedure.command_obj.nil?
81
+ procedure.map_params.each_pair do |param_key_recv, param_keys|
82
+ param_keys.each do |param_key|
83
+ procedure.params[param_key] = previous_procedure.command_obj.instance_variable_get('@'+param_key_recv.to_s)
84
+ end
85
+ end
86
+ else
87
+ procedure.map_params.each_pair do |param_key_recv, param_keys|
88
+ param_keys.each do |param_key|
89
+ procedure.params[param_key] = previous_procedure.params[param_key_recv]
90
+ end
91
+ end
92
+ end
93
+
94
+ if not procedure.proc.nil?
95
+ procedure.proc.call(procedure.params)
96
+ self.execute_(i_proc+1)
97
+ else
98
+ procedure.proc_withblock.call(procedure.params) do
99
+ self.execute_(i_proc+1)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end