{"id":32479680,"url":"https://github.com/svera/coreander","last_synced_at":"2026-05-01T10:02:08.516Z","repository":{"id":38315858,"uuid":"326230742","full_name":"svera/coreander","owner":"svera","description":"Your books. Anytime. Anywhere.","archived":false,"fork":false,"pushed_at":"2025-10-23T14:17:02.000Z","size":74099,"stargazers_count":34,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-23T14:42:50.022Z","etag":null,"topics":["calibre","ebooks","epub","go","golang","index","kepub","kindle","kobo","pdf","reader","search","server"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/svera.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-01-02T17:05:18.000Z","updated_at":"2025-10-23T14:17:04.000Z","dependencies_parsed_at":"2023-11-27T18:26:27.677Z","dependency_job_id":"7ee0c175-30d3-41e1-8dad-d05677defcf1","html_url":"https://github.com/svera/coreander","commit_stats":null,"previous_names":[],"tags_count":115,"template":false,"template_full_name":null,"purl":"pkg:github/svera/coreander","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svera%2Fcoreander","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svera%2Fcoreander/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svera%2Fcoreander/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svera%2Fcoreander/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/svera","download_url":"https://codeload.github.com/svera/coreander/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svera%2Fcoreander/sbom","scorecard":{"id":640487,"data":{"date":"2025-08-11","repo":{"name":"github.com/svera/coreander","commit":"95c2527329e26abae9ce189d8cc8e905c8e0c69d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.4,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":10,"reason":"21 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/27 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/go.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: COPYING:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: COPYING:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v4.10.5 not signed: https://api.github.com/repos/svera/coreander/releases/238990135","Warn: release artifact v4.10.4 not signed: https://api.github.com/repos/svera/coreander/releases/238644372","Warn: release artifact v4.10.3 not signed: https://api.github.com/repos/svera/coreander/releases/233434498","Warn: release artifact v4.10.2 not signed: https://api.github.com/repos/svera/coreander/releases/231998233","Warn: release artifact v4.10.1 not signed: https://api.github.com/repos/svera/coreander/releases/231997379","Warn: release artifact v4.10.5 does not have provenance: https://api.github.com/repos/svera/coreander/releases/238990135","Warn: release artifact v4.10.4 does not have provenance: https://api.github.com/repos/svera/coreander/releases/238644372","Warn: release artifact v4.10.3 does not have provenance: https://api.github.com/repos/svera/coreander/releases/233434498","Warn: release artifact v4.10.2 does not have provenance: https://api.github.com/repos/svera/coreander/releases/231998233","Warn: release artifact v4.10.1 does not have provenance: https://api.github.com/repos/svera/coreander/releases/231997379"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/svera/coreander/go.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/svera/coreander/go.yml/main?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T10:33:50.691Z","repository_id":38315858,"created_at":"2025-08-21T10:33:50.692Z","updated_at":"2025-08-21T10:33:50.692Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281196987,"owners_count":26459680,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-26T02:00:06.575Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["calibre","ebooks","epub","go","golang","index","kepub","kindle","kobo","pdf","reader","search","server"],"created_at":"2025-10-27T01:01:35.153Z","updated_at":"2026-05-01T10:02:08.494Z","avatar_url":"https://github.com/svera.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"A personal documents server, Coreander indexes the documents (EPUBs and PDFs with no DRM) that it finds in the passed folder, and provides a web interface to search and access them.\n\n[![Follow us on Bluesky](https://img.shields.io/badge/Bluesky-0285FF?logo=bluesky\u0026logoColor=fff\u0026label=Follow%20me%20on\u0026color=0285FF)](https://bsky.app/profile/coreanderapp.bsky.social)\n\n![Coreander home](assets/home.png)\n*Coreander home*\n\n## Features\n* Single binary with all dependencies included. Just download and run, no installation required.\n* Search by author, title and even document series ([Calibre's](https://calibre-ebook.com/) `series` meta supported)\n* Improved search for documents with metadata in English, Spanish, French, Italian, German and Portuguese, including genre and singular/plural forms of words in the results among others.\n* Estimated reading time calculation.\n* Responsive web interface available in English, Spanish, German, Russian and French, more languages can be easily added.\n* New documents added or removed to/from the library folder are automatically indexed (Linux only).\n* [Send to email supported](#send-to-email).\n* Read indexed epubs and PDFs from Coreander's interface thanks to [foliate-js](https://github.com/johnfactotum/foliate-js).\n* Reading progress sync between multiple devices, E.G.: start reading in your cellphone and resume reading from your tablet where you left off.\n* Restrictable access only to registered users.\n* Upload documents through the web interface.\n* Download as kepub (epub for Kobo devices) converted on the fly thanks to [Kepubify](https://github.com/pgaskin/kepubify).\n* Gather information about authors from [Wikidata](https://wikidata.org).\n\n## Installation\n\nBinaries for Windows 64 bit, Linux 32 and 64 bits for both X86 and ARM (Raspberry Pi and other SBCs) and Macs with Intel and Apple processors are available at [releases](https://github.com/svera/coreander/releases/latest). Just download and unzip the one appropriate for your system.\n\n### Building from source\nCoreander's only requirement is the Go compiler. The minimum required Go version is stated in the [`go.mod`](go.mod) file.\n\nWhen cloning Coreander's repository, use Git's `--recurse-submodules` flag to also retrieve `foliate-js` contents as well, which is required for the reader component:\n\n```\ngit clone git@github.com:svera/coreander.git --recurse-submodules\n```\n\nThere are two possibilities for building Coreander from source:\n* If you have [Mage](https://magefile.org) installed in your system, just type `mage install` from the source code folder.\n* Otherwise, a simple `go build` or `go install` will do, although no version information will be added to the executable.\n\n## How to use\nAlthough it can be executed as any desktop app, Coreander is designed to be run as a service managed by [systemd](https://systemd.io) or any other service manager. For example, in Raspberry Pi OS, just create a file called `/etc/systemd/system/coreander.service` with the following contents:\n\n```\n[Unit]\nDescription=coreander\n\n[Service]\nRestart=always\nRestartSec=5s\nWorkingDirectory=\u003cabsolute path to directory which contains coreander binary\u003e\nExecStart=\u003cabsolute path to coreander binary\u003e\nPermissionsStartOnly=true\nSyslogIdentifier=coreander\nUser=\u003cuser which will execute this service\u003e\nEnvironment=\"LIB_PATH=\u003cabsolute path to the library\u003e\"\n\n```\n\nthen, start the service with `service coreander start`. You can manage it with the usual commands `start`, `stop` and `status`. Refer to your service manager documentation for more information.\n\nCoreander requires the absolute path where your documents are located as an argument. You can also pass it through the `LIB_PATH` environment variable.\n\nOn first run, Coreander will index the documents in your library, creating a database with those entries located at `$home/coreander/index`. Depending on your system's performance and the size of your library this may take a while. Also, the database can grow fairly big, so make sure you have enough free space on disk.\n\nEvery time it is run, the application scans the library folder only for documents not yet indexed and adds them to the index. You can force to index all documents whether they were previously indexed or not by passing the `--force-indexing` flag or setting the environment variable `FORCE_INDEXING` to `true`.\n\nEven if the application is still indexing entries, you can access its web interface right away. Just open a web browser and go to `localhost:3000` (replace `localhost` with the hostname / IP address of the machine where the server is running if you want to access it from another system). It is possible to change the listening port just executing the application with the `-p` or `--port` flags, or the `PORT` environment variable (e. g. `coreander -p 4000` or `PORT=4000 coreander`)\n\n### Setting up an Internet-facing server\n\nIf you plan to set up Coreander in a public Internet server such as a VPS, using [Caddy](https://caddyserver.com/) as a reverse proxy is strongly recommended, as it is dead simple to set up and comes with several niceties such as HTTPS out of the box through [Let's Encrypt](https://letsencrypt.org/).\n\nFor example, if you have Coreander listening to port 3000 in your server and a domain called `coreander.example.com` that points to the IP address of your server, you can just tell Caddy to route requests to `coreander.example.com` to Coreander by putting this in Caddy's `Caddyfile`:\n\n```\ncoreander.example.com {\n    reverse_proxy :3000\n}\n```\n\nRefer to [Caddy documentation](https://caddyserver.com/docs) for more information.\n\n### Email\n\nSome features rely on having an SMTP email service set up, and won't be available otherwise:\n\n* Send document to email.\n* Recover user password.\n* Invite new users.\n\nYou can use any email service that allows sending emails using the SMTP protocol, like [GMX](https://gmx.com/mail). The following flags or environment variables need to be defined:\n\n|Flag|Environment variable|Description|\n|----|--------------------|-----------|\n|`--smtp-server`  | `SMTP_SERVER`  | The URL of the SMTP server to be used, for example `mail.gmx.com`.|\n|`--smtp-port`    | `SMTP_PORT`    | The port number used by the email service, defaults to `587`. |\n|`--smtp-user`    | `SMTP_USER`    | The user name. |\n|`--smtp-password`| `SMTP_PASSWORD`| User's password. |\n\n#### Send to email\n\nCoreander can send documents through email. This way, you can take advantage of services such as [Amazon's send to email](https://www.amazon.com/gp/help/customer/display.html?nodeId=G7NECT4B4ZWHQ8WV), which also automatically converts EPUB and other formats to the target device.\n\n### User management and access restriction\n\nCoreander distinguishes between two kinds of users: regular users and administrator users, with the latter being the only ones with the ability to create new users and upload and delete documents.\n\nBy default, Coreander allows unrestricted access to its contents, except management areas which require an administrator user. To allow access only to registered users in the whole application, pass the `-a` or `--require-auth` flags, or the `REQUIRE_AUTH=true` environment variable.\n\nOn first run, Coreander creates an admin user with the following credentials:\n\n* Email: `admin@example.com`\n* Password: `admin`\n\n\u003e [!CAUTION]\n\u003e For security reasons, it is strongly encouraged to add a new admin and remove the default one as soon as possible.\n\n### Settings\n\nRun `coreander -h` or `coreander --help` to see help.\n\nIn case both a flag and its equivalent environment variable are passed, flag takes precedence.\n\n|Flag|Environment variable|Description|\n|----|--------------------|-----------|\n|                                     |`LIB_PATH`                | Absolute path to the folder containing the documents.\n|`-p` or `--port`                     |`PORT`                    | Port number in which the webserver listens for requests. Defaults to 3000.\n|`-b` or `--batch-size`               |`BATCH_SIZE`              | Number of documents persisted by the indexer in one write operation. Defaults to 100.\n|`--cover-max-width`                  |`COVER_MAX_WIDTH`         | Maximum horizontal size for documents cover thumbnails in pixels. Defaults to 600.\n|`--author-image-max-width`           |`AUTHOR_IMAGE_MAX_WIDTH`  | Maximum horizontal size for author images in pixels. Set to 0 to keep original image size. Defaults to 600.\n|`--illustrated-min-amount`           |`ILLUSTRATED_MIN_AMOUNT`  | Minimum number of illustrations (excluding cover) for a document to be considered illustrated. Only raster images in PNG, GIF and JPEG formats are taken into account. Defaults to 2.\n|`--illustrated-min-size`             |`ILLUSTRATED_MIN_SIZE`    | Minimum size in megapixels for an image to count as an illustration. Defaults to 0.25.\n|`-c` or `--cache-dir`                |`CACHE_DIR`                       | Directory where to store cache files. Defaults to `~/.coreander/cache`.\n|`--client-static-cache-ttl`          |`CLIENT_STATIC_CACHE_TTL`         | Client-side cache duration for static assets (CSS, JS, images) in seconds. Defaults to 31536000 (1 year).\n|`--client-dynamic-image-cache-ttl`   |`CLIENT_DYNAMIC_IMAGE_CACHE_TTL`  | Client-side cache duration for dynamically generated images (covers, author images) in seconds. Defaults to 86400 (24 hours).\n|`--server-static-cache-ttl`          |`SERVER_STATIC_CACHE_TTL`         | Server-side cache duration for static assets (CSS, JS, images) in seconds. Defaults to 31536000 (1 year).\n|`--server-dynamic-image-cache-ttl`   |`SERVER_DYNAMIC_IMAGE_CACHE_TTL`  | Server-side cache duration for dynamically generated images (covers, author images) in seconds. Defaults to 86400 (24 hours).\n|`-f` or `--force-indexing`           |`FORCE_INDEXING`          | Whether to force indexing already indexed documents or not. Defaults to false.\n|`--smtp-server`                      |`SMTP_SERVER`             | Address of the send mail server.\n|`--smtp-port`                        |`SMTP_PORT`               | Port number of the send mail server. Defaults to 587.\n|`--smtp-user`                        |`SMTP_USER`               | User to authenticate against the SMTP server.\n|`--smtp-password`                    |`SMTP_PASSWORD`           | User's password to authenticate against the SMTP server.\n|`-s` or `--jwt-secret`               |`JWT_SECRET`              | String to use to sign JWTs.\n|`-a` or `--require-auth`             |`REQUIRE_AUTH`            | Require authentication to access the application if true. Defaults to false.\n|`--min-password-length`              |`MIN_PASSWORD_LENGTH`     | Minimum length acceptable for passwords. Defaults to 5.\n|`--words-per-minute`                 |`WORDS_PER_MINUTE`        | Defines a default words per minute reading speed that will be used for not logged-in users. Defaults to 250.\n|`--session-timeout`                  |`SESSION_TIMEOUT`         | Specifies the maximum time a user session may last, in hours. Floating-point values are allowed. Defaults to 24 hours.\n|`--recovery-timeout`                 |`RECOVERY_TIMEOUT`        | Specifies the maximum time a user recovery link may last, in hours. Floating-point values are allowed. Defaults to 2 hours.\n|`--invitation-timeout`               |`INVITATION_TIMEOUT`      | Specifies the maximum time a user invitation link may last, in hours. Floating-point values are allowed. Defaults to 72 hours.\n|`--invite-email-list-max-length`     |`INVITE_EMAIL_LIST_MAX_LENGTH` | Maximum length in bytes of the comma-separated invitation email list field (admin invite form). Defaults to 2000.\n|`--invite-max-recipients`           |`INVITE_MAX_RECIPIENTS`   | Maximum number of distinct email addresses allowed in one invitation submit. Defaults to 50.\n|`-u` or `--upload-document-max-size` |`UPLOAD_DOCUMENT_MAX_SIZE`| Maximum document size allowed to be uploaded to the library, in megabytes. Set this to 0 to unlimit upload size. Defaults to 20 megabytes.\n|`-m` or `--share-comment-max-size`   |`SHARE_COMMENT_MAX_SIZE`  | Maximum length for share comments in characters. Defaults to 280.\n|`--share-max-recipients`             |`SHARE_MAX_RECIPIENTS`    | Maximum number of recipients allowed when sharing a document. Defaults to 10.\n|`-d` or `--fqdn`                     |`FQDN`                    | Domain name of the server. If Coreander is listening to a non-standard HTTP / HTTPS port, include it using a colon (e. g. example.com:3000). Defaults to `localhost`.\n|`-v` or `--version`                  |                          | Show version number.\n\n\n## Screenshots\n\n![Search results in dark mode](assets/search-results.png)\n*Search results in dark mode*\n\n![Document detail](assets/doc-detail.png)\n*Document detail*\n\n![Reading interface](assets/reading.png)\n*Reading interface*\n\n![Reading interface](assets/reading-mobile.png)\n*Reading interface in mobile device*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvera%2Fcoreander","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsvera%2Fcoreander","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvera%2Fcoreander/lists"}