Git Product home page Git Product logo

bookwyrm's Introduction

πŸ“œ Bookwyrm

This project has been archived: due to the moving-target nature of ebook sources and a lost interest in the utility I will no longer maintain the code base as it is presented here. Consider this repository abondonware.


bookwyrm(1) is a ncurses utility for downloading ebooks and other publications that are available on the Internet. Given some input data via command line options, bookwyrm will search for any matches and present them to you in a text user interface. Items are found by the help of plugins that parses sources of these items. Currently, the following sources are queried:

  • Library Genesis

Selected items can be viewed for details, printing all bookwyrm knows about the item. When it is implemented, additional details will be fetched from some external database (unless the source itself holds enough data to satisfy), such as the Open Library or WorldCat.

Both bookwyrm and plugins may print logs during run-time. These can be viewed by pressing TAB. All unread logs are printed to stderr upon program termination.

For example, one might run bookwyrm as follows:

$ bookwyrm --title "discrete mathematics" --extension pdf

asciicast

Dependencies

Aside from a C++17-compliant compiler and CMake 3.4.3, bookwyrm depends on a few libraries:

  • fmtlib, for a lot of string formatting;
  • ncurses, for the TUI;
  • pybind11, for Python plugins, and
  • fuzzywuzzy, for fuzzily matching found items with what's wanted.
  • Python 3, for Python plugin support.
  • libcurl, for downloading items over HTTP.

All libraries that are not in bold font are non-essential and may be subject to removal later in development. Some dependencies are submodules in lib/; external dependencies are ncurses, Python 3 and libcurl.

Furthermore, the available Python plugins depend on some external packages. These are listed in etc/requirements.txt.

If you're using Nix(OS), all dependencies are declared in etc/default.nix. A suitable development environment can be generated by sourcing etc/shell.nix with nix-shell(1).

Building instructions

$ git clone https://github.com/tmplt/bookwyrm.git && cd bookwyrm
$ git submodule update --init --recursive
$ mkdir build && cd build
$ cmake .. && make

bookwyrm's People

Contributors

joshcho avatar tmplt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

bookwyrm's Issues

uncaught std::runtime_error some times when exiting tui

Sometimes when terminating, an std::runtime_error is thrown from the a Python thread. This is because of commit ac409a9 where the threads are all detached - instead of having to wait on them.

Pybind11's Gitter chat confirmed that this is a known problem with multithreading.

I'll see if I can find a way to catch this exception.

Implement downloading of items

For now, to keep things simple, this will be done with cURL.

After selecting all the items and pressing some new yet-to-be-bound key, we'll kill another screen and download the items. While this is happening, seeker threads will terminate. Some adjustments will be needed to not block the program until all seekers are dead.

For displaying downloads, I'll mimick how lgogdownloader does it (omitting the progress bar for now).

Clean up the TUI

The TUI code is messy and in a dire need of a review. Now that we're using ncurses, WINDOWs should be used to modularize the screens, hopefully increasing drawing performance while we're at it.

Flush unseen log entries to stdout

So in a case where the user doesn't open the log, and an error occurs, they are still notified about it when the program terminates.

This can be done by simply logger_->flush_buffer_to_screen() in screen_butler::meta_action() just before return toggle_log().

This will require the screen butler to know about the logger as well, something a lot of other classes already know about. Perhaps we should make a simple butler base class that holds a shared pointer to the logger?

item: streamline exacts_t construction

Instead of specifying a second argument for the file extension, we instead want scripts to:

exacts = bw.exacts_t({'year': year, 'pages': pages, 'extension': extension})

in differance to the current:

exacts = bw.exacts_t({'year': year, 'pages': pages}, extension)

screens/log: always scroll the whole screen when detached.

When scrolling in a detached state, we will always on a move() unless we're in the beginning of the entries. To fix this with the current implementation, we would change at_first_entry in move() to be true when we're on the first entry + how many entries fit on the screen.

Invalid treatment of arguments using single -

$ bookwyrm -atest
error: missing value for -atest; see --help

Expected:

$ bookwyrm -atest
error: unrecognized option -atest; see --help

I think bookwyrm only reads the first character on single-hyphen arguments, so -atest would thus be treated as the -a option. A check to see if there are more characters past the first would suffice.

Throw custom exception instead of a GeneratorExit

A custom exception is much more documenting, and that would remove the odds of some not-manually-thrown GeneratorExit escaping but not being logged as an error.

According to pybind11's Gitter chat, using register_exception and throwing it in called Python code might make it suitable as an argument to pybind11::error_already_set::matches (or something else called match).

Immidiately Interrupt source threads when terminating

When quitting the menu, bookwyrm should terminate. Currently, as we rely on std::thread there is no way to interrupt the source scripts, so we must wait until they're done. Obviously, we want to interrupt the threads instead.

Topical reading:

Segmentation fault on NixOS

Within a properly defined environment, bookwyrm compiles without issues but segfaults upon runtime when Python modules are loaded. Aside from investigating this issue, a default.nix should be written.

Immediately interrupt worker threads when terminating

When we terminate bookwyrm, we want the worker thread to immediately join. Currently we poll inside the source scripts whether we should return. This is slow. We'll want to create some interruptable_thread::interrupt() that throws some internal exception and stops everything instantly.

I'd like to keep boiler-plate a minimum in the actual scripts. We could check for interrupt in script_butler::add_item(), but we don't know how long it will take to get there, since the script needs to fetch the item in question first.

Perhaps we could spawn a nested thread that just waits until it's time to throw an interrupt exception. But that means we have two threads for each source. Ugly.

Or perhaps there is some hack we can exploit in pybind11. But if that is the case, the script butler will turn ugly if and when we decide to add support for other languages.

For now we'll just have to sprinkle checks in appropriate places in the source scripts.

screens/log: log entries outside the screen are considered read.

E.g. if there are so many logs that they fill up more than the window height, the entries "above" and outside the screen will still be considered read when opening the log. Similarly, if we're detached, any logs "below" and outside the screen will also be considered read.

Add a HACKING file

So that eventual (if any) contributors don't have to breadth-first search the code to understand how everything is interconnected.

Segfault when feeding the bookwyrm more than 99 items

It's defenitely something wrong with the reallocation of the array holding att ITEM*s. If less than 99 items (but more than 49) items are fed, we instead segfault when the item_array is destructed.

I blame ncurses for me having to write my own C.

Strip spdlog dependency

Other than the horrible state of logger.{cpp,hpp}, we use but a smidge of spdlog's abilities, so we should remove this dependency and roll our own.

Use `.` as default download path

Currently the program does not assume a default path if none is given. It makes sense to have it default to the current directory or . as that would be the msot common use case.

Fix the TUI logger

The logger broke with commit aa3805e; unread logs are no longer dumped to std{out,err} and the user is no longer notified about new logs. This will hopefully be fixed now when the TUI code will be modulerized.

Python `seekers` require external libraries not noted in the README.md

The Python script libgen.py requires the following external libraries to work (for me at least):

  • furl
  • requests
  • isbnlib

These are not listed in the README.md and should probably just be automagically downloaded if possible when building the project, otherwise they should be stated as requirements for certain 'seekers' to work.

Segmentation fault on NixOS

Within a properly defined environment, bookwyrm compiles without issues but segfaults upon runtime when Python modules are loaded. Aside from investigating this issue, a default.nix should be written.

python: rewrite implementation to use class

Instead of calling a function in the found modules, we should instead call something in a class. The finally create book may be a few functions down; it would be much handier if one could just feed the books there instead of having to return them through a few levels.

Let the screen butler manage termbox presentation

Currently, screen::base::refresh() is only called in screen::multiselect_menu. What we want to do is to make all screens work independently from each other, so we'll want to move screen updating to the screen butler, logically. The problem is that then the screen is only refreshed when screen_butler::update_screens() is called, e.g., only from scripts.

Should we manage this with some observer pattern? Are there better ways?

Write script logs to a log screen

Instead of waiting until program termination to dump all logs, we could instead have a screen for this. Better yet if we can have this in a screen tab of some sort. When in the main view, we could signal to the user that a new log has been made by making the log tab bold or something.

We should be able to write a sink for spdlog for this.

Support more compilers/platforms

With 049df29, abi::__forced_unwind is now caught to "safely" terminate the Python threads. This exception is an implementation detail only available in GCC.

As of this commit, bookwyrm is not portable and may only work on Linux.

Confirmed platforms and compilers:

  • Linux
    • GCC
    • Clang
  • FreeBSD
    • GCC
    • Clang
  • OpenBSD
    • GCC
    • Clang

Menu implementation

Next up in line of stuff to implement is the menu. The get it off the ground we'll just make it list the contents of a vector<item>, with each line being an item and what data it holds.

When it comes to receiving the items, the menu class will have some .append() member function that we bind to python as feed(). The menu class itself we'll bind as bookwyrm. When the instance is then passed onto Python as find(wanted, bookwyrm), we can then write bookwyrm.feed((nonexacts, exacts)) for each item the script constructs.

For the actual (graphical) implementation, I'll see if I can find something modern-C++-ish. Above just the menu, I'll want to implement submenus (alike how when you open an email in mutt) and some status bar (which scripts are still running? Total items found, script errors, etc).

Candidates are:

  • AnsiGL
  • ncurses (netbsd-curses)?

bundle termbox into lib/

Termbox is currently an external dependency, a count of which I want to be 0 before first release.

Termbox build with waf which required Python, so that isn't a problem (we require it to build bookwyrm in the first place). Either we submit some CMakeLists.txts upstream, or we do the simple task of executing waf from our own.

Properly configure CMake build files

We currently compile tests and whatnot in libraries in lib/, which is rather useless. CMake also prints some warnings when configuring files for fmt/. That should be fixed/suppressed.

Let screen::base handle all padding.

It might be a good idea to rewrite base::change_cell() to add/subtract the padding values accordingly. Not being worried about these values in the real screens would be nice. Investigate if this is possible.

undefined symbol in Python bindings

For some odd reason, command_line::parser::get_many(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&&) const is depended upon. Remove this dependency.

Replace termbox with ncurses

Ncurses was initially the plan when I started working on the TUI. Since most other programs used it, I saw no reason not to use it. Unfortunately I stumbled upon some issues getting the most simple of functionality to work, so instead I wrote everything from scratch with termbox. While this allowed me to make the TUI just the way I wanted it, it has without questions given me some headaches too β€” in the form of self-inflicted bugs that is.

Thinking back, I believe the issue I had related to pointer invalidation on vector resize, a solution to which I figured out not very long ago. So perhaps I should give it another chance?

Perhaps a good idea is to just get v1.0.0 out and then focus on improving the machinery?

Wrap long option descriptions in --help

Instead of letting the terminal emulator handle the wrapping, we should make long descriptions wrap with the same indention. Makes --help a bit easier to read.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.