liber

package module
v0.0.0-...-5b1548f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 5, 2023 License: MIT Imports: 53 Imported by: 0

README

liber

Software to manage an ebook collection. It supports EPUB, MOBI and PDF formats, and it will fetch metadata and cover images on external sources (currently Google Books). It offers powerful search functionality over a HTTP interface.

Another useful feature is the ability to synchronize remote collections (currently in one direction only), making it possible for a group of people to manage a centralized ebook repository.

Installation

Binaries are available in the form of Debian packages. They will take care of installing all the necessary dependencies. If this isn't an option, you can build the software from source.

Debian packages

Add this line to your sources.list:

deb [signed-by=/usr/share/keyrings/incal-archive-keyring.gpg] http://debian.incal.net/debian liber/

Then make sure the GPG key used to sign the repository is installed, update the package sources, and install the liber package:

$ gpg --keyserver hkp://keys.openpgp.org/ --recv 06F524BFE221CD1F65DF57F5C0EAC2F9CE9ED9B0
$ gpg --export --export-options export-minimal 06F524BFE221CD1F65DF57F5C0EAC2F9CE9ED9B0 | sudo tee /usr/share/keyrings/incal-archive-keyring.gpg > /dev/null
$ sudo apt-get update
$ sudo apt-get install liber
Build from source

To compile liber from source, you will need a working Go environment (note that the Go version in Debian wheezy is too old, you should install a more recent version from the Go website).

Building and installing the code is the simply a matter of running

$ go get -d git.autistici.org/ale/liber
$ go install git.autistici.org/ale/liber/...

This will place the resulting liber executable in $GOPATH/bin.

Usage

liber will store its database in a local directory, ~/.liber by default. Use the --db-dir option if you'd like to change this.

If you want to manage a local collection, the assumption is that you are storing all your ebooks in a single place (below a single directory, possibly organized into further subdirectories). You can control this with the (mandatory) option --book-dir.

Indexing a local ebook collection

To index a local ebook collection, run the following command:

$ liber --book-dir=/path/to/ebooks update

The tool will attempt to identify books on Google Books. It is possible that more than one match is found, in which case liber will open a dialog box to ask you interactively to pick the right match.

You can run liber update as many times as you like (for example whenever you add an ebook to your collection), it will automatically detect new files and files that have been removed.

Integration with Calibre

If you use Calibre to mantain your ebook collection, you can index it with liber by simply pointing its --book-dir option at the Calibre library directory. liber will read Calibre metadata files and cover images, and it will not perform remote searches for book metadata.

Searching

You can search the index from the command line, for example:

$ liber search "Das Kapital"

This will print a list of documents that match the query. For the full query syntax, see the Bleve documentation.

Synchronizing with a remote server

To upload the contents of the local database (including the file contents themselves) to a remote liber server, run the following command:

$ liber sync http://remote.server.address/
Running the HTTP interface

The HTTP interface can be started with:

$ liber --book-dir=/path/to/ebooks server

This will start an HTTP server on port 3000, listening on all interfaces. The HTTP server needs some templates and static content which the Debian package installs in /usr/share/liber/htdocs.

The HTTP server will store uploaded files into the directory specified by --book-dir. You should use the same value that you passed to liber update.

Documentation

Index

Constants

View Source
const (
	SourceDB = 1 << iota
	SourceFS
)

Variables

View Source
var (
	BookBucket     = []byte("ebook")
	FileBucket     = []byte("file")
	BookFileBucket = []byte("ebook_file")
)

Functions

func GetFileType

func GetFileType(path string) (string, error)

func NewHttpServer

func NewHttpServer(db *Database, storage, cache *RWFileStorage, addr string) *http.Server

func NewRemoteServer

func NewRemoteServer(remoteURL string) *remoteServer

Types

type Book

type Book struct {
	Id        BookId
	CoverPath string
	Metadata  *Metadata
}

func (*Book) String

func (b *Book) String() string

type BookId

type BookId uint64

func NewID

func NewID() BookId

func ParseBinaryID

func ParseBinaryID(b []byte) BookId

func ParseID

func ParseID(s string) BookId

func (BookId) Key

func (id BookId) Key() []byte

func (BookId) String

func (id BookId) String() string

type Database

type Database struct {
	// contains filtered or unexported fields
}

func NewDb

func NewDb(path string) (*Database, error)

func (*Database) Close

func (db *Database) Close()

func (*Database) Delete

func (db *Database) Delete(bucket, key []byte) error

func (*Database) DeleteBook

func (db *Database) DeleteBook(bookid BookId) error

func (*Database) DeleteFile

func (db *Database) DeleteFile(path string) error

func (*Database) Dump

func (db *Database) Dump(w io.Writer) error

Dump the contents of the database to a Writer.

func (*Database) Find

func (db *Database) Find(uniqueIds []string) (*Book, error)

Find a book matching the given metadata, if possible.

func (*Database) Get

func (db *Database) Get(bucket, key []byte, obj interface{}) error

func (*Database) GetBook

func (db *Database) GetBook(bookid BookId) (*Book, error)

func (*Database) GetBookFiles

func (db *Database) GetBookFiles(bookid BookId) ([]*File, error)

func (*Database) GetFile

func (db *Database) GetFile(path string) (*File, error)

func (*Database) ListBooks

func (db *Database) ListBooks(w io.Writer, matchFuncs ...func(book *Book) bool) error

ListBooks writes IDs of books that match any of a series of functions to an io.Writer.

func (*Database) Put

func (db *Database) Put(bucket, key []byte, obj interface{}) error

func (*Database) PutBook

func (db *Database) PutBook(b *Book) error

func (*Database) PutFile

func (db *Database) PutFile(f *File) error

func (*Database) RawPut

func (db *Database) RawPut(key, value []byte) error

func (*Database) RefineFunc

func (db *Database) RefineFunc(dir string, chooser MetadataChooserFunc) func(*Book) error

func (*Database) Reindex

func (db *Database) Reindex() error

Reindex the entire database. This is an administrative operation, to be performed after an incompatible index schema change. It will delete the existing index and re-create it from scratch.

func (*Database) Restore

func (db *Database) Restore(r io.Reader) error

Restore a backup to the current database (assuming it is empty).

func (*Database) Scan

func (db *Database) Scan(bucket []byte) *DatabaseIterator

Scan an entire bucket.

func (*Database) Search

func (db *Database) Search(queryStr string, offset, limit int) (*SearchResult, error)

Search the database with a query string.

func (*Database) Suggest

func (db *Database) Suggest(term string) (*SearchResult, error)

Autocomplete runs a fuzzy search for a term.

func (*Database) Sync

func (db *Database) Sync(storage *FileStorage, remote SyncClient) error

Sync the local database with a remote one. This is a one-way synchronization: files missing on the remote side will be uploaded to it.

func (*Database) Update

func (db *Database) Update(dir string, chooser MetadataChooserFunc)

func (*Database) WithBookIDs

func (db *Database) WithBookIDs(r io.Reader, f func(book *Book) error) error

WithBookIDs calls a function on books whose IDs are read from the specified io.Reader.

type DatabaseIterator

type DatabaseIterator struct {
	// contains filtered or unexported fields
}

func (*DatabaseIterator) Close

func (i *DatabaseIterator) Close() error

func (*DatabaseIterator) Id

func (i *DatabaseIterator) Id() BookId

func (*DatabaseIterator) Next

func (i *DatabaseIterator) Next() bool

func (*DatabaseIterator) RawKey

func (i *DatabaseIterator) RawKey() []byte

func (*DatabaseIterator) RawValue

func (i *DatabaseIterator) RawValue() []byte

func (*DatabaseIterator) Value

func (i *DatabaseIterator) Value(obj interface{}) error

type File

type File struct {
	Path     string
	FileType string
	Mtime    time.Time
	Size     int64
	Error    bool
	Id       BookId
}

func (*File) HasChanged

func (f *File) HasChanged(info os.FileInfo) bool

type FileStorage

type FileStorage struct {
	Root string
}

FileStorage exposes a read-only filesystem hierarchy as a root for relative paths (so that you can move archives around while the database is still valid). Calls will still accept absolute paths for backwards compatibility.

func NewFileStorage

func NewFileStorage(root string) *FileStorage

func (*FileStorage) Abs

func (s *FileStorage) Abs(path string) string

Return the absolute path of a file, given its relative path.

func (*FileStorage) Create

func (s *FileStorage) Create(path string) (*os.File, error)

Create a new file for the given key. Directories containing the output file will be automatically created.

func (*FileStorage) Exists

func (s *FileStorage) Exists(path string) bool

Exists returns true if the specified file exists.

func (*FileStorage) Open

func (s *FileStorage) Open(path string) (*os.File, error)

Open a file.

func (*FileStorage) Rel

func (s *FileStorage) Rel(abspath string) (string, error)

Return the relative path of a file with respect to the storage root.

func (*FileStorage) Rename

func (s *FileStorage) Rename(oldpath, newpath string) error

Rename oldpath to newpath.

func (*FileStorage) Walk

func (s *FileStorage) Walk(w *util.Walker, fn filepath.WalkFunc)

type Metadata

type Metadata struct {
	Title       string
	Date        string
	Description string
	ISBN        []string
	Creator     []string
	Language    []string
	Publisher   []string
	Format      []string
	Keywords    []string
	Sources     []MetadataSource
}

func (*Metadata) Complete

func (m *Metadata) Complete() bool

Complete returns true if we're satisfied with the quality of the information about this book. If this returns true, remote checks will be skipped.

func (*Metadata) Equals

func (m *Metadata) Equals(other *Metadata) bool

Equals returns true if we think the two Metadata objects refer to the same book.

func (*Metadata) Merge

func (m *Metadata) Merge(other *Metadata)

Merge with a more authoritative metadata source. Fields that are set in 'other' will take precedence over the ones in the receiver.

func (*Metadata) String

func (m *Metadata) String() string

func (*Metadata) Sufficient

func (m *Metadata) Sufficient() bool

Sufficient returns true if the object contains enough information. If this check does not pass, the book won't be added to the database.

func (*Metadata) Uniques

func (m *Metadata) Uniques() []string

Uniques returns the list of possible unique tokens for this book.

type MetadataChooserFunc

type MetadataChooserFunc func(string, []*Metadata) *Metadata

type MetadataProvider

type MetadataProvider interface {
	Name() string
	Lookup(*FileStorage, string, string) (*Metadata, error)
	GetBookCover(*FileStorage, string) (string, error)
}

A metadata provider generates metadata from the local filesystem.

type MetadataRefiner

type MetadataRefiner interface {
	Name() string
	Lookup(*Metadata) ([]*Metadata, error)
	GetBookCover(*Metadata) ([]byte, error)
}

A metadata refiner improves on existing metadata and may provide more than one result to choose from. It usually involves talking to a remote service.

type MetadataSource

type MetadataSource struct {
	Name string
	ID   string
}

type RWFileStorage

type RWFileStorage struct {
	*FileStorage
	Nesting int
}

RWFileStorage adds a read-write API on top of a FileStorage, based on unique keys and directory sharding.

func NewRWFileStorage

func NewRWFileStorage(root string, nesting int) *RWFileStorage

func (*RWFileStorage) Path

func (s *RWFileStorage) Path(key string) string

Path of the file corresponding to the given key, relative to the root directory.

type SearchResult

type SearchResult struct {
	Results    []*Book
	NumResults int
}

type SyncClient

type SyncClient interface {
	DiffRequest(*diffRequest) (*diffResponse, error)
	SendBook(*Book, *FileStorage, []*File) error
}

Directories

Path Synopsis
cmd
third_party

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL