class Kamishibai::Database

Attributes

bookcodes[R]
files[R]

Public Class Methods

new( db_filepath, bookmarks_filepath ) click to toggle source
# File lib/kamishibai/database.rb, line 17
def initialize( db_filepath, bookmarks_filepath )
        @db_savepath = db_filepath
        @db_dirty = true

        if File.exists?( @db_savepath )
                load_database
        else
                # create fresh database
                @db = {}
                # indexes
                @bookcodes = []
                @files = {}
                @inodes = {}
        end


        # bookmark section
        @bookmarks_savepath = bookmarks_filepath
        @bookmarks_dirty = false

        if File.exists?( @bookmarks_savepath )
                load_bookmarks
        end
end

Public Instance Methods

add_book(filepath) click to toggle source
# File lib/kamishibai/database.rb, line 42
def add_book(filepath)
        bookcode = gen_bookcode
        o = Kamishibai::Book.new(bookcode, filepath)

        if o.pages
                @db[ bookcode ] = o
                @bookcodes << bookcode
                if File.exists?( filepath )
                        @files[ File.basename( filepath ).delete('ÿ') ] = bookcode # utf8-mac puts ÿ in filename, need to remove first for cross os support
                        @inodes[ o.inode ] = bookcode
                end

                @db_dirty = true

                puts "added book. #{bookcode} #{filepath}" if $debug
                bookcode
        end
end
add_books(srcs, recursive = true) click to toggle source

add book from directories, if existing booka are found, modify instead

# File lib/kamishibai/database.rb, line 115
def add_books(srcs, recursive = true)
        srcs = cleanup_srcs( srcs )
        
        for src in srcs
                # stopped using find module, because it wrack encoding havoc in windows (gives ??? character in unicode filename)
                # now using Dir.glob instead
                if recursive
                        search = '/**/*.cbz'
                else
                        search = '/*.cbz'
                end

                Dir.glob(File.expand_path(src).escape_glob + search).delete_if { |f|
                        restricted_dir?(f)
                }.each { |f|
                        bc = get_bookcode_byfilename( f )
                        o  = get_book( bc )
                        fs = File.stat(f)
                        o2 = get_book( @inodes[ fs.ino ] )

                        if o
                                # book exists in db
                                puts "book match(m1):     #{File.basename(f)} == #{File.basename(o.fullpath)}" if $debug == 2
                                
                                # update data with new path
                                o.fullpath = f

                                # update index, as bookcodes is the list that keeps actual books that exists
                                @bookcodes << o.bookcode
                        elsif o2 and fs.size == o2.size
                                # found existing book using inode and size, can detected changed filename in same filesystem
                                puts "book match(m2):     #{File.basename(f)} == #{File.basename(o2.fullpath)}" if $debug == 2

                                o2.fullpath = f
                                o2.title    = Kamishibai::CBZFilename.title( f )
                                o2.author   = Kamishibai::CBZFilename.author( f )

                                # update indexes
                                @bookcodes << o2.bookcode
                                @files[ File.basename(f) ] = o2.bookcode
                        else
                                # book don't exist in db
                                self.add_book(f)
                        end
                }
        end

        puts "Found #{@bookcodes.length} books" if $debug
end
books() click to toggle source
# File lib/kamishibai/database.rb, line 92
def books
        @db
end
get_book(bookcode) click to toggle source
# File lib/kamishibai/database.rb, line 65
def get_book(bookcode)
        @db[ bookcode ]
end
get_book_byfilename(filename) click to toggle source
# File lib/kamishibai/database.rb, line 74
def get_book_byfilename(filename)
        filename = File.basename( filename )
        bookcode = @files[ filename ]
        get_book( bookcode )
end
get_bookcode_byfilename(filename) click to toggle source
# File lib/kamishibai/database.rb, line 69
def get_bookcode_byfilename(filename)
        filename = File.basename( filename )
        @files[ filename ]
end
get_bookmark(bookcode) click to toggle source
# File lib/kamishibai/database.rb, line 88
def get_bookmark(bookcode)
        get_book( bookcode ).page
end
has_bookcode?(bookcode) click to toggle source
# File lib/kamishibai/database.rb, line 61
def has_bookcode?(bookcode)
        @bookcodes.include?( bookcode )
end
refresh_bookcodes() click to toggle source

refresh @bookcodes, making sure all the books have valid path

# File lib/kamishibai/database.rb, line 97
def refresh_bookcodes
        bookcodes = []
        for bookcode, book in @db
                if File.exists?( book.fullpath )
                        book.fullpath_valid = true
                        bookcodes << bookcode
                else
                        book.fullpath_valid = false
                end
        end

        @bookcodes = bookcodes
end
save() click to toggle source

save database

# File lib/kamishibai/database.rb, line 166
def save
        if @db_dirty
                # create dir if dir doesn't exist
                if ! FileTest.exists?( File.dirname( @db_savepath ) )
                        FileUtils.mkdir_p( File.dirname( @db_savepath ) )
                end
                
                db = {}
                @db.each { |bookcode, book|
                        next unless book.pages # skip invalid book that contain no page/images

                        db[ bookcode ] = {
                                :title    => book.title,
                                :author   => book.author,
                                :fullpath => book.fullpath,
                                :size     => book.size,
                                :inode    => book.inode,
                                :mtime    => book.mtime,
                                :itime    => book.itime,
                                :rtime    => book.rtime,
                                :page     => book.page,
                                :pages    => book.pages
                        }
                }
                File.binwrite( @db_savepath, JSON.pretty_generate( db ) )
                
                @db_dirty = false

                puts "db saved (#{db.length} books) #{Time.now}" if $debug
        end
end
save_bookmarks() click to toggle source

save bookmarks

# File lib/kamishibai/database.rb, line 199
def save_bookmarks
        if @bookmarks_dirty
                # save bookmarks
                if ! FileTest.exists?( File.dirname( @bookmarks_savepath ) )
                        FileUtils.mkdir_p( File.dirname( @bookmarks_savepath ) )
                end

                bookmarks = {}
                @db.each { |bookcode, book|
                        page = book.page  # last read page
                        time = book.rtime # last read time

                        if page and page > 1
                                dat = {
                                        :p => page,
                                        :r => time
                                }
                                bookmarks[bookcode] = dat
                        end
                }
                
                File.binwrite( @bookmarks_savepath, JSON.pretty_generate( bookmarks ) )
                
                @bookmarks_dirty = false

                puts "bookmarks saved (#{bookmarks.length} bookmarks) #{Time.now}" if $debug
        end
end
set_bookmark(bookcode, page) click to toggle source
# File lib/kamishibai/database.rb, line 80
def set_bookmark(bookcode, page)
        puts "set_bookmark #{bookcode} #{page}" if $debug
        @bookmarks_dirty = true
        o = get_book(bookcode)
        o.page  = page
        o.rtime = Time.now.to_i
end

Private Instance Methods

cleanup_srcs( dir_lists ) click to toggle source

clean up and sanity check on directory lists

# File lib/kamishibai/database.rb, line 233
def cleanup_srcs( dir_lists )
        srcs = dir_lists.collect { |src|
                pn = Pathname.new( src )
                fp = pn.expand_path.cleanpath.to_s
        
                if FileTest.directory?( fp ) and not restricted_dir?( fp )
                        fp
                end
        }
        srcs.compact!
        p srcs if $debug
        
        srcs
end
gen_bookcode() click to toggle source

generate a unique bookcode, lookup bookcode existance by using db

# File lib/kamishibai/database.rb, line 249
def gen_bookcode
        while true
                word = GenChar(3)
                break unless @bookcodes.include?(word) # find next available word
        end
        return word
end
load_bookmarks() click to toggle source

load bookmarks

# File lib/kamishibai/database.rb, line 317
def load_bookmarks
        bookmarks = {}

        str = File.binread( @bookmarks_savepath )

        JSON.parse( str ).each { |bookcode, h|
                if get_book( bookcode )
                        get_book( bookcode ).page  = h['p']
                        get_book( bookcode ).rtime = h['r']
                end
        }
end
load_database() click to toggle source

load database

# File lib/kamishibai/database.rb, line 258
def load_database
        @db = {}
        
        # indexes for db, help to speed up database search
        @files = {} # hash of files linked to bookcodes, format: files[basename] = bookcode
        @bookcodes = [] # list of bookcodes, format: [ bookcode_a, bookcode_b, bookcode_c, ... ]
        @inodes = {} # list of file inodes, format: inodes[inode] = bookcode

        str = File.binread( @db_savepath )

        JSON.parse( str ).each { |bookcode, h|
                o = Kamishibai::Book.new
                o.bookcode = bookcode
                o.title    = h['title']
                o.author   = h['author']
                o.fullpath = h['fullpath']
                o.size     = h['size']
                o.mtime    = h['mtime']
                o.inode    = h['inode']
                o.itime    = h['itime'] # imported time
                o.rtime    = h['rtime'] # last read time
                o.page     = h['page']  # last read page
                o.pages    = h['pages']

                unless o.pages
                        puts "Book contain no images!!! skipping... #{bookcode} #{o.fullpath}"
                        next
                end

                @db[ o.bookcode ] = o
                # update indexes
                @files[ File.basename( o.fullpath ).delete('ÿ') ] = o.bookcode # utf8-mac puts ÿ in filename, need to remove first for cross os support
                @inodes[ o.inode ] = o.bookcode

                # if book exists
                if File.exists?( o.fullpath )
                        fs = File.stat( o.fullpath )
                        o.fullpath_valid = true

                        # repopulate data if doesn't exist
                        o.title    = Kamishibai::CBZFilename.title( o.fullpath )  unless o.title
                        o.author   = Kamishibai::CBZFilename.author( o.fullpath ) unless o.author
                        o.size     = fs.size                                      unless o.size
                        o.mtime    = fs.mtime                                     unless o.mtime
                        o.inode    = fs.ino                                       unless o.inode

                        # update indexes
                        @bookcodes << o.bookcode
                        @inodes[ o.inode ] = o.bookcode
                end
        }
        
        # db format:   @db[ bookcode ] = Book obj
        # + indexes    @files = { basename_a => bookcode_a, basename_b => bookcode_b, ... }
        #              @bookcodes = [ bookcode_a, bookcode_b, ... ]
        #              @inodes = { inode_a => bookcode_a, inode_b => bookcode_b, ... }
end