Compare commits

..
1966 Commits
Author SHA1 Message Date
Ozzie Isaacs e0e0422010 Upates for new release 2022-01-24 19:18:40 +01:00
Ozzie Isaacs 01ab75a158 Updated requirements for gdrive and gmail
Updated teststatus
2022-01-24 18:47:34 +01:00
Ozzie Isaacs d9c10b830a Added variable to allow loading cover from localhost 2022-01-24 18:47:34 +01:00
Ozzie Isaacs 35f6f4c727 Deleted book formats remove book from synced to kobo table
updated teststatus
2022-01-24 18:47:34 +01:00
Ozzie Isaacs 3b216bfa07 Kobo sync token is now also created if accessed from localhost(fixes #1990)
Create kobo sync token button is now "unclicked" after closing dialog
Additional localhost route is catched
If book format is deleted this also deletes the book synced to kobo status
2022-01-24 18:47:34 +01:00
Ozzieisaacs e8e2f789e5 Fix #2287 (books can't be added to shelf from search) 2022-01-24 12:37:15 +01:00
Ozzie Isaacs bbef41290f Fix delete book format wasn't working 2022-01-22 14:01:32 +01:00
Ozzie Isaacs 81b85445d8 Added missing unique marker on comments table (#2278) 2022-01-22 11:51:34 +01:00
Ozzie Isaacs 35209ede67 Update cover extraction with comicapi for webp files (fixes #2280) 2022-01-22 10:31:18 +01:00
Ozzie Isaacs 0c0313f375 Prevent creating a public shelf without permission 2022-01-18 17:55:10 +01:00
Ozzie Isaacs 6bf0753978 Prevent wrong use of safe statement 2022-01-18 17:39:54 +01:00
Ozzie Isaacs a02f621f08 Added id for testability 2022-01-17 18:38:37 +01:00
Ozzie Isaacs de1bc3f9af Fix #2265 (add book to shelf on popup for book details)
Updated testresults
2022-01-17 17:46:57 +01:00
Ozzie Isaacs 01090169a7 Version bump
update dependencies in setup.cfg
Update security bug list
2022-01-16 12:55:15 +01:00
Ozzie Isaacs b564a97cdf Update version
Update testresult
2022-01-16 12:06:02 +01:00
Ozzie Isaacs a118fffc99 Added missing chardet (used by requests in older versions) 2022-01-15 19:58:13 +01:00
Ozzie Isaacs 5b59aab81a Udpate requirements and config.cfg 2022-01-15 18:34:21 +01:00
Ozzie Isaacs 7d3d0c661e Merge remote-tracking branch 'fr/master' 2022-01-15 09:19:55 +01:00
Ozzie Isaacs f6f20ebc77 Update teststatus 2022-01-15 09:18:51 +01:00
Thomas 58cb54c76f small typo 2022-01-13 22:47:47 +01:00
Thomas 3fc326fa48 Update French translation 2022-01-13 22:45:16 +01:00
Ozzie Isaacs a50aff67a2 Merge remote-tracking branch 'korean/master' 2022-01-10 17:38:09 +01:00
Ozzie Isaacs 3c1f5fd37f Update Test results 2022-01-10 17:35:18 +01:00
byword77 8ae066c387 Add files via upload 2022-01-10 11:59:16 +09:00
Ozzie Isaacs 0feb62c142 Improvements delete user (delete also depending entries in tables)
Fixes kobo sync with sync only selected shelfs
2022-01-09 17:43:20 +01:00
Ozzie Isaacs 96b1e8960b Bugfix send to kindle with multiple formats 2022-01-09 12:55:38 +01:00
Ozzie Isaacs df67079573 Fixes for kobosync with multiple users (#2230) 2022-01-08 19:03:59 +01:00
Ozzie Isaacs e3dbf7a88d Bugfixes load metadata
Improvements for testing load metadata
2022-01-07 12:40:03 +01:00
byword77 8dd0585919 Add files via upload 2022-01-07 11:07:19 +09:00
Ozzie Isaacs c830a5936e Added dse to supported languages 2022-01-06 14:10:06 +01:00
Ozzie Isaacs 405f3c181f Added korean locale 2022-01-06 14:04:49 +01:00
Ozzie Isaacs 6d839d5cc7 Bugfixes from testrun 2022-01-04 21:12:59 +01:00
Ozzieisaacs bbadfa2251 bugfixes load metadata 2022-01-04 21:11:52 +01:00
Ozzieisaacs 7b8b2f93a0 Merge remote-tracking branch 'scholary/master' 2021-12-30 14:55:39 +01:00
Ozzieisaacs c1030dfd13 Update dependency scholary 2021-12-30 14:45:31 +01:00
Ozzieisaacs a90177afa0 Better version output in about page (exe file, pyPi, git commit string removed if empty) 2021-12-30 14:45:31 +01:00
Ozzieisaacs c095ee3c14 Fix #2243 (whitespaces are trimmed also for normal search) 2021-12-30 14:45:31 +01:00
Ozzieisaacs ae1f515446 Bugfix uncheck all ekements in books list and user list
Improved testability for books list
2021-12-30 14:45:31 +01:00
Ozzieisaacs 0548fbb685 Bugfix post commands without updater 2021-12-30 14:45:31 +01:00
Ozzieisaacs f22e4d996c Proxy kobo library sync at the end of local sync 2021-12-30 14:45:31 +01:00
Ozzieisaacs 3e0d8763c3 Prevent 2 public shelfs with same names due to changing public property 2021-12-30 14:45:31 +01:00
Ozzieisaacs 47f5e2ffb4 Remove python2 urllib imports
Fix for "javascript:" script links in identifier
2021-12-30 14:45:31 +01:00
Ozzieisaacs f39dc100b4 Migrated some routes to POST
- shelf massadd
- resetpassword
- delete shelf
- send to kindle
2021-12-30 14:45:31 +01:00
Ozzieisaacs 573c9f9fb4 Improved logging (right stacklevel on mail exceptions)
Updated jsonschema requirements
2021-12-30 14:45:31 +01:00
Ozzieisaacs 785726deee Migrated some routes to POST
- delete shelf, import ldap users
- delete_kobo token, kobo force full sync
- shutdown, reconnect, shutdown
2021-12-30 14:45:30 +01:00
cbartondock 4edd1914b4 Fixed google scholar issues 2021-12-23 23:16:41 -05:00
cbartondock 222929e741 Fixed extra s in scholar metadata 2021-12-23 18:05:20 -05:00
cbartondock 70b67077cc Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-12-23 15:58:45 -05:00
Ozzie Isaacs ec73558b03 Bugfix advanced search for language
Update results from testrun
2021-12-23 19:18:09 +01:00
Ozzieisaacs bdedec90dd Catch more Gdrive errors (#2233) 2021-12-23 11:13:08 +01:00
Ozzieisaacs d45085215f Update Translation 2021-12-22 19:08:15 +01:00
Ozzie Isaacs b85627da5c Fix for adding/deleting visibility restrictions on custom columns/tags 2021-12-19 11:29:54 +01:00
Ozzie Isaacs 592288cb22 Fix inverted "convert to English characters" setting 2021-12-19 08:04:13 +01:00
Ozzie Isaacs 2e3a3ee460 Update dependencies in setup.cfg 2021-12-19 07:28:46 +01:00
Ozzie Isaacs b7927a0df1 Bugfix handling of stacktrace from calibre 2021-12-18 18:38:17 +01:00
Ozzie Isaacs 021298374e Improved debug output for task added
Improved handling of calibre output on windows
2021-12-18 17:31:33 +01:00
Ozzie Isaacs 92f65882b2 Added log4j statement 2021-12-16 06:21:16 +01:00
Ozzie Isaacs f0399d04b7 Merge remote-tracking branch 'bookmark_csrf/master' 2021-12-14 17:59:32 +01:00
Ozzie Isaacs 9b57fa25de Merge remote-tracking branch 'zh/master' 2021-12-14 17:52:12 +01:00
Ozzie Isaacs afbe77de3d Merge remote-tracking branch 'border/patch-1' 2021-12-14 17:50:02 +01:00
xlivevil d26d357151 Merge branch 'master' into master 2021-12-15 00:17:26 +08:00
Laurin Neff 4db9691cfc Remove white border in full-screen cover preview 2021-12-13 19:36:21 +01:00
Ozzie Isaacs 45c433caab Added "hmj" to supported languages. Fix for "bit" language support (Fix #2217) 2021-12-13 18:26:47 +01:00
Ozzie Isaacs 25422b3411 Fix for #2195 Sync token only updated after complete library sync and sync token content is discarded on first sync to enable real forced full sync 2021-12-12 20:31:45 +01:00
xlivevil a184f4e71a Merge branch 'master' into master 2021-12-08 22:58:30 +08:00
cbartondock 4569188008 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-12-07 08:37:27 -05:00
Ozzie Isaacs 9d9acb058d Add button to force full kobo sync 2021-12-06 21:02:06 +01:00
Ozzie Isaacs 7d67168a4a Update test result 2021-12-06 20:27:25 +01:00
cbartondock 09751d8b87 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-12-05 19:00:15 -05:00
Ozzie Isaacs fd5ab0ef53 Bugfix handle archive bit 2021-12-05 18:01:56 +01:00
Ozzie Isaacs 3bf173d958 Added response for kobo-benefits route and kobo-gettest route 2021-12-04 15:44:41 +01:00
cbartondock 98d630d453 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-12-04 09:21:01 -05:00
Ozzie Isaacs eb2e816bfd Switch encoding in kobo metadata to ensure utf-8 characters to show up properly (finally) 2021-12-04 14:58:28 +01:00
Ozzie Isaacs bd01e840ca Delete books in shelfs, downloaded books, kobo sync status, etc on database change (fixes #620) 2021-12-04 11:50:25 +01:00
Ozzie Isaacs 91a21ababe Allow download of archived books 2021-12-04 11:16:33 +01:00
Ozzie Isaacs f4096b136e Added chinese sign language (csl) to supported languages 2021-12-04 10:57:53 +01:00
cbartondock 7598dfe952 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-12-01 16:17:14 -05:00
Ozzie Isaacs 5ed3b1cf53 On master: Order of language count in /language (fixes #2200) 2021-12-01 21:38:43 +01:00
Ozzie Isaacs 7640ac1b3b Books are removed from synced books upon archiving (from kobo or calibre-web side)
unicode texts (title, author) are showing up right on kobo reader
Added some missing kobo routes (prevents 404 response)
Added a lot of debug output on kobo sync requests
2021-12-01 20:29:51 +01:00
Jonathan Fenske 66874f8163 Update read.html
include the CSR token input
2021-11-30 22:25:45 -06:00
Jonathan Fenske 3f91313303 Update epub.js
send the CSRF token when adding bookmarks
2021-11-30 22:24:34 -06:00
xlivevil 8438b2a07b Update Simplified Chinese translation 2021-12-01 12:14:57 +08:00
xlivevil 67e3721530 fix(tinymce Simplified Chinese locale):rename zh_CN to zh_Hans_CN 2021-12-01 11:28:03 +08:00
cbartondock 2252d661c0 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-11-27 14:06:36 -05:00
Ozzie Isaacs 87e526642c Bugfix edit series_index
Bugfix invalid languages
2021-11-27 18:23:06 +01:00
Ozzie Isaacs 7f9da94a18 Tie visibility of upload buttons to upload right only 2021-11-27 17:43:51 +01:00
Ozzie Isaacs ec7c2db971 Added package variable for generating "exe" file with pyinstaller 2021-11-27 12:26:35 +01:00
cbartondock fcd2b68359 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-11-23 13:59:43 -05:00
Ozzie Isaacs a1d372630d Added missing language bit (fixes #2187)
Added handling of wrong .jpg cover file content
Guest sorting options are now stored in the session
Updated teststatus
2021-11-23 19:32:48 +01:00
cbartondock fc859afb92 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-11-22 09:59:36 -05:00
Ozzie Isaacs 2e0d0a2429 Update requirements 2021-11-21 18:31:35 +01:00
Ozzie Isaacs d084a06e63 Bugfix create shelf for users not allowed to create public shelfs 2021-11-21 16:21:27 +01:00
Ozzie Isaacs e880238cb9 Add missing filter for current user in KoboSyncedBooks queries 2021-11-21 16:19:32 +01:00
cbartondock f58c5bee1c Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-11-21 09:23:52 -05:00
Ozzie Isaacs cbb9edac19 Bugfix search in books list
Fix renaming upper to lowercase letters
Update test results
2021-11-21 13:23:34 +01:00
Ozzie Isaacs 1b8bd27b3c Added cve number for csrf bug 2021-11-21 12:35:53 +01:00
Ozzieisaacs 6cb713d62c Added filtering of languages
Bugfix show all allowed languages in user settings in case restrictions currently apply
2021-11-21 10:21:45 +01:00
Ozzieisaacs 642af2f973 Added support for missing locale Enu 2021-11-21 09:28:03 +01:00
Ozzieisaacs 9273843062 Removed double declared functions 2021-11-21 09:14:16 +01:00
cbartondock 2989586c6d Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-11-20 18:54:38 -05:00
Ozzie Isaacs 5ede079401 Handling of invalid cover files on upload 2021-11-20 13:45:41 +01:00
Ozzie Isaacs 7ad419dc8c Fix upload of cover and book formats containing html characters 2021-11-20 13:40:23 +01:00
Ozzie Isaacs bcdc976414 Added missing check for creating public shelfs 2021-11-20 13:00:54 +01:00
Ozzie Isaacs 6aad9378b8 Fix visiblility upload right on enabled upload feature 2021-11-20 12:44:34 +01:00
Ozzie Isaacs 6f5390ead5 Changed error message in case of trying to delete a shelf unauthorized
Removed outcommented text
2021-11-20 12:17:03 +01:00
Ozzie Isaacs d624b67e93 Fix #2174 (default sorting order now is timestamp again) 2021-11-20 11:57:51 +01:00
Ozzie Isaacs 01cc97c1b2 Added langugae support for Cholón (fixes #2183) 2021-11-20 11:32:51 +01:00
cbartondock 7c016265d2 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-11-10 08:59:23 -05:00
Ozzie Isaacs 974549b1af Removed technosoft2000 docker container 2021-11-08 20:36:41 +04:00
Ozzieisaacs add502d236 Fix opds search and opds list of read books 2021-11-07 20:18:33 +04:00
cbartondock 294c594cbb Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-11-06 14:19:37 -04:00
Ozzieisaacs 60aa016734 Handling of missing required dependency during dependency check 2021-11-06 21:17:48 +04:00
Ozzieisaacs 27e8fbd248 Show dependencies in about section from automatic dependency check
Bugfix and refactored dependency check
Added output of googledrive dependencies as fallback option
2021-11-06 20:58:51 +04:00
cbartondock d856c4d78e Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-11-04 14:00:51 -04:00
Ozzieisaacs 25b09a532f Fixed missing handle_error in convert calibre task (database readonly case) 2021-11-04 21:23:02 +04:00
Ozzieisaacs c1f4ca36b6 Current sorting order visible in all sidebar selectors, and search results
Sorting "hot" books only ascending and descending according to download numbers
Downloaded books sorting according to authors name working
2021-11-04 20:51:48 +04:00
Ozzieisaacs 58379159fb Fix shown cover in series grid view (#979) 2021-11-04 17:32:31 +04:00
Ozzieisaacs 17470b3b56 Check versions of dependencies at startup and generate logfile output if not fitting (#2157) 2021-11-04 16:38:55 +04:00
Ozzieisaacs 42cc13d1e2 Mark which functions are selected on list pages 2021-11-03 21:07:16 +04:00
Ozzieisaacs ecc5cb167e Upload setting in user template only visible if upload enabled
Delete book setting only visible if edit book setting is ticked
2021-11-03 20:32:17 +04:00
Ozzieisaacs d72210c6ae Exclude upload rights visibility if upload is not activated 2021-11-03 19:05:24 +04:00
Ozzieisaacs 61deda1076 Updated security history 2021-11-03 18:29:30 +04:00
Ozzieisaacs 1e0ff0f9c2 Fix #2045 ("fetch metadata" update appends to the existing tags instead or replacing them) 2021-11-03 18:16:15 +04:00
cbartondock 00bf1f5ec9 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-11-02 14:25:46 -04:00
Ozzieisaacs 2b6f5b1565 Fix csrf check in list pages 2021-11-02 21:32:29 +04:00
cbartondock e5abc5f281 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-11-02 13:09:59 -04:00
Ozzieisaacs 95371d0d7f Fix shelf grid ordering for inverted order at page load
Ordering buttons now visible on medium size screens
2021-11-02 20:27:50 +04:00
Ozzieisaacs c7df8a1a34 Fix missing csrf token in series grid view 2021-11-02 18:57:28 +04:00
Ozzieisaacs b414d91964 Fix for #2162 (Epub viewer isn't displaying images) 2021-11-02 18:55:56 +04:00
cbartondock 82164fc8e7 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-11-01 10:00:18 -04:00
Ozzieisaacs a5415e00d5 Fix grid to list in series view
Fix sort asc, desc in author and series list
2021-11-01 13:11:49 +01:00
cbartondock 434029270b Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-31 20:42:21 -04:00
Ozzie Isaacs b3b85bf692 Fix position read mark in standard theme 2021-10-31 16:33:35 +01:00
Ozzie Isaacs a36c6da3ae Fix position read mark in standard theme 2021-10-31 16:30:51 +01:00
Ozzie Isaacs 9e72c3b40d Fix position read mark in standard theme 2021-10-31 16:18:27 +01:00
cbartondock a0cebfbfb1 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-31 08:29:27 -04:00
Ozzie Isaacs 64e833f5d6 Updated readme
Version Bump
2021-10-31 12:00:20 +01:00
Ozzie Isaacs 4da64ceb23 Update to version 0.6.14 2021-10-31 11:31:53 +01:00
cbartondock 99ec99b539 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-30 13:28:56 -04:00
Ozzie Isaacs 3077b854d7 Merge remote-tracking branch 'de/patch-1' 2021-10-30 16:37:53 +02:00
Ozzie Isaacs a8317d900b Bugfix for edit custom ratings in list edit mode
Bugfix for deleting custom enum in list edit mode
2021-10-30 15:50:17 +02:00
KN4CK3R 668bf3a15e Fix typo in german translation 2021-10-30 13:41:33 +02:00
Ozzie Isaacs 481e52b503 Removed technosoft2000 docker reference 2021-10-30 09:56:39 +02:00
Ozzie Isaacs bbb65ec804 Merge remote-tracking branch 'trustedhost/master' 2021-10-30 09:40:04 +02:00
Ozzie Isaacs 4b7b646692 Merge remote-tracking branch 'autocap/patch-1' 2021-10-30 09:36:48 +02:00
Ozzie Isaacs 65cfb1ccbc Merge remote-tracking branch 'it/patch-26' 2021-10-30 09:34:56 +02:00
Ozzie Isaacs 9e9d7b3642 Merge remote-tracking branch 'mime/fix_mime_type_not_executable' 2021-10-30 09:33:37 +02:00
Ozzie Isaacs 1294672809 Bugfix search with excluded shelfs 2021-10-30 07:31:12 +02:00
i7-8700 857584a929 fix "MIME type ('text/plain') is not executable" on windows 2021-10-27 11:33:56 +08:00
cbartondock 75c68d92ec Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-26 09:58:36 -04:00
ElQuimm b4772d9b66 Update italian version of message.po 2021-10-26 11:10:46 +02:00
Ozzie Isaacs 382cd9458f Fix for #2126 (iOS covers are not displayed during infinite scroll on standard theme) 2021-10-25 20:03:48 +02:00
Ozzie Isaacs be7ac7e163 Update infinite scrolling javascript 2021-10-25 19:17:10 +02:00
cbartondock 27f71d910b Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-24 18:59:10 -04:00
Bernat 9f260128cf Prevent virtual keyboard login auto capitalization
Stops virtual keyboards, such as the ones on mobile devices, to default to uppercase for the first letter of the login user input field.
2021-10-24 20:14:47 +02:00
Ozzie Isaacs cdd38350fe Updated tinymce editor, enabled raw html edit 2021-10-24 17:14:50 +02:00
Ozzie Isaacs aefed40a2f Fix for missing message "flask-wtf not installed" 2021-10-23 18:44:29 +02:00
cbartondock 88278672d8 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-23 09:45:11 -04:00
Ozzie Isaacs bd0071354c Remove include subdomwains from hsts protection (#2114) 2021-10-23 09:45:04 +02:00
cbartondock c6bf62a6eb The recent changes to content security policy broke custom theming. I fixed it by adding a trusted hosts field to Server Configuration 2021-10-22 15:35:10 -04:00
cbartondock 95544ef885 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-22 09:20:11 -04:00
Ozzie Isaacs fe4db16a7e html editor in books list 2021-10-21 20:13:04 +02:00
cbartondock 9b127a9f97 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-21 11:09:47 -04:00
Ozzie Isaacs 9e4aeac16d Remove WTF_CSRF_SSL_STRICT workaround for missing referrers 2021-10-17 16:00:02 +02:00
cbartondock 9653308300 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-17 09:50:11 -04:00
Ozzie Isaacs 7671a1d5c8 Fix errormessage after update 2021-10-17 15:36:19 +02:00
Ozzie Isaacs bd6b5ac873 Fix load covers in metadata load screen 2021-10-17 15:06:37 +02:00
Ozzie Isaacs 00dc60da79 Added translation for traditional chinese 2021-10-17 15:02:16 +02:00
Ozzie Isaacs 708861bcd5 Enabed edit of custom texts (including categories) in books list 2021-10-17 14:29:13 +02:00
Ozzie Isaacs 24a2c0a5cf Enable edit of custom text in book table 2021-10-17 14:11:52 +02:00
Ozzie Isaacs 1e1d3a7c81 Enable edit of enum column in books list 2021-10-17 14:05:18 +02:00
Ozzie Isaacs 2ebddcfee3 Lowered version of needed flask-wtf dependency (#2137) 2021-10-17 10:05:50 +02:00
Ozzie Isaacs 4517f5b0cb Fix #2138 (Icons not showing in caliblur theme) 2021-10-17 10:00:04 +02:00
Ozzie Isaacs 666015e867 Fix datepicker localized month names
Removed redundant parenthesis in kobo.py response
2021-10-16 20:53:44 +02:00
Ozzie Isaacs 9d5e9b28ae Enabled editing of "number" custom_columns in books list 2021-10-16 20:46:16 +02:00
Ozzie Isaacs 6f1e78b9a3 Bugfix book list with language restriction or archived books 2021-10-16 20:43:22 +02:00
cbartondock d5aa345da6 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-16 14:40:56 -04:00
Ozzie Isaacs e060c62742 Fix exit on missing flask-wtf 2021-10-16 18:42:26 +02:00
cbartondock 5695268d1b Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-16 09:27:39 -04:00
Ozzie Isaacs cea10d3945 Merge remote-tracking branch 'comic_sort/comic_reader_sort' 2021-10-16 11:50:46 +02:00
Ozzie Isaacs fe21d15194 Merge remote-tracking branch 'cn/fix/bootstrap-table-locale'
# Conflicts:
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-af.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ar.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-bg.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ca.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-cs.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-da.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-de.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-el.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-es.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-et.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-eu.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-fa.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-fi.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-fr.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-he.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-hr.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-hu.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-id.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-it.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ja.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ka.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ko.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-nl.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-pl.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-pt_BR.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ro.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ru.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-sk.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-sv.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-tr.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-uk.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-zh_Hans_CN.min.js
2021-10-16 11:48:00 +02:00
Ozzie Isaacs 369d5059c3 Merge remote-tracking branch 'br/patch-2' 2021-10-16 11:43:27 +02:00
Ozzie Isaacs 56a9c62421 Merge remote-tracking branch 'cn/chinese/master'
# Conflicts:
#	cps/templates/search_form.html
2021-10-16 11:41:09 +02:00
Ozzie Isaacs 50d703e2d8 Chunked reading status on kobo sync
Bugfix loading text on shelf delete
Bugfix sort books list according to selection without selection
2021-10-16 11:28:35 +02:00
cbartondock 5aefc893de Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-15 15:58:11 -04:00
Ozzie Isaacs 6e5d9d7657 Bugfix toggle readstatus in modal dialog 2021-10-15 19:26:20 +02:00
Ozzie Isaacs 1be7dfcdca Merge remote-tracking branch 'origin/master' 2021-10-15 18:57:18 +02:00
Ozzie Isaacs e58eb8dac1 Show checkbox from boolean custom columns on details page with caliblur theme 2021-10-15 18:57:00 +02:00
Ozzie Isaacs d02eb842c7 Update testresults 2021-10-12 18:40:04 +02:00
Ozzie Isaacs f3efef1f60 Fix stored css bug in all typeahead functions (update typeahead -> bugfix typeahead) 2021-10-11 19:56:54 +02:00
cbartondock 659481c83b Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-10-11 09:55:09 -04:00
Ozzie Isaacs bad4c01474 Fix stored css bug in all typeahead functions (update typeahead -> bugfix typeahead) 2021-10-10 18:02:18 +02:00
Ozzie Isaacs cd53d57516 Fix for remote login 2021-10-10 10:26:01 +02:00
Ozzie Isaacs ac54899415 Bugfixes kobo sync 2021-10-10 10:23:58 +02:00
Ozzie Isaacs abe46e1862 Show checkbox from boolean custom columns on details page with caliblur theme 2021-10-09 15:01:38 +02:00
Ozzie Isaacs 3be47d6e57 edit_books prepared for kobo sync 2021-10-09 14:57:23 +02:00
Ozzie Isaacs 25f608d109 Bugfixes from testrun (load images from gdrive)
Fix locale for new users
2021-10-09 09:37:10 +02:00
Ozzie Isaacs aca5324914 Bugfix arrange shelf
Bugfix remote login
Bugfix perform Update
2021-10-06 22:06:33 +02:00
Ozzie Isaacs d8f9e2feb2 Bugfixes for user import with default locale and default language
Bugfixes from testrun
2021-10-06 18:41:01 +02:00
Ozzie Isaacs ed26d34961 Code cleaning (remove python2) 2021-10-04 19:23:24 +02:00
Ozzie Isaacs 50919d4721 Added handling for missing flask-wtf dependency
Added CSRF protection (via flask-wtf)
Moved upload function to js file
Fixed error page in case of csrf failure
2021-10-04 19:23:20 +02:00
Ozzie Isaacs 5edde53fed Improved sync for kobo with additional table 2021-10-03 09:58:45 +02:00
Ozzie Isaacs 1c15e10ac0 Improved csrf protection for remote login 2021-10-03 09:58:45 +02:00
Ozzie Isaacs 52be2ad4a2 Improved DJVU Reader 2021-10-03 09:32:29 +02:00
Ozzie Isaacs 43fdef5e53 Improved textreader 2021-10-03 09:31:24 +02:00
Ozzie Isaacs b699796236 Improved CSRF protection 2021-10-03 08:03:14 +02:00
Ozzie Isaacs b82d03c12c Removed js from search_form, tasks
Added translation of bootstrap-select in user table
2021-10-03 08:01:58 +02:00
Ozzie Isaacs b8eb557761 Corrected translation german -> Anzeigesprache 2021-10-03 08:00:53 +02:00
Ozzie Isaacs ba40c6693e Merge remote-tracking branch 'filepicker/fix-filemodal' 2021-10-02 08:32:44 +02:00
Ozzie Isaacs e064a3ec2b Removed unnecessary spaces in book convert texts 2021-10-02 07:53:36 +02:00
GarcaMan f6561456f7 New sort for Comic Reader 2021-10-01 05:47:52 +00:00
xlivevil deb91996a8 fix:bootstrap-table locale
Add data-locale in table tag
Add bootstrap-table-locale-all-min-js
Remove bootstrap-table locale dir
2021-09-30 20:09:02 +08:00
Ozzie Isaacs cd1fe6dde0 Fix #2085 (Misaligned shelf names after glyphicon) 2021-09-29 19:26:21 +02:00
Ozzie Isaacs 3f6a466ca7 Further language support fixes (displaying "non locale" languages translated) 2021-09-29 19:00:02 +02:00
cbartondock 50f4fe6546 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-09-29 09:34:11 -04:00
Ozzie Isaacs 861277460d Merge remote-tracking branch 'origin/master' 2021-09-28 18:50:11 +02:00
Fernando Mesquita 83babf88fc msgid "Read Books" --> msgstr "Livros Lidos" 2021-09-28 12:03:07 -03:00
Ozzieisaacs 58735caff3 Enhancements for displaying languages on non english locale 2021-09-26 17:04:53 +02:00
cbartondock 844eb6c379 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-09-25 15:33:56 -04:00
xlivevil 1b8410e786 Update Simplified Chinese translation 2021-09-25 23:15:44 +08:00
xlivevil fed9eff7b8 Fix the publishstart option in advsearch 2021-09-25 22:10:46 +08:00
xlivevil bf5de95fdc Update Simplified Chinese translation 2021-09-25 22:08:05 +08:00
Ozzie Isaacs 2e25e797dd Fix #2002 (Added missing default locale and default language view upon importing ldap user) 2021-09-25 14:08:49 +02:00
Ozzie Isaacs c1ac68e2ae Fix #2053 (Hovering on cover, now shows tooltip also in Caliblur! Theme) 2021-09-25 14:01:17 +02:00
Ozzie Isaacs 623a92ebec Version Bump
Merge branch 'Develop'
2021-09-25 10:49:20 +02:00
Ozzie Isaacs 2edcd16119 Update version to 0.6.13 for release 2021-09-25 08:34:20 +02:00
Ozzie Isaacs af202bd6d1 Merge remote-tracking branch 'pt_br/patch-1' 2021-09-25 08:25:06 +02:00
Ozzie Isaacs d5a332a84e Update test results 2021-09-25 08:23:14 +02:00
Fernando Mesquita d6884164a5 Update messages.po
Read = Leia > Lido
2021-09-25 01:07:31 -03:00
cbartondock 707556a36d Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-09-23 09:14:51 -04:00
Ozzie Isaacs 356a4f588e Merge remote-tracking branch 'nl/master' 2021-09-22 20:43:29 +02:00
Ozzie Isaacs 241b31458d Added ancient and modern Greek translation to greek language 2021-09-22 20:34:18 +02:00
Ozzie Isaacs efb04ddd8f Fix #2061 (Defective utf-16 txt files) 2021-09-22 19:58:20 +02:00
Anatolii Fetisov 781ca7a3f3 Fix filemodal file selection dialog 2021-09-18 09:49:28 +03:00
Jeroen Hellingman 6f6d8df431 Update messages.po
Review of Dutch translations (native speaker); improving consistency in vocabulary still needed.
2021-09-02 11:25:58 +02:00
cbartondock 9ebde57fc3 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-08-31 18:44:18 -04:00
Ozzie Isaacs 8dc1e9bfa4 Updated test result 2021-08-31 08:33:09 +02:00
Ozzie Isaacs e3db2796c9 Merge branch 'master' into Develop
# Conflicts:
#	test/Calibre-Web TestSummary_Linux.html
2021-08-30 20:18:21 +02:00
Ozzie Isaacs 42ef049b63 Catch error on ldap import 2021-08-30 20:17:56 +02:00
cbartondock 8930426f2a Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-08-30 11:35:10 -04:00
Ozzie Isaacs ceffa3a108 Removed xss on shelf add/remove action 2021-08-30 17:06:11 +02:00
Ozzie Isaacs c0a06eec46 Removed xss on shelf add/remove action 2021-08-30 17:05:53 +02:00
Ozzie Isaacs 86ef1d47e8 Bugfixes from testrun 2021-08-30 08:02:21 +02:00
cbartondock b835aa660a Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-08-29 14:05:21 -04:00
Ozzie Isaacs 4d92d7da3a Removed timelogging on metadata search 2021-08-29 14:37:15 +02:00
Ozzie Isaacs d1e6a85803 Parallel requests of metadata provider 2021-08-29 14:36:05 +02:00
Ozzie Isaacs d8bad7394a Merge remote-tracking branch 'caliblur/master' 2021-08-29 13:31:46 +02:00
Ozzie Isaacs f5062d1354 Merge remote-tracking branch 'it/patch-1' 2021-08-29 13:31:21 +02:00
Ozzie Isaacs 1d79d9ded2 Bugfix from tests (displaying of book languages in user list) 2021-08-29 11:31:10 +02:00
Ozzieisaacs 10e212fcde Merge branch 'master' into Develop 2021-08-29 10:44:13 +02:00
Ozzie Isaacs 1fa267ce1b Final fix for escaping html special chars in tables 2021-08-28 15:47:57 +02:00
cbartondock abcf9a1808 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-08-28 09:35:12 -04:00
Ozzie Isaacs d4cfad6363 Fixed several text problems from tasks
Fixed task update
2021-08-28 11:32:13 +02:00
Ozzie Isaacs 3a24561ca2 Removed additional " from convert message 2021-08-28 10:32:40 +02:00
Ozzie Isaacs 5c19a8aacc Bugfix edit comments
Testupdate
2021-08-28 08:24:38 +02:00
Ozzie Isaacs 3946ef8f0d Merge branch 'master' into Develop
# Conflicts:
#	cps.py
#	cps/web.py
2021-08-27 16:16:24 +02:00
cbartondock 6a2868c68d Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-08-27 10:13:05 -04:00
Ozzie Isaacs 7ae3255ea9 Revert Content-Security-Policy header 2021-08-27 14:28:30 +02:00
Ozzie Isaacs 91e6d94c83 Improved displaying of username and task title in tasks 2021-08-27 14:27:35 +02:00
Ozzie Isaacs e615073893 Add all html special characters to the escaped characters in bootstrap table 2021-08-27 12:56:08 +02:00
Ozzie Isaacs 32e27712f0 Added lxml to needed requirements
Improved displaying of series title, book of series, comments and custom comments
2021-08-27 09:43:32 +02:00
cbartondock ff39fac50f Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-08-26 17:58:53 -04:00
Daniela Mazza 80d3ba42b4 Update messages.po
Changed translate of "Read Books": the meaning is exactly "Libri letti", not "Libri da leggere"
2021-08-26 19:16:38 +02:00
Ozzie Isaacs d25cfb7499 Fix for #2097 (Quotes are now handled properly in UI-editable tables) 2021-08-26 18:03:59 +02:00
cbartondock 24ad15be11 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-08-19 08:30:13 -04:00
Ozzie Isaacs a35c635987 Update python metadata search 2021-08-18 21:38:20 +02:00
Ozzie Isaacs aa9fdd2ada Merge branch 'master' into Develop 2021-08-18 20:32:33 +02:00
Ozzie Isaacs afa585eb65 Added -f flag for compatibility reasons 2021-08-18 20:32:13 +02:00
cbartondock 03acb77162 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-08-15 12:06:55 -04:00
Ozzie Isaacs 28ca39ca13 Add logging of user sessions 2021-08-15 12:43:19 +02:00
cbartondock b05c17b8bb Fixed book covers being too wide in search/shelves/discover on mobile 2021-08-14 21:50:05 -04:00
cbartondock 3839af65c4 add python-version to gitignore for managed pyenv compatibility 2021-08-14 15:57:09 -04:00
Ozzie Isaacs 275e073c42 Fix #2085 (Missing spaces between glyphicon and text on sidebar) 2021-08-10 20:17:30 +02:00
Ozzie Isaacs c4876010e9 Merge remote-tracking branch 'pdf/master' 2021-08-09 16:46:19 +02:00
xlivevil bce69b2dfc Add pdf.js font file 2021-08-07 20:51:10 +08:00
xlivevil fb97e39d9f Merge branch 'master' of https://github.com/xlivevil/calibre-web 2021-08-05 21:39:04 +08:00
xlivevil 913690df78 Fix #1913(set lazyload in pdf reader)
Add favicon.ico in pdf reader
2021-08-05 21:37:39 +08:00
Ozzie Isaacs e68a3f18fa Merge branch 'master' into Develop 2021-08-01 20:23:19 +02:00
Ozzie Isaacs 1534827ad7 With merge button disabled it's no longer possible to open merge dialog 2021-08-01 20:23:04 +02:00
Ozzie Isaacs b36422bc05 Update list/grid button action (reverse proxy problem) 2021-08-01 20:06:48 +02:00
Ozzie Isaacs 1e2335dea0 Merge remote-tracking branch 'caliblur/master' 2021-08-01 17:35:30 +02:00
Ozzie Isaacs e052590270 Merge remote-tracking branch 'chinese/master'
# Conflicts:
#	cps/translations/zh_Hans_CN/LC_MESSAGES/messages.mo
#	cps/translations/zh_Hans_CN/LC_MESSAGES/messages.po
#	messages.pot
2021-08-01 17:31:47 +02:00
Ozzie Isaacs 41ca85268f Update translation files 2021-08-01 17:27:18 +02:00
Ozzie Isaacs 0e9709f304 Make Book-No. of book-range to translatable text 2021-08-01 17:09:29 +02:00
Ozzie Isaacs ceec1051d5 Added option to save books with no nenglish characters
Imporvements on metadata search
2021-08-01 13:50:17 +02:00
cbartondock 81ccc11c9c fixed dropdowns going off screen in caliblur 2021-07-31 12:51:51 -04:00
Ozzie Isaacs 702e96ddd6 Update load metadata 2021-07-31 09:18:05 +02:00
Ozzie Isaacs 53603f79bd Get_meta button unfocused on return to edit books 2021-07-31 09:00:34 +02:00
Ozzie Isaacs 250cafe814 Merge branch 'master' into Develop 2021-07-30 21:00:01 +02:00
Ozzie Isaacs 16633ef1d3 Fix #2029 (Import LDAP User with "." in the name) 2021-07-30 20:45:33 +02:00
Ozzie Isaacs f0a5225524 Merge branch 'master' into Develop 2021-07-30 16:58:30 +02:00
Ozzie Isaacs a32b36bf81 Fixed missing joins for sorting according to series in read/unread and rated views 2021-07-30 16:58:20 +02:00
Ozzie Isaacs 302679719d Merge branch 'master' into Develop
# Conflicts:
#	cps/admin.py
#	cps/converter.py
#	cps/subproc_wrapper.py
#	test/Calibre-Web TestSummary_Linux.html
2021-07-30 16:33:06 +02:00
Ozzie Isaacs a63baa1758 better logged in session protection 2021-07-30 16:28:37 +02:00
cbartondock 752192a057 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-07-30 09:34:50 -04:00
Ozzie Isaacs e245a147d9 Revert accidentally committed store user session 2021-07-30 10:16:52 +02:00
Ozzie Isaacs 0ec2bcd897 Fixes from testrun 2021-07-30 09:25:19 +02:00
xlivevil 19c75d6790 Update Simplified Chinese translation 2021-07-29 14:00:02 +08:00
cbartondock 0654156dd6 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-07-27 11:24:23 -04:00
Ziding Zhang e4b0434733 Create SECURITY.md
A simple instruction for security researchers in future.
2021-07-27 13:22:24 +02:00
cbartondock b32721c293 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-07-27 06:39:29 -04:00
Ozzie Isaacs c5e39a7523 Fix divs in user edit page 2021-07-27 08:09:57 +02:00
cbartondock 0db837c0ce Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-07-26 14:44:16 -04:00
Ozzie Isaacs 53dae32897 Fix multiple messages on windows after change config with reboot 2021-07-26 16:50:21 +02:00
Ozzie Isaacs 018f3ca250 Sort authors additionally to series and series_index (Fix #2001)
Sqlalchemy version2 is now a global flag
2021-07-26 07:52:01 +02:00
Ozzie Isaacs a1a8a0cf29 Logout if logged out and don't allow to get logged in afterwards 2021-07-25 05:24:03 +02:00
Ozzie Isaacs f9c3e751f6 Fixes for handling shelf requests without title 2021-07-24 05:49:16 +02:00
Ozzie Isaacs c7b057ec51 Merge remote-tracking branch 'shelf_edit/security_fixes' into master 2021-07-24 05:34:24 +02:00
Ozzie Isaacs 85ea762054 Handle shelf request without title 2021-07-24 05:33:51 +02:00
Ozzie Isaacs 56cd62ed90 Fix show edit user after exception 2021-07-23 20:12:37 +02:00
Ozzie Isaacs 9a8c342e61 Fix deleting user (deleting shelfs and so on failed before) 2021-07-23 20:03:20 +02:00
Ozzie Isaacs 3b81ea37f4 Fix entries of user table are visible if database has no tags 2021-07-23 19:46:01 +02:00
Ozzie Isaacs 3c8bfc31e4 fix change name allowd as non admin 2021-07-23 19:34:46 +02:00
Ileana Maricel Barrionuevo 59881367fe Security fixes: Report 85176e1f-7920-4824-87ea-8eb5b5e505e0: Exposure of Private Personal Information to an Unauthorized Actor in janeczku/calibre-web 2021-07-22 01:05:11 -03:00
Ileana Maricel Barrionuevo c8ebaee0f7 Security fix improved: user should not edit other shelve's titles 2021-07-22 00:41:07 -03:00
Ileana Maricel Barrionuevo d5d0ad50fa Fixed security issue: a user could edit others' shelves. 2021-07-21 22:08:41 -03:00
cbartondock 6ef792d65d Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-07-12 12:08:55 -04:00
Ozzie Isaacs 20fa9f5523 Fix encoding errors on windows while downloading logbooks 2021-07-12 17:33:35 +02:00
Ozzie Isaacs 616cc2018a Fix show cover
Update more debug output for kobo sync
2021-07-12 14:58:03 +02:00
Ozzie Isaacs e69b1adccd Fix #2053 (Add tooltip for complete title on hover over cover and title) 2021-07-12 14:17:28 +02:00
Ozzie Isaacs 280efad939 #2052 (wrong series index shown for series_index >=100) 2021-07-12 14:04:23 +02:00
Ozzie Isaacs 15ec6bec95 fix #2014 (User menu dropdown in caliblur is tiny and presents scrollbars)
Fix display of nonexistent series_index
Fix caliblur add-to-shelf
2021-07-11 13:15:13 +02:00
Ozzie Isaacs aae81c3d24 Fix #2048 (Display book title in reader) 2021-07-11 12:52:46 +02:00
Ozzie Isaacs 259ac94b93 Fix error unclosed IO on external binary version query 2021-07-11 09:19:27 +02:00
Ozzie Isaacs a27314464a Merge branch 'master' into Develop 2021-07-11 08:50:14 +02:00
Ozzie Isaacs 87f07003f4 Removed invalid code
Sqlalchemy 2.0 compatibility for kobo sync
2021-07-11 08:49:47 +02:00
Ozzie Isaacs 1bf065fd04 Bugfix with encoding errors windows 2021-07-11 07:38:15 +02:00
Ozzie Isaacs f8de7e75cc Fix error unclosed IO on external binary version query 2021-07-11 09:19:46 +02:00
cbartondock 7d586b3745 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-07-10 13:21:27 -04:00
Ozzie Isaacs a56e071a19 Fix #2043 (Multiuser kobo sync with restrict to shelfs working)
Sync only selected shelfs is stored correct on creating user
2021-07-10 17:09:04 +02:00
Ozzie Isaacs 480aecb16c Fix #2046 (Deleting book with additional "/" in database path is working) 2021-07-10 08:27:29 +02:00
Ozzie Isaacs ec7803fa76 Update python search Metadata 2021-07-10 07:38:16 +02:00
cbartondock 91938fd18a Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-07-08 15:52:14 -04:00
Ozzie Isaacs aa2d3d2b36 Update python search Metadata 2021-07-07 21:24:29 +02:00
Ozzie Isaacs d5e9cdc5b7 Search Metadata improvements 2021-07-07 21:10:38 +02:00
Ozzie Isaacs 305e75c0ae Clarification for pip command 2021-07-07 16:42:05 +02:00
Ozzie Isaacs 0d247fef6a Fixes for grab metadata in python 2021-07-06 20:24:27 +02:00
Ozzie Isaacs 94da61c57e Basic Metadata mechanism in python 2021-07-05 18:55:54 +02:00
Ozzie Isaacs 430ccd9ab1 Merge branch 'master' into Develop 2021-06-29 18:52:02 +02:00
Ozzie Isaacs 47d94d9bd6 Search metadata without installed google scholar working (fix #2024) 2021-06-29 18:38:02 +02:00
Ozzie Isaacs a6d1f6039d Merge remote-tracking branch 'es/spanish-translation' into master
# Conflicts:
#	cps/translations/es/LC_MESSAGES/messages.po
2021-06-29 18:30:37 +02:00
Ozzie Isaacs 31234a4b98 Merge remote-tracking branch 'fr/Update-French-transations' into master
# Conflicts:
#	cps/translations/fr/LC_MESSAGES/messages.po
2021-06-29 18:25:57 +02:00
Ozzie Isaacs 476275ea53 Merge remote-tracking branch 'po/master' into master
# Conflicts:
#	cps/translations/pl/LC_MESSAGES/messages.po
2021-06-29 18:25:25 +02:00
Ozzie Isaacs 792d4a65bc Fix typo 2021-06-29 18:24:35 +02:00
Ozzie Isaacs 0e2dca5f4d Fix upload of books uppercase extensions (#2038) 2021-06-26 20:14:52 +02:00
Ozzie Isaacs 557296b7be Fix upload of books uppercase extensions 2021-06-26 20:13:56 +02:00
JFernando122 2236191263 Fixing typos on spanish translation 2021-06-22 23:37:19 -05:00
JFernando122 1138c86868 improved spanish translation with adrocampo's review 2021-06-22 14:22:28 -05:00
Thomas 08500c66a8 Update French translations
The French translation is normally completely now
2021-06-19 16:01:25 +02:00
Ozzie Isaacs 67836006c5 Successfull testrun 2021-06-19 14:44:57 +02:00
JFernando122 fa03a9ee25 Updated spanish translation 2021-06-17 21:49:04 -05:00
cbartondock bf4564e365 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-06-13 21:38:25 -04:00
Radoslaw Kierznowski 6a96664381 Update translations 2021-06-12 15:41:48 +02:00
Ozzie Isaacs e6e3032f02 Merge remote-tracking branch 'pl/master' into master 2021-06-12 08:52:14 +02:00
Ozzie Isaacs 6d424f0a30 Merge remote-tracking branch 'nl/patch-1' into master 2021-06-12 08:50:51 +02:00
Ozzie Isaacs a6f0375db3 Merge remote-tracking branch 'it/patch-25' into master 2021-06-12 08:50:13 +02:00
Ozzie Isaacs 1833e8fdb4 Success message after database change 2021-06-12 08:48:55 +02:00
Radoslaw Kierznowski 70151c2e11 Update Translations 2021-06-10 15:23:12 +02:00
JVT038 ab69962e8a Completed Translation for Dutch (NL) 2021-06-09 20:26:09 +02:00
ElQuimm 075fe994af Update italian message.po
Updated version
2021-06-08 21:11:36 +02:00
Ozzie Isaacs 1aca1b9fdd Fixed duplicate ids in logviewer 2021-06-06 16:14:30 +02:00
Ozzie Isaacs 9fea5a55f4 Merge branch 'master' into Develop 2021-06-06 12:18:04 +02:00
Ozzie Isaacs 1a0bf45c34 Check file/folder permissions before update 2021-06-06 12:16:47 +02:00
Ozzie Isaacs 67874e07b6 Fix routes for reverse proxy 2021-06-05 18:41:52 +02:00
Ozzie Isaacs ced0bcfe33 Fix missing " in books table 2021-06-05 18:41:52 +02:00
Ozzie Isaacs 8c0aa79f78 Fix #1915 (more than 10 books at a time are displayed in books table) 2021-06-05 18:41:52 +02:00
Ozzie Isaacs 93e8c5be32 Fixes for flask version 2.1
Fixes for compatibility with sqlalchemy 2.0
2021-06-05 18:41:42 +02:00
Ozzie Isaacs d9f86aecd2 Fix change_permission 2021-06-05 13:51:16 +02:00
Ozzie Isaacs e9552fedef Merge branch 'master' into Development 2021-06-05 10:23:06 +02:00
Ozzie Isaacs 84e1c6e809 Fix for #2004 (pdf viewer buttons missing in safari) 2021-06-05 08:08:08 +02:00
Ozzie Isaacs aadd6fd7e0 Possible fix for #2003 (Calibre theme download icon broken) 2021-06-03 12:35:09 +02:00
Ozzie Isaacs 59987ed359 Merge branch 'master' into Develop 2021-05-28 18:22:43 +02:00
Ozzie Isaacs a79600c81f Mass change book title and author (fix #1996) 2021-05-28 18:22:29 +02:00
Ozzie Isaacs e8a4c3c6b9 Merge remote-tracking branch 'shields/patch-3' into master 2021-05-28 17:46:53 +02:00
Ozzie Isaacs 62fce26651 Bugfix extended search term with excluded series/shelfs 2021-05-28 14:57:35 +02:00
Ozzie Isaacs 25add6511f Catch error on search for new custom column (created after start of calibre-web) 2021-05-28 14:54:18 +02:00
Ozzie Isaacs b2a28cd39a Merge branch 'Develop' into master 2021-05-28 14:23:47 +02:00
Ozzie Isaacs 6de3aebf3a Fix for #1998 (Error 500 with configured oauth on user setup page accessed by admins) 2021-05-28 14:23:30 +02:00
Ozzie Isaacs 1b7e422772 Changed error page to display logout route in case of unconfigured 2021-05-28 13:56:07 +02:00
Ozzie Isaacs b0f48b7f00 Merge branch 'master' into Develop 2021-05-26 19:58:10 +02:00
Ozzie Isaacs 94b07d05c1 First half of #1996 (editing single books) 2021-05-26 19:57:58 +02:00
Ozzie Isaacs 4392fec7f5 Added fullscreen cover viewer 2021-05-26 19:40:41 +02:00
flying-sausages c1d0ec076b Shield cleanup 2021-05-26 17:20:54 +02:00
Ozzie Isaacs a47d6cd937 Fix confirm dialog database change
Gdrive setup basically working again
Moved basicconfig behind login
Database setup separated from other setup
Config page is using ajax (flask >2 and slow computers)
2021-05-26 14:50:44 +02:00
Ozzie Isaacs dcdb5e2a9e Merge branch 'master' into Develop 2021-05-22 19:52:53 +02:00
Ozzie Isaacs 240325dc18 Update installation instructions 2021-05-22 19:52:20 +02:00
Ozzie Isaacs e599d2ec05 Merge remote-tracking branch 'scholar/master' into master 2021-05-22 19:30:57 +02:00
Ozzie Isaacs c62a417cbf Merge branch 'Develop' into master 2021-05-22 19:29:58 +02:00
Ozzie Isaacs 98fc1ee0a7 Comic reader code cleaning 2021-05-22 19:28:30 +02:00
Ozzie Isaacs 78d0fd811b Version bump 2021-05-22 14:57:55 +02:00
Ozzie Isaacs 54d06e580d Release version 0.6.12 2021-05-22 14:08:46 +02:00
Ozzie Isaacs a62fca1e55 Merge branch 'master' into Develop 2021-05-22 11:28:59 +02:00
Ozzie Isaacs 7b1d23eba4 Restored Discord Widget 2021-05-22 10:03:48 +02:00
Ozzie Isaacs 2502c279fc Update discord 2021-05-22 09:57:47 +02:00
Ozzie Isaacs 878fc8c2fd Added download stat badge 2021-05-21 20:58:10 +02:00
Ozzie Isaacs 64902eebcb Merge remote-tracking branch 'batches/patch-2' into master 2021-05-21 20:54:06 +02:00
flying-sausages e520f6afc4 Add Shields to README.md 2021-05-20 22:48:51 +02:00
Ozzie Isaacs 0cc1ae9324 Updated Testresult for Linux 2021-05-20 17:54:25 +02:00
cbartondock 1b2124aa35 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-05-19 16:47:19 -04:00
Ozzie Isaacs bd4fde9e63 Fix #1992 handle invalid numbers of books seriesindex 2021-05-19 19:54:44 +02:00
Ozzie Isaacs c85cfa90a4 Update testresults on windows
Added encoding on fb2 upload
2021-05-19 19:21:09 +02:00
Ozzie Isaacs a0449b50c8 Downgrade flask -> to slow during reboot 2021-05-17 17:54:43 +02:00
Ozzie Isaacs 010c0bfc7d Improved error handling for content too long 2021-05-16 14:07:16 +02:00
Ozzie Isaacs 394b063b8c Fixes for caliblur theme 2021-05-16 13:25:29 +02:00
Ozzie Isaacs 251780bed6 Added google scholar as metadata provider 2021-05-16 13:24:42 +02:00
Ozzie Isaacs decc2a9c79 Merge branch 'master' into Develop 2021-05-16 13:19:38 +02:00
Ozzie Isaacs b62d84424e Merge remote-tracking branch 'comic/comic_viewer_changes' into master 2021-05-16 13:19:28 +02:00
Ozzie Isaacs e15324d2cd Merge branch 'master' into Develop 2021-05-16 09:38:00 +02:00
Ozzie Isaacs 20b84a9459 Unified translations
Update translations for release
2021-05-16 09:37:45 +02:00
Ozzie Isaacs 109198a374 Merge branch 'master' into Develop 2021-05-16 09:03:58 +02:00
Ozzie Isaacs dafc68f049 Updated requirements 2021-05-16 09:03:47 +02:00
Ozzie Isaacs 3e5c944365 Changed backend for comic reader, now supports rar5 2021-05-16 08:35:20 +02:00
Ozzie Isaacs d95838309e Added config option for shelf sync behavior 2021-05-15 10:45:51 +02:00
Ozzie Isaacs 4745fc0db1 Bugfix search for publish dates and custom column dates
Bugfix save umplauts in comments unescaped (as calibre does)
Improved testability
2021-05-15 07:51:32 +02:00
Ozzie Isaacs b3648187ff Bugfix search for publishdates and custom column dates
Bugfix save umplauts in comments unescaped (as calibre does)
Improved testability
2021-05-15 07:51:12 +02:00
cbartondock b35483edf8 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-05-14 23:31:05 -04:00
Ozzie Isaacs f29088e854 Merge branch 'master' into Develop
# Conflicts:
#	cps/kobo.py
2021-05-14 19:59:35 +02:00
Ozzie Isaacs b009dfe4ee Always use bootstrap datepicker 2021-05-14 19:58:06 +02:00
Ozzie Isaacs eba94f430c Updated js libs 2021-05-14 09:29:24 +02:00
Ozzie Isaacs 06347b7e3c Bugfixes from testrun 2021-05-14 08:26:56 +02:00
Ozzie Isaacs 6bc426b21d Fix edit_books.js 2021-05-14 07:29:48 +02:00
cbartondock e0fac8d2c0 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-05-13 11:25:59 -04:00
Ozzie Isaacs 4a849aab7f Merge remote-tracking branch 'requirements/patch-1' into master 2021-05-13 16:28:54 +02:00
Ozzie Isaacs ad2d0c84e4 Update swedish translation 2021-05-13 16:28:02 +02:00
Ozzie Isaacs 6bf360fbfb Added "comments" type to supported custom columns 2021-05-13 14:00:01 +02:00
Ozzie Isaacs 380292a8aa Custom column datetime now searchable (#1984) 2021-05-13 13:31:36 +02:00
jonyxx-alt f9949da745 Update Swedish translation
Upload files that has been updated
2021-05-13 11:04:57 +00:00
Ozzie Isaacs b0cc52e0aa Enable custom column datetime (adv. search not working yet) #1984 2021-05-13 10:39:36 +02:00
Ozzie Isaacs 9ef705650b Access pages with stored order per default (#1987)
Fix for toggle-text of enable-sort button on shelf page
2021-05-13 09:41:27 +02:00
Ozzie Isaacs c6dadbe75e restrictions are now applied to kobo sync requests (Fix #1938) 2021-05-13 09:17:01 +02:00
cbartondock 0a65c05083 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-05-07 09:05:27 -04:00
Robert Schütz 21026340ad remove singledispatch from requirements
It's not used anywhere.
2021-05-05 14:30:00 +02:00
Ozzieisaacs eb2273247f Changed texts in edit shelf page for Kobo shelf sync 2021-05-02 15:59:40 +02:00
Ozzieisaacs 02fc698f1c Some little code refactoring 2021-05-02 10:05:25 +02:00
Ozzieisaacs 8dc11e89bd Merge remote-tracking branch 'koko_sync/feature/kobo-shelf' into Develop 2021-05-02 09:43:47 +02:00
cbartondock 12c3264000 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-05-01 21:55:09 -04:00
Ozzieisaacs b34672ed19 Merge branch 'master' into Develop 2021-05-01 20:54:01 +02:00
Ozzieisaacs 541c8c4b93 Improved error handling for disapearing custom column linked to visiblility restrictions 2021-05-01 20:52:48 +02:00
Ozzieisaacs b97373bf37 Improved error handling for disapearing custom column linked to read status 2021-05-01 18:42:57 +02:00
Ozzieisaacs c0b561cb5a Better input check for custom_columns 2021-05-01 17:10:29 +02:00
Ozzieisaacs bd3ccfd0a9 Merge remote-tracking branch 'cn/master' into master 2021-05-01 16:33:47 +02:00
Ozzieisaacs 5470acd3af Fix #1964 (RefreshError with unconfigured gdrive) 2021-05-01 12:45:28 +02:00
Ozzie Isaacs 64696fe973 Bugfixes edit user list (Fix #1938) 2021-05-01 08:36:39 +02:00
cbartondock f2cd93dc54 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-29 10:01:18 -04:00
Ozzie Isaacs ed2fa4cdd8 Update error handling for user list (#1938) 2021-04-28 20:49:16 +02:00
cbartondock c2c4636961 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-28 08:43:44 -04:00
dalin 03cca1d1c0 update Simplified Chinese 2021-04-28 16:15:21 +08:00
dalin 354b075885 Merge remote-tracking branch 'upstream/master' 2021-04-28 14:15:42 +08:00
Ozzie Isaacs de7f039b99 Update list user editor (#1938) 2021-04-27 20:01:17 +02:00
cbartondock c2e530af17 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-26 13:49:25 -04:00
Ozzie Isaacs 19797d5d23 Merge remote-tracking branch 'it/patch-24' into master 2021-04-26 19:05:25 +02:00
Ozzie Isaacs 144c2b5fc7 Renaming ipadress - ip_address
Bugfix user table
Result testrun
Updated cn translation
2021-04-26 19:03:01 +02:00
cbartondock 577b525508 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-26 10:23:24 -04:00
GarcaMan 7da40d1c2e Added option to remove Y-Scrollbar and reset page scroll 2021-04-25 19:59:53 +00:00
Ozzie Isaacs 4e3a5ca33b Added additional debug messages, catch additional errors in updater 2021-04-25 11:30:53 +02:00
Ozzie Isaacs 97e4707f72 user list column value and tags editor (#1938)
Bugfixes for massedit in user list (#1938)
Changed no. of debug messages
2021-04-25 10:43:01 +02:00
cbartondock 541dd6b579 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-22 18:12:19 -04:00
Ozzie Isaacs 450ee43677 Additional logging for emails 2021-04-22 19:14:56 +02:00
cbartondock e57229e670 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-22 12:22:45 -04:00
Ozzie Isaacs c0b2e886d2 bugfix books list with selected books and stored on state 2021-04-21 19:28:22 +02:00
Ozzie Isaacs bb4749c65b Result for testrun
Added mass delete of users
refactores user table refresh
Bugfix for sorting with selected users
Bugfix delete books #1938
2021-04-21 19:23:56 +02:00
cbartondock 1ef2a96465 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-19 12:20:54 -04:00
ElQuimm 5aa37c68a2 Updated version of italian.po
Thank you.
2021-04-19 10:11:26 +02:00
Ozzie Isaacs 6e5a1a1f4d Merge remote-tracking branch 'add_Babelio/patch-1' into master 2021-04-18 12:05:00 +02:00
Ozzie Isaacs b624ce16c3 Merge remote-tracking branch 'it/patch-23' into master 2021-04-18 12:04:08 +02:00
Ozzie Isaacs 3be5b5f919 Merge remote-tracking branch 'comic_reader/master' into master 2021-04-18 12:02:21 +02:00
Ozzie Isaacs 04ac5b69ac Further improvements on user list #1938 2021-04-18 12:01:11 +02:00
Ozzie Isaacs 9cc14ac5c7 Fix for #1905 prevent invalid json data in gmail_token 2021-04-18 11:33:14 +02:00
BuildTools 755eb1405b Fix progress bar direction 2021-04-18 04:25:45 +09:00
subdiox 0138294b36 Fix an issue that space key doesn't work intentionally when inverting reading direction 2021-04-18 03:20:41 +09:00
Ozzie Isaacs c0a4addf30 Cancel button in User edit now leads to the right page back #1938 2021-04-17 18:30:55 +02:00
Ozzie Isaacs 39bbee0eeb Books sort with non Books table column working #1938 2021-04-17 10:27:30 +02:00
Ozzie Isaacs 39dda3f534 Fix opds login with colon in password #1952 2021-04-15 18:02:52 +02:00
Ozzie Isaacs 1cb8dbe795 Update migration routine 2021-04-15 17:42:39 +02:00
cbartondock 85f1ca6101 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-15 08:43:28 -04:00
Ozzie Isaacs e13820bbf0 Update exception upon migration of database #1935 2021-04-15 12:05:03 +02:00
malletfils 3973362457 Update db.py
Just adding support for Babelio (french website about books) in the link section
2021-04-14 19:57:02 +02:00
cbartondock 2f3f13afb9 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-14 09:30:05 -04:00
Ozzie Isaacs b38877e193 Document change 2021-04-13 19:47:55 +02:00
Ozzie Isaacs 0e1dbb5377 Copy author names for displaying (#1935) 2021-04-13 19:41:44 +02:00
Ozzie Isaacs f07cc8b103 Update optional-requirements: flask-dance
Catch error for invalid oauth tokens
Fixes for displaying error messages on deleting books from list
Fixes for displaying error messages on deleting bookformats
Removed non working sorting in books list
2021-04-13 19:26:10 +02:00
Ozzie Isaacs 67775bc797 Update requirements
Catch error for invalid oauth tokens
Fixes for displaying error messages on deleting books from list
Fixes for displaying error messages on deleting bookformats
2021-04-13 19:08:02 +02:00
ElQuimm 05933a5f0c Updated italian message.po
I have not removed the #, fuzzy lines, but modified the corresponding values.
2021-04-13 18:51:50 +02:00
cbartondock e15ebd5aac Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-12 19:02:26 -04:00
Ozzie Isaacs d32b2ca524 Prevent traceback after delete user
flash message in case last admin role is removed #1938
2021-04-12 19:04:27 +02:00
Ozzie Isaacs d0a895628e Prevent delete of Guest user #1938 2021-04-12 18:45:44 +02:00
Ozzie Isaacs 90f2b3fb21 Refactored list checkbox sort 2021-04-12 18:39:09 +02:00
Ozzie Isaacs 0f95800dde Update sqlalchemy-utils dependency for oauth
Sort for state checkbox in user list and books list working
2021-04-12 18:23:25 +02:00
cbartondock ff99cd2456 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-11 16:26:55 -04:00
Ozzieisaacs 04971f8672 Bugfix wrong js file in user list 2021-04-11 20:01:40 +02:00
Ozzieisaacs b6177b27f4 Sorting of users in table according to selection possible 2021-04-11 19:59:20 +02:00
Ozzieisaacs ae97e87506 Delete user working from user table (#1938)
Comment in helper
2021-04-10 11:32:25 +02:00
cbartondock df91ca500f Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-08 20:25:02 -04:00
Ozzie Isaacs 2d73f541c0 Bugfix sort books list and user list
Prevent transferring password hash to client
2021-04-08 19:37:08 +02:00
Ozzie Isaacs 7561eabe52 Implement Backend to deny editing Guest rights restriction #1938 2021-04-07 18:56:17 +02:00
Ozzie Isaacs 067fb1b0b7 Prevent delete Guest user and redirect to admin page after user delete 2021-04-07 18:47:48 +02:00
Ozzie Isaacs 78071841cc After Deleting a book the list page is still displayed #1938 2021-04-07 18:19:48 +02:00
Ozzie Isaacs fac232229e Added missing ead/unread category in user list #1938 2021-04-07 17:49:19 +02:00
Ozzie Isaacs a43021e87c Fix for #1938 2021-04-07 17:46:17 +02:00
cbartondock eb599373ee prevented dropdowns from going off screen in caliblur 2021-04-06 13:21:36 -04:00
cbartondock 7b529b5f9e merge remote 2021-04-06 13:05:55 -04:00
Ozzie Isaacs 1a0de3b3cf Merge remote-tracking branch 'de_translation/patch-1' into master 2021-04-06 18:08:32 +02:00
Ozzie Isaacs 947154dc9c Merge branch 'development' into master 2021-04-06 18:06:25 +02:00
Ozzie Isaacs 8acd1f1fe4 Code refactoring and improved error handling for edit user list
Update teststatus
2021-04-06 17:29:42 +02:00
Ozzie Isaacs 665210e506 Fixes for book edit with title sort and author sort 2021-04-04 14:01:06 +02:00
Ozzie Isaacs 91b9370a21 Merge branch 'master' into development
# Conflicts:
#	cps/static/css/libs/bootstrap-table.min.css
#	cps/static/js/libs/bootstrap-table/bootstrap-table-editable.min.js
#	cps/static/js/libs/bootstrap-table/bootstrap-table.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-af-ZA.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ar-SA.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-bg-BG.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ca-ES.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-cs-CZ.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-da-DK.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-de-DE.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-el-GR.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-en-US.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-es-AR.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-es-CL.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-es-CR.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-es-ES.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-es-MX.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-es-NI.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-es-SP.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-et-EE.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-eu-EU.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-fa-IR.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-fi-FI.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-fr-BE.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-fr-CH.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-fr-FR.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-fr-LU.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-he-IL.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-hr-HR.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-hu-HU.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-id-ID.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-it-IT.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ja-JP.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ka-GE.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ko-KR.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ms-MY.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-nb-NO.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-nl-BE.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-nl-NL.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-pl-PL.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-pt-BR.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-pt-PT.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ro-RO.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ru-RU.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-sk-SK.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-sr-Cyrl-RS.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-sr-Latn-RS.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-sv-SE.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-th-TH.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-tr-TR.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-uk-UA.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-ur-PK.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-uz-Latn-UZ.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-vi-VN.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-zh-CN.min.js
#	cps/static/js/libs/bootstrap-table/locale/bootstrap-table-zh-TW.min.js
2021-04-02 17:13:22 +02:00
Ozzie Isaacs ca0aa600b4 Bugfix german translation 2021-04-02 17:12:26 +02:00
Ozzie Isaacs 1c42c4c969 Update bootstrap-table
Fixes for book edit
2021-04-02 17:11:16 +02:00
cbartondock 389f0ae452 Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-04-02 10:41:25 -04:00
Ozzie Isaacs 6e406311c3 Fix #1928 (ldap_import_user_filter missing in to_save) 2021-04-02 08:40:29 +02:00
cbartondock 00a24756f4 get rid of ugly outline on hover over book 2021-04-01 14:06:24 -04:00
cbartondock 9025f312cc Fixed read in browser button in caliblur theme 2021-04-01 13:53:53 -04:00
cbartondock d5e453edd3 added scholarly to libraries in about page 2021-03-31 22:43:23 -04:00
cbartondock 26cc64bdd6 Use google scholar to fetch metadata 2021-03-31 22:16:00 -04:00
robochud 87884c1af2 Update messages.po
very little typo
2021-03-31 00:56:12 +02:00
Ozzie Isaacs c0623a949c Merge remote-tracking branch 'caliblur/master' into master 2021-03-29 20:54:04 +02:00
cbartondock 42a23ea23c removed some dumb graphical inconsistencies 2021-03-29 14:35:48 -04:00
cbartondock 710c31d1ca Fixed book details not loading after infinite scroll 2021-03-29 14:13:22 -04:00
cbartondock f637ba4dad Fixed border display in book details 2021-03-29 13:52:09 -04:00
Ozzie Isaacs 80d2c60cef Update testresults 2021-03-29 18:03:09 +02:00
Ozzie Isaacs b17d71e4c3 Update optional-requirements.txt
Bugfix Mail task after convert task
2021-03-28 20:36:08 +02:00
Ozzie Isaacs 3c5bd3a605 Added gmail.json file to excluded file, added file also to excluded file during update 2021-03-28 15:01:56 +02:00
Ozzie Isaacs 7cc8d1e693 remove file 2021-03-28 14:58:07 +02:00
Ozzie Isaacs 99520d54a5 Added ability to send emails via gmail (#1905)
Gmail email sending
2021-03-28 14:51:01 +02:00
Ozzie Isaacs e10a8c078b Merge branch 'master' into development
# Conflicts:
#	cps/templates/email_edit.html
2021-03-27 18:36:11 +01:00
Ozzie Isaacs 7a196fed7c Prevent empty email port and server address(#1906) 2021-03-27 18:34:57 +01:00
Ozzie Isaacs c418c7e725 Prevent empty email from field (#1906) 2021-03-27 18:31:49 +01:00
Ozzie Isaacs e35748deff Fix wording and tabs 2021-03-27 17:30:54 +01:00
Ozzie Isaacs b57efbe31c Fix wording and tabs 2021-03-27 17:30:10 +01:00
Ozzie Isaacs 8f91437701 Implementation for gmail server with OAuth2 started 2021-03-27 16:36:24 +01:00
Ozzie Isaacs a7eb547ca4 Renamed brazilian datepicker file 2021-03-27 12:40:23 +01:00
Ozzie Isaacs 0ceb12f74f Renamed brazilian datepicker file 2021-03-27 12:40:01 +01:00
Ozzie Isaacs 4960624de7 Merge branch 'master' into development 2021-03-27 12:20:28 +01:00
Ozzie Isaacs 2c92f24d89 Added Brazilian translation 2021-03-27 12:20:07 +01:00
Ozzie Isaacs 0b7c679dba Changed test email message (fix #657) 2021-03-27 09:48:43 +01:00
Ozzie Isaacs aab3cdc58a Changed test email message 2021-03-27 09:47:43 +01:00
Ozzie Isaacs 3c63f5b204 Merge branch 'master' into development 2021-03-27 09:46:12 +01:00
Ozzie Isaacs 0b97bbf827 Merge remote-tracking branch 'div_a/use-kobo-for-download-link' into master 2021-03-27 09:39:44 +01:00
Ozzie Isaacs 970dbb0c59 Merge branch 'master' into development
# Conflicts:
#	cps/opds.py
#	cps/templates/admin.html
2021-03-27 09:38:12 +01:00
Ozzie Isaacs d21d3c2ceb Merge remote-tracking branch 'div_a/use-btn-anchors' into master 2021-03-27 09:33:28 +01:00
Ozzie Isaacs 0f6493b8ce Update Teststatus 2021-03-27 09:30:59 +01:00
Ozzie Isaacs f26beec1d3 Updated pdf reader 2021-03-25 18:57:40 +01:00
Ozzie Isaacs c4225e29ed Updated pdf reader 2021-03-25 18:57:25 +01:00
Ozzie Isaacs 9243326cd3 Updated testresult 2021-03-25 18:30:31 +01:00
Ozzie Isaacs 86beb8023a Downgrade sqlachemy, as it breaks oauth 2021-03-24 18:47:59 +01:00
Ozzie Isaacs f4e134742b Fix updater
Bugfixes from testruns
Update Testresults
2021-03-24 18:46:03 +01:00
Ozzie Isaacs 2b17bf4114 Update tests
Fixes upload book
2021-03-23 18:57:04 +01:00
Ozzie Isaacs c4f0fc8f7b Update tests
Fixes upload book
2021-03-23 17:57:49 +01:00
Ozzie Isaacs 3d6c836e7d Update tests 2021-03-23 17:39:51 +01:00
Gavin Mogan c279055af4 Use the kobo auth'd version for download link when proxied -- Fixes #1908 2021-03-22 18:08:41 -07:00
Gavin Mogan 657cba042a Use btn classes on anchors not div so the entire button is clickable 2021-03-22 17:25:38 -07:00
Ozzie Isaacs 7a58e48cae Bugfixes opds feed 2021-03-22 19:01:18 +01:00
Ozzie Isaacs 670eab62bf Update opds feed with letters for all titles, authors, categories and series 2021-03-22 17:46:15 +01:00
Ozzie Isaacs fc85586809 Bugfixes for sqlalchemy 1.4.0 2021-03-22 16:33:21 +01:00
Ozzie Isaacs 837fc4988d Letterize authors 2021-03-21 20:21:10 +01:00
Ozzie Isaacs 4664b47851 Fixed alphabetical order in list and grid view
Completed download section
2021-03-21 19:31:32 +01:00
Ozzie Isaacs 9864d932e0 Changed user.nickname to user.name
Added function to view downloads of all users for admins
2021-03-21 18:55:02 +01:00
Ozzie Isaacs 436f60caa9 refactored some functions 2021-03-21 14:17:07 +01:00
Ozzie Isaacs e9530eda9d Bugfix from refactoring 2021-03-21 13:46:13 +01:00
Ozzie Isaacs f4ddac16f9 Improved error logging for #1905 2021-03-21 11:58:51 +01:00
Ozzie Isaacs 33bdc07f55 Fix for #1845 (ods not working in Moonreader an Librera)
Fix opds search with wrong parameter no longer causes error 500
2021-03-21 11:57:42 +01:00
Ozzie Isaacs 130a4ed2d3 Fix opds and error logging in mail 2021-03-21 11:54:39 +01:00
Ozzie Isaacs 59ebc1af8a Code refactoring 2021-03-21 08:20:04 +01:00
Ozzie Isaacs 82e15d2e98 Merge branch 'master' into development
# Conflicts:
#	test/Calibre-Web TestSummary_Linux.html
2021-03-21 07:28:52 +01:00
Ozzie Isaacs 9c842f1895 Bugfixes pdf xmp parsing 2021-03-21 07:28:35 +01:00
Ozzie Isaacs 8cc849488b Code cosmetics 2021-03-21 07:15:38 +01:00
Ozzie Isaacs fcaa232967 Merge remote-tracking branch 'origin/master' into master 2021-03-21 07:11:37 +01:00
Ozzie Isaacs d3f8153b90 Merge branch 'master' into development 2021-03-20 19:34:16 +01:00
Ozzie Isaacs 99ecf22790 Merge remote-tracking branch 'origin/master' into master 2021-03-20 18:10:42 +01:00
Ozzie Isaacs b1b7ee65b4 Refactored advanced search 2021-03-20 18:10:27 +01:00
Ozzie Isaacs 6889456662 Merge remote-tracking branch 'adv_search/master' into master 2021-03-20 17:48:21 +01:00
Ozzie Isaacs 081553dc9f Disable blank issue templates 2021-03-20 16:27:47 +01:00
Ozzie Isaacs 5d8d796807 Compatibility for sqlalchemy 2.0 2021-03-20 10:09:08 +01:00
Ozzie Isaacs f3d88fc746 Update sqlalchemy 1.4 working 2021-03-20 09:31:29 +01:00
Ozzie Isaacs d87ccae6c9 Merge branch 'master' into development
# Conflicts:
#	cps/server.py
#	test/Calibre-Web TestSummary_Linux.html
2021-03-19 20:33:38 +01:00
Ozzie Isaacs 2760a7816d Fix metadata recognition fb2 files 2021-03-19 20:32:15 +01:00
Ozzie Isaacs 8f5c649d0f Updated dependency comicapi (removed pypdf2)
Updated dependency pyPDF2 ->pyPDF3
Fixed broken updater in case of http error
Bugfixes from testrun
Bugfix load cover for BasicMetadata
2021-03-19 13:35:52 +01:00
Ozzie Isaacs fcf9e7a1ef Upload pdf fixes:
Handle no title
Handle no author
Fix import of more than one language
Add missing pdf upload publisher handling
2021-03-17 19:06:51 +01:00
Ozzie Isaacs 2be7b6480a Merge remote-tracking branch 'pdf/XMP_Metadata3' into master 2021-03-17 19:05:26 +01:00
cbartondock f5ded86c02 removed extraneous logs 2021-03-16 19:18:57 -04:00
rra 8abfaf0ffd Parse XMP metadata in separate function, add exception, try multiple metadata formats 2021-03-16 17:53:33 +01:00
Ozzie Isaacs b070ba142f Selects are working in user management with generic confirm dialog 2021-03-16 15:52:31 +01:00
Ozzie Isaacs bd7c6828bf Selects are working in user management 2021-03-16 15:03:38 +01:00
cbartondock d0671ec58c Merge branch 'master' of https://github.com/janeczku/calibre-web 2021-03-15 21:09:51 -04:00
cbartondock 1e40ffd1cc merge changes 2021-03-15 21:08:41 -04:00
Ozzie Isaacs da2c3e9ed7 Edit user mass change checkbox working 2021-03-15 16:46:27 +01:00
Ozzie Isaacs f62d6abb69 Merge branch 'master' into development
# Conflicts:
#	cps/server.py
#	test/Calibre-Web TestSummary_Linux.html
2021-03-15 13:53:23 +01:00
Ozzie Isaacs 12ad7a6322 Suppress some errors 2021-03-15 13:52:44 +01:00
Ozzie Isaacs b75247ea3a Suppress some errors 2021-03-15 13:48:05 +01:00
Ozzie Isaacs 9a963bbe79 Refactored code
Testrun
2021-03-15 13:10:17 +01:00
Ozzie Isaacs 994bc8b0e4 Removed dropdown button on single file listen/read (Fix #1840) 2021-03-15 09:06:40 +01:00
Ozzie Isaacs 2451605033 Merge remote-tracking branch 'djvu/read-djvu' into master 2021-03-15 08:43:25 +01:00
Ozzie Isaacs 10942527f3 Merge branch 'master' into development
# Conflicts:
#	test/Calibre-Web TestSummary_Linux.html
2021-03-15 08:22:12 +01:00
Ozzie Isaacs 4909ed5ccd Merge remote-tracking branch 'cliblur/master' into development
# Conflicts:
#	cps/static/css/style.css
2021-03-15 08:21:44 +01:00
Ozzie Isaacs 5cf5df68dc Merge remote-tracking branch 'cliblur/master' into master 2021-03-15 08:19:56 +01:00
Ozzie Isaacs dd32cc99ea Merge remote-tracking branch 'es/patch-1' into master 2021-03-15 08:17:14 +01:00
Ozzie Isaacs 79092dc8eb Merge remote-tracking branch 'it/patch-21' into master 2021-03-15 08:11:41 +01:00
Ozzie Isaacs 6229e4610a Updated teststatus and bugfix convert ebooks 2021-03-15 08:10:42 +01:00
Northguy bfe36d3f4a change in color definition
Making color the same as in:
.container-fluid .book .meta .author, .container-fluid .book .meta .author > a {
    color: hsla(0, 0%, 100%, .45)
}
2021-03-15 00:12:02 +01:00
Northguy d42bf44fad Added same color for series name and series number 2021-03-14 23:46:33 +01:00
rra 33e352819c Merge remote-tracking branch 'upstream/master' into XMP_Metadata3 2021-03-14 19:58:26 +01:00
Ozzie Isaacs 53ee0aaee1 Some functions refactored 2021-03-14 17:34:47 +01:00
Ozzie Isaacs 42707a19bd Code cosmetics 2021-03-14 16:57:33 +01:00
Ozzie Isaacs 0888706790 Code cosmetics 2021-03-14 16:53:01 +01:00
Ozzie Isaacs 16453a05f8 Code cosmetics 2021-03-14 16:02:37 +01:00
Ozzie Isaacs 2fbb7466d3 Code cosmetics 2021-03-14 15:44:40 +01:00
Ozzie Isaacs f29f94f45f Code cosmetics 2021-03-14 15:41:36 +01:00
Ozzie Isaacs cd973868fc Code cosmetics 2021-03-14 15:29:34 +01:00
Ozzie Isaacs 3c35f02cac Code cosmetics 2021-03-14 15:18:45 +01:00
Ozzie Isaacs 22c93e2389 Merge branch 'master' into development 2021-03-14 15:06:20 +01:00
Ozzie Isaacs 8c751eb532 Some code cosmetics 2021-03-14 15:06:09 +01:00
Ozzie Isaacs 4df443e007 Some code cosmetics 2021-03-14 14:40:04 +01:00
Ozzie Isaacs f52fa41439 Fix restart server
Some code cosmetics
2021-03-14 14:29:40 +01:00
Ozzie Isaacs f77d72fd86 Merge branch 'master' into development
# Conflicts:
#	cps/static/css/style.css
2021-03-14 14:06:33 +01:00
Ozzie Isaacs 9b80c84794 Some code cosmetics 2021-03-14 14:05:36 +01:00
Ozzie Isaacs 725fc658f8 Some code cosmetics 2021-03-14 13:28:52 +01:00
alfred82santa 24bbf226a1 Sync reading state only for books on kobo shelves 2021-03-14 11:29:23 +01:00
Ozzie Isaacs e4e27662f5 Merge remote-tracking branch 'url/patch-1' into master 2021-03-14 08:35:37 +01:00
cbartondock 83474da7b5 fixed being able to click through dropdown in advanced search results 2021-03-07 22:54:34 -05:00
cbartondock 9146e5f287 fixed advanced search mass add to shelves in caliblur 2021-03-07 19:53:54 -05:00
cbartondock ff4502c63a Made shelf search user specific 2021-03-07 15:23:05 -05:00
cbartondock 9711bd8fe1 added actions boxes to drop downs 2021-03-06 22:34:39 -05:00
cbartondock 05139e53be advanced shelf search is working 2021-03-06 22:15:18 -05:00
cbartondock 870b2642a9 advanced shelf search is almost working 2021-03-06 21:54:39 -05:00
ElQuimm d31b26ae7d Updated italian message.po
Have a nice day.
2021-03-04 14:26:36 +01:00
Zaroz 5511925ba2 Removed elif "url" identifier format type
Removed elif "url" identifier format type, since else output is identical
2021-03-03 21:18:08 -06:00
Angel Docampo f96b20717d Updated spanish messages.po
Corrected a grammatical error
2021-03-04 00:01:03 +01:00
Zaroz 940c9c45d7 Updated db.py
changed __repr__ else statement to allow for custom id entries
2021-03-02 23:46:02 -06:00
Ozzie Isaacs 87d6008dfc Fix for #1870 (png was missing in supported picture formats for comic viewer) 2021-02-27 09:23:34 +01:00
Ozzie Isaacs b9c0c8d2dc Update bootstrap table to 1.18.2 2021-02-20 20:03:39 +01:00
Ozzie Isaacs 81c30d5fd5 Add missing files from bootstrap editable
Added user-table single-select header for locale and default-language
2021-02-20 19:55:51 +01:00
Ozzie Isaacs 0aa33d88a5 Merge branch 'master' into development 2021-02-20 14:19:39 +01:00
Ozzie Isaacs e64a504bb1 Working Locale and default language selection in user table edit 2021-02-20 14:18:27 +01:00
jvoisin bc876a159e Declare variables before using them
It should fix the following stacktrace:

```
[2021-02-18 14:46:14,771] ERROR {cps:1891} Exception on / [GET]
Traceback (most recent call last):
  File "/opt/calibre/vendor/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/opt/calibre/vendor/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/opt/calibre/vendor/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/opt/calibre/vendor/flask/_compat.py", line 39, in reraise
    raise value
  File "/opt/calibre/vendor/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/opt/calibre/vendor/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/opt/calibre/cps/usermanagement.py", line 38, in decorated_view
    return login_required(func)(*args, **kwargs)
  File "/opt/calibre/vendor/flask_login/utils.py", line 272, in decorated_view
    return func(*args, **kwargs)
  File "/opt/calibre/cps/web.py", line 719, in index
    return render_books_list("newest", sort_param, 1, page)
  File "/opt/calibre/cps/web.py", line 422, in render_books_list
    entries, random, pagination = calibre_db.fill_indexpage(page, 0, db.Books, True, order)
  File "/opt/calibre/cps/db.py", line 610, in fill_indexpage
    return self.fill_indexpage_with_archived_books(page, pagesize, database, db_filter, order, False, *join)
  File "/opt/calibre/cps/db.py", line 635, in fill_indexpage_with_archived_books
    #    book = self.order_authors(book)
UnboundLocalError: local variable 'entries' referenced before assignment
```
2021-02-18 17:02:58 +01:00
Ozzieisaacs 4aa1a838ed Removed f-strings, making it compatible with python 3.5 2021-02-15 14:17:05 +01:00
Ozzieisaacs 095a51edd0 Convert tabs to spaces in server.py (related to #1862) 2021-02-15 13:33:42 +01:00
Ozzie Isaacs a3a11bdf3f Changed checkbox states are saved on server 2021-02-14 17:49:40 +01:00
Ozzie Isaacs 70b503f3d4 Merge branch 'master' into development
# Conflicts:
#	test/Calibre-Web TestSummary_Linux.html
2021-02-13 14:36:42 +01:00
Ozzie Isaacs bbf609b880 Fix #1859 (Upload of jpg files without installed imagemagick doesn't work) 2021-02-13 14:34:41 +01:00
Ozzie Isaacs 0992bafe30 Bulk User management 2021-02-13 13:17:02 +01:00
Ozzie Isaacs c810c5275a Merge branch 'master' into development 2021-02-09 18:05:32 +01:00
Ozzie Isaacs 3c1b06872d Updated testresults
Changed optional-requirements
Prevent redirect 308 on /<data> routes (#1854)
2021-02-09 18:04:56 +01:00
Ozzie Isaacs cefdd2f66c suppress asyncio message always on restart or shutdown 2021-02-08 20:39:21 +01:00
Ozzie Isaacs 5dac13b1da Revert change in ub.py 2021-02-08 20:17:02 +01:00
alfred82santa 6014b04b2a Use BookShelf added_date as date reference 2021-02-08 20:10:12 +01:00
Ozzie Isaacs 8aebf48193 Update handling for package data 2021-02-08 20:09:36 +01:00
Ozzie Isaacs fbb905957b Prevent redirect 308 on /<data> routes 2021-02-08 20:09:36 +01:00
Ozzie Isaacs e0ce135838 Move "create_engine" call 2021-02-08 20:09:36 +01:00
Ozzie Isaacs 60497c60c1 Update creating Home_Config variable for packaging support, added .HOMEDIR to ignored filename during update 2021-02-07 09:20:37 +01:00
Ozzie Isaacs 251a77c8b4 Merge branch 'master' into Development
Improved packaging support
2021-02-07 08:54:29 +01:00
alfred82santa 2b7c1345ee Fix disable shelf kobo sync 2021-02-07 00:21:51 +01:00
alfred82santa 69b7d94774 Fixes and remove shelf kobo sync flag when kobo sync disabled 2021-02-07 00:19:24 +01:00
Ozzie Isaacs 7b7494b8a4 Added executable folder to gitignore 2021-02-06 21:42:29 +01:00
alfred82santa 8fe762709b Fix mistake 2021-02-06 21:15:36 +01:00
alfred82santa a3f17deb17 Added options in order to synchronize only selected shelf on Kobo device 2021-02-06 20:29:43 +01:00
Ozzie Isaacs 9390dcdd43 Update optional requirements 2021-02-06 11:33:20 +01:00
Ozzie Isaacs e6fb460071 New restart routine for executable files
Fix log in updater
New source option updater available
2021-02-06 09:42:27 +01:00
Ozzie Isaacs 6137fdeb33 Version bump 2021-02-02 19:11:02 +01:00
Ozzie Isaacs 4a4d02ea6a Added translations 2021-02-02 19:04:55 +01:00
Ozzie Isaacs be26e5f152 Update Teststatus
Update Version
2021-02-02 18:52:31 +01:00
Ozzie Isaacs 127bfba135 fix wrong path in get_update_status js function 2021-02-01 19:00:10 +01:00
Ozzie Isaacs 7efae3c125 Renamed "Recently Added" to "Books" 2021-01-31 19:20:43 +01:00
Ozzie Isaacs 1e5af21000 Fix #1843 (get path to script via html file and known js file instead of randomly picking last one) 2021-01-31 19:01:34 +01:00
Ozzie Isaacs 33a0a4c173 Changed function for getting path in js file 2021-01-31 18:55:32 +01:00
Ozzie Isaacs eeb7974e05 User table:
Added button for single user edit
Added delete-trash-icon (not working)
Roles are displayed correct per user
Guest user is not visible if anonymous browsing is disabled
2021-01-31 14:54:45 +01:00
Ozzie Isaacs f45ea1a31c Merge branch 'master' into development 2021-01-31 13:21:47 +01:00
Ozzie Isaacs a866dbaa80 Fix mimetype in comic reader 2021-01-31 11:21:09 +01:00
Ozzie Isaacs 62447d6b89 Basic User edit in tables 2021-01-31 10:17:57 +01:00
Ozzie Isaacs 93f0724b83 Merge branch 'development' into master 2021-01-31 09:11:35 +01:00
Ozzie Isaacs 724762843d Update Teststatus 2021-01-31 09:10:42 +01:00
Ozzie Isaacs ff16afbf0b Merge branch 'master' into development 2021-01-30 17:55:45 +01:00
Ozzie Isaacs 9d7ef25062 Fix Kobo sync & Update Teststatus 2021-01-30 17:55:17 +01:00
Ozzie Isaacs 88078d65e9 Fix #1482 (do not shorten title in book detail page) 2021-01-30 14:57:59 +01:00
Ozzie Isaacs b07a97c17e Merge remote-tracking branch 'webp/comic-webp' into master 2021-01-30 14:56:26 +01:00
Ozzie Isaacs 41e7d65e2a Merge remote-tracking branch 'caliblur/master' into master 2021-01-30 14:54:16 +01:00
Ozzie Isaacs 7fa5865cf6 Merge remote-tracking branch 'autoconv/kepub_autoconv' into development
# Conflicts:
#	cps/kobo.py
#	cps/kobo_auth.py
2021-01-30 14:47:18 +01:00
Ozzie Isaacs e0b8fe3b1a Merge branch 'master' into development 2021-01-30 14:41:46 +01:00
Ozzie Isaacs 4a11dd1e16 Fix mistyping "option" 2021-01-28 20:20:59 +01:00
Ozzie Isaacs 34a474101f Fix #1838 (Log message on failed OPDS login) 2021-01-28 20:05:58 +01:00
Ozzie Isaacs e6799e7a04 Improved detection of invalid email addresses (#1831) upon registering 2021-01-27 19:18:40 +01:00
Ozzie Isaacs 0f83f9992c Added swipe support for epub reader (fixes #925)
Cleaned reader js include files
2021-01-24 14:19:46 +01:00
Ozzie Isaacs d2ad78eb40 Added swipe support for comic reader and txt reader (#925)
Bugfix for txt file not present on serving file
2021-01-24 11:28:17 +01:00
Ozzie Isaacs 0b32738f4e Fix Store UI settings in flask session for guest user (#1820)
Updated testresults
Fix Filepicker (absolute instead of abs)
2021-01-24 07:31:40 +01:00
Ozzie Isaacs a9cedb3fca Add logger to db.py 2021-01-23 13:35:30 +01:00
Ozzie Isaacs 51f9cd4bb4 Fix english language names 2021-01-18 21:24:13 +01:00
Ozzie Isaacs a1668e2411 Version Bump 2021-01-17 16:37:54 +01:00
Ozzie Isaacs 9418045a2c Updated Translation
Version bump
Fixed errors in requirements file(s)
2021-01-17 16:28:28 +01:00
Ozzie Isaacs a7da6d210a Added hint for python 2 2021-01-17 10:30:56 +01:00
chbmb 59a41dc844 Correct name for LinuxServer
Nothing important, but it's LinuxServer not Linuxuser.
2021-01-17 09:54:16 +01:00
Ozzie Isaacs e09f2c9beb Added Password change on cli 2021-01-17 09:17:46 +01:00
Ozzie Isaacs 4bc3c8d9ac Added missing mimetype (fix #1811) 2021-01-17 07:54:28 +01:00
Ozzie Isaacs 9acea8adf4 Fixed logging of exception in debug_or_exception handler for python version <3.8 2021-01-12 20:51:49 +01:00
Ozzie Isaacs e5f754ed0e improved session handling 2021-01-11 14:18:01 +01:00
Ozzie Isaacs 263a8f9048 Added catching of missing invalid_request 2021-01-10 14:57:54 +01:00
Ozzie Isaacs 6f9e52792a No autoflush on metadata.db change 2021-01-10 11:01:54 +01:00
Ozzie Isaacs 4a9b01e93b Added IntegrityError to catched error 2021-01-10 10:23:14 +01:00
Ozzie Isaacs b7de23e895 Merge remote-tracking branch 'fix/unused_imports' into master 2021-01-10 10:18:01 +01:00
Ozzie Isaacs f358f78da8 Merge remove duplicate ids 2021-01-10 10:16:58 +01:00
jvoisin b8ab66369e Remove some unused imports 2021-01-07 17:59:08 +01:00
jvoisin 54a78d5565 Remove duplicate id from the search form 2021-01-07 17:40:18 +01:00
mmonkey b4324cd685 Merge remote-tracking branch 'upstream/master' into master 2021-01-04 12:24:11 -06:00
Ozzieisaacs ca212c8737 Kobo sync limit set to 100
Remove python2 support from readme
2021-01-04 18:45:47 +01:00
Ozzieisaacs 6fe4ed3e24 Merge branch 'master' into Develop 2021-01-03 19:28:12 +01:00
Ozzieisaacs a659f2e49d Improved logging for emails
Removed private data from debug export
2021-01-03 19:27:34 +01:00
OzzieIsaacs 760fbbb357 Fix shelf time_created vs. time_last_modified 2021-01-03 16:41:38 +01:00
OzzieIsaacs 56388145b5 Fixes from testrun 2021-01-03 15:40:17 +01:00
Ozzieisaacs cd60db417c Code refactor shelf handling 2021-01-03 11:53:06 +01:00
Ozzieisaacs 5cce01215f Code refactoring ub.session.commit()
Code cosmentics admin.py
2021-01-03 09:53:34 +01:00
mmonkey bc8bdfe385 Merge remote-tracking branch 'upstream/master' into master 2021-01-02 20:21:15 -06:00
Ozzieisaacs 4578af7a6d Fix export of logfiles (#1794) 2021-01-02 20:38:11 +01:00
Ozzieisaacs 9e1cdd8f57 Merge remote-tracking branch 'it/patch-20' into master
# Conflicts:
#	cps/translations/it/LC_MESSAGES/messages.po
2021-01-02 19:37:59 +01:00
OzzieIsaacs 682c3b834f Revert unrar5 experiment 2021-01-02 15:32:06 +01:00
OzzieIsaacs e269bab186 Merge branch 'Develop' into master 2021-01-02 14:54:43 +01:00
OzzieIsaacs 33a89c5d89 Updated test status on Linux 2021-01-02 14:54:10 +01:00
Ozzie Isaacs 139047b22b Updated test status on windows 2021-01-02 14:16:33 +01:00
OzzieIsaacs 9b50114852 Fixes from testrun 2021-01-02 07:51:55 +01:00
Ozzieisaacs b100d198e8 Merge branch 'master' into Develop
Remove relate to referrer for tag/custom column allow / deny dialog
2020-12-31 15:12:37 +01:00
Ozzieisaacs 7849f2fb4b Remove relate to referrer for tag/custom column allow / deny dialog 2020-12-31 15:08:56 +01:00
Ozzieisaacs b35ecddde3 Added Id on Filechooser dialog for testability 2020-12-31 09:54:40 +01:00
Ozzieisaacs bde7921016 Fix modal path id for calibre db filepicker
Fix SyncToken last-Book-id missing
2020-12-30 10:05:15 +01:00
Ethan Lin ee28e3346b Merge pull request #21 from janeczku/master
merge from janeczku/master
2020-12-29 10:31:41 +08:00
Ozzieisaacs d33b0587cb Advanced search tags are now multiselects (#1240) 2020-12-28 13:44:17 +01:00
Ozzieisaacs 7e0ed537b7 irst steps Advanced search with mulitselects 2020-12-27 19:12:27 +01:00
Ozzieisaacs 1e351eb01d Search for read status 2020-12-27 18:59:33 +01:00
Ozzieisaacs 1a83bddf8c Merge bubble read status 2020-12-27 13:53:21 +01:00
Ozzieisaacs 2a63c35743 Activate serverside filepicker with parameter in unconfigured state 2020-12-27 11:27:15 +01:00
Ozzieisaacs 27dcbcd7e1 paged and orderable shelfs
Fix for non writable settings db with non configured calibre-web
2020-12-27 10:24:51 +01:00
mmonkey 0cf4c7b7b7 Merge remote-tracking branch 'upstream/master' into master 2020-12-24 03:01:55 -06:00
ElQuimm 623372387d Update italian message.po
Merry Christmas and Happy Holidays :-)
2020-12-23 13:45:19 +01:00
OzzieIsaacs abf0f4d699 Updated Testresult
Fixed delete book call
2020-12-23 10:08:54 +01:00
Ozzieisaacs 2bea447de5 Fix show archived books 2020-12-23 09:07:49 +01:00
Ozzieisaacs f6538b6110 New delete user button
refactored confirm dialogs
2020-12-21 19:50:12 +01:00
Ozzieisaacs 2d3ae71a3d Fixed button for email config (Fix #1766) 2020-12-21 19:13:55 +01:00
Ozzieisaacs 9a20faf640 Revert accidentally deleted lines in caliblur! theme 2020-12-17 19:10:02 +01:00
andylizi 123493ee59 Fix #1255 (support webp in comic viewer) 2020-12-17 23:54:06 +08:00
mmonkey 2d498dd138 Preserve publisher links, and fix formatting in custom columns for CaliBlur theme. 2020-12-16 00:58:45 -06:00
Ozzieisaacs 376214e2d2 Pinned greenlet to 0.4.16 max 2020-12-13 18:33:20 +01:00
Ozzieisaacs 62da469fd1 Shelfs are now paginated (sorting buttons are disabled)
Changed gevent dependencys
2020-12-13 18:32:44 +01:00
Ozzieisaacs d64009e23e preparation for filtered and ordered shelfs 2020-12-13 13:54:09 +01:00
Ozzieisaacs fd8b642d64 Code cosmetics css
Code cosmetics js
Fixes for links with remote_login
2020-12-13 09:53:18 +01:00
OzzieIsaacs d5ed5cd665 Fixes from tests 2020-12-12 15:16:22 +01:00
OzzieIsaacs fa95d064ff Fix get_sidebar_config 2020-12-12 12:03:11 +01:00
Ozzieisaacs 1905e0ee6f refactoring to prevent web.py being the middle of the universe 2020-12-12 11:23:17 +01:00
Ozzieisaacs 96b18faea1 Merge remote-tracking branch 'nl/master' into master 2020-12-12 10:06:16 +01:00
Ozzieisaacs 0d7f2e157a Update Download Debug package
- include config
- bugfix for stream logger
2020-12-12 10:02:11 +01:00
Marcel 2d66936d8b NL translation update
NL translation update
2020-12-12 09:24:01 +01:00
Ozzieisaacs b637a63e71 Refactored exception logging 2020-12-12 08:11:00 +01:00
Ozzieisaacs 1ae778d81e Fix #1753 (errorhandling on route serve_book) 2020-12-12 06:49:44 +01:00
Ozzieisaacs f4412ee96b Fix #1753 (errorhandling on route serve_book) 2020-12-12 06:41:12 +01:00
Ozzieisaacs 9130aceb5a Changed admin page 2020-12-11 20:55:09 +01:00
Ozzieisaacs b8336c03c3 Changed admin page 2020-12-11 20:54:24 +01:00
Ozzieisaacs 76c3ade394 Changed logging in worker thread 2020-12-11 17:03:18 +01:00
Ozzieisaacs d9b22fd513 log exceptions only in debug mode 2020-12-11 16:46:02 +01:00
Ozzieisaacs 88ea998f8b Only register gdrive callback if gdrive is enabled
With enabled gdrive return on change if no watch callback is configured, instead of send request to google drive
2020-12-11 15:56:42 +01:00
Ozzieisaacs 8b605aeaa8 Only register gdrive callback if gdrive is enabled 2020-12-11 15:53:10 +01:00
Ozzie Isaacs db91577485 Use calibre-web folder in tempdir on upload cover and metadata backup
fix upload cover on windows (slash vs. backslash)
2020-12-11 13:34:29 +01:00
Ozzie Isaacs 5d9404863d Fix detection and removal of metadata.db ending in calibre-directory
Update requirements
2020-12-11 09:11:17 +01:00
Ozzieisaacs d3986ca14a Server side file browser 2020-12-11 08:37:37 +01:00
Ozzieisaacs 2508c1abb2 Started implement server side filechooser 2020-12-10 14:41:45 +01:00
OzzieIsaacs 983e3b2274 Bugfix allowed formats for comics
Bugfix editing archived books
2020-12-09 19:02:10 +01:00
Ozzieisaacs 72a02e087c Update optional pydrive requirement
Bugfix cover url download for Wand insted of Pillow
Fix for gdrive with unknown certificates
2020-12-09 15:14:08 +01:00
Ozzieisaacs 352b4a0b73 Remove Pillow as dependency 2020-12-09 14:18:39 +01:00
Ozzieisaacs d957b2d20f Fix detect correct encoding for txt-reader 2020-12-09 11:04:29 +01:00
Ozzieisaacs dcab8af8ab Fixes for kobo sync 2020-12-09 09:41:23 +01:00
OzzieIsaacs e1987c34d9 Revert expire on commit 2020-12-09 08:49:18 +01:00
OzzieIsaacs a80a8aab1c Fix LDAP import user 2020-12-08 20:13:36 +01:00
OzzieIsaacs d6fbcdb09d Fix merge problem (ub prefix in ub.py) 2020-12-08 13:56:17 +01:00
OzzieIsaacs d39b28b011 Fix for existing book format with gdrive 2020-12-08 13:34:15 +01:00
OzzieIsaacs 8f36128fe3 Merge branch 'session' into Develop 2020-12-08 11:49:39 +01:00
OzzieIsaacs 986d4c99bd Fix oauth ub session 2020-12-08 11:24:20 +01:00
Ozzieisaacs f677dcb1f4 Fix missing optional parameter initSession 2020-12-08 08:19:18 +01:00
Ozzieisaacs 1a9b220ec2 Session no longer expires on commit (only in worker thread) 2020-12-08 08:04:46 +01:00
Ozzieisaacs d15d252af7 Session no longer expires on commit 2020-12-08 08:01:42 +01:00
Ozzieisaacs 5e3618716d Fix missing session rollback on commit error 2020-12-07 19:53:34 +01:00
Ozzieisaacs f13522559d Fixed problems on startup with config session 2020-12-07 13:51:52 +01:00
Ozzieisaacs 777c2726d3 Changed session_handing 2020-12-07 08:52:52 +01:00
Ozzieisaacs c25afdc203 Chunked sync 2020-12-06 13:21:25 +01:00
Ozzieisaacs c25f6d7c38 Prefer kepub in kobo sync 2020-12-06 06:01:10 +01:00
Ozzieisaacs 388e46ee81 Merge remote-tracking branch 'prefer_kepub/prefer-kepub' into master (send kepub instead of epub) 2020-12-06 05:57:56 +01:00
Ozzieisaacs 242866948f Merge branch 'master' into Develop 2020-12-05 08:34:12 +01:00
Ozzieisaacs 15bb0ce990 Fix for #1439 (send kepub file instead of epub for kobo epub3 request)
Fix archived books are editable
2020-12-04 19:23:36 +01:00
Ozzieisaacs a82911ea5d Fixed missing variable exception 2020-12-04 14:50:34 +01:00
Ozzieisaacs 9a8f20317b Update ldap import user -> improve error messages 2020-12-04 11:13:39 +01:00
Ozzieisaacs b605a0f622 Update error message LDAP import user 2020-12-03 21:25:02 +01:00
Ozzieisaacs 046a074c3a Catch attribute error on ldap import user
Fixes for Login with Windows AD
2020-12-03 20:15:31 +01:00
Ozzieisaacs 7c96fac95c Removed unnecessary parameters 2020-12-03 17:33:30 +01:00
Ozzieisaacs a3ef53102d Fix warning message on ldap import 2020-12-03 17:08:51 +01:00
Ozzieisaacs 68513b775b Wording 2020-12-03 16:20:31 +01:00
Ozzieisaacs a79dcc93f6 Fixed description for LDAP filter 2020-12-03 16:19:42 +01:00
Ozzieisaacs 7aabfc573b Merge branch 'master' into Develop
# Conflicts:
#	cps/admin.py
#	cps/config_sql.py
#	cps/templates/config_edit.html
#	cps/web.py
2020-12-03 16:03:37 +01:00
Ozzieisaacs 22dde5d18e Merge remote-tracking branch 'ldap_import/feat/ldap-import-user-identifier' into Develop
# Conflicts:
#	cps/admin.py
2020-12-03 16:02:38 +01:00
Ozzieisaacs 56505457eb Merge remote-tracking branch 'ldap_import/feat/ldap-import-user-identifier' into master
# Conflicts:
#	cps/admin.py
2020-12-03 16:01:15 +01:00
Ozzieisaacs 5930c6d5fb remove parenthesis in LDAP Message 2020-12-03 14:22:37 +01:00
Ozzie Isaacs 6b162a4e49 Updated windows testresult 2020-12-03 11:36:40 +01:00
Ozzieisaacs c3b9888b31 Fix #1739 (opds download with anonymous browsing enabled) -> download rights of guest user are now respected again 2020-12-03 09:42:41 +01:00
Ozzieisaacs cb8dfdde4c Fix #1739 (opds download with anonymous browsing enabled) 2020-12-03 08:25:36 +01:00
OzzieIsaacs ff5d333fc8 Updated testresult 2020-12-02 18:23:28 +01:00
Ozzieisaacs 8eb4b6288a Added id's for testablility 2020-12-02 18:19:30 +01:00
Ozzieisaacs f18836be90 Fix for #1435 (download not allowed with for opds links, with ldap login and a cookie in the download request) 2020-12-02 14:19:49 +01:00
Ozzieisaacs 3372070a58 Fix change title regex
Merge branch 'Develop' into master
2020-12-02 11:09:55 +01:00
Ozzieisaacs f99e2ebd13 Changed wording for tooltips 2020-12-02 09:08:56 +01:00
Ozzieisaacs 4feb26eefb Added series order option (#1715)
Added authors order option (#1301)
Added tooltips for ordering options
Fixed ratings, formats, languages order option
2020-12-01 14:51:25 +01:00
Ozzieisaacs 2da7cd2064 Merge remote-tracking branch 'it/patch-18' into master 2020-12-01 14:11:25 +01:00
Ozzieisaacs 9d7daf7afd Kobo links to /v1/products/books/external are responded
Merge remote-tracking branch 'kobo/patch-1' into master
2020-12-01 14:03:03 +01:00
Ozzieisaacs cb1ebc1cd0 Drag 'n drop for files 2020-12-01 13:52:41 +01:00
Ozzieisaacs 6ad56a0859 Merge branch 'master' into Develop 2020-11-30 18:37:14 +01:00
Ozzieisaacs 8515781564 Fix #1727 (import rarfile 4.0 fails on python3.5) 2020-11-30 18:36:45 +01:00
ElQuimm 7e2bfbd255 update italian message.po
some minors changes.
2020-11-26 14:35:15 +01:00
Jennifer Thakar e2325f7ba4 Forward Overdrive requests to Kobo Store
When loading books from OverDrive, Kobo readers make requests to `/v1/products/books/external/<overdrive ids>`.
This adds a route to forward these requests to the Kobo Store, so that OverDrive still works when using Calibre-Web's Kobo sync server.
2020-11-22 15:06:37 -08:00
OzzieIsaacs 9afdab8c52 Fix from merge convert_from _to 2020-11-22 11:57:10 +01:00
Ozzieisaacs f620d4a9ca Fix LDAP errors 2020-11-22 11:19:14 +01:00
Ozzieisaacs fb1e763bbe Fix browser caching problem on change cover 2020-11-22 10:07:25 +01:00
Ozzieisaacs ecea7e7493 Revert "Fix browser caching problem on change cover"
This reverts commit b9536812f4.
2020-11-22 10:06:54 +01:00
Ozzieisaacs 560ade00b4 Fix browser caching problem on change cover 2020-11-22 10:03:10 +01:00
Ozzieisaacs 81ea24ad54 Merge branch 'master' into df 2020-11-22 09:34:11 +01:00
Ozzieisaacs 747b25046a Merge branch 'master' into Develop 2020-11-22 09:16:27 +01:00
Ozzieisaacs b9536812f4 Fix browser caching problem on change cover 2020-11-22 09:09:41 +01:00
Ozzieisaacs eed2f0a430 Merge remote-tracking branch 'comic/master' into master 2020-11-22 08:45:02 +01:00
Ozzieisaacs 31fe8cd263 Improvement for #1721 (shrinked generic cover) 2020-11-22 08:28:52 +01:00
Ozzieisaacs a3fadbaa1a Shrinked size of generic cover 2020-11-22 08:28:10 +01:00
Ozzieisaacs e2be655d74 Update LDAP, fix Windows AD login (#1697) 2020-11-22 08:17:00 +01:00
Ozzieisaacs 2cd653c773 Merge remote-tracking branch 'origin/Develop' into Develop 2020-11-22 08:08:57 +01:00
Ozzieisaacs 6538aff02f Merge branch 'master' into Develop 2020-11-22 08:08:27 +01:00
OzzieIsaacs c1e3dec9be Limit max requests version to 2.25 (testing problem) 2020-11-21 17:21:18 +01:00
Ozzieisaacs 42c13ae135 Fix for #1718 (fetch of metadata from google without cover leads to exception) 2020-11-20 20:35:07 +01:00
Ozzieisaacs 9bd51c650b Add config options for client certificate authentication 2020-11-20 19:47:50 +01:00
Ozzieisaacs ba1c1c87c4 Merge remote-tracking branch 'kobo/feature/use-kobo-specific-download-urls' into Develop 2020-11-20 19:47:25 +01:00
Ozzieisaacs ceefba2743 Fix for #1550 (password prompt for LDAP and anonymous browsing) 2020-11-15 17:16:01 +01:00
Ozzieisaacs 70da46b05e Merge branch 'master' into Develop 2020-11-15 16:15:02 +01:00
Ozzieisaacs 32b7b39223 Added function to download debug information 2020-11-15 14:25:27 +01:00
verglor 2343c79126 Use djvu_html5 to read djvu format in browser 2020-11-15 13:19:37 +01:00
verglor 09a5a69f86 djvu_html5 0.3.0-beta1 static assets 2020-11-15 13:09:32 +01:00
Ozzieisaacs 4081895a78 exclude _pysqlite.so from being overwritten 2020-11-14 15:53:56 +01:00
Ozzieisaacs a522566a0c Merge remote-tracking branch 'kepubify/patch-1' into master 2020-11-14 13:24:58 +01:00
Ozzieisaacs 013c4e9c35 Merge remote-tracking branch 'epub/recompute_epub' into master 2020-11-14 13:22:42 +01:00
Ozzieisaacs 067f289050 Merge remote-tracking branch 'comic/comic' into master 2020-11-14 13:21:56 +01:00
Ozzieisaacs 06511b92aa Merge remote-tracking branch 'epub/GruberMarkus-patch-1' into master 2020-11-14 13:20:26 +01:00
Ozzieisaacs 32f4c9eabf Merge remote-tracking branch 'fr/master' into master 2020-11-14 13:16:08 +01:00
Ozzieisaacs 14bc345883 Merge remote-tracking branch 'audio/fix-audio-icon' into master 2020-11-14 13:14:21 +01:00
Ozzieisaacs d76b4fd7ea Merge remote-tracking branch 'it/patch-17' into master 2020-11-14 13:12:36 +01:00
ElQuimm 83cdd7e9fb update italian message.po
some minor update to the translation.
2020-11-13 11:17:46 +01:00
verglor 50441bae62 Fix missing audio icon for other audio formats than mp3 2020-11-10 18:08:22 +01:00
Martin 5b0766a9b0 Correct spelling 2020-11-10 10:06:37 +01:00
Martin d979fe8e5f fix fr translation : sed cryptage/chiffrement 2020-11-10 10:04:47 +01:00
Markus Gruber f2c52fd278 Update jszip to 3.5.0. Update epub.js to 0.3.88.
Fixes several problems when viewing EPUBs in a browser, for example when jumping to a certain chapter in the table of contents does not work.
2020-11-09 15:47:27 +01:00
Ozzieisaacs 87d60308f2 Merge remote-tracking branch 'caliblur/issue/caliblur-981' into master 2020-11-08 19:29:10 +01:00
L0garithmic 64ebc56c87 Kepubify
the current link sends you to a specific version. The link I suggest, sends you to the "latest" version.
2020-11-08 09:31:53 -06:00
Ozzieisaacs 58d485cbb5 Fix #1702 (invalid timestamps during kobo sync caused by malformed database) 2020-11-07 12:49:39 +01:00
Ozzieisaacs e99dd3310c Exchanged douban apikey 2020-11-07 12:18:33 +01:00
Ozzieisaacs 400f6e02a5 Fix #1668 (upload of books with language set to different than UI language and not showing all books)
Fix for only showing external port if kobo is really activated in admin menu
2020-11-07 11:44:02 +01:00
jvoisin 700b0609df Don't recompute metadata for epubs 2020-11-06 21:36:49 +01:00
cbartondock bc52f90ed4 Merge remote-tracking branch 'upstream/master' 2020-11-02 11:36:45 -05:00
Ozzieisaacs 0771546dad Log exception on user import 2020-11-01 18:25:38 +01:00
jvoisin 95a1a71a66 Minor refactor of comic.py 2020-10-31 22:28:24 +01:00
OzzieIsaacs b9b8e3f632 Update testresults 2020-10-31 20:12:22 +01:00
Ozzieisaacs 1e03a2ae40 Merge branch 'master' into Develop 2020-10-31 20:07:41 +01:00
Ozzieisaacs 25da6aeeca Merge remote-tracking branch 'sec_fixes/space' into master 2020-10-31 20:04:42 +01:00
Ozzieisaacs 00b422807b Merge remote-tracking branch 'sec_fixes/edit_auth' into master 2020-10-31 20:04:12 +01:00
Ozzieisaacs 130701a7bb Merge remote-tracking branch 'sec_fixes/admin_update' into master 2020-10-31 20:02:42 +01:00
Ozzieisaacs ff88e68904 Add missing locale files 2020-10-31 19:58:22 +01:00
Ozzieisaacs 55fcf23d2b Merge remote-tracking branch 'sec_fixes/negate' into master 2020-10-31 19:37:47 +01:00
Ozzieisaacs 1b0b4c4cc5 Merge remote-tracking branch 'sec_fixes/ldap' into master 2020-10-31 19:29:17 +01:00
Ozzieisaacs cd57731593 Merge remote-tracking branch 'sec_fixes/unused_imports' into master 2020-10-31 19:24:46 +01:00
Ozzieisaacs 37a80b935d Added greek translation 2020-10-31 19:20:00 +01:00
Ozzieisaacs 4d61aec153 Merge remote-tracking branch 'zh/trans' into master 2020-10-31 19:07:10 +01:00
Ozzieisaacs 1adf25d50b Update Italian translation 2020-10-31 19:06:09 +01:00
Julian Naydichev ae33aee3f6 When serving a download URL via KoboSync, use a URL that is specific to Kobo 2020-10-31 14:50:08 +01:00
jvoisin 2c99e71626 Remove a superfluous space 2020-10-29 18:17:32 +01:00
jvoisin e7f7775efa Require edit permissions to edit books, even via ajax 2020-10-29 14:52:20 +01:00
jvoisin 8b60a19577 Don't leak to non-admin users the current installed version 2020-10-29 14:03:18 +01:00
Ozzieisaacs 5701e08db9 Fix for #1668 2020-10-28 20:37:52 +01:00
Ozzie Isaacs 72a2fc49f8 Update Windows testresults 2020-10-28 20:23:19 +01:00
jvoisin d2617322c6 Negate a condition
- removes two levels of indentation
- makes it clear that if the wrong tokens are provided nothing will happen
- remove a useless nested function
2020-10-27 19:41:05 +01:00
jvoisin fa82745f64 Put import_ldap_users behind a login 2020-10-27 19:26:04 +01:00
jvoisin 19b2a334e4 Remove unused imports 2020-10-27 11:06:43 +01:00
vagra 627c2adf08 SImple Chinese translation updated. 2020-10-26 22:56:58 +08:00
ElQuimm e3e137ca50 updated italian message.po 2020-10-22 16:31:25 +02:00
cbartondock 0978be580f Merge remote-tracking branch 'upstream/master' 2020-10-21 13:01:25 -04:00
Ozzieisaacs 5792838333 Add OSError to catched Gevent Error 2020-10-20 17:38:37 +02:00
Ozzieisaacs f9995583a5 Merge remote-tracking branch 'translate/patch-1' into master 2020-10-20 17:12:25 +02:00
KN4CK3R 4cc68bd139 Fixed typo. 2020-10-20 13:45:01 +02:00
cbartondock d2510ad1bc Merge remote-tracking branch 'upstream/master' 2020-10-17 21:46:26 -04:00
celogeek 4d81d3613c display the check when books are read 2020-10-17 16:49:57 +02:00
celogeek 7d28963a32 connect read books to all render 2020-10-17 16:49:38 +02:00
celogeek b2594468b4 add helper to get all read books 2020-10-17 16:49:06 +02:00
celogeek 754b9832e9 fix height container 2020-10-17 13:30:19 +02:00
celogeek 097ac879ea render read 2020-10-17 13:24:46 +02:00
Ozzieisaacs bc0416cbb4 Fix for #1660 (advanced search for custom columns working, headline for advanced search working) 2020-10-16 20:24:15 +02:00
Ozzieisaacs 2814617e4b Fix for #1660 (Pagination in advanced search not working, error 500 for no filter in advanced search)
Fix #1666 (Pagination in search not working)
2020-10-16 19:56:24 +02:00
cbartondock da9dfd166d fixed incorrect cover widths 2020-10-16 13:51:48 -04:00
cbartondock 1be07a42df Flex display to fix columns issue 2020-10-16 13:41:48 -04:00
cbartondock 1d83a6a898 distinguish convert from and convert to extensions 2020-10-16 11:51:59 -04:00
Ghighi 2ff286b672 natural solution, pagination is changing on new page 2020-10-16 00:43:57 +03:00
Ozzie Isaacs e8620a0986 Fix logging error on windows with invalid goodreads key/secret 2020-10-14 20:48:01 +02:00
Ozzie Isaacs 7fb18bbdc7 Update Testresults on windows 2020-10-14 19:54:58 +02:00
Ozzieisaacs 5b67b687d3 Removed remaining code from view downloaded books in user section
Fixes for #1661
2020-10-13 19:45:27 +02:00
Ghighi Eftimie 9adcfa99f4 trigger infinite scroll script only on templates where .load-more class is present 2020-10-11 22:35:56 +03:00
Ghighi Eftimie e723aaa5f6 fix for history state (+1 not needed) 2020-10-11 21:56:49 +03:00
Ozzie Isaacs d128b037a5 Fix for editing files on windows 2020-10-11 18:01:26 +02:00
Ozzieisaacs 99fda00442 Merge remote-tracking branch 'caliblur/issue/caliblur-1560' into master 2020-10-11 12:43:21 +02:00
Ghighi Eftimie f574f8faf0 better js check 2020-10-10 18:34:55 +03:00
Ghighi Eftimie cedfa90d76 fix for #981 2020-10-10 17:51:46 +03:00
Ghighi Eftimie f1e6f6e505 fixes for #1560 2020-10-10 14:58:06 +03:00
Ghighi Eftimie b4f95cced7 Merge remote-tracking branch 'upstream/master' 2020-10-10 14:51:55 +03:00
Ozzieisaacs e16c0caebb Fix opds search 2020-10-10 12:53:10 +02:00
Ozzieisaacs 52489a484a Merge remote-tracking branch 'Knepherbird/master' into master
# Conflicts:
#	cps/jinjia.py
#	cps/templates/detail.html
#	cps/templates/discover.html
#	cps/templates/index.html
#	cps/web.py
2020-10-10 12:47:49 +02:00
Ozzieisaacs e1d5c2c578 Merge remote-tracking branch 'caliblur/issue/caliblur-1594' into master 2020-10-10 12:29:30 +02:00
Ozzieisaacs 49f49632ad Renamed CalibLur.css 2020-10-10 12:22:52 +02:00
Ghighi Eftimie 6dadc6fb1e same fix but hopefully better 2020-10-10 13:15:02 +03:00
Ozzieisaacs a58a2f5fe4 Added missing file for tr locale of datepicker 2020-10-10 11:53:15 +02:00
Ghighi Eftimie c33c6bbff0 fix for #1594 2020-10-10 12:39:52 +03:00
Ozzieisaacs 093f90d4c1 Update translation files 2020-10-10 11:38:40 +02:00
Ozzieisaacs 20ffa325d3 Fix #1642 2020-10-10 10:53:08 +02:00
Ghighi Eftimie 5027304801 Merge remote-tracking branch 'upstream/master' 2020-10-10 11:50:19 +03:00
Ozzieisaacs 85d5afd6d9 Merge branch 'Develop' into master 2020-10-10 10:38:11 +02:00
OzzieIsaacs df295e92ee Merge remote-tracking branch 'origin/Develop' into Develop 2020-10-10 10:33:12 +02:00
Ozzieisaacs 2e67bd2407 Fix add to shelf from search 2020-10-10 10:32:53 +02:00
OzzieIsaacs 9aa01ee8cf Merge branch 'master' into Develop 2020-10-10 10:14:33 +02:00
OzzieIsaacs 6b993ad329 Update test results 2020-10-10 10:14:09 +02:00
OzzieIsaacs d70ded0993 Fix for search 2020-10-10 07:47:27 +02:00
OzzieIsaacs 3dacdcc8bb Merge remote-tracking branch 'worker/db' into Develop 2020-10-10 07:31:08 +02:00
OzzieIsaacs bb03026589 Fixes from merge problems 2020-10-10 07:30:03 +02:00
Ghighi Eftimie 2f69e3141e Merge remote-tracking branch 'upstream/master' 2020-10-07 09:16:34 +03:00
Ozzieisaacs 1f4564da76 Merge remote-tracking branch 'es/patch-1' into master 2020-10-06 21:48:42 +02:00
OzzieIsaacs 3b8e5ddfb3 Merge remote-tracking branch 'worker/db' into Develop
# Conflicts:
#	cps/tasks/convert.py
2020-10-06 21:40:47 +02:00
Nacho Soler edc293f96a Update
Add some missings translations
2020-10-06 16:43:00 +02:00
blitzmann 3fa4149bb0 Fix reference issue 2020-10-05 23:15:42 -04:00
OzzieIsaacs 4b68a6ff23 Updates tests 2020-10-04 19:25:06 +02:00
Ozzieisaacs 28116c49dc Merge branch 'worker_task' into Develop 2020-10-04 19:23:32 +02:00
Ozzieisaacs 6e6f144b7a Paginated search and advanced search
Wraparound on books list deactivated
2020-10-04 19:23:06 +02:00
Ozzieisaacs e3f4f24c3e Fixes for failed email and conversions with gdrive 2020-10-04 13:59:33 +02:00
Ozzieisaacs eb37e3a52b Fix UI Deelete Buttons in Edit Books page
Fix Conversion of multiple formats of one book in the queue with gdrive
2020-10-04 12:09:52 +02:00
Ozzieisaacs 95d540630e Change ldap_certpath to file 2020-10-04 06:15:35 +02:00
Ozzieisaacs 23d66a0d68 Fix 2020-10-03 21:43:48 +02:00
Ozzieisaacs 0d64692c84 Fix for convert + email task with gdrive 2020-09-30 19:29:57 +02:00
Ozzieisaacs 1cb640e51e Update minimum required version of SQLAlchemy (Fix #1641) 2020-09-29 18:19:00 +02:00
Ozzieisaacs 2d98285545 Update minimum required version of SQLAlchemy 2020-09-29 18:16:56 +02:00
OzzieIsaacs 376001100a Bugfixes from last testrun 2020-09-28 21:24:47 +02:00
Ozzieisaacs e2954249f8 Update chinese translation 2020-09-27 19:22:41 +02:00
Ozzieisaacs cc0b0196f4 Store UI settings in flask session for guest user 2020-09-27 19:12:10 +02:00
Ozzieisaacs 6dfa171b4e Added id's for testing
moved downloaded books section
2020-09-27 16:00:17 +02:00
Ozzieisaacs b140073988 Merge branch 'master' into Develop
Fix #1629 (Gevent Tracebacks with SSL encryption)
2020-09-27 13:02:25 +02:00
Ozzieisaacs c22bc857b0 Fix #1629 (Gevent Tracebacks with SSL encryption) 2020-09-27 13:00:07 +02:00
Ozzieisaacs 497fbdcdfc Save view settings 2020-09-27 12:37:41 +02:00
Ozzieisaacs 861f1b2ca3 Merge branch 'master' into Develop
# Conflicts:
#	test/Calibre-Web TestSummary_Linux.html
2020-09-27 08:54:32 +02:00
Ozzieisaacs 6108ef4c89 Version update to 0.6.10 Beta 2020-09-27 07:43:56 +02:00
OzzieIsaacs a9c0bcb4a2 Updated testresults
Version bump for release
2020-09-27 07:15:03 +02:00
Ozzie Isaacs 8f9de05768 Update Test results windows 2020-09-27 06:33:41 +02:00
Ozzieisaacs e61e94f0fa Merge remote-tracking branch 'it/patch-15' into master
Updated Translations
2020-09-26 16:19:34 +02:00
Ozzieisaacs 85aac02593 Merge remote-tracking branch 'css/master' into master 2020-09-26 16:13:53 +02:00
Ozzieisaacs 9a678c41fe Fix error from merge 2020-09-26 09:42:40 +02:00
Ozzieisaacs 7c8f6ce62f Merge branch 'master' into Develop
# Conflicts:
#	cps/comic.py
#	cps/editbooks.py
#	cps/isoLanguages.py
2020-09-26 07:54:38 +02:00
Ozzieisaacs 9a896ea81e Removed logging of headers as it caused trouble while showing logfile in UI 2020-09-26 07:51:29 +02:00
Ozzieisaacs 422c1893c0 Fix for the fix cover_url 2020-09-24 11:02:12 +02:00
ElQuimm f1cb5276d7 Update italian message.po
removed typo line 127
2020-09-24 10:54:06 +02:00
Ozzieisaacs bed1b24340 Fixes from test of upload restrictions 2020-09-24 10:54:02 +02:00
Ozzieisaacs da909ff084 Fixes from test of upload restrictions 2020-09-23 20:50:34 +02:00
Ozzieisaacs 8f743b70a4 Revert the tolino stuff 2020-09-22 20:25:58 +02:00
Ozzieisaacs a761017116 Additional debug output for #1527 2020-09-21 19:09:02 +02:00
Ozzieisaacs f06cc25a99 Fix for immediate logout with next="/logout"
Fix tolino per default with deactivated Strict-Transport-Security
2020-09-21 18:34:39 +02:00
Ozzieisaacs eff8480d5c Show listen in browser formats in lowercase 2020-09-21 18:24:50 +02:00
Ozzieisaacs eec303de49 Fix #1621 (Link to contributing.md file wrong) 2020-09-21 14:18:23 +02:00
ElQuimm 07a936c5e8 italian version of messages.po updated 2020-09-21 10:53:29 +02:00
Ryan Long a6002a2c6c 1622_updated_css 2020-09-20 23:41:20 -04:00
Ozzieisaacs 7ba014ba49 Fix "is not a valid language" on upload of comic books
Fix metadata excration of comic books
updated bootstrap table
updated handling of upload formats restrictions
2020-09-20 15:05:52 +02:00
Ozzieisaacs 165c649f31 Fix "is not a valid language" on upload 2020-09-20 11:44:03 +02:00
Ozzieisaacs 4cf71dd336 Fix "is not a valid language" on upload 2020-09-20 11:41:44 +02:00
Ozzieisaacs c0a401216b Add links to contribution guidelines 2020-09-20 10:10:58 +02:00
Ozzieisaacs 2d712a3841 Fix #1612 2020-09-20 10:03:05 +02:00
Ozzieisaacs a2b5b4dd17 Merge remote-tracking branch 'identifier/master' into master 2020-09-20 10:01:46 +02:00
blitzmann 0480edce2a Clarify need for WeakSet 2020-09-18 21:52:45 -04:00
Alexander Yakovlev 4eded82102 Add ISFDB 2020-09-15 17:39:13 +07:00
Alexander Yakovlev ec4ff83465 Add ISSN tags 2020-09-15 13:50:34 +07:00
Alexander Yakovlev 8745b8b051 nice title for Litres tags 2020-09-15 13:47:57 +07:00
Alexander Yakovlev 4e28c3cadb add Litres references 2020-09-15 13:41:01 +07:00
blitzmann 76c724c783 Remove global session object, this is now wrapped in the CalibreDB class 2020-09-13 21:37:47 -04:00
blitzmann 032cb59388 Fix resetting the session when first configuring the calibre-db on first boot up 2020-09-13 13:16:11 -04:00
OzzieIsaacs e29247774c Bugfixes for uploading books to GDrive with new worker 2020-09-12 13:55:36 +02:00
blitzmann 18d16f9a8b Initial attempt at setting up CalibreDB as a class that carries the engine and DB connection, and the instance being the session 2020-09-11 22:52:40 -04:00
OzzieIsaacs d137735be1 Fix #805 (First request to gdrive fails) 2020-09-11 20:56:54 +02:00
dickreckard 65929c02bc isolanguage parsing of xmp data 2020-09-11 10:49:45 +00:00
root 22466d6b98 xmp data processing added to the uploader 2020-09-11 10:08:55 +00:00
dickreckard 23fe79c618 Update uploader.py 2020-09-11 03:42:19 +02:00
OzzieIsaacs b202ca5619 Updated test result 2020-09-09 07:00:09 +02:00
OzzieIsaacs 7929711fea Improvements for file uploading format restriction 2020-09-08 20:57:39 +02:00
OzzieIsaacs 49a028a599 Bugfix not unlink generic cover on upload 2020-09-08 19:04:04 +02:00
OzzieIsaacs 670cbcd336 Merge branch 'master' into Develop 2020-09-07 21:33:11 +02:00
Ozzieisaacs 449d31e8a1 Refactored update_dir_structure_file 2020-09-07 21:26:59 +02:00
Ozzieisaacs fe82583813 Merge branch 'database_fix' into Develop 2020-09-07 21:23:35 +02:00
Ozzieisaacs 1450a21d00 Fix links to amazon (#1461) 2020-09-07 18:27:43 +02:00
Ozzieisaacs ae15544aed Merge branch 'master' into database_fix
# Conflicts:
#	cps/editbooks.py
2020-09-07 18:21:33 +02:00
Ozzieisaacs 4b7a37cf7d Bugfix empty email attachment size 2020-09-07 18:19:54 +02:00
dickreckard cb7727900c Update uploader.py
default cover changed from none to pdf_preview when metadata parsing fails
2020-09-07 13:30:03 +02:00
Ozzieisaacs e012726cd4 Fix #1461 (parse Amazon_* identifiers) 2020-09-06 19:31:31 +02:00
Ozzieisaacs f49688fdb9 Fix #1461 (parse Amazon_* identifiers) 2020-09-06 19:31:03 +02:00
Ozzieisaacs e32b017431 Revert "Test revert global Session"
This reverts commit 393869e538.
2020-09-06 10:59:34 +02:00
Ozzieisaacs 393869e538 Test revert global Session 2020-09-06 10:27:10 +02:00
Ozzieisaacs d3bde0408f Improvederror handling for editing identifier 2020-09-05 18:47:28 +02:00
Ozzieisaacs 34d3225984 Errorhandling edit identifier 2020-09-05 18:46:11 +02:00
Ozzieisaacs eaed53e25b Fix for author edit error (2 same sort_authors lead maybe to choose wrong one) 2020-09-05 18:23:14 +02:00
OzzieIsaacs feacbe8ebd Possible Fix for database crash after adding new format and accessing calibre database afterwards 2020-09-05 10:24:32 +02:00
norangebit bdf6052388 Conversion to kepub when creating a sync token 2020-09-03 21:57:14 +02:00
Ozzieisaacs ec0a0190e7 Merge remote-tracking branch 'polish/master' into master 2020-09-01 20:18:29 +02:00
norangebit 99d653eece Add automatic conversion in kepub
Automatic conversion from epub to kepub of new book on Kobo sync.
2020-09-01 19:27:14 +02:00
OzzieIsaacs f825c5ae83 Merge branch 'master' into Develop 2020-09-01 19:26:13 +02:00
OzzieIsaacs 173484c30e Fix #1002, #1581 (Public shelfs not accessible as guest user) 2020-09-01 19:25:57 +02:00
OzzieIsaacs 884270093b Merge remote-tracking branch 'worker/tasks' into Develop 2020-08-31 13:00:13 +02:00
Dawid Gliwka 62e7ab8c2b Update polish translation 2020-08-30 21:17:56 +02:00
blitzmann ded480207b Add link to convert task, fixes #1589 2020-08-30 13:54:51 -04:00
blitzmann ef49e2b5b3 Revert daemon in favor of timeout 2020-08-30 13:49:45 -04:00
blitzmann b0a055a870 Rename email.py -> mail.py to avoid shadowing standard email module 2020-08-30 13:31:59 -04:00
blitzmann 9b9e29a3b6 Implement worker thread as a daemon 2020-08-30 13:29:42 -04:00
OzzieIsaacs 1a9a436cbe Fixed wrong translation string
Removed unused variables from callback in server.py
Update Testresults
2020-08-30 17:11:11 +02:00
OzzieIsaacs 62dd29d2f3 Renamed email to mail due to naming conflict in python2 2020-08-30 08:49:53 +02:00
OzzieIsaacs d406d91856 Merge remote-tracking branch 'worker/tasks' into Develop 2020-08-30 08:32:09 +02:00
OzzieIsaacs 98494c610a Merge branch 'master' into Develop 2020-08-30 08:31:35 +02:00
OzzieIsaacs 649a553fa4 Merge remote-tracking branch 'metadata/master' into master 2020-08-30 08:30:32 +02:00
OzzieIsaacs e17a06d7bd Merge remote-tracking branch 'oauth/oauth-typo' into master 2020-08-30 08:28:27 +02:00
OzzieIsaacs 4b14cc6a74 Merge remote-tracking branch 'oauth/oauth-typo' into Develop 2020-08-30 08:28:14 +02:00
OzzieIsaacs 65560ab65e Merge remote-tracking branch 'google_oauth/patch-1' into master 2020-08-30 08:26:48 +02:00
OzzieIsaacs b65095fd0f Merge remote-tracking branch 'google_oauth/patch-1' into Develop 2020-08-30 08:26:34 +02:00
OzzieIsaacs 28733179d2 Merge remote-tracking branch 'caliblur/editMetaFix' into Develop 2020-08-30 08:25:17 +02:00
OzzieIsaacs 960d23ca50 Merge remote-tracking branch 'caliblur/blurPaginationFix' into Develop 2020-08-30 08:23:06 +02:00
Michael Knepher 057f70ea9c Add author sort 2020-08-29 18:53:00 -07:00
blitzmann 3e378bd665 Some more clean up 2020-08-29 21:04:49 -04:00
blitzmann c120138f26 Fixes for pagination ugliness for caliBlur! style 2020-08-29 20:58:30 -04:00
blitzmann 31b20362ec caliBlur! style: Fixes issue with edit metadata button not getting styled correctly 2020-08-29 18:45:23 -04:00
blitzmann e7eb5b6ea6 Improvements to task processing
* Moves clean up to separate function for organization
* moves the `self.dequeued.append(item)` immediately after `self.queue.get()` so that we don't wait for it to show up

(cherry picked from commit bc9372e88f0c8855694431f811702d7fb899a97e)
2020-08-29 12:25:33 -04:00
OzzieIsaacs fe91ed815e Updated testresults with merged new worker 2020-08-29 12:46:12 +02:00
OzzieIsaacs 9e5cad0dc8 Merge new worker thread 2020-08-29 11:14:52 +02:00
OzzieIsaacs 36cbc42363 Better test output html file 2020-08-28 16:51:53 +02:00
blitzmann 4cb82ea9bd Revert testing condition that decreased number of tasks kept 2020-08-27 21:49:55 -04:00
blitzmann 572ac4a17b Fix for deleting old, completed tasks
(cherry picked from commit e066d7a4b0f47d3327696a11795cdc923ff0f6f3)
2020-08-27 21:46:20 -04:00
Ozzie Isaacs 6c552f6b43 Update tests Windows 2020-08-27 22:29:47 +02:00
Ozzie Isaacs 9723129436 Updated dependency comicapi version 2020-08-27 21:03:36 +02:00
Ozzie Isaacs dc5191f8ba Added unrar binary is found on windows 2020-08-27 21:01:45 +02:00
OzzieIsaacs d79726899f Updated testresult linux 2020-08-26 21:44:31 +02:00
Ozzie Isaacs 8ab5710098 Updated testresuts Windows 2020-08-26 21:43:58 +02:00
OzzieIsaacs 61d628d596 oauth problem solved 2020-08-26 18:22:56 +02:00
Sean Leonard 078fc25845 Remove Google+ OAuth scope
The scope is no longer available per https://developers.google.com/+/api-shutdown

Fixes #1472 
Fixes #1573
2020-08-26 08:56:56 -07:00
Marvel Renju 67eb4b317a Fix typo
google oauth provider obtain link was pointing to github
2020-08-26 03:15:39 +01:00
blitzmann 6322919bc7 Merge branch 'Develop' into tasks
# Conflicts:
#	cps/db.py
2020-08-25 00:15:41 -04:00
blitzmann b81b8a1dea Fix registration email 2020-08-25 00:05:20 -04:00
blitzmann f3a3797850 Fail the convert task if the email subtask fails 2020-08-24 21:28:55 -04:00
blitzmann 5ec1283bb1 Remove threading for the calibre DB class 2020-08-24 21:03:59 -04:00
blitzmann 8634b0c6f0 Remove left over placeholder code 2020-08-24 21:00:15 -04:00
Ozzie Isaacs d89830af61 Fix anonymous user has no modified_flag error 2020-08-24 21:00:13 +02:00
Ozzie Isaacs ef1736b571 Fix error on guest user (view settings missing) 2020-08-24 20:38:06 +02:00
Dave Mogle d951ee4b83 Prefer kepub (#1439)
Only offer kepub download URL over Kobo sync API when available
2020-08-24 13:43:54 -04:00
blitzmann 04081f62c4 Delete old worker thread class / logic 2020-08-23 23:34:41 -04:00
blitzmann 0f28dc5e55 Remove the queue stuff for CalibreDB (is no longer used) 2020-08-23 23:17:07 -04:00
blitzmann 508f49df18 Remove completed tasks and sort the tasks by date added when calling .tasks 2020-08-23 23:00:23 -04:00
blitzmann bec280c6b1 Add some error handling 2020-08-23 21:51:44 -04:00
blitzmann 6a8ae9c0c4 Merge remote-tracking branch 'upstream/master' into tasks
# Conflicts:
#	cps/helper.py
2020-08-23 21:38:56 -04:00
blitzmann ac22483f98 Add error handling to the email task within the convert task 2020-08-23 21:35:05 -04:00
blitzmann 59d56d5c83 py27 support (I think) and some clean up 2020-08-23 21:21:55 -04:00
OzzieIsaacs cdaad2fb4a Merge branch 'master' into Develop 2020-08-23 21:23:00 +02:00
OzzieIsaacs 843279bacb Merge remote-tracking branch 'jef/jef/download-kobo' into master 2020-08-23 21:22:44 +02:00
blitzmann a000de0270 Some clean up 2020-08-23 13:33:57 -04:00
blitzmann bf41b04cfa Remove convert task from db.py - with the fixed from #1565, this no longer seems to be needed 2020-08-23 13:07:24 -04:00
blitzmann 9ce2e8ea53 Fix progress indication for emails that have been completed. 2020-08-23 12:58:24 -04:00
OzzieIsaacs f066926fc9 Merge branch 'master' into Develop 2020-08-23 10:56:10 +02:00
OzzieIsaacs 4c38b0ab10 Prepare for save name sort order 2020-08-23 10:56:00 +02:00
OzzieIsaacs cf35c9dcef Merge remote-tracking branch 'name/patch-2' into master 2020-08-23 10:53:18 +02:00
OzzieIsaacs 45ff9394f2 Fix comma separated author names during for upload 2020-08-23 09:44:42 +02:00
blitzmann 414043ded1 Remove references to old worker, turn off calibre_db task queue (for now until I can determine if it's needed still), and attempt to re-implement email progress tracking (not working at the moment) 2020-08-22 23:35:48 -04:00
blitzmann 2533c9c14e Continue converting tasks - email and upload tasks 2020-08-22 22:44:28 -04:00
blitzmann f10f0dada6 First working PoC with a new task structure 2020-08-22 16:31:00 -04:00
OzzieIsaacs 282859bc1b Merge remote-tracking branch 'github/master' into master 2020-08-22 15:38:40 +02:00
OzzieIsaacs a3ae97a5a3 Fix #1574 (author name not shown in change book order in shelfs) 2020-08-22 15:37:40 +02:00
OzzieIsaacs ed8275a20b Fix #1574 (author name not shown in change book order in shelfs) 2020-08-22 15:35:21 +02:00
OzzieIsaacs f2add3f788 Migration of view settings working in User database
Book Merge gives now feedback on what is done
2020-08-22 10:27:09 +02:00
OzzieIsaacs ad144922fb Merge with master 2020-08-22 09:23:29 +02:00
OzzieIsaacs b9c0f2a3d3 Merge remote-tracking branch 'origin/master' into master 2020-08-21 19:27:19 +02:00
OzzieIsaacs 0cc07362b8 Fix for #1573 2020-08-21 19:26:58 +02:00
Brandon Ingli 4ee5dcaff3 Elevate Log Messages in web.py
Elevates login failure log messages and register failure log messages from INFO to WARNING, "Unknown Error" to ERROR, and fixes misspelling of "address" in web.py log messages. Misspelling remains in variable names to avoid breaking changes.
2020-08-17 11:29:10 -05:00
Ozzie Isaacs 4d44746a88 Change settings database gdrive watch to JSON 2020-08-15 15:07:03 +02:00
OzzieIsaacs 1535bdbcd8 Merge remote-tracking branch 'memorydatabase/issue/1564' 2020-08-15 12:08:59 +02:00
OzzieIsaacs ecb160b28d Merge remote-tracking branch 'pypy/fix-pypy3-settings-database-error' 2020-08-15 10:58:08 +02:00
OzzieIsaacs 7e9941def0 Updated test results 2020-08-14 21:02:59 +02:00
OzzieIsaacs f9c6fb30bf Excluded series type again, as it causes problems upon reconnect 2020-08-14 19:43:54 +02:00
Ozzie Isaacs 94ad93ebd7 Added series like custom columns #1501 2020-08-11 18:56:34 +02:00
blitzmann 0e1ec5034e Fix for #1564 - using memory database in multiple threads.
See also: https://docs.sqlalchemy.org/en/13/dialects/sqlite.html#using-a-memory-database-in-multiple-threads
2020-08-11 12:44:55 -04:00
Marvel Renju 76b0505bd9 Change all "conn = engine.connect()" statements to "with engine.connect() as conn:" in ub.py
Changed all the statements in ub.py to use python context managers so that conn.close() is called automatically.  (https://docs.sqlalchemy.org/en/13/core/connections.html)
2020-08-10 03:42:36 +01:00
OzzieIsaacs b309c1fc91 Fix filenames (Escape "\") for searching calibre excecutable on windows 2020-08-09 15:11:54 +02:00
OzzieIsaacs b9a802a19c Merge remote-tracking branch 'cover_path/patch-1' 2020-08-09 14:54:36 +02:00
OzzieIsaacs a882ad3e65 Merge remote-tracking branch 'contrib/patch-1' 2020-08-09 14:52:01 +02:00
Ryan Holmes 969105b205 Trim whitespace from filename
This avoids an OSError when the book's metadata has whitespace at the end of it.
2020-08-09 01:08:00 -04:00
Ryan Holmes 28bfb06c67 Revert the deletion of another line
This was done by mistake, whoops!
2020-08-09 00:57:30 -04:00
Ryan Holmes 704dcb3e58 Move assignment of new_coverpath
With the assignment originally being within the try, if the try failed, the exception wouldn't have access to the value
2020-08-09 00:55:56 -04:00
Efreak a7e723d8d4 Spelling/grammar in CONTRIBUTING.md 2020-08-08 01:06:19 +00:00
Ren Wei 4c6f5096be get metadata, typo, if no result from google, it will display the noresult msg, regardless of the others results. 2020-08-01 15:12:20 +08:00
Ozzie Isaacs 1a1d105fae Fix #1538 (Floating point numbers showing 2 decimals on details page 2020-07-23 19:31:48 +02:00
Ozzie Isaacs 42a0639bb5 Fix #1533 (Invalid LDAP Cert Path no longer crashes app) 2020-07-23 19:23:57 +02:00
Ozzie Isaacs e27b08203d Fix #1531 (white background on transparent cover instead of black one) 2020-07-23 18:41:38 +02:00
Clément Poissonnier 1ca4583896 feat(ldap): add a field that allows to override LDAP User Object Filter when a user is imported 2020-07-23 12:12:00 +02:00
Ozzie Isaacs 25fc6f1937 Further fixes for #1530 (Handle improper migrated database with config_mature_content_tags, allowed_tags, denied_tags, denied_column_value, allowed_column_value NULL instead of "") 2020-07-22 18:44:11 +02:00
Ozzie Isaacs 0ccc3f7252 Fixes for windows (moving files not allowed -> Close pdf after metadata extracting, add os.path.normcase to path while renaming folders, as thi caused also trouble
Added hint for missing ghostcript on cover extraction
2020-07-21 20:14:08 +02:00
Ozzie Isaacs 66acd1821d Update Gdrive integration (Error Handling on Callback and wording) 2020-07-21 18:01:38 +02:00
Ozzie Isaacs 93a0217d5f Fix for #1530 (Handle improper migrated database with config_mature_content_tags NULL instead of "") 2020-07-20 20:28:10 +02:00
Jef LeCompte 711a697570 Merge remote-tracking branch 'upstream/master' into jef/download-kobo 2020-07-13 01:50:38 -04:00
Ozzieisaacs f8139f3198 Store last selected view for sidebar (not for categories, series, publishers, ..)
Started making search paged
2020-07-11 12:09:34 +02:00
Ozzieisaacs df01022f49 Added save user view settings 2020-07-08 21:18:38 +02:00
Ozzieisaacs 450411a732 #1344 (Support Multiple authors, but not showing up on Kobo reader)
Fix for #1439 (reading progress was not stored, as user login was wrong)
2020-07-05 20:54:36 +02:00
Ozzieisaacs f80c67828b Fix #1500 (Custom ratings of increment 0.5 are allowed) 2020-07-05 14:35:57 +02:00
Ozzieisaacs d1889a5e06 Fix #1502 (program info only visible in about section if user is admin) 2020-07-05 14:00:40 +02:00
Ozzieisaacs 12263ff02f Fix #1423 (OverflowError thrown during sync on some Linux Systems if one of the timestamps is outside range 1970 to 2038) 2020-07-05 13:55:59 +02:00
Ozzieisaacs 76f914cbc2 Fixed logging in SyncToken 2020-07-05 13:52:29 +02:00
Ozzieisaacs c1f5252b3f Fix #1509 (OSError thrown during sync on Windows if one of the timestamps is outside range 1970 to 2038) 2020-07-05 13:40:33 +02:00
Ozzieisaacs 20c6f79a44 Changed behavior delete books with subfolders (additional warning message, but book is deleted) 2020-07-05 10:44:49 +02:00
Ozzieisaacs ee6f1405d4 Fix #1456 (Added route to robots.txt) 2020-07-04 21:22:19 +02:00
Ozzieisaacs ee3541d74e Fix kobo links for reverse proxies with subdomains (and docker?) #1470 2020-07-04 13:35:08 +02:00
Jef LeCompte e048388213 feat(api): include external port option
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-07-03 12:58:58 -04:00
Ozzieisaacs 3ff3431b17 Merge branch 'master' into Develop 2020-06-30 19:59:38 +02:00
Ozzieisaacs 8608ff11f7 Fix #1507 (Password generation on python2 working again) 2020-06-30 19:58:07 +02:00
Michael Knepher 7e0d9fbace series_index filter to show x.0 as x 2020-06-29 23:34:26 -07:00
Ozzieisaacs c6c9cfea22 Merging books basically working 2020-06-29 20:14:48 +02:00
Ozzieisaacs a758976c69 Merge branch 'master' into Develop 2020-06-29 18:47:16 +02:00
OzzieIsaacs a14192b7e0 Updated testresults 2020-06-28 22:31:18 +02:00
OzzieIsaacs 601464083b Fix for task wrap around 2020-06-28 13:44:21 +02:00
Ozzieisaacs ccca5d4d1c Merge branch 'master' into Develop
# Conflicts:
#	cps/templates/layout.html
2020-06-28 12:11:46 +02:00
Ozzieisaacs ba10657829 Add fix for read only gdrive file 2020-06-28 12:06:27 +02:00
Ozzieisaacs 6315655f93 Re-add missing po files 2020-06-28 12:05:16 +02:00
Ozzieisaacs 533cb23b73 Merge remote-tracking branch 'next/bug/login-next-get-param' 2020-06-28 10:01:41 +02:00
Ozzieisaacs 0b95424a0d Merge remote-tracking branch 'issue_template/patch-1' 2020-06-28 09:50:58 +02:00
Ozzieisaacs 852f252d13 Prevent invalid variable
Make text in kobo_auth_screen consistent
2020-06-28 09:48:05 +02:00
Ozzieisaacs 080042882f Merge remote-tracking branch 'cz/master' 2020-06-28 09:33:18 +02:00
Ozzieisaacs dde5b08c47 Re enabled gevent as dependency
Fix #1399 (Calibre-web starting with installed and not activated gdrive denpendencies without internet connection again)
2020-06-27 13:36:33 +02:00
Ozzieisaacs 88d2c60ee8 Catch some errors related to non writable settings db 2020-06-27 13:22:16 +02:00
Ghighi Eftimie eeff5a5d43 fix for hidden input 'next' on login form 2020-06-27 12:00:08 +03:00
Michael Knepher 67dd4a72b0 Add series info to all book "meta" displays 2020-06-26 12:26:36 -07:00
Ozzieisaacs a0b8cc21cc Fix #1503 (js error on login screen) 2020-06-23 15:07:14 +02:00
Ozzieisaacs 329a7a03a5 Fix for errors editing/uploading books with duplicate tags/authors/language names
Additional parsing of epubs for cover files
Fix for change of database with linked read_column and read column isn't present any more
2020-06-22 19:11:58 +02:00
Ozzieisaacs d0a3503d74 Fix #1493 (stay logged in with enabled remember token, use remember token) 2020-06-20 19:02:23 +02:00
Ozzieisaacs 59b78f9984 enable disabling of remember_me function 2020-06-20 15:41:26 +02:00
Ozzieisaacs bf75f16169 Updated Chinese translation 2020-06-20 13:55:34 +02:00
Ozzieisaacs 2f833dc457 Fix login with remember me token 2020-06-20 13:46:12 +02:00
Ozzieisaacs 22344a3971 Improvements for delete book 2020-06-18 20:39:45 +02:00
Ozzieisaacs 8dde6ba60f UI improvements table buttons 2020-06-12 21:40:09 +02:00
Ozzieisaacs d44f283a05 View status in books table is stored 2020-06-12 16:15:54 +02:00
Ozzieisaacs c18d5786dd Improved validation check 2020-06-12 13:45:07 +02:00
Ozzieisaacs f26ccfe16c Table edit: validator routine to prevent empty fields working 2020-06-11 21:36:12 +02:00
Ozzieisaacs 1c681ee378 Improvements for books table editor 2020-06-11 21:19:09 +02:00
flying-sausages 4c1ae44bbe Fixed inconsistencies in bug report template, improved examples 2020-06-11 14:59:51 +01:00
Ozzieisaacs 94b5ec91cc Title in table translatable
Edit some elements in table possible
Checkbox state is kept over page change in book table
Fix missing div in layout
2020-06-11 08:48:23 +02:00
Ozzieisaacs 6bfbf3ee41 Update layout 2020-06-11 08:35:23 +02:00
Lukáš Heroudek fc24fa337e Updated CZ translation 2020-06-09 21:15:09 +01:00
Ozzieisaacs 7b4306b1d6 UI improvements (same colors of buttons, etc.)
Changed Editable default value
2020-06-09 20:46:02 +02:00
Ozzieisaacs 4516cc0d65 Listen button only visible if user has read permissions
Audioformat fix
Table edit functions only available if user has edit rights
2020-06-08 21:57:52 +02:00
Ozzieisaacs 308784c601 Hide listen button if user has no read/listen permissions 2020-06-08 21:56:40 +02:00
Ozzieisaacs 9145c9a52c Fix #1397 (Reenabled m4a, m4b audio playback) 2020-06-08 21:50:11 +02:00
Ozzieisaacs 4038cb5b85 Internal paged Search prepared
Search for table list is working
2020-06-08 17:34:03 +02:00
Ozzieisaacs 628658972c Merge branch 'master' into Develop 2020-06-07 19:39:17 +02:00
Ozzieisaacs db0fe9a755 Fix for #1474 (old comicapi with installed unrar, but missing unrar-lib) 2020-06-07 15:41:53 +02:00
Ozzieisaacs fdf10e3d2e Fix #1473 (reconnect not working via web-route access) 2020-06-07 14:11:41 +02:00
Ozzieisaacs ded3e06a9b Updated french translation 2020-06-07 06:48:51 +02:00
Ozzieisaacs 0dd0605a1f Book list for merging 2020-06-06 21:21:10 +02:00
Ozzieisaacs 827b0c6e50 Changed pubdate to timestamp 2020-06-06 09:52:35 +02:00
Ozzieisaacs d1b533848d Changed pubdate to timestamp 2020-06-05 20:13:39 +02:00
Ozzieisaacs 13ae28edab Fix #1449 (Shelf download menu wasn't working for books with more than one format) 2020-06-04 20:34:31 +02:00
Ozzieisaacs 82253219e8 Fix #1449 (Shelf download menu wasn't working for books with more than one format) 2020-06-04 20:33:14 +02:00
Ozzieisaacs 94592b74a6 Merge branch 'master' into Develop 2020-06-03 20:15:55 +02:00
Ozzieisaacs eef2112e1e #1430 (changed color of rating stars) 2020-06-03 20:14:07 +02:00
Ozzieisaacs b83d56eff2 Version bump 2020-06-03 19:10:36 +02:00
Ozzieisaacs 4c539b6db4 Fix #1448 (Public shelfs are accessible even if not logged in) 2020-06-03 19:10:07 +02:00
OzzieIsaacs 2ad329e64c Preparation for release 2020-06-02 22:12:36 +02:00
Ozzieisaacs 4de89ec6ce Merge remote-tracking branch 'it/patch-14' 2020-06-02 20:58:17 +02:00
Ozzieisaacs fc885c8fa2 Merge remote-tracking branch 'cz/patch-1' 2020-06-02 20:51:31 +02:00
Ozzieisaacs ef2c98ba39 Fix #1453 (error unrar binary not found) 2020-06-02 20:51:08 +02:00
ElQuimm 41d922867e updated italian version of message.po
Thank you.
2020-06-02 09:02:44 +02:00
Ozzieisaacs 89223760e6 Merge branch 'master' into Develop 2020-06-01 10:58:49 +02:00
Ozzieisaacs 9a8a1f75ca For for error unrar binary not found 2020-06-01 10:54:41 +02:00
flying-sausages 52e8e7e4b0 Some czech translations 2020-05-31 22:51:41 +01:00
OzzieIsaacs 93f65484de Update Teststatus 2020-05-29 09:11:52 +02:00
Ozzieisaacs 7d08cde8b8 Update error handling cover upload 2020-05-29 06:59:40 +02:00
Ozzieisaacs d3c2bf7dd4 Merge remote-tracking branch 'es/patch-1' 2020-05-28 18:50:16 +02:00
Michael Knepher 54cf3652b0 Add series name and index to book cover info 2020-05-27 21:57:59 -07:00
Ozzieisaacs 5607d2086d Added error handling for cover upload 2020-05-27 20:41:16 +02:00
Ozzieisaacs 27ed918896 Enabled search for archived books 2020-05-27 19:19:17 +02:00
Ozzieisaacs 9b2df9cfd9 Fix #1441 (list copy function not available on python2, crashes edit metadata) 2020-05-27 18:38:50 +02:00
Michael Knepher 5dd08e438c Merge remote-tracking branch 'upstream/master' 2020-05-27 09:06:43 -07:00
Ozzieisaacs 2f8c8c3a28 Merge remote-tracking branch '/wolviex' 2020-05-27 10:50:13 +02:00
Wolviex dde7cf18f7 removed extra reference to calibre_db (calibre_db.calibre_db..) typo? 2020-05-27 01:41:15 -07:00
Rafael Roa 48aadbf716 Update messages.po 2020-05-26 23:28:29 +02:00
Ozzieisaacs 5514af60e5 Merge remote-tracking branch 'it/patch-13' 2020-05-26 18:43:12 +02:00
ElQuimm e8449eb02f Updated version of italian message.po
Thank you.
2020-05-26 18:37:15 +02:00
Ozzieisaacs 9ea21a7ecb Possible fix for #1436 2020-05-26 18:20:32 +02:00
Ozzieisaacs fec86c2862 Update Grid/list view of series 2020-05-26 15:19:32 +02:00
Ozzieisaacs 11e5d4c5b7 Merge remote-tracking branch 'es/patch-2' 2020-05-25 21:57:26 +02:00
Ozzieisaacs b852fb0e26 Merge branch 'Develop' 2020-05-25 21:30:21 +02:00
Ozzieisaacs 0fc18bf3b1 Fix for #1398 (prevent empty series_index field) 2020-05-25 19:34:31 +02:00
Rafael Roa d4be584782 Update messages.po
Here is the whole file traslated
2020-05-25 17:35:46 +02:00
Knepherbird 2120d72901 Merge pull request #3 from janeczku/master
Merging current upstream master
2020-05-24 15:25:49 -07:00
Ozzieisaacs 6f9c08f906 Fix typo RarExecutable 2020-05-24 20:54:23 +02:00
Ozzieisaacs 70c666c380 Upload book without reload complete library 2020-05-24 20:40:58 +02:00
Ozzieisaacs 46197d82b5 Edit and Upload books refactored 2020-05-24 20:19:43 +02:00
Ozzie Isaacs e4eab17595 Fix version detect of binaries on windows 2020-05-24 17:24:54 +02:00
Ozzieisaacs cf10244f20 Fix for failed recovery of config_logfile 2020-05-24 09:59:45 +02:00
Ozzieisaacs 570684d308 Fix custom bool column not visible in adv search if linked to read status 2020-05-23 21:26:39 +02:00
Ozzieisaacs 244db8d894 Fix from tests advanced search for custom columns 2020-05-23 21:17:58 +02:00
Ozzieisaacs 96d6018ecc Added ability to view comicapi version
Changed required comicapi version
Unified "cannot" and "Cannot" texts
Removed annoying "was already removed" string from log
2020-05-23 16:20:19 +02:00
OzzieIsaacs 73ad6dd0c4 Fix kobo sync (sync tags) 2020-05-23 14:40:50 +02:00
OzzieIsaacs d0e15da352 Fix lcase function 2020-05-23 12:51:48 +02:00
Ozzieisaacs b1b293a3ec Fix order_authors 2020-05-23 11:09:50 +02:00
Ozzieisaacs 5f0660a4e5 Refactored helper.py and db.py 2020-05-23 10:16:29 +02:00
Ozzieisaacs ec3a3a73ef Merge branch 'master' into Develop 2020-05-23 08:50:24 +02:00
Ozzieisaacs 087c4c5929 Merge remote-tracking branch 'opds/master' 2020-05-23 08:48:08 +02:00
Ozzieisaacs e0ee2e0801 Merge remote-tracking branch 'typo/master' 2020-05-23 08:47:08 +02:00
Michael Knepher c79a9e9858 Fix typo "Shelfs" to "Shelves" 2020-05-22 11:43:52 -07:00
OzzieIsaacs b3fdce36af Update Testresults 2020-05-22 09:01:39 +02:00
OzzieIsaacs b7535b9526 Merging master branch
- fix title sort function
- fix focus on search
2020-05-21 22:31:29 +02:00
OzzieIsaacs 0cf1cc5587 Fixes from tests 2020-05-21 22:26:19 +02:00
Ozzieisaacs 098dab889a Fixed title sorting routine 2020-05-21 19:37:54 +02:00
Ozzieisaacs cc856c7cd1 Merge remote-tracking branch 'search_focus/activate-search-focus-if-search-in-progress' 2020-05-21 19:18:02 +02:00
Ozzieisaacs a20a155d39 Merge remote-tracking branch 'typo/patch-2' into Develop 2020-05-21 19:14:29 +02:00
Ozzieisaacs 1a458fe39f Fix for #1407 converting books should now be possible again 2020-05-21 18:16:11 +02:00
celogeek 051ffdda35 activate search focus if search in progress 2020-05-21 16:42:02 +02:00
OzzieIsaacs a48418364c Fiexes from tests 2020-05-21 13:54:28 +02:00
Ozzieisaacs b75497231e Additional fix for #1407 (metadata.db is now held in memory, app.db is attached to it -> joins between both databases possible -> book_read_link is joined for getting result) 2020-05-21 09:28:35 +02:00
Knepherbird 5cceeb6ef2 Fix: correct property typo
Correcting 'box-sizeing' to 'box-sizing'
2020-05-19 13:10:25 -07:00
Ozzieisaacs 29b94c5615 Fix for #1407 (to many read books lead to to large sql query) -> only fix for linked calibre-column 2020-05-19 21:36:22 +02:00
Ozzieisaacs 81fc1eccd3 Fix for #1407 (to many read books lead to to large sql query) -> only fix for linked calibre-column 2020-05-19 21:35:56 +02:00
Braincoke 22fae51c9d Fix XML parsing error when using OPDS feeds
Using the OPDS feeds with MoonReader yielded the following error:
"Error parsing XML: unbound prefix".
This was due to a missing namespace in the feed.xml template.
See https://github.com/janeczku/calibre-web/issues/1403 for more
information.
2020-05-18 20:07:02 +02:00
Ozzieisaacs 4332f7a640 Better detection of localhost for kobo sync (possibly related to #1400) 2020-05-17 21:44:12 +02:00
Ozzieisaacs d0e603e62d Better detection of localhost for kobo sync 2020-05-17 21:42:25 +02:00
Ozzieisaacs 38c28f4358 Merge branch 'master' into Develop
# Conflicts:
#	cps/admin.py
#	cps/constants.py
#	cps/static/css/caliBlur.min.css
#	cps/uploader.py
2020-05-17 16:22:58 +02:00
Ozzieisaacs 742799b4ac Added missing float custom column to search form 2020-05-17 16:10:10 +02:00
Ozzieisaacs 5405dc5141 Fix for #1387 (saving settings with enabled gdrive metadata watch led to crash) 2020-05-17 11:15:46 +02:00
Ozzieisaacs 013793f989 Fix for #1391 (Kobo sync not working if series is given, but no series_index) 2020-05-17 10:46:48 +02:00
Ozzieisaacs 2468cf63cc Fix for #1397 (changed supported audio files)
Changed max gevent version
Fix for #1397 (changed supported audio files)
2020-05-17 10:07:36 +02:00
Ozzieisaacs 8e9b5d7e50 Merge remote-tracking branch 'caliblur/master' 2020-05-15 21:01:08 +02:00
Ozzieisaacs a33515d907 Merge remote-tracking branch 'refactor/refactor_uploader' 2020-05-15 20:36:00 +02:00
Ozzieisaacs a276a33081 Merge remote-tracking branch 'nl/master' 2020-05-15 20:34:30 +02:00
h1f0x e325c3dbf6 fixed div selection in caliBlur.js 2020-05-14 12:29:52 +02:00
h1f0x b3fef625a8 Fixed Calibur views: series, authors, publishers, ratings, file formats, detail view 2020-05-14 11:57:38 +02:00
Ozzieisaacs 13994a5f96 Merge branch 'master' into Develop 2020-05-13 20:16:29 +02:00
Ozzieisaacs e8ac62cdd8 Moved password replace to prevent incomplete session 2020-05-13 20:15:35 +02:00
Ozzieisaacs 1bc7134ec2 Fix error 500 on reset password in debug mode 2020-05-13 20:04:43 +02:00
Ozzieisaacs 273572f44c Merge branch 'master' into Develop
# Conflicts:
#	cps/ub.py
2020-05-13 20:03:54 +02:00
Ozzieisaacs ac37483d47 Fix for #1391 (kobo sync errors out if read/unread books had been present in app.db during initial database migration) 2020-05-13 19:43:14 +02:00
Ozzieisaacs 0cc2b49296 Merge branch 'master' into Develop
# Conflicts:
#	cps/templates/book_edit.html
2020-05-12 19:10:19 +02:00
Ozzieisaacs 44d5adc16f Fix #1390 2020-05-12 19:08:51 +02:00
Ozzieisaacs f749fc641b Temporary fix for #1390 2020-05-12 17:42:24 +02:00
Ozzieisaacs 87c76c09e2 temporary fix for #1390 2020-05-12 17:41:49 +02:00
Ozzieisaacs e787f9dd9f Automatic username (#1172) 2020-05-12 17:23:58 +02:00
Ozzieisaacs ec7d5b17ab Added table view for books 2020-05-12 16:32:26 +02:00
Ozzieisaacs 47641eee59 Merge branch 'master' into Develop 2020-05-12 16:16:04 +02:00
Ozzieisaacs 42abe28cc1 Fix for #1389 (import ldap users with whitespaces) 2020-05-12 16:13:56 +02:00
Ozzieisaacs b48afa38ac Fix #1386 (Add asin to recognized identifiers) 2020-05-12 14:44:57 +02:00
Ozzieisaacs f7269d8df2 Fix for #1385 (Private shelves are listed twice in the "Add to shelf" dropdown menu) 2020-05-12 14:39:13 +02:00
Ozzieisaacs ce0fab8d2f Fix duplicate shelf names in "search" 2020-05-12 14:37:13 +02:00
Ozzieisaacs 33472567de Improved Debug output on send email 2020-05-11 19:28:22 +02:00
Ozzieisaacs f5e12328dc Fix for #1382 (Restrictions with "&" in it can't be deleted) 2020-05-11 18:41:34 +02:00
Ozzieisaacs 486c0f2937 Fix for #1382 (Restrictions with "&" in it can't be deleted) 2020-05-11 18:41:16 +02:00
jvoisin e69c4cd1dc Refactor a bit cps/uploader.py 2020-05-11 13:15:30 +02:00
Marcel e0d3ccd8d1 Update messages.po 2020-05-10 21:05:39 +02:00
Ozzieisaacs 16a3deec2c Merge branch 'master' into Develop
# Conflicts:
#	cps/helper.py
2020-05-10 19:24:55 +02:00
OzzieIsaacs 92db00692a Merge all headers to download response
Updated test results
2020-05-10 14:58:18 +02:00
OzzieIsaacs fe88010a72 Merge remote-tracking branch 'sec_fixes/minor_fix_caliblur' 2020-05-10 14:57:19 +02:00
OzzieIsaacs 99ae4be2c2 Merge remote-tracking branch 'sec_fixes/bump_jquery' 2020-05-10 10:43:20 +02:00
OzzieIsaacs a9085752c1 Fix error "email" not in to_save 2020-05-10 10:26:22 +02:00
OzzieIsaacs e1fbc9255c Merge remote-tracking branch 'sec_fixes/bump_underscore' 2020-05-10 10:26:01 +02:00
OzzieIsaacs f33e25ac40 Merge remote-tracking branch 'sec_fixes/cookies_improvement' 2020-05-10 10:22:21 +02:00
OzzieIsaacs 51365ab006 Merge remote-tracking branch 'sec_fixes/strong_session_protection' 2020-05-10 10:21:19 +02:00
OzzieIsaacs d61b7e48d7 Merge remote-tracking branch 'sec_fixes/random_password' 2020-05-10 10:18:40 +02:00
OzzieIsaacs f590b24f85 Merge remote-tracking branch 'sec_fixes/https' 2020-05-10 10:17:36 +02:00
Ozzieisaacs 308fd55483 #1141 (Setting for file size limit on email) 2020-05-09 20:29:17 +02:00
Ozzieisaacs fefb44e612 #1356 (fixes for readonly metadata.db)
Fix remove trailing metadata.db at entering calibre_db_path
2020-05-09 19:54:28 +02:00
jvoisin dd3b562f1a Change some links from http to https 2020-05-09 17:11:56 +02:00
jvoisin 30c9aa3df9 Minor fixes to caliBlur.js
- Add alt attributes to images
- Fix a broken tag
2020-05-09 17:07:22 +02:00
jvoisin 688184e255 Bump jquery 2020-05-09 17:00:03 +02:00
Ozzieisaacs 75fb7c2e95 Allowing upload extensions (#1119) 2020-05-09 16:54:22 +02:00
jvoisin 264b4b669e Bump underscorejs version from 1.9.1 to 1.12.2 2020-05-09 16:54:21 +02:00
Ozzieisaacs 51f12c51ad Fix #1361 (covers of archived books not shown) 2020-05-09 16:37:02 +02:00
Ozzieisaacs 03d134697c Fix #1361 (covers of archived books not shown) 2020-05-09 16:36:08 +02:00
Ozzie Isaacs e706e1a68d Update CONTRIBUTING.md 2020-05-09 16:15:52 +02:00
Ozzieisaacs ff3f42db95 Fix #1364 (translated format identifier)
Updated french Translation
2020-05-09 16:12:55 +02:00
Ozzieisaacs e8aedeac36 Refactored admin.py 2020-05-09 16:00:31 +02:00
Ozzie Isaacs 2bf6b263ed correction of contribution guideline 2020-05-09 15:58:10 +02:00
jvoisin bf166b757a Improve a bit the cookie's hardening
- Samesite for session cookies as well as the remember me ones
- Httponly
2020-05-09 14:42:28 +02:00
jvoisin b4165335a7 Use strong sessions protection
See https://flask-login.readthedocs.io/en/latest/#session-protection for
details
2020-05-09 14:34:14 +02:00
jvoisin 2a1bf2fa71 Generate strong random passwords 2020-05-09 14:24:20 +02:00
Ozzieisaacs 718d50a037 Starting again without traceback (moved gdriveutil import) 2020-05-09 12:17:28 +02:00
Ozzieisaacs 41960ada4a Autodetect binaries 2020-05-09 11:04:35 +02:00
Ozzieisaacs 0a02caad04 Improvements 2020-05-09 11:01:00 +02:00
Ozzieisaacs ff75bdba9e Merge branch 'master' into Develop 2020-05-08 19:05:08 +02:00
Ozzieisaacs 189243a9b0 Merge remote-tracking branch 'publisher_sort/patch-1' 2020-05-08 15:04:45 +02:00
Ozzieisaacs 34e339c506 Merge remote-tracking branch 'it/patch-12' 2020-05-08 14:59:51 +02:00
Ozzieisaacs a437c603c6 Merge remote-tracking branch 'kepubify/Develop' into Develop
# Conflicts:
#	cps/admin.py
#	cps/helper.py
#	cps/templates/config_edit.html
#	cps/web.py
2020-05-08 14:53:21 +02:00
Ozzieisaacs 4e940f7fa0 Added response header for improving security 2020-05-08 14:49:12 +02:00
Knepherbird 69fde7dead Update web.py
Set db.Publishers query to order by name column, because publishers.sort column is empty.
2020-05-07 13:55:59 -07:00
Ozzieisaacs 4368c182a0 Make goodreads compatible for betterreads dependency 2020-05-06 20:57:54 +02:00
Ozzieisaacs 48f4b12c0e Merge branch 'master' into Develop
# Conflicts:
#	cps/editbooks.py
2020-05-06 18:47:33 +02:00
Ozzieisaacs 6a6c1b6b21 Fix for #1358, #1355 2020-05-06 16:25:03 +02:00
Ozzieisaacs 51808d2ad4 Version Bump 2020-05-05 20:31:12 +02:00
Ozzieisaacs 0735fb1e92 Fix #1349 (Fix error on move cover with foreign file systems, e.g. samba shares)
Preparation for release
2020-05-05 20:28:10 +02:00
Ozzieisaacs 850a85915b Fix #1354 (Error on uploading single book, because of missing rarfile) 2020-05-05 18:48:40 +02:00
ElQuimm 148f1109c6 updated messages.po
just a little update for coherence with Read/da leggere -> Archived/da archiviare.
Sorry :-)
2020-05-04 20:56:58 +02:00
Ozzieisaacs fcbeeca305 Merge remote-tracking branch 'it/patch-11' 2020-05-04 20:21:05 +02:00
Ozzieisaacs fb16429867 Randomize flask secret_key 2020-05-04 19:02:03 +02:00
Ozzieisaacs e1439b529b Config Options for limiting email size, change username to e-mail adress, use kepubify
Added work on Unrar5 decompression (breaks comic reader totally)
2020-05-04 18:19:30 +02:00
ElQuimm db38d7ee78 Updated version of italian.po
:-)
2020-05-03 21:30:06 +02:00
Ozzieisaacs 0adcd1b3d9 UI Improvements
Added additional restrictions to Calibre DB interface
2020-05-03 10:55:33 +02:00
OzzieIsaacs 36a984ce3c Revert proxyfix 2020-05-02 18:17:52 +02:00
Ozzieisaacs fcefd8031a Fix #985 (png and webp are extracted as cover files from comic files) 2020-05-02 11:24:30 +02:00
Ozzieisaacs 64bebaa1d1 Update Upload formats 2020-05-02 10:46:00 +02:00
Ozzieisaacs 0138ff9e16 Added additional config options 2020-05-02 10:18:01 +02:00
Ozzieisaacs 9bc085a23e Fixes for comic reader 2020-05-02 09:35:14 +02:00
Ozzieisaacs 1ce432b136 Merge remote-tracking branch 'kobo/fix_covers_merge' 2020-05-02 09:34:24 +02:00
Michael Shavit e0fbfa44a4 Fix issue with cover images introduced during the merge of #1277. 2020-05-02 01:55:14 -04:00
Ozzieisaacs 0a92d79ec0 Merge remote-tracking branch 'cover-series/feature/add-cover-serie-view' into Develop
# Conflicts:
#	cps/static/css/style.css
#	cps/ub.py
#	cps/web.py
2020-05-01 17:25:13 +02:00
Ozzieisaacs b95f6563cc Merge remote-tracking branch 'read-config/remove-duplicate-read-status-without-filter' into Develop 2020-05-01 17:19:13 +02:00
Ozzieisaacs 547bbecef1 Merge branch 'master' into Develop 2020-05-01 17:16:28 +02:00
Ozzieisaacs 700cb3b553 Merge remote-tracking branch 'NL/master'
Updated all strings
2020-05-01 17:15:59 +02:00
Ozzieisaacs 8646f8f23a Merge branch 'Develop'
# Conflicts:
#	cps/__init__.py
2020-05-01 14:51:54 +02:00
OzzieIsaacs 99cc69c67d Update Teststatus 2020-05-01 14:38:54 +02:00
OzzieIsaacs 2c5d76908a Added missing upload format 2020-05-01 13:34:16 +02:00
Ozzieisaacs 832b34fc54 Improved errorhandling for resending password
Improved errorhandling for editing user
2020-05-01 12:00:45 +02:00
Ozzieisaacs 000b85ff81 Fixes for deleting books(error handling and user feedback) 2020-05-01 10:26:35 +02:00
Ozzieisaacs bb317d54f2 Fix reject reset password without configured email server 2020-05-01 08:37:54 +02:00
Ozzieisaacs d6f41d8dc0 Fix error 404 on reset password (Fix #1342) 2020-05-01 08:33:50 +02:00
Marcel 6dff5ed679 NL language update 2020-04-30 21:30:50 +02:00
OzzieIsaacs fb8b6310d5 Fix from tests 2020-04-30 20:58:01 +02:00
Ozzieisaacs 02aaf17ac5 Fix #1339 (Proxyfix import with old werkzeug versions causes traceback) 2020-04-30 19:21:08 +02:00
Ozzieisaacs b160a8de0b Merge branch 'master' into Develop
# Conflicts:
#	cps/__init__.py
#	cps/comic.py
#	cps/editbooks.py
#	cps/helper.py
#	cps/kobo.py
#	cps/translations/nl/LC_MESSAGES/messages.mo
#	cps/translations/nl/LC_MESSAGES/messages.po
#	cps/ub.py
#	cps/uploader.py
#	cps/web.py
2020-04-30 18:08:28 +02:00
Ozzieisaacs e3246fd751 Merge remote-tracking branch 'key' 2020-04-30 17:29:41 +02:00
Ozzieisaacs 91b1775f50 Fix #1225 (Unrar binary added, cover files from cbr files can be extracted) 2020-04-29 19:02:35 +02:00
Ozzieisaacs fb18ab1ca5 Fix #866 (Recent book sidebar element can't be removed anymore) 2020-04-29 18:57:39 +02:00
Ozzieisaacs 01ff55c84e Removed non working filters for search 2020-04-29 17:57:53 +02:00
jvoisin 523aab2e9e Don't use an hardcoded session key
This fixes a trivial authentication bypass,
according to https://flask.palletsprojects.com/en/1.1.x/quickstart/#sessions
2020-04-29 13:59:34 +02:00
Ozzieisaacs 9a7d9da654 Merge remote-tracking branch 'js_caliblur/xss' 2020-04-29 12:08:51 +02:00
Ozzieisaacs e9446556a1 Merge remote-tracking branch 'ru/master' 2020-04-29 12:06:35 +02:00
jvoisin 806a5f209f Fix two minor xss 2020-04-29 11:33:33 +02:00
ZIzA c864b368b0 Russian language update 2020-04-29 01:30:14 +04:00
Ozzieisaacs 27eb09fb19 Add unrar Support 2020-04-28 20:23:39 +02:00
Ozzieisaacs bea7223a0a Renabled cbrimage extraction (via unrar and rarfile) 2020-04-28 16:50:08 +02:00
Ozzieisaacs 0297823bda Merge remote-tracking branch 'codecosmetic/move_var' 2020-04-28 15:33:25 +02:00
Ozzieisaacs d1bce5c2d9 Update nl translation from development branch 2020-04-27 21:15:19 +02:00
Ozzieisaacs 46c0ae3ccc Revert accidently deleted nl translation strings 2020-04-27 21:11:43 +02:00
Ozzieisaacs ce6b689147 Code cosmetics 2020-04-27 20:22:55 +02:00
Ozzieisaacs 2d92818613 Code cosmetics 2020-04-27 20:01:13 +02:00
jvoisin 487878819e Move a few variables around
This should prevent a couple of crashes
due to undeclared variables.
2020-04-27 12:03:54 +02:00
Ozzieisaacs 6682b1ced1 Fix download of book covers with enabled pillow from url 2020-04-26 21:00:29 +02:00
Ozzieisaacs bc89b0658a Fix deletion of books with multiple custom column links
Fix delete of author-folder in case last book of author was deleted (#1269)
2020-04-26 20:44:37 +02:00
Ozzieisaacs d9dde36c74 Merge remote-tracking branch 'improve_read/sort-book-name' search results are ordered according to sort field in book title 2020-04-26 19:00:36 +02:00
Ozzieisaacs 44284ea5fb Merge remote-tracking branch 'opds/master'
# Conflicts:
#	cps/translations/cs/LC_MESSAGES/messages.po
#	cps/translations/de/LC_MESSAGES/messages.po
#	cps/translations/es/LC_MESSAGES/messages.po
#	cps/translations/fi/LC_MESSAGES/messages.po
#	cps/translations/fr/LC_MESSAGES/messages.po
#	cps/translations/hu/LC_MESSAGES/messages.po
#	cps/translations/it/LC_MESSAGES/messages.po
#	cps/translations/ja/LC_MESSAGES/messages.po
#	cps/translations/km/LC_MESSAGES/messages.po
#	cps/translations/nl/LC_MESSAGES/messages.po
#	cps/translations/pl/LC_MESSAGES/messages.po
#	cps/translations/ru/LC_MESSAGES/messages.po
#	cps/translations/sv/LC_MESSAGES/messages.po
#	cps/translations/uk/LC_MESSAGES/messages.po
#	cps/translations/zh_Hans_CN/LC_MESSAGES/messages.po
#	messages.pot
2020-04-26 18:55:23 +02:00
Ozzieisaacs 9f0c0b34af Merge remote-tracking branch 'order_category/master' 2020-04-26 18:50:28 +02:00
Ozzieisaacs 87ec44aed5 Merge remote-tracking branch 'improve_reaad/keep-focus-on-search-input' 2020-04-26 18:38:09 +02:00
Ozzieisaacs 898e6b4f80 Calibre-Web is rebooted everytime login type ic shanged (from and to standard authentication and between login methods) 2020-04-26 18:24:22 +02:00
Ozzieisaacs dea2600913 Merge remote-tracking branch 'oauth/patch-2' Fix oauth in combination with nginx reverse proxy 2020-04-26 18:23:16 +02:00
Ozzieisaacs dc46ad16ae Bugfix view shelfs on book detail page 2020-04-26 11:35:47 +02:00
Ozzieisaacs 456550a943 Bugfix view shelfs on detiled page
bugfix datetime in archive mode
2020-04-26 11:34:10 +02:00
Ozzieisaacs 7b789b3701 Fix opds with shelves
Fix errorhandler ldap without ldap
2020-04-26 08:40:53 +02:00
Ozzieisaacs 0480d493cf Fix opds login with ldap, if ldap server is down 2020-04-25 21:12:07 +02:00
Ozzieisaacs b4d7733e0a Merge branch 'master' into Develop
# Conflicts:
#	cps/templates/list.html
#	cps/translations/cs/LC_MESSAGES/messages.po
#	cps/translations/de/LC_MESSAGES/messages.po
#	cps/translations/es/LC_MESSAGES/messages.po
#	cps/translations/fi/LC_MESSAGES/messages.po
#	cps/translations/fr/LC_MESSAGES/messages.po
#	cps/translations/hu/LC_MESSAGES/messages.po
#	cps/translations/it/LC_MESSAGES/messages.po
#	cps/translations/ja/LC_MESSAGES/messages.po
#	cps/translations/km/LC_MESSAGES/messages.po
#	cps/translations/nl/LC_MESSAGES/messages.po
#	cps/translations/pl/LC_MESSAGES/messages.po
#	cps/translations/ru/LC_MESSAGES/messages.po
#	cps/translations/sv/LC_MESSAGES/messages.po
#	cps/translations/uk/LC_MESSAGES/messages.po
#	cps/translations/zh_Hans_CN/LC_MESSAGES/messages.po
#	messages.pot
2020-04-25 20:06:25 +02:00
Ozzieisaacs 8b8fe7a0ae bugfix on create shelv via kobo sync protocol
bugfix for totally wrong json requests
prevent empty shelf names on kobo create shelf
Removed errorhandler 404
2020-04-25 20:02:55 +02:00
Ozzie Isaacs 85ffc90f66 Update markup 2020-04-25 08:56:51 +02:00
Ozzieisaacs fa38798066 Added contributing file 2020-04-25 08:55:01 +02:00
Ozzieisaacs d657330584 Fix for removing admin role from last admin user (in addition to prevent delete of last admin user) #1326 2020-04-25 07:13:55 +02:00
Ozzieisaacs 36cb79de62 Merge remote-tracking branch 'turkish/master' 2020-04-24 22:14:57 +02:00
Ozzieisaacs 063ee5e855 Merge remote-tracking branch 'remove_usage_local_var_undeclared'
Code cosmetics
2020-04-24 21:05:56 +02:00
Ozzieisaacs 7393b69757 Fix for #1326 (typo) 2020-04-24 19:25:11 +02:00
Ozzieisaacs 8bd1903d98 Fix for #1326 (opds feed user login not working -> download was not possible) 2020-04-24 18:37:29 +02:00
jvoisin d8bf540db2 Remove an undeclared and useless local variable 2020-04-24 18:04:27 +02:00
Ozzieisaacs e29f17ac46 Merge remote-tracking branch 'kobo/shelves' into Develop
# Conflicts:
#	cps/kobo.py
#	cps/shelf.py
2020-04-24 16:56:08 +02:00
iz 1770f3fd0d Update turkish translation headers 2020-04-23 22:47:24 +03:00
iz 4239f2ed71 Add turkish translation 2020-04-23 22:37:44 +03:00
iz 3939ec28ba Add turkish language names 2020-04-23 22:37:35 +03:00
Michael Shavit 742ec2b38d Fix issue with the delete_book changes introduced in
41a3623
2020-04-22 00:19:33 -04:00
Michael Shavit 9296d35517 Fix bug with shelf deletions for Kobo.
We were incorrectly setting the user_id field in the ShelfArchive table
2020-04-21 23:57:20 -04:00
Michael Shavit 06c15a792e Minor fixes to the Kobo shelves implementation (mostly typos) 2020-04-21 23:36:47 -04:00
Ozzieisaacs 95ca1e6a9d Fix for #1319 2020-04-20 18:56:39 +02:00
Ozzieisaacs 1df82110d1 Update Italian language translation 2020-04-19 19:13:10 +02:00
Ozzieisaacs 24c743d23d Code cosmetics 2020-04-19 19:08:58 +02:00
ElQuimm f1b1ebe29e Updated italian version of messages.po 2020-04-19 16:38:30 +02:00
Jeff 6384cdc74d Fix https github oauth
while using https domian and nginx as proxy, a `ProxyFix` is required.
2020-04-19 19:53:41 +08:00
celogeek d093fbb069 Keep previous search value and focus 2020-04-19 13:12:02 +02:00
celogeek f9b4505843 Sort search result by Books sort
It is far easier to search for a
series or anything and see
books in sort order
2020-04-19 13:03:46 +02:00
celogeek ca2bcc647d Handle read config
Allow advance search
Remove duplicate status on show
2020-04-19 12:50:58 +02:00
pthiben b90048d72e fix badge color on grid view to match list view 2020-04-18 23:41:01 -04:00
pthiben a5fe08e84c Fix button color that now matches HEAD on master
Update name for HTML Series that changed with HEAD
2020-04-18 23:32:15 -04:00
pthiben 2874cf531c Merge remote-tracking branch 'origin/feature/add-cover-serie-view' into feature/add-cover-serie-view
# Conflicts:
#	cps/ub.py
#	cps/web.py
2020-04-18 23:27:56 -04:00
pthiben ea7058e896 Update button lables: it seems strange to click on 'Grid' to get the list view and vice versa 2020-04-18 23:23:56 -04:00
pthiben 38bb10d36b apply suggestion from @OzzieIsaacs that fixes sorting with caliblur theme.
@OzzieIsaacs : I have no idea what the consequences are about this CSS style change. I played around in caliblur and did not notice anything weird, but I'm no calibre-web hardcore user
2020-04-18 23:23:56 -04:00
pthiben 58943bb156 update filtering so that it also uses isotope everywhere.
Fix asc/desc that did not match list view
2020-04-18 23:23:56 -04:00
pthiben 2d66da3cb9 restrict button for grid<->list switch to series lists 2020-04-18 23:23:56 -04:00
pthiben b7efbf9040 resynced grid view with list view
Changed drop-down menu to button, with same style as the other buttons. I'll probably have to make a last sync with master for final approval
2020-04-18 23:23:56 -04:00
pthiben 5222e157cb fix standard theme badges so that they stand on top left corner instead of top right: each element's width in the list seems to be double the size of the image, so right alignment gets tricky. https://github.com/janeczku/calibre-web/pull/986#issuecomment-517999218 suggests top-left alignment which does make a lot of sense. Using this for now. Maintainer might have a better idea to fix it 2020-04-18 23:23:55 -04:00
pthiben 1e3a948977 fix linter errors
Fix the sorting
Save the sorting state
Remove unnecessary filter
Add support for grid view
2020-04-18 23:22:51 -04:00
pthiben 20cc5107da Update button lables: it seems strange to click on 'Grid' to get the list view and vice versa 2020-04-18 22:57:25 -04:00
pthiben a6a4d5f09b apply suggestion from @OzzieIsaacs that fixes sorting with caliblur theme.
@OzzieIsaacs : I have no idea what the consequences are about this CSS style change. I played around in caliblur and did not notice anything weird, but I'm no calibre-web hardcore user
2020-04-18 22:56:24 -04:00
pthiben 028c53287d update filtering so that it also uses isotope everywhere.
Fix asc/desc that did not match list view
2020-04-18 22:54:58 -04:00
pthiben 24a9bea137 restrict button for grid<->list switch to series lists 2020-04-18 22:16:49 -04:00
pthiben ef1a2d1730 resynced grid view with list view
Changed drop-down menu to button, with same style as the other buttons. I'll probably have to make a last sync with master for final approval
2020-04-18 22:10:21 -04:00
pthiben 6abff36e07 fix standard theme badges so that they stand on top left corner instead of top right: each element's width in the list seems to be double the size of the image, so right alignment gets tricky. https://github.com/janeczku/calibre-web/pull/986#issuecomment-517999218 suggests top-left alignment which does make a lot of sense. Using this for now. Maintainer might have a better idea to fix it 2020-04-18 20:36:27 -04:00
Ozzieisaacs 902685a197 Fix text in user config section (random books in Detail View) 2020-04-18 21:30:28 +02:00
Ozzieisaacs c04b146486 Fix #1309 (fix duplicate shelf names in book detail view) 2020-04-18 21:15:02 +02:00
Ozzieisaacs 7bb5afa585 Merge remote-tracking branch 'kobo/shelves' into Develop 2020-04-18 21:12:21 +02:00
Ozzieisaacs 06fde4fcd0 Fix #1311 (Enable LDAP Anonymous Login) 2020-04-18 11:48:34 +02:00
Ozzieisaacs 195845ab0c Fix 2020-04-17 18:17:35 +02:00
Ozzieisaacs 81a329f1e7 Fix for #1087 ( Caliblur! Theme button alignment) 2020-04-17 18:16:28 +02:00
OzzieIsaacs cd6272a1c9 Update teststatus 2020-04-16 22:00:39 +02:00
Ozzieisaacs 53be752787 Merge remote-tracking branch 'it/patch-10' 2020-04-16 20:17:02 +02:00
Ozzieisaacs 42ac06c114 Merge remote-tracking branch 'nl/Develop' into Develop 2020-04-16 20:14:56 +02:00
Ozzieisaacs 9e159ed5ab Merge branch 'master' into Develop
# Conflicts:
#	cps/config_sql.py
#	cps/ub.py
#	cps/web.py
2020-04-16 20:12:27 +02:00
Ozzieisaacs 2c42972230 Fix for #1307 (Oauth login not working)
- Changed blueprint reference in Backend from name to id, users can now again be found
- Depending on version of flask-dance the resultcode of authorized is set different to prevent redirect loop with newer versions(>1.3)
- Redirect to login page in case no user is linked to current oauth account
- Flash messages upon successfull login, successsfull linked account
2020-04-16 17:58:42 +02:00
aribes f926e58891 Changing ordering logic when showing books from a category 2020-04-16 11:37:04 +10:00
Ozzieisaacs a784c6bd52 Fixes for oauth login after programming basic tests 2020-04-15 22:03:21 +02:00
ElQuimm 05d78f5cb5 Update italian version of message.po
Have a nice day!
2020-04-15 10:59:08 +02:00
pthiben 4ef7615d88 Merge remote-tracking branch 'origin/feature/add-cover-serie-view' into feature/add-cover-serie-view
# Conflicts:
#	cps/ub.py
2020-04-14 14:53:23 -04:00
pthiben 77c2783a3e fix linter errors
Fix the sorting
Save the sorting state
Remove unnecessary filter
Add support for grid view
2020-04-14 14:48:06 -04:00
Ozzieisaacs ce4f1258b5 Fix #1293 (error 500 on search without query) 2020-04-14 19:27:18 +02:00
Ozzieisaacs 3fbaba6693 Fix #1307 2020-04-14 18:28:16 +02:00
Ozzieisaacs a8b36aed92 Temporary fix for #1307 2020-04-14 14:13:54 +02:00
Ozzieisaacs 4749eccfa5 Added fix for python2 regex
Fix for python2 attributeError instead of TypeError on login with wrong openLDAP setting
Added default empty string on LDAPCertificate
Fix ldap as scheme for tls connection
Enabled add user on LDAP Authentication
LDAP config port is now number input
Added header for user import config
Added python ldap version to about section
Fix: It's no longer possible to login via fallback password as long as LDAP server is available
Fix: TypeError on bind is now catched and transformed to error message
Update Readme
Fixes for ldap
2020-04-14 10:58:32 +02:00
pthiben 5b1dfc123f fix linter errors
Fix the sorting
Save the sorting state
Remove unnecessary filter
Add support for grid view
2020-04-13 17:27:14 -04:00
Michael Shavit 41a3623fcc [Kobo] Add Shelf/Collection support.
Implements the v1/library/tags set of endpoints to sync CalibreWeb
shelves with the Kobo device.
Drive-by: Refactors shelf.py to consolidate how user permissions are checked.
Drive-by: Fix issue with the sync endpoint that arrises when a book is
hard-deleted.
2020-04-12 22:29:20 -04:00
Marcel 296ac203d4 Update messages.po 2020-04-11 12:32:37 +02:00
xcffl 0c9436ca82 Regenerate translation files 2020-04-11 00:06:56 +08:00
xcffl 70c9dd1b95 Fix opds format errors & extend info 2020-04-11 00:06:50 +08:00
xcffl 80753b1115 Add vscode configs into .gitignore. 2020-04-08 23:01:57 +08:00
Ozzieisaacs a194216568 Merge remote-tracking branch 'origin/master' 2020-04-05 19:10:27 +02:00
Ozzieisaacs 8bee424cc0 Merge remote-tracking branch 'ldap/master'
# Conflicts:
#	cps/admin.py
#	cps/templates/admin.html
#	cps/templates/config_edit.html
#	cps/web.py
2020-04-05 17:31:41 +02:00
Ozzie Isaacs 25ab3cabfe Add question for logfile to Issue Template 2020-04-04 18:28:43 +02:00
Ozzieisaacs 587174b771 Fix #1272 2020-04-04 08:53:22 +02:00
Ozzieisaacs 3e1c34efe6 Merge remote-tracking branch 'fix/fix_covers' into Develop 2020-04-04 06:57:54 +02:00
Ozzieisaacs 5864637f1c Merge branch 'master' into Develop 2020-04-04 06:22:17 +02:00
Ozzieisaacs ec6b346ca1 Update Translation 2020-04-03 19:50:29 +02:00
Ozzieisaacs e99f5bcced Merge remote-tracking branch 'english/master' 2020-04-03 19:46:26 +02:00
Ozzieisaacs b89309ab82 Merge remote-tracking branch 'po/master' 2020-04-03 19:27:10 +02:00
OzzieIsaacs 2d230ec96a Updated Teststatus 2020-04-02 21:13:43 +02:00
Ozzieisaacs 4550333f1e Added redirect after create shelf 2020-04-02 20:19:05 +02:00
Ozzieisaacs 3ba610eb64 Revert accidentally committed changes in opds feed 2020-04-02 19:07:41 +02:00
Ozzieisaacs 2436c6a118 Merge remote-tracking branch 'caliblur/master' 2020-04-02 18:27:21 +02:00
Ozzieisaacs 4de80b26c1 Merge remote-tracking branch 'public_shelf/calibre-web_645'
# Conflicts:
#	cps/templates/feed.xml
#	cps/templates/layout.html
2020-04-02 18:24:32 +02:00
Ozzieisaacs bab14a1fbf Update shelfs handling, bugfix changed updater 2020-04-02 18:23:24 +02:00
Ozzieisaacs 0c27ff11b9 Update Updater 2020-04-01 18:45:16 +02:00
BeckyDTP 734e2ffbb2 Updated Polish translations 2020-03-31 21:53:13 +02:00
hexeth da42c51af2 Updated to exclude new modules 2020-03-31 08:42:08 -07:00
Michael Shavit 7cb6801241 Fix issue with cover images. 2020-03-30 02:17:08 -04:00
Ozzieisaacs f6c04b9b84 Merge branch 'master' into Develop 2020-03-29 16:48:56 +02:00
Ozzieisaacs 4eacb21259 Update updater
Update change logfile
code cosmetics js files
2020-03-29 16:44:24 +02:00
Ozzie Isaacs 6d1a3ccdcc Improve logger for windows 2020-03-28 07:13:51 +01:00
Josh O'Brien c870f6e87d English Language V2 2020-03-19 13:10:10 +11:00
Ozzieisaacs 6d907094d7 Update Readme 2020-03-14 11:22:27 +01:00
Ozzieisaacs 6643f0d1e0 Merge remote-tracking branch 'nl/master'
# Conflicts:
#	cps/translations/nl/LC_MESSAGES/messages.mo
#	cps/translations/nl/LC_MESSAGES/messages.po
2020-03-14 10:45:58 +01:00
Ozzieisaacs 20b07e0752 Merge remote-tracking branch 'sv/master'
# Conflicts:
#	cps/translations/sv/LC_MESSAGES/messages.mo
#	cps/translations/sv/LC_MESSAGES/messages.po
2020-03-14 10:39:27 +01:00
Ozzieisaacs 092423adc7 Merge remote-tracking branch 'sv/master'
# Conflicts:
#	cps/translations/sv/LC_MESSAGES/messages.mo
#	cps/translations/sv/LC_MESSAGES/messages.po
2020-03-14 10:38:50 +01:00
Ozzieisaacs a50ca1a85f Fix #1259 2020-03-14 10:35:58 +01:00
Jony 02199c8c1d Update messages.po (Swedish)
Update Swedish translation
2020-03-14 09:32:33 +01:00
Jony c166c92685 Merge pull request #3 from janeczku/master
Update fork
2020-03-14 09:31:29 +01:00
Ozzieisaacs f243515261 Fix #950 (sorting order in comics) 2020-03-14 07:15:15 +01:00
Ozzieisaacs 98181fe21c Merge remote-tracking branch 'fix/kobo_book_delete' into Develop 2020-03-13 17:00:38 +01:00
Unknown a26ce8d8b5 Updated & corrected Dutch translations
Un-wonky-fied some literal translations, corrected contexts an respected punctuations, whitespaces, etc.....

See https://github.com/janeczku/calibre-web/issues/606#issuecomment-595913808
2020-03-13 14:01:42 +01:00
Michael Shavit de0e27c512 Fix #1164 merge. 2020-03-12 20:09:26 -04:00
Ozzieisaacs 09e7d76c6f Merge remote-tracking branch 'kobo_book_delete' into Develop
# Conflicts:
#	cps/kobo.py
#	cps/services/SyncToken.py
#	cps/templates/book_edit.html
#	cps/ub.py
2020-03-12 20:43:39 +01:00
Ozzieisaacs d597e05fa9 Merge remote-tracking branch 'reading_state' into Develop
# Conflicts:
#	cps/kobo.py
2020-03-12 20:35:24 +01:00
Ozzieisaacs 98dc991339 Merge remote-tracking branch 'more_kobo_fixes' into Develop 2020-03-12 20:33:22 +01:00
Ozzieisaacs 1d40434d2b Merge remote-tracking branch 'it/patch-9' 2020-03-12 20:32:08 +01:00
Ozzieisaacs 46b87dc7eb Fix for testability of kobo 2020-03-09 20:25:59 +01:00
ElQuimm fe7c56d269 italian updated version of messages.po
09.03.2020
2020-03-09 09:11:41 +01:00
OzzieIsaacs 5ba4801a79 Updated test result 2020-03-08 08:02:15 +01:00
Michael Shavit ad564e25ca More fixes for Kobo Sync
- Fix incorrect maintenance of the Synctoken timestamps.
- Fix issue where the SyncToken isn't included in the response when
kobo_proxying is disabled.
2020-03-08 01:20:54 -05:00
Ozzieisaacs 404be948d4 Merge remote-tracking branch 'ldap/Develop' into Develop
# Conflicts:
#	cps/admin.py
#	cps/web.py
2020-03-07 13:39:47 +01:00
Ozzieisaacs 8cbc345f36 Merge remote-tracking branch 'identifier/develop/edit_identifiers' into Develop 2020-03-07 13:35:58 +01:00
Ozzieisaacs 89927fd7e9 Merge ComicVine API 2020-03-07 13:33:35 +01:00
Ozzieisaacs 6b4a024234 Merge branch 'master' into Develop 2020-03-07 12:47:38 +01:00
Ozzieisaacs 18794831e0 Chang link to issue template 2020-03-07 11:27:50 +01:00
Ozzieisaacs 3fb851304f Merge remote-tracking branch 'ru/master' 2020-03-07 11:21:10 +01:00
Ozzieisaacs d267338837 Fixes for Kobo sync
Better output on upload cover
Fix for download after access to opds/fileformat
Fix osd search link
Added ratings to opds feed
Change for kobo sync for testing
2020-03-07 11:07:43 +01:00
Michael Shavit 8e1641dac9 Add support for syncing Kobo reading state. 2020-03-01 22:01:05 -05:00
Michael Shavit 57d37ffba8 Add schema support for more reading states to the ReadBook table. 2020-03-01 20:26:42 -05:00
ZIzA 82afa81220 up 2020-02-29 20:41:51 +04:00
ZIzA d730eb8d31 fix 2020-02-29 20:26:52 +04:00
ZIzA 5a219b580f ru update 2020-02-29 19:10:01 +04:00
Ozzieisaacs fb83bfb363 Fix for #1223 (pdf-reader isn't working on chrome, IE, Edge) 2020-02-29 09:55:54 +01:00
Ozzie Isaacs df7d3d18b6 pdf reader 2020-02-29 08:33:09 +01:00
Wanoo a0535aa3db Add ComicVine Api
Fetching Metadata for comicBook with ComicVine API
2020-02-28 16:04:07 +01:00
Ozzieisaacs 202b6121ab Fix for #1227 (Download books not possible with gevent IPV6 connection)
Fix issue where books aren't correctly ordered by Date Added
2020-02-26 20:05:44 +01:00
Ozzieisaacs 4e8b814ec2 Fix download URL for IPV6 2020-02-26 20:04:15 +01:00
Ozzieisaacs 6becca17bf Merge remote-tracking branch 'fix/fix_time' into Develop 2020-02-26 18:09:01 +01:00
Ozzieisaacs c8b64d4162 Update chinese translation Merge remote-tracking branch 'cn/patch-1' 2020-02-26 18:03:26 +01:00
Jeff 0854303710 Update Chinese translation 2020-02-26 19:47:25 +08:00
Michael Shavit cba3e62e71 Fix issue where books weren't correctly ordered by Date added on the
Kobo device.
2020-02-26 01:06:03 -05:00
Ozzieisaacs dcba720e97 Merge remote-tracking branch 'restrict/patch-1' 2020-02-25 16:06:24 +01:00
Rewerson 6c614c06f6 restricted_tags -> denied_tags
Fix for the next error after update:
Traceback (most recent call last):
  File "cps.py", line 34, in <module>
    from cps import create_app
  File "/home/rewerson/lib/web/cps/__init__.py", line 68, in <module>
    config = config_sql.load_configuration(ub.session)
  File "/home/rewerson/lib/web/cps/config_sql.py", line 348, in load_configuration
    update({"restricted_tags": conf.config_mature_content_tags}, synchronize_session=False)
  File "/home/rewerson/.local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 3862, in update
    update_op.exec_()
  File "/home/rewerson/.local/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py", line 1693, in exec_
    self._do_exec()
  File "/home/rewerson/.local/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py", line 1874, in _do_exec
    values = self._resolved_values
  File "/home/rewerson/.local/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py", line 1840, in _resolved_values
    desc = _entity_descriptor(self.mapper, k)
  File "/home/rewerson/.local/lib/python2.7/site-packages/sqlalchemy/orm/base.py", line 402, in _entity_descriptor
    "Entity '%s' has no property '%s'" % (description, key)
sqlalchemy.exc.InvalidRequestError: Entity '<class 'cps.ub.User'>' has no property 'restricted_tags'
2020-02-25 16:30:51 +03:00
Ozzieisaacs 9a812f11e7 Merge remote-tracking branch 'it/patch-8'
# Conflicts:
#	cps/translations/it/LC_MESSAGES/messages.po
2020-02-24 19:40:10 +01:00
Ozzieisaacs 917132fe26 Update Translation (german and russian)
Merge remote-tracking branch 'it/patch-8'

# Conflicts:
#	cps/translations/it/LC_MESSAGES/messages.po
2020-02-24 19:38:12 +01:00
Ozzieisaacs 187ca5dc8f Fix #1221 2020-02-24 19:08:54 +01:00
Ozzieisaacs 7d795771d3 Fix #1221 2020-02-24 19:02:38 +01:00
ElQuimm e51bc4ea78 Update italian message.po
Thank you for your job :-)
2020-02-23 21:23:00 +01:00
Ozzieisaacs 2dc3235d4f Merge branch 'master' into Develop 2020-02-23 20:08:37 +01:00
Ozzieisaacs 040bb4a5a8 Merge remote-tracking branch 'origin/master' 2020-02-23 20:07:51 +01:00
Ozzieisaacs fc4436f091 Update Translation 2020-02-23 20:07:21 +01:00
Ozzie Isaacs 5dbdef25d3 Windows compatibility 2020-02-23 17:24:25 +01:00
Ozzie Isaacs b9f3ac2eea Windows compatability 2020-02-23 17:23:38 +01:00
Ozzieisaacs 9fc0c3b3de Merge remote-tracking branch 'English_texts/master'
# Conflicts:
#	cps/templates/config_edit.html
#	cps/templates/config_view_edit.html
#	cps/templates/layout.html
#	cps/templates/search_form.html
#	cps/templates/user_edit.html
2020-02-23 13:27:44 +01:00
Ozzieisaacs 4f81184da0 Update translation 2020-02-23 13:22:57 +01:00
Ozzieisaacs 8223561844 Merge branch 'master' into Develop 2020-02-23 13:21:11 +01:00
Ozzieisaacs 32a6beae65 Merge remote-tracking branch 'fix/kobo'
# Conflicts:
#	cps/kobo.py
2020-02-23 13:17:59 +01:00
Ozzieisaacs 146068c936 Merge branch 'Develop'
# Conflicts:
#	cps/db.py
#	cps/templates/user_edit.html
2020-02-23 13:15:30 +01:00
Ozzieisaacs 3b8c5ef21a Merge remote-tracking branch 'get_metadata/patch-1'
Fix #1210 Load multiple authors correct via get metadata
2020-02-23 13:14:12 +01:00
Ozzieisaacs e60ef8fc97 Calibre-web version visible in about section
Update Calibre-web Version info
2020-02-23 12:40:11 +01:00
Ozzieisaacs 24d755b123 Update translations
Merge remote-tracking branch 'it/patch-7'
2020-02-23 10:55:56 +01:00
Ozzieisaacs 7c89f0b5b9 Merge with branch develop
Release version
2020-02-23 09:08:01 +01:00
Ozzieisaacs 134a10f56c Merge remote-tracking branch 'origin/Develop' into Develop
# Conflicts:
#	cps/updater.py
2020-02-23 08:58:47 +01:00
Ozzieisaacs 3a70c86f49 Update updater to handle venv folders 2020-02-23 08:58:13 +01:00
Ozzieisaacs ac431bbc4a Limit requirements 2020-02-23 08:58:13 +01:00
OzzieIsaacs 371097eb4d Update Updater 2020-02-23 07:54:58 +01:00
OzzieIsaacs 6346059698 Changed optional-requirements 2020-02-23 06:53:17 +01:00
Ozzieisaacs 372c284ad4 Merge branch 'master' into Develop 2020-02-22 16:24:06 +01:00
Ozzie Isaacs 264ccdbf6d Update bug_report.md 2020-02-22 13:36:31 +01:00
Ozzie Isaacs b95150ff11 Update bug report 2020-02-22 13:33:21 +01:00
Ozzie Isaacs 81fc04f24d Update bug_report.md 2020-02-22 13:29:36 +01:00
Ozzie Isaacs 3d4ebddb04 Update issue templates 2020-02-22 13:27:56 +01:00
Ozzie Isaacs de299e0d6a Update issue templates 2020-02-22 13:25:31 +01:00
Johnny A. dos Santos 29cb8bfec4 Fix #1210 2020-02-21 18:25:02 -03:00
Ozzieisaacs b7f3e00fbf Update updater to handle venv folders 2020-02-21 18:04:26 +01:00
Ozzieisaacs 27a18d60a7 Merge remote-tracking branch 'fix/robust_proxy' into Develop
# Conflicts:
#	cps/kobo.py
2020-02-19 18:20:03 +01:00
Ozzieisaacs de8f6d3e8d Limit requirements 2020-02-19 18:15:40 +01:00
Ozzieisaacs 6893635251 Handle kobo auth request
Handle access from localhost for kobo
2020-02-18 20:36:32 +01:00
ElQuimm 94a38a3b47 udate message.po in italian
Hello, 
updated one more time the translation :-)
I think the string "Author list" is missing.
Thank you!
Quimm
2020-02-17 21:03:33 +01:00
Michael Shavit 7d99e21d0d Merge remote-tracking branch 'original/Develop' into kobo_book_delete 2020-02-17 14:49:42 -05:00
Michael Shavit df3eb40e3c Make KoboStore proxying more robust.
* Add a timeout to prevent hanging when the KoboStore isn't reachable.
* Add back a the dummy auth implementation for when proxying is
disabled.
* Return the dummy auth response as a fallback when failing to contact
the KoboStore.
* Don't contact the KoboStore during the /sync API call when proxying is
disabled.
2020-02-17 14:37:02 -05:00
Ozzieisaacs ba6b5f8fd1 Merge branch 'master' into Develop 2020-02-17 18:42:53 +01:00
Josh O'Brien 8f518993a4 Merge branch 'master' into master 2020-02-18 00:21:59 +11:00
Niktia Pchelin dac48a2610 #645 - changes create_shelf and edit_shelf to allow user create public and private shelves with the same name 2020-02-16 23:38:35 -05:00
Niktia Pchelin 7c0d10da79 #645 - displays '(public)' next to user's public shelves in OPDS feed 2020-02-16 22:47:32 -05:00
Niktia Pchelin d77b52af96 #645 - displays '(public)' next to public shelves created by the user 2020-02-16 22:24:00 -05:00
Ozzieisaacs 29f6463ed9 Fix #1149 (Prevent invalid file extensions on Kindle Paperwhite download) 2020-02-16 19:55:05 +01:00
Ozzieisaacs ed0bdbf31d Fix for #1199 (missing referrer) 2020-02-16 19:39:32 +01:00
Ozzieisaacs b152d3e06d Merge remote-tracking branch 'auth_token/fix/reverse-proxy-authentication-with-bearer-token' 2020-02-16 19:24:28 +01:00
Ozzieisaacs 16cd57fe55 Merge remote-tracking branch 'cover_layout/fix-pull-left-cover-layout' 2020-02-16 19:19:10 +01:00
Ozzieisaacs 3f578122a3 Merge remote-tracking branch 'it/patch-6' 2020-02-16 18:56:14 +01:00
Ozzieisaacs 51a27322be Merge remote-tracking branch 'cn/master' 2020-02-16 18:53:27 +01:00
OzzieIsaacs 050feed5dc Updated test result 2020-02-16 16:53:54 +01:00
Ozzieisaacs e3ddc16657 Fix opds login not working anymore (due to kobo sync protocol) 2020-02-16 14:25:15 +01:00
André Frimberger 33cdf20cd5 Remove trailing whitespaces 2020-02-16 10:25:01 +01:00
Ozzieisaacs 317e59df4b Bugfixes from tests 2020-02-15 16:02:31 +01:00
Ozzieisaacs a9a6f5b97e Renamed restrict -> deny 2020-02-15 10:21:45 +01:00
Ozzieisaacs 8b1444ebc2 Improved testability
Less content exposed with restricted content
Tornado restart and stop working with systemd
2020-02-15 09:08:39 +01:00
Kyos 509071949a Moved style to css file 2020-02-13 21:05:24 +01:00
ElQuimm 697d857549 message.po italian 2020-02-13 11:29:26 +01:00
Ozzieisaacs 2ea45b1fdc Removed shebang on non executable scripts 2020-02-10 18:37:47 +01:00
Ozzieisaacs 726595e117 Update for testability 2020-02-10 18:34:10 +01:00
Kyos 1666e32aaf Fixes cover layouts in user edit page 2020-02-09 22:31:08 +01:00
Kyos 6a69bbe4b5 Fixes cover layouts in user edit page 2020-02-09 22:20:52 +01:00
André Frimberger 7a608b4fb0 fix binascii.Error with reverse proxy bearer token
When an authenticating reverse proxy (e.g. Keycloak Gatekeeper) adds a Bearer token in the Authorization header, every request fails with HTTP status code 500.  The corresponding error in the logs is: binascii.Error: Incorrect padding. 
Despite "reverse_proxy_header_login" is enabled, calibre-web tries first to base64decode the bearer token and fails. This patch just reverses the order in which the authentication methods  are checked.
2020-02-09 17:21:22 +01:00
Ozzieisaacs 814ad87a42 Updated pdf viewer to 2.2.228 (#1184) 2020-02-09 17:02:47 +01:00
Ozzieisaacs 3e4b5e23fa Updated pdf viewer to 2.2.228 (#1184) 2020-02-09 17:02:28 +01:00
Ozzieisaacs ab24ed8088 Handle sorting of hidden books #1123
Prevent downloading of covers from hidden books
2020-02-09 14:31:42 +01:00
Ozzieisaacs 50ba2e329a Merge branch 'master' into Develop
# Conflicts:
#	cps/shelf.py
2020-02-09 07:00:04 +01:00
Ozzie Isaacs c1e2a98f46 Merge remote-tracking branch 'origin/master' 2020-02-08 14:40:28 +01:00
Ozzie Isaacs e04aa80fd6 Fix #1181 and Fix #1182 handle removed "is_xhr" on werkzeug version 1.0.0 2020-02-08 14:40:13 +01:00
Ozzie Isaacs 482e977af4 Clarified installation procedure 2020-02-08 13:27:51 +01:00
Ozzie Isaacs 2535bbbcf1 Fix #1180 working on windows with tornado and python <3.8 again 2020-02-08 13:24:01 +01:00
Ozzieisaacs 6698773d81 Improved testability 2020-02-08 11:33:31 +01:00
xcffl aefaf47f4c Update Simplified Chinese translation 2020-02-03 17:26:17 +08:00
Josh O'Brien 9b49125776 English Language Updates
Changes to provide consistency for English language.
2020-02-03 14:22:00 +11:00
Ozzieisaacs b33a2ac90d Fix #1170 Auth-digest Header no longer crashs calibre-web
Fix #1161 Shelfs are reordering again
Update Sortable.js to 2.10.1
Code cosmetics
2020-02-02 07:47:27 +01:00
Ozzieisaacs f67953c447 Update translation
Merge remote-tracking branch 'cz/patch-11'
2020-02-01 15:03:03 +01:00
Ozzieisaacs 981632f599 Merge remote-tracking branch 'it/patch-5' 2020-02-01 15:02:10 +01:00
Ozzieisaacs a6c453d826 Merge remote-tracking branch 'pl/pl_translate_update' 2020-02-01 15:01:58 +01:00
Ozzieisaacs 4087e685f4 Fix auto detection of locale 2020-02-01 13:40:29 +01:00
Ozzieisaacs 5255085de1 Fix auto detection of locale 2020-02-01 13:38:11 +01:00
ElQuimm 9247ded710 Update - italian version of message.po 2020-01-29 21:41:54 +01:00
Jerzy Piątek 0bb0cbaef0 Updated polish translations 2020-01-28 22:28:58 +01:00
Lukáš Heroudek 0f7d272e13 Update messages.po 2020-01-28 10:03:40 +00:00
Ozzieisaacs 00dafe3121 Fix restrict columns 2020-01-27 20:34:36 +01:00
Ozzieisaacs e44494aad0 Kobo sync enable/disable working 2020-01-27 20:32:37 +01:00
Ozzieisaacs 4ab3dc2599 Merge branch 'master' into Develop
# Conflicts:
#	cps/admin.py
2020-01-27 18:20:50 +01:00
Ozzieisaacs acfad7a982 Update Italian translation 2020-01-27 18:17:17 +01:00
Ozzieisaacs b29b5b7ac1 Merge remote-tracking branch 'github/fix-admin-view-log-file' 2020-01-27 18:14:16 +01:00
ElQuimm 7803ffb995 Update italian message.po
Thank you.
2020-01-27 15:07:00 +01:00
Ghighi Eftimie fc79cdfaa2 fix mismerge 2020-01-27 15:24:11 +02:00
Michael Shavit f9dbc6bc78 Clean-up book from ArchivedBook on hard-delete.
This change also adds a warning to the hard-delete prompt that deleted
books should first be archived if the Kobo Sync feature is enabled.
An alternative would be to keep a permanent record of hard-deleted
book.
2020-01-26 16:20:10 -05:00
Michael Shavit dc7aaae235 Now that CalibreWeb delete requests are respected, we can forward
them to the KoboStore for books that aren't in Calibre.

Note: There's still an edge case where a book is removed from Calibre
without first being archived, in which case the delete call will fail.
2020-01-26 16:01:27 -05:00
Michael Shavit 9804a98af8 Merge remote-tracking branch 'original/Develop' into kobo_book_delete 2020-01-26 15:58:57 -05:00
Ghighi Eftimie 647e954e8a fix admin view of error log 2020-01-26 20:53:03 +02:00
Ozzieisaacs 004d9118bc Merge branch 'master' into Develop 2020-01-26 19:37:14 +01:00
Ozzieisaacs 594c8aad91 Update Version Info 2020-01-26 19:36:15 +01:00
Ozzieisaacs 542a0008c9 Merge remote-tracking branch 'ru/master' 2020-01-26 19:33:37 +01:00
Ozzieisaacs 24f7918aa4 Merge remote-tracking branch 'it/patch-4' 2020-01-26 19:31:52 +01:00
Ozzieisaacs 2eec329bdf Merge branch 'master' into Develop
# Conflicts:
#	cps/templates/user_edit.html
#	optional-requirements.txt
2020-01-26 19:29:36 +01:00
Ozzieisaacs 0411d4a8c9 Added 2 new kobo settings: Enable Kobo Sync (currently not working) and proxy Requests to Kobo
Added fix for kobo reader generating requests without right port number, causing url_for not working correct
2020-01-26 16:52:40 +01:00
Ozzieisaacs a986faea56 Merge remote-tracking branch 'fix/fix_creation_time' into Develop 2020-01-26 16:50:38 +01:00
Ozzieisaacs ad71d0a03f Merge remote-tracking branch 'kobo_/develop/fix-new-user' into Develop 2020-01-26 14:43:44 +01:00
Ozzieisaacs 0955c6d6fb Update Kobo 2020-01-26 14:42:53 +01:00
Michael Shavit d30b44ee0f Minor formatting changes per codacy review. 2020-01-26 01:12:52 -05:00
Michael Shavit a6f4db0f25 Fix bug where last_created is incorectly set in the SyncToken. 2020-01-26 00:32:05 -05:00
Michael Shavit 4547c328bc Delete/Restore book from Kobo device upon (un)archiving of a book in the web UI. 2020-01-26 00:29:36 -05:00
Michael Shavit 5027aeb3a0 Fix bug where last_created is incorectly set in the SyncToken. 2020-01-26 00:29:36 -05:00
Michael Shavit c0239a659c Add UI support for archived books.
Archived books will no longer appear in any book lists or searches, and
may only be restored from the Archive view.
2020-01-26 00:27:54 -05:00
Michael Shavit e404da4192 Add support for book 'deletion' (i.e archiving) from a Kobo device. 2020-01-26 00:16:55 -05:00
Simon Latapie 69fa7d0091 new user: disable kobo token on new user page
kobo token generator function is related to a user id, which is not
present on new user page.
Disable the Kobo token part when creating a new user.
2020-01-25 22:41:55 +01:00
ZIzA e1d6aec682 quick fix
sorry
2020-01-21 23:06:22 +04:00
ZIzA 155795a18e Russian language update 2020-01-21 22:29:23 +04:00
ZIzA 8c4052e884 Update README.md 2020-01-21 22:22:10 +04:00
Ozzie Isaacs 3c63e2b7e4 Update version number 2020-01-21 07:04:18 +01:00
Simon Latapie 9b119fa724 edit book: manage identifiers 2020-01-20 22:26:43 +01:00
ElQuimm a17c1c063e Update messages.po
:-)
Thank you
2020-01-20 22:05:11 +01:00
Ozzieisaacs 6728f5da2d Update Czech translation 2020-01-20 20:32:41 +01:00
Lukáš Heroudek 16adeae5c3 Update messages.po 2020-01-20 15:23:54 +00:00
Lukáš Heroudek 485eba94cc Update messages.po 2020-01-20 14:41:51 +00:00
Lukáš Heroudek 5a074348ac Update messages.po 2020-01-20 14:02:23 +00:00
Ozzieisaacs cd9bb56db5 Cleanup Kobo integration 2020-01-20 06:14:53 +01:00
Сергей 8150f934fd Update README.md 2020-01-20 01:48:57 +04:00
Сергей 4c8f3f7bae Add files via upload 2020-01-20 01:46:41 +04:00
Сергей ab5f176f58 Update README.md 2020-01-20 01:45:37 +04:00
Ozzieisaacs b294ac00ed Update for updated dependencies on comicapi 2020-01-19 17:45:04 +01:00
Ozzie Isaacs 165cbad67b Delete tess.py 2020-01-19 15:04:49 +01:00
Ozzieisaacs b30da58eb9 Update german translation 2020-01-18 12:55:18 +01:00
Ozzieisaacs b0fb6b858d Merge remote-tracking branch 'swedish/patch-4' 2020-01-18 12:29:22 +01:00
Jony 53ce22ef5e Update Swedish translation
I translated the new strings.
2020-01-18 12:18:05 +01:00
Ozzieisaacs 8e7a52f44e Merge remote-tracking branch 'swedish/master' 2020-01-18 12:04:49 +01:00
OzzieIsaacs 05a35be019 Update test result 2020-01-18 11:53:23 +01:00
Jony 4406220f70 Update Swedish translation
Update file
2020-01-18 11:25:07 +01:00
Jony 51a6cff411 Merge pull request #2 from janeczku/master
Update respository
2020-01-18 11:24:03 +01:00
Ozzieisaacs 8f4253adbd Fix for limiting domains (now no restriction to domain only) 2020-01-18 10:32:09 +01:00
Ozzieisaacs 3e404101bd Merge remote-tracking branch 'cc/develop/custom_float' into Develop 2020-01-15 17:58:57 +01:00
Ozzieisaacs 65105d9dbe Merge remote-tracking branch 'cc/develop/custom_float' into Develop 2020-01-15 17:58:23 +01:00
Ozzieisaacs 3a4d351a57 Merge remote-tracking branch 'develop/calibur-fix-colon' into Develop 2020-01-15 17:57:00 +01:00
Ozzieisaacs ce66c752c4 Updated czech translation
removed language selection for guest user
2020-01-14 18:21:31 +01:00
Lukáš Heroudek 4e42a179fa Update messages.po 2020-01-14 16:45:45 +00:00
Ozzieisaacs 973f555544 Merge branch 'master' into Develop
(updated tinymce and bootstrap datepicker)
2020-01-13 18:39:25 +01:00
Ozzieisaacs 1d7e52c198 Merge with develop:
- No. of unread books correct calculated
- logviewer handles stream output correct
- Id for testablility in email server setup
2020-01-13 18:37:29 +01:00
Ozzieisaacs 1b42dd1043 Update czech and german translation 2020-01-13 18:24:47 +01:00
Lukáš Heroudek 77e0022252 Update messages.po
Added missing and clenup
2020-01-13 10:29:14 +00:00
Simon Latapie 56964a890b caliBlur theme: fix custom column display that contain colons 2020-01-12 14:26:07 +01:00
Simon Latapie cef41661dd custom columns: add Float type support
- remove float datatype from cc_exceptions
- handle float datatype like int or bool
- change edit template to modify input step (0.01 precision, like
  in calibre UI)
2020-01-12 14:16:08 +01:00
Ozzieisaacs 68ca0b86da Updated tiniymce + locale
updated datepicker + locale
Included cs, fi language, updated ru language
2020-01-12 14:11:53 +01:00
Ozzieisaacs 79a9ef4859 Make Kobo optional
move jsonschema dependency to optional-requirements.txt
Added version of jsonschema to about section
Added additional column to RemoteAuthToken table
Update configuration of Kobo sync protocol
2020-01-12 13:42:39 +01:00
Ozzieisaacs 2798dd5916 Merge remote-tracking branch 'fix/kobo' into Develop
# Conflicts:
#	cps/db.py
#	cps/web.py
2020-01-11 18:35:04 +01:00
Ozzieisaacs 8143c16c14 Added texts for allowed denied tags in configuration
Removed domain only restriction (now it's also possible to allow/deny name parts of users email)
Fix no. of displayed books in unread books section, with applied restrictions
2020-01-11 13:28:09 +01:00
Ozzieisaacs 42435ab34a Improved testablility 2020-01-08 19:52:05 +01:00
Lukáš Heroudek 434fb2e7cb Add files via upload 2020-01-08 12:06:13 +00:00
Lukáš Heroudek bce70bf17c Update messages.po 2020-01-08 12:05:36 +00:00
Lukáš Heroudek cde44178c4 Create messages.po 2020-01-08 12:03:52 +00:00
Ozzieisaacs 661ed17d23 Handle stream output in logviewer
Add migration of global matrue content settings to user based settings
Fix Caliblur Theme (Publisherslist)
Allow/deny list/edit/add/delete of tags and custom columns
Colored table background for tags restriction
2020-01-07 20:26:59 +01:00
Ozzieisaacs c659f28334 Fix #1128 2020-01-06 11:52:59 +01:00
Ozzieisaacs 218e35e3aa Merge remote-tracking branch 'origin/Develop' into Develop 2020-01-05 16:20:46 +01:00
Ozzieisaacs cabad83418 moved language selection back, default value for restriction columns
Merge branch 'master' into Develop

# Conflicts:
#	cps/editbooks.py
2020-01-05 16:20:36 +01:00
Ozzieisaacs 24ae7350f5 Fix # #1127 (user template show random books in detail view not saved) 2020-01-05 16:18:51 +01:00
Ozzieisaacs c60277f4d3 Capitalize language selection in User settings
Remove sql statement from log.debug statement upon creation of new column in settings database
2020-01-05 14:07:26 +01:00
Ozzieisaacs 6a07cfba65 Merge remote-tracking branch 'proxy_login/1105-reverse-proxy-login'
Fix for creation of bool config settings (before: new bool columns where always created with true as default)
2020-01-05 13:38:51 +01:00
Ozzieisaacs 87c415830f Merge branch 'master' into Develop
# Conflicts:
#	cps/editbooks.py
2020-01-05 13:37:45 +01:00
Ozzieisaacs c78c63e1d5 Merge remote-tracking branch 'fix_reconnect'
# Conflicts:
#	cps/web.py
2020-01-05 08:47:03 +01:00
Ozzieisaacs 56ee8c56ba Fix #1122
(Uploading books with applied language restriction leads no longer to error 500)
2020-01-05 08:40:57 +01:00
Ozzieisaacs 48495f0d66 Merge branch 'master' into Develop
# Conflicts:
#	cps/helper.py
#	cps/templates/user_edit.html
#	cps/web.py
2020-01-04 07:57:54 +01:00
Ozzieisaacs 8ad84a7ceb Fix for #1123 (mature content is visible in shelfs) 2020-01-02 17:11:30 +01:00
Ozzieisaacs 32e818af6a Fix #1124 2020-01-02 16:09:06 +01:00
Ozzieisaacs d9adb4fc94 Improvements for limit tags 2020-01-01 17:30:08 +01:00
Ozzieisaacs 513ac6cfb4 Fix for #768 (If email server is configured, admins can send user passwords, also domains can be denied from registration)
Fixes from tests
Fix response opds with read/unread
changed db_reconnect
Changed output for error 500 (now including error message)
Fix in task queue after 20 messages
2020-01-01 17:29:01 +01:00
Ozzieisaacs 1da4efec86 Merge branch 'master' into Develop 2019-12-31 10:52:45 +01:00
Ozzieisaacs 1c630eb604 fixes from tests 2019-12-30 15:16:09 +01:00
Ozzieisaacs 1c18a788f4 Merge remote-tracking branch 'tags_restrict/master' into Develop 2019-12-30 15:15:07 +01:00
Ozzieisaacs 5887f0fe6b Fix for #768 (If email server is configured, admins can send user passwords, also domains can be denied from registration) 2019-12-29 13:54:52 +01:00
ground7 b782489a8c ldap opds download bugged 2019-12-28 21:52:26 -07:00
Ozzieisaacs 01381488f4 Fixes from tests 2019-12-28 16:18:21 +01:00
ground7 6555d5869f attempt regular login if ldap login fails as fallback 2019-12-27 23:45:42 -07:00
ground7 54c4f40188 added LDAP import
update defaults
2019-12-27 23:12:18 -07:00
Ozzieisaacs 62e8bee2a8 Fix response opds with read/unread
changed db_reconnect
Changed output for error 500 (now including error message)
Fix in task queue after 20 messages
2019-12-24 13:02:53 +01:00
Michael Shavit 9ec3ddd492 Fix the HandleCoverImage endpoint so that it requires login, and doesn't
take unused parameters.
2019-12-22 16:59:00 -05:00
Michael Shavit d81dbb13e4 Support Epub downloads 2019-12-22 16:59:00 -05:00
Michael Shavit c238367b64 Reload database on every call to v1/library/sync. This fixes an issue where side-loaded books appear in the sync response with no download urls. 2019-12-22 16:59:00 -05:00
Michael Shavit cdcb8a50d1 Fix /reconnect endpoint, which was broken by https://github.com/janeczku/calibre-web/commit/006e596c7221729c9a37b79037fa72bb88506492 2019-12-22 16:58:55 -05:00
Michael Shavit 520c695401 Fix /reconnect endpoint, which was broken by https://github.com/janeczku/calibre-web/commit/006e596c7221729c9a37b79037fa72bb88506492 2019-12-22 16:54:16 -05:00
Michael Shavit b831b9d6b2 Integrate with the official Kobo store endpoint so that no
functionanility is lost by overriding the api_endpoint setting.

Requests are either:
 * Redirected to the Kobo Store
 * Proxied to the Kobo Store
 * Proxied to the Kobo Store and merged with results from CalibreWeb.
2019-12-22 13:40:49 -05:00
Ozzieisaacs bbe91f439a Merge from master 2019-12-22 15:28:43 +01:00
Ozzieisaacs b586a32843 Fix #1115 (comic reader not working under iOS, maybe invalid issue)
Improvement for #925 (Next/Prev buttons are bigger)
2019-12-22 15:24:22 +01:00
Ozzieisaacs 288944db2c Merge remote-tracking branch 'kobo_sync/kobo' into Develop
# Conflicts:
#	cps.py
#	cps/kobo.py
#	cps/kobo_auth.py
#	cps/ub.py
2019-12-20 19:24:31 +01:00
Ozzieisaacs f2c07d8f81 Update Kobo sync 2019-12-20 19:17:08 +01:00
Michael Shavit d6a9746824 Add a filter to the Sync request endpoint to ignore books that don't
have any formats supported by the device.
2019-12-20 01:28:53 -05:00
Michael Shavit f84274f1c5 git add missing generate_kobo_auth_url.html 2019-12-20 01:08:15 -05:00
Michael Shavit 2118d920f5 Formatter. 2019-12-20 01:04:12 -05:00
Michael Shavit 207004beff Remove config_server_url setting. 2019-12-20 01:02:49 -05:00
Michael Shavit 27d084ce39 Remove the KoboUserKey-based Authentication.
Instead, the user generates the api_endpoint url to set on their device
by visiting http://.../kobo_auth/generate_auth_token.
The generated url will contain a RemoteAuthorizationToken that will be
included on all subsequent requests from the device to the kobo/
endpoints. (In contrast, the device is authenticated using a session cookie on
requests to the download endpoint).

Also use Flask.url_for to generate download urls.
2019-12-20 00:55:53 -05:00
Ozzieisaacs f705889c23 Inital Kobo 2019-12-17 20:28:20 +01:00
Ozzieisaacs 7098d08888 Added option to convert AZW3 to mobi for sending to kindle 2019-12-15 18:44:02 +01:00
Ozzieisaacs eabc6e23be Test Email now send to user's email address (#834)
Added forgot/reset password routine (#1098, #1063)
2019-12-15 17:08:17 +01:00
Ozzieisaacs b6d7207ec3 Added platform information for better debugging 2019-12-15 13:33:38 +01:00
Ozzieisaacs c33623efee Unified wording for recently added books, series, categories, etc in opds and web UI ( #1045)
Added file formats and languages to opds feed
2019-12-15 13:32:34 +01:00
Ozzieisaacs 2215bf3d7f Implemented #1083 (Advanced search for extensions) 2019-12-15 11:35:07 +01:00
Ozzieisaacs 86fe970651 More fixes for googledrive 2019-12-14 22:22:27 +01:00
Andrew Roberts 3dc372c573 fixed typo 2019-12-12 21:38:45 -05:00
Andrew Roberts efcee0a7b7 added reverse proxy configuration form and handler 2019-12-12 21:31:21 -05:00
Andrew Roberts 39b6b100f9 whitespace 2019-12-12 21:31:19 -05:00
Andrew Roberts 9351ff032f whitespace 2019-12-12 21:31:17 -05:00
Andrew Roberts f0760c07d8 added admin display of reverse proxy settings 2019-12-12 21:31:12 -05:00
Andrew Roberts 77b0954c70 use a macro for the display of boolean settings 2019-12-12 21:28:50 -05:00
Andrew Roberts af7dbbf1e4 added logic for reverse proxy login 2019-12-12 21:27:40 -05:00
Andrew Roberts b661c2fa92 added config fields to settings table 2019-12-12 21:27:38 -05:00
Ozzieisaacs e308a74dc2 Fix (#1103) Internal server error with Goodreads and no result for author name on Goodreads 2019-12-12 20:08:16 +01:00
Michael Shavit 040d7d9ae3 Remove unused import and fix python3 compatibility, as per Ozielsaacs comments. 2019-12-11 00:12:35 -05:00
Michael Shavit f9b1e84704 Remove backblaze leftovers 2019-12-10 23:57:53 -05:00
Ozzieisaacs eede894e72 Merge remote-tracking branch 'merge-metadata' 2019-12-09 20:53:16 +01:00
Michael Shavit 55c0bb6d34 Set the "Size" attribute for Kobo download_urls, and refactor the code
to eventually allow formats other than KEPUB.
2019-12-08 17:28:25 -05:00
Michael Shavit 2b55b9b250 Use the login_user Cookie to authorize download requests instead of
passing the UserKey over url params.
2019-12-08 15:33:57 -05:00
Ozzieisaacs 22add37b64 Merge remote-tracking branch 'fix typo in config_edit.html #1097'
Updated translations
2019-12-08 10:10:32 +01:00
Ozzieisaacs 8a9695d48e Fix getting metadata from douban (#858) 2019-12-08 09:52:57 +01:00
Ozzieisaacs e0faad1e59 Handle no write permission to tmp folder (#1060) 2019-12-08 09:40:54 +01:00
Michael Shavit fffa2d5a1b Support passing the Auth token as a url param.
This is required to support ebook downloads which the Kobo device emits
without any auth headers.

* Also some other small bug fixes discovered during device testing.
2019-12-07 22:55:07 -05:00
Michael Shavit 0926ae530c Remove custom_column usages from an earlier commit. 2019-12-07 21:08:53 -05:00
Michael Shavit 0b709f7dfb Merge branch 'master' into kobo 2019-12-07 20:04:54 -05:00
Michael Shavit b5da2c4199 Clean-up: Fix import order in kobo.py, and other minor formatting
changes.
2019-12-07 19:54:49 -05:00
Michael Shavit 9ede01f130 * Add a UserKeyToken to the User table for Kobo authorization.
* Add proper authorization checks on the new Kobo endpoints.

Important Note: As a side-effect, all CalibreWeb API calls can be
authorized using this token (i.e without a username&password).
2019-12-07 19:54:44 -05:00
Christian Keil c61463447f Merge metadata of uploaded book versions. 2019-12-06 15:00:01 +01:00
Michael Shavit 55b54de6a0 Add simple get_download_url implementation to replace the backblaze-backed implementation 2019-12-05 19:06:39 -05:00
Michael Shavit 5357867103 Add initial support for Kobo device Sync endpoint.
- Supports /v1/library/sync call to get list of books
- Supports /v1/library/metadata call to get metadata for a given book
  + Assumes books are stored on Backblaze for metadata call
- Changes to helper.py so that we can return no cover instead of a blank
image.
2019-12-05 01:56:59 -05:00
zhiyue 222797e631 support douban book search using apikey 2019-12-04 11:59:06 +08:00
dalin 92841b46d7 update Simplified Chinese translations. 2019-12-03 16:32:03 +08:00
dalin 6fe60d5c5e Merge branch 'master' of https://github.com/idalin/calibre-web 2019-12-03 16:07:09 +08:00
dalin 4c2323fcc9 fix typo in config_edit.html 2019-12-03 16:06:25 +08:00
Ozzieisaacs fda0ab1e86 FIx for (#1092 listening to mp3 not working) 2019-12-01 12:36:55 +01:00
Ozzieisaacs 54079b36ae Fix #1095 (epub viewer not working if only viewer rule wa sapplied) 2019-12-01 12:21:21 +01:00
Ozzieisaacs f8a99c60d8 Fix for #1096 (exception on digest request) 2019-12-01 09:33:11 +01:00
Ozzieisaacs 2f27a7b0ce Merge remote-tracking branch 'd/master' 2019-11-26 10:50:55 +01:00
Ozzieisaacs 8af178c19c Fix for gdrive not working #1081 2019-11-26 10:46:06 +01:00
Ozzieisaacs 78f9ee86b1 Fix pdf cover
Fix massadding books
Add feature inform of duplicate books
2019-11-26 08:19:03 +01:00
Ozzieisaacs ab5873984e Merge remote-tracking branch 'translation/patch-3' 2019-11-17 06:59:22 +01:00
Ozzieisaacs 62ea8b8913 Logging to stdout, proposal form #1078 2019-11-16 10:09:34 +01:00
Ozzieisaacs a4416c202d Merge remote-tracking branch 'rename/develop' 2019-11-16 08:01:18 +01:00
Jony 1f5edffccf Fix typo and update translation 2019-11-16 07:49:07 +01:00
Ozzieisaacs 651260022c Merge remote-tracking branch 'search_title/hotfix-searchform-title' 2019-11-16 07:29:00 +01:00
Ozzieisaacs 2e4344f7ea Merge remote-tracking branch 'swedish/master' 2019-11-16 07:27:08 +01:00
Jony 3cb7e77b60 Update messages.po 2019-11-14 18:52:06 +01:00
Ghighi Eftimie f782dc1857 fix for search title 2019-11-14 12:08:19 +02:00
Jony 7179f133bb Merge pull request #1 from janeczku/master
Update from original.
2019-11-12 19:34:34 +01:00
Ozzieisaacs 88f31ddad1 Fix for #1034 2019-11-07 21:04:03 +01:00
Ozzieisaacs a7ab7fcf06 Fix #1068 PDF cover Images inverted or incorrect single image grabbed from cover page 2019-11-03 09:49:54 +01:00
Ozzieisaacs 6f61e80c97 Fix #1074, #1071 2019-10-31 15:46:38 +01:00
Ozzieisaacs d1afdb4aac Fix #1074, #1071 2019-10-31 15:44:36 +01:00
Ozzieisaacs 1112dc82c9 Merge remote-tracking branch 'origin/dependabot/pip/pyyaml-5.1' 2019-10-30 20:25:53 +01:00
dependabot[bot] e47b0c6433 Bump pyyaml from 3.12 to 5.1
Bumps [pyyaml](https://github.com/yaml/pyyaml) from 3.12 to 5.1.
- [Release notes](https://github.com/yaml/pyyaml/releases)
- [Changelog](https://github.com/yaml/pyyaml/blob/master/CHANGES)
- [Commits](https://github.com/yaml/pyyaml/compare/3.12...5.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-10-29 13:55:45 +00:00
Jan Guzej 94ae9937f0 Add flash show book template 2019-10-26 13:45:06 +02:00
Jan Guzej fadd085b57 Checking and warrying on possible duplicity 2019-10-26 11:54:27 +02:00
Ozzieisaacs 5167ee520e Solve cropped image pdf import (#1068) 2019-10-22 19:11:40 +02:00
Ozzieisaacs f758a1cc64 Solve inverted image pdf import (#1068) 2019-10-21 19:33:09 +02:00
Ozzieisaacs 2145be6db2 Improvement for #1062 2019-10-20 16:47:15 +02:00
Ozzieisaacs c740fe9124 Merge remote-tracking branch 'github_2/it-adds-info-to-shelf-order' 2019-10-20 15:50:52 +02:00
Ozzieisaacs a371e40c66 Merge remote-tracking branch 'github_3/hotfix/epub-import'
Improved cover extraction from epub files
2019-10-20 15:48:06 +02:00
Ozzieisaacs ccc6184342 Merge remote-tracking branch 'github_1/patch-1' 2019-10-20 15:03:37 +02:00
Ozzieisaacs c8c2d6659c Merge remote-tracking branch 'public_reconnect/master' 2019-10-20 15:03:02 +02:00
Ozzieisaacs 1413f26c85 Merge remote-tracking branch 'github_readme/master' 2019-10-20 15:02:07 +02:00
Jan Guzej c7d7a7597c remove language from array metadata 2019-10-19 21:49:18 +02:00
Jan Guzej fbb7663a2f epub metadata import fix 2019-10-19 14:04:15 -04:00
Kyos c93dd32179 Fixed typo and column size for LG screens 2019-10-19 12:02:14 +02:00
Kyos 7165826011 Adds Authors, Series and Book Cover to the shelf order view 2019-10-19 10:57:48 +02:00
Kyos ada727a570 Adds Authors, Series and Book Cover to the shelf order view 2019-10-19 10:52:03 +02:00
gwenhael 01b0f9534c fix issue #1064
Allow for finer steps in serie-index
2019-10-18 15:12:27 +02:00
DenysNahurnyi 0735283d45 Fix syntax errors in README.md 2019-10-08 20:48:26 +03:00
zelazna 3764c33a3a Add the posibility to change the username 2019-10-01 15:36:00 +02:00
Ozzieisaacs 9fc02f67c2 Debug output for lcase 2019-09-27 15:30:39 +02:00
Ozzieisaacs 0c40e40dc3 Fix logfile loading behind reverse proxy (#1047) 2019-09-27 08:15:10 +02:00
Ozzieisaacs e31df16309 Revert bug in updater.py preventing new files from being created 2019-09-24 19:00:47 +02:00
Ozzieisaacs d7ea5bb9d7 Fix for #1037
Update German translation
2019-09-17 18:25:17 +02:00
Ozzieisaacs 6cda5fee0d Fix language selection on python3 2019-09-06 20:56:17 +02:00
Ozzieisaacs 1fb45d769f Merge remote-tracking branch 'requirements/patch-1' 2019-09-06 19:07:47 +02:00
Ozzieisaacs ca5e285c5a Merge branch 'Develop' 2019-09-06 19:05:02 +02:00
Ozzieisaacs fb0eebfc52 Merge remote-tracking branch 'spanish/master' 2019-09-06 19:03:03 +02:00
Ozzieisaacs dd90fb003e Merge remote-tracking branch 'french/master' 2019-09-06 19:01:45 +02:00
Ozzieisaacs 61cd044255 Merge remote-tracking branch 'polish/master' 2019-09-06 19:01:17 +02:00
Ozzieisaacs 879d02081a Fix #1021 2019-09-06 18:57:41 +02:00
Ozzieisaacs 051bc53aa2 Fix for #1009 2019-09-02 19:27:34 +02:00
Ozzie Isaacs a7fdbad8b4 Changed minimum flask version
Minimum flask version to 1.0.2 due to blueprint issues
2019-09-01 16:35:30 +02:00
Angel Docampo 5515772903 updated spanish translations 2019-08-27 13:16:23 +02:00
Angel Docampo ff900fd9c0 updated spanish translations 2019-08-27 13:15:18 +02:00
YamakuniandJohan Bonneau eec4be7a29 Update cps/translations/fr/LC_MESSAGES/messages.po
Co-Authored-By: Johan Bonneau <lhaagounet@gmail.com>
2019-08-25 01:01:05 +01:00
Alex Viscreanu 6a821b8a75 Fix SSLHandshakeError error on gdrive callback
changes: Update google-api-python-client and httplib2 versions
details: https://github.com/googleapis/google-api-python-client/issues/453
2019-08-24 23:43:49 +02:00
YamakuniandJohan Bonneau 1385ecb383 Update cps/translations/fr/LC_MESSAGES/messages.po
Co-Authored-By: Johan Bonneau <lhaagounet@gmail.com>
2019-08-23 16:02:21 +01:00
YamakuniandJohan Bonneau 74418f3139 Update cps/translations/fr/LC_MESSAGES/messages.po
Co-Authored-By: Johan Bonneau <lhaagounet@gmail.com>
2019-08-23 16:02:13 +01:00
YamakuniandJohan Bonneau 72def4b97b Update cps/translations/fr/LC_MESSAGES/messages.po
Co-Authored-By: Johan Bonneau <lhaagounet@gmail.com>
2019-08-23 16:02:04 +01:00
YamakuniandJohan Bonneau 564c3b4778 Update cps/translations/fr/LC_MESSAGES/messages.po
Co-Authored-By: Johan Bonneau <lhaagounet@gmail.com>
2019-08-23 16:01:47 +01:00
YamakuniandJohan Bonneau c9eff4a70c Update cps/translations/fr/LC_MESSAGES/messages.po
Co-Authored-By: Johan Bonneau <lhaagounet@gmail.com>
2019-08-23 16:01:38 +01:00
YamakuniandJohan Bonneau 879f63d1c1 Update cps/translations/fr/LC_MESSAGES/messages.po
Co-Authored-By: Johan Bonneau <lhaagounet@gmail.com>
2019-08-23 16:01:01 +01:00
YamakuniandJohan Bonneau 3fb458dd19 Update cps/translations/fr/LC_MESSAGES/messages.po
Co-Authored-By: Johan Bonneau <lhaagounet@gmail.com>
2019-08-23 16:00:52 +01:00
Yamakuni d9a73b4fa3 French translation
Add and modify some little things
2019-08-21 15:21:17 +01:00
Ozzieisaacs 23b3bfd967 Additional fix #1016 2019-08-20 19:12:40 +02:00
Ozzieisaacs f543d7f486 Fix #1016 2019-08-20 18:32:04 +02:00
Radosław Kierznowski 6a058d2c52 Update polish translation 2019-08-18 22:08:08 +02:00
Radosław Kierznowski c73698e8fd Merge https://github.com/janeczku/calibre-web 2019-08-18 21:54:29 +02:00
Vincent Kriek 38a255e069 Add automatic epub to kepub conversion using kepubify 2019-08-18 21:44:19 +02:00
Ozzieisaacs ff41775dbb Merge remote-tracking branch 'pwr/unpickle-iso-languages' into Develop 2019-08-17 17:27:06 +02:00
Ozzieisaacs 7e530618b7 Merge branch 'Develop' 2019-08-17 16:12:26 +02:00
Ozzieisaacs d04a78afe6 Merge remote-tracking branch 'public_shelf/Develop' into Develop 2019-08-17 16:03:29 +02:00
Ozzieisaacs f566237be0 Merge remote-tracking branch 'bootstrap/Develop' into Develop 2019-08-17 15:59:13 +02:00
Ozzieisaacs 87fa4a57b5 Merge branch 'master' into Develop 2019-08-17 15:57:39 +02:00
Dmitriy Istomin a65ad9483c update Bootstrap v3.4.0 -> 3.4.1 2019-08-16 11:18:39 -04:00
W1ndst0rm 4cbdccd39e Fix for https://github.com/janeczku/calibre-web/issues/1002 2019-08-13 23:07:15 -06:00
Ozzieisaacs 9356148e2d Added more information about dependencies 2019-08-06 19:53:33 +02:00
Ozzieisaacs 4be55285d8 Fix #1001 2019-08-06 18:38:17 +02:00
Ozzieisaacs 2caee35884 Merge branch 'master' into Develop 2019-08-03 20:29:28 +02:00
Ozzieisaacs 3eae2e9c2c Changed text for not found imports 2019-08-03 18:24:56 +02:00
Ozzieisaacs e9fb5d9f25 Bugfix for comicapi 2019-08-03 14:09:54 +02:00
Ozzieisaacs 6261981656 Fix for #991
Removed additional psace before Advanced search (Pull request #996)
Set startup message for not relevant imports to debug, to reduce confusion
2019-08-03 12:56:32 +02:00
Ozzieisaacs 82ca3f31f9 Merge remote-tracking branch 'pwr/master' 2019-07-31 17:40:50 +02:00
Ozzieisaacs 97f3aa8325 Update dutch language 2019-07-31 17:38:28 +02:00
Daniel Pavel 7c503b4a31 provide a default logging configuration (fixes #987) 2019-07-31 09:42:10 +03:00
Daniel Pavel 9f8cab99e3 Moved language names from iso639.pickle to a python file 2019-07-30 15:16:24 +03:00
Ozzieisaacs 5f25b81004 Final fix for #983 2019-07-29 21:43:00 +02:00
Ozzieisaacs 73bbffccaa Fix for login issue on MacOS 2019-07-28 21:29:54 +02:00
Radosław Kierznowski 43ad7d6e29 Add Flask-SimpleLDAP to requirements.txt 2019-07-27 20:26:58 +02:00
Radosław Kierznowski 2c27d631b4 Add goodreads to requirements.txt 2019-07-27 14:55:12 +02:00
Ozzieisaacs eb31b4b00b Merge branch 'master' into Develop 2019-07-27 07:23:22 +02:00
Ozzieisaacs f59d9d5aa8 Merge remote-tracking branch 'polish/master' 2019-07-27 07:19:30 +02:00
Radosław Kierznowski 746b7b1262 Update polish translation 2019-07-26 23:04:04 +02:00
Radosław Kierznowski 2d67d55b73 Merge pull request #1 from janeczku/master
Merge oryginalnego repo
2019-07-26 21:38:27 +02:00
Ozzieisaacs 5f228fbb40 Update german translation 2019-07-26 17:20:48 +02:00
Ozzieisaacs 12576393cf Merge remote-tracking branch 'spanish/patch-1'
Merge remote-tracking branch 'german/master'
2019-07-26 16:41:52 +02:00
Mainak 7f43a2e104 Update messages.po
update and revision of the Spanish translation file.
2019-07-26 11:45:45 +02:00
Ozzieisaacs 00f17bb697 Mature contents no longer displayed in/allowed to (#975):
- typeahead tags
- advanced search tags buttons
- read
- download
2019-07-25 21:42:46 +02:00
Ozzieisaacs cf00b4eebf Cover upload gives Error 500 fix #972 (leftover from refactoring)
OPDS cannot be downloaded Fix #973 (wrong blueprint selected with wrong authentication type)
Read books with link to calibre wern't detected correct Fix #971 (Refactoring error "is" is not equal to "==" for sqlalchemy)
2019-07-24 18:43:23 +02:00
Ozzieisaacs be5c67fddd Merge branch 'master' into Develop 2019-07-23 21:41:27 +02:00
Ozzieisaacs fc4dc36c65 Fix #969 (duplicate code "init" in epub reader)
Fix for #890
2019-07-23 19:26:01 +02:00
Ozzieisaacs 97a0dccdec Fix for display of format, series, category, ratings,
Fix for display of language (sorting not working yet)
2019-07-22 21:38:52 +02:00
Ozzieisaacs 9f64a96502 Fix for #890 2019-07-22 18:28:45 +02:00
Ozzieisaacs b9c3a3fcea Fix #652 2019-07-21 18:19:07 +02:00
Ozzieisaacs 6d43e0422a Fix for non found flask_login version (#968) 2019-07-21 17:45:21 +02:00
Ozzieisaacs 0d7e58ce79 Fix for #968 (database conversion fails for default strings under python2.7) 2019-07-21 16:23:31 +02:00
Ozzieisaacs 3e008ef29b Fix update dates shown in local time format again
Fix "to update" history is shown again
2019-07-21 13:28:55 +02:00
Ozzieisaacs 5c6be5d6d0 Fix for python 3 and existing unrar entry in db
deleted unnecessary lines in config html template
2019-07-21 12:58:48 +02:00
Ozzieisaacs 2bd4eff56f Merge remote-tracking branch 'pwr/config_sql' into Develop 2019-07-21 09:50:18 +02:00
Ozzieisaacs 38f3c2d5b9 Reenabled multiple oauth provider
deleted duplicate download counting function
2019-07-21 09:45:36 +02:00
Ozzieisaacs c6542fdec6 New Oauth code 2019-07-20 20:01:05 +02:00
Ozzieisaacs 26a7d9ef30 Merge branch 'Develop'
# Conflicts:
#	cps/__init__.py
#	cps/about.py
#	cps/admin.py
#	cps/cli.py
#	cps/config_sql.py
#	cps/constants.py
#	cps/converter.py
#	cps/db.py
#	cps/editbooks.py
#	cps/gdriveutils.py
#	cps/helper.py
#	cps/logger.py
#	cps/oauth.py
#	cps/server.py
#	cps/services/simpleldap.py
#	cps/ub.py
#	cps/web.py
#	cps/worker.py
#	optional-requirements.txt
#	setup.cfg
#	setup.py
2019-07-17 19:07:05 +02:00
Daniel Pavel 847dbfc021 fixed custom columns handling on dispose 2019-07-17 11:42:19 +03:00
Ozzieisaacs 929f32335f Merge remote-tracking branch 'pwr/config_sql' into Develop 2019-07-16 21:15:06 +02:00
Ozzieisaacs 61a8eccf18 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	setup.cfg
2019-07-16 21:13:51 +02:00
Ozzieisaacs d01a0c6617 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	optional-requirements.txt
2019-07-16 21:09:24 +02:00
Ozzieisaacs d168e3bfdb Add licence to oauth
fix comicapi dependency
2019-07-16 21:08:37 +02:00
Daniel Pavel 99c6247baf use the standard socket library to validate the ip address argument 2019-07-14 22:06:40 +03:00
Daniel Pavel a334ef28e7 about page: build the versions dictionary only once 2019-07-14 21:15:46 +03:00
Daniel Pavel 63634961d4 cleaner worker api
the worker thread now stops on its own
2019-07-14 20:28:32 +03:00
Ozzieisaacs d82289e303 Deactivate ldap
Fix setup for pypi
2019-07-14 18:37:44 +02:00
Daniel Pavel a836df9a5a more robust disposing of database session
avoid spamming the log with debug messages from libraries
2019-07-14 14:44:48 +03:00
Ozzieisaacs 8bfcdffeb6 Fix feature support 2019-07-14 13:20:40 +02:00
Ozzieisaacs e411c0fded Fix logging in debug mode 2019-07-14 09:18:37 +02:00
Ozzieisaacs 4708347c16 Merge branch 'Develop'
# Conflicts:
#	MANIFEST.in
#	README.md
#	cps/helper.py
#	cps/static/js/archive/archive.js
#	cps/translations/nl/LC_MESSAGES/messages.mo
#	cps/translations/nl/LC_MESSAGES/messages.po
#	cps/ub.py
#	cps/updater.py
#	cps/web.py
#	cps/worker.py
#	optional-requirements.txt
2019-07-13 20:54:21 +02:00
Ozzieisaacs be64961de5 Code cosmetics comic reader 2019-07-13 19:55:51 +02:00
Ozzieisaacs 405a3909b0 Fix for opds with LDAP authentication 2019-07-13 17:51:25 +02:00
Ozzieisaacs e734bb120a Merge remote-tracking branch 'github/config_sql' into Develop 2019-07-09 19:29:58 +02:00
Daniel Pavel 006e596c72 Moved config class into separate file.
Moved Goodreads and LDAP services into separate package.
2019-07-07 16:05:51 +03:00
Ozzieisaacs 499a66dfb0 Additional glyphicons for music on search and author page
Fix duplicate user and email (now case insensitive)
Output of calibre on stderr is now logged (full traceback in debug-log, otherwise, only errormessage)
Natural sorting for comic reader
Fix for long running tasks
2019-07-06 14:46:25 +02:00
Krakinou 11c8b47c39 Merge remote-tracking branch 'upstream/Develop' into Develop
Conflicts:
	cps/web.py
2019-07-01 22:58:11 +02:00
Krakinou 00a29f3d88 Check for change before encoding 2019-07-01 21:45:35 +02:00
Krakinou e5b9da5201 Error management 2019-07-01 21:44:58 +02:00
Ozzieisaacs ad44e58c7a Sorting for comics
Audiobook support
2019-06-29 14:23:39 +02:00
Ozzieisaacs 572b5427c7 Fix Encoding issues for python2 2019-06-23 21:11:45 +02:00
Ozzieisaacs 32af660f86 Improvements for logfile viewer
Fix for tornado-server with deactivated accesslog doesn't log to normal log anymore
Merge from master for unique user ids, get_metadata,
fix Goodreads integration
Update Translation (merge NL, update DE)
2019-06-22 19:55:59 +02:00
Ozzieisaacs cc8a431532 Merge remote-tracking branch 'socket/unix-socket' into Develop 2019-06-21 09:46:03 +02:00
Ozzieisaacs 5c7aeb2f2c Change GDrive 2019-06-20 20:12:01 +02:00
Daniel Pavel e254565901 support binding the http server to a unix socket file instead of TCP socket 2019-06-18 08:57:37 +03:00
Krakinou 3d0beba261 Base64 2019-06-17 23:47:35 +02:00
Krakinou 147947662c Base64 2019-06-17 23:46:38 +02:00
Ozzieisaacs f40fc5aa75 Update LDAP 2019-06-16 08:59:25 +02:00
Ozzieisaacs 9b74d51f21 Merge remote-tracking branch 'ldap/master' into Develop
# Conflicts:
#	cps/server.py
#	cps/templates/config_edit.html
#	cps/ub.py
#	cps/updater.py
#	cps/web.py
#	optional-requirements-ldap.txt
#	setup.cfg
2019-06-16 08:20:01 +02:00
Ozzieisaacs d45b1b8ea5 Fix #937
logviewerintegrated
Code cosmetics
2019-06-15 21:18:13 +02:00
Krakinou 4437d7376d Merge pull request #2 from Krakinou/flaskldap
Solve typo
2019-06-14 22:56:21 +02:00
Krakinou 304db0d20e Solve typo 2019-06-14 22:55:17 +02:00
Ozzieisaacs 26949970d8 Revert logging functions
Fix access logger for tornado
2019-06-11 20:07:51 +02:00
Ozzieisaacs 8e4539cf8e Prevent delete of last admin user 2019-06-10 19:26:01 +02:00
Ozzieisaacs 546ed65e1d Update logging
Fix sort order author
Fixes sorting view
Moved version info
added feature limit listening to single ipaddress
2019-06-10 14:15:21 +02:00
Ozzieisaacs 14b6202eec Code cosmetics
Fixes func in helper,web
Fixes for pdf reader
fixes for calling from another folder
renamed to calibreweb for importing in python caller script
2019-06-08 13:45:27 +02:00
Ozzieisaacs 50973ffb72 Merge remote-tracking branch 'constants/Develop-logging-cleanup' into Develop 2019-06-08 06:52:41 +02:00
Krakinou 9a5ab97d78 Merge branch 'master' into master 2019-06-08 01:41:43 +02:00
Krakinou 6190e64956 Merge pull request #1 from Krakinou/flaskldap
Flaskldap integration
2019-06-08 01:03:59 +02:00
Krakinou 79286c9384 encode password 2019-06-08 00:54:45 +02:00
yjouanique c4e3f3670f Added public /reconnect endpoint 2019-06-07 12:15:31 +07:00
Daniel Pavel b89ab9ff10 logging clean-up
- moved most constants to separate file
- sorted and cleaned-up imports
- moved logging setup to separate file
2019-06-06 18:10:22 +03:00
Krakinou 97d12b94f6 Correct settings update 2019-06-04 00:47:49 +02:00
Krakinou e4d801bbaf initial flask_simpleldap implementation 2019-06-02 22:07:22 +02:00
Ozzieisaacs a02f949d23 Fix for updater with beta releases 2019-06-02 18:09:44 +02:00
Ozzieisaacs b4e0d039ef Revert setup.cfg file 2019-06-02 09:35:42 +02:00
Ozzieisaacs bb0d5c5538 Working for pip and "normal" start for python3 and python2 2019-06-02 09:33:45 +02:00
Ozzieisaacs f5b335e8e9 Update setup 2019-06-01 09:51:20 +02:00
Ozzieisaacs 67bd5d41aa Update Version info 2019-05-31 20:06:07 +02:00
Ozzieisaacs 1879dcb24a Merge remote-tracking branch 'setup/feature/setuptools-integration' into Develop 2019-05-31 19:48:09 +02:00
Ozzieisaacs 6662a58cb0 Update translationfiles 2019-05-31 15:48:19 +02:00
Ozzieisaacs 4fecce0a0d Merge branch 'master' into Develop
# Conflicts:
#	cps/helper.py
#	cps/static/js/archive/unrar.js
#	cps/templates/readcbr.html
#	cps/templates/readpdf.html
#	cps/translations/de/LC_MESSAGES/messages.mo
#	cps/translations/de/LC_MESSAGES/messages.po
#	cps/translations/es/LC_MESSAGES/messages.mo
#	cps/translations/es/LC_MESSAGES/messages.po
#	cps/translations/fr/LC_MESSAGES/messages.mo
#	cps/translations/fr/LC_MESSAGES/messages.po
#	cps/translations/it/LC_MESSAGES/messages.mo
#	cps/translations/it/LC_MESSAGES/messages.po
#	cps/translations/ja/LC_MESSAGES/messages.mo
#	cps/translations/ja/LC_MESSAGES/messages.po
#	cps/translations/km/LC_MESSAGES/messages.mo
#	cps/translations/km/LC_MESSAGES/messages.po
#	cps/translations/nl/LC_MESSAGES/messages.mo
#	cps/translations/nl/LC_MESSAGES/messages.po
#	cps/translations/pl/LC_MESSAGES/messages.mo
#	cps/translations/pl/LC_MESSAGES/messages.po
#	cps/translations/ru/LC_MESSAGES/messages.mo
#	cps/translations/ru/LC_MESSAGES/messages.po
#	cps/translations/sv/LC_MESSAGES/messages.mo
#	cps/translations/sv/LC_MESSAGES/messages.po
#	cps/translations/uk/LC_MESSAGES/messages.mo
#	cps/translations/zh_Hans_CN/LC_MESSAGES/messages.mo
#	cps/translations/zh_Hans_CN/LC_MESSAGES/messages.po
#	cps/web.py
#	messages.pot
#	optional-requirements.txt
2019-05-31 11:17:47 +02:00
Ozzieisaacs f70c839014 Added additional permission viewer 2019-05-19 18:39:34 +02:00
Ozzieisaacs 0c80f5c63a Update Teststatus 2019-05-12 19:44:52 +02:00
Ozzieisaacs 3b03aa30a6 Fix for advanced search 2019-05-06 20:51:44 +02:00
Ozzieisaacs 9b3b2acb49 Sort button is correctly visible on list pages
Publisher list is working
2019-04-22 19:17:23 +02:00
Ozzieisaacs 406d1c76c9 Sorting and filtering of lists working (except file formats)
Refactored and bugfixing show_cover
Refactored import of helper in web.py
Fix for displaying /me (gettext) throwing error 500
Fix get search results throwing error 500
Fix routing books_list for python2.7
Fix for "me" and "settings" pages
Update sidebarview and list view
2019-04-22 19:11:35 +02:00
Ozzieisaacs bfd0e87a17 Merge branch 'master' into Develop
# Conflicts:
#	cps/helper.py
#	cps/reverseproxy.py
2019-04-21 08:50:31 +02:00
Ozzieisaacs 2de4bfdcf2 Merge branch 'master' into Develop
# Conflicts:
#	cps/book_formats.py
#	cps/helper.py
#	cps/web.py
2019-04-20 18:32:46 +02:00
Ozzieisaacs f1a65a2aeb Clarified licences for isolanguages.py and reverseproxy.py 2019-04-20 17:57:06 +02:00
Ozzieisaacs 05da2ae3c7 Update search for cyrillic letters 2019-04-14 18:20:45 +02:00
Ozzieisaacs 4ae9d4a749 Merge branch 'master' into Develop
# Conflicts:
#	cps/web.py
#	cps/worker.py
2019-04-14 18:18:39 +02:00
Ozzieisaacs 2253708da7 Merge remote-tracking branch 'proxy/patch-1' into Develop 2019-04-14 10:54:09 +02:00
Ozzieisaacs 51e591bd25 Added updated translation 2019-04-13 16:46:06 +02:00
Ozzieisaacs 2a5f2ff7b3 Merge branch 'master' into Develop
# Conflicts:
#	cps/templates/readpdf.html
#	cps/translations/uk/LC_MESSAGES/messages.po
#	cps/web.py
2019-04-13 16:42:09 +02:00
Ozzieisaacs 1c9ff6421d Fix uploader 2019-03-26 18:23:30 +01:00
Ozzieisaacs dc93222579 Update 2 column author list view 2019-03-26 17:54:12 +01:00
Ethan Lin 8143bc7873 Merge pull request #20 from janeczku/master
merge janeczku/master
2019-03-26 11:27:11 +08:00
Ozzieisaacs 772f978b45 Improved code quality 2019-03-24 16:24:43 +01:00
Ozzieisaacs 0f1db18eae Simplified typeahead 2019-03-24 16:14:42 +01:00
Ozzieisaacs 6940bb9b88 Code improvement 2019-03-24 15:58:43 +01:00
Ozzieisaacs 07649d04a3 Fix updater
Update translations
Code cleaning updater
2019-03-24 15:27:23 +01:00
Ozzieisaacs 39a3f70084 Fix for slow updater 2019-03-24 15:22:41 +01:00
tomjmul 8e8486497f Restirct a user to a set of tags 2019-03-19 13:53:41 +00:00
Ozzieisaacs e5593d9a7f Integrated author in sorting functions 2019-03-16 21:14:01 +01:00
Ozzieisaacs 3f2a9c8bae Code improvement 2019-03-16 17:33:15 +01:00
Ozzieisaacs 7c69589c5b Code cosmetics unrar.js 2019-03-16 17:30:24 +01:00
Ozzieisaacs 149e9b4bd4 Code cosmetis unrar 2019-03-16 17:28:21 +01:00
Ozzieisaacs a360b1759a Code cosmetics
bugfix import HttpError from pydrive
2019-03-16 17:20:14 +01:00
Ozzieisaacs 765b817384 Refactored shelf.py and editbooks.py 2019-03-16 16:53:22 +01:00
Ozzieisaacs baf83b2f5a Refactored generating download links 2019-03-16 16:23:40 +01:00
Ozzieisaacs 9c1b3f136f Improved sorting for rated,random, hot books, read/unread book 2019-03-16 15:48:09 +01:00
Ozzieisaacs a66873a9e2 Added file formats view 2019-03-11 18:42:30 +01:00
Ozzieisaacs 4a33278596 Update ratings 2019-03-10 19:22:35 +01:00
Ozzieisaacs 6d2270d931 Fixes for Oauth 2019-03-10 12:54:32 +01:00
Ozzieisaacs 1db1c2e7df Enabling LDAP working again
LDAP/Github oauth and Google oauth no credentials/parameters are rejected now
2019-03-10 11:12:44 +01:00
Ozzieisaacs da3fcb9a72 Merge branch 'master' into Develop
# Conflicts:
#	cps/book_formats.py
#	cps/static/css/style.css
#	cps/static/js/uploadprogress.js
#	cps/templates/author.html
#	cps/templates/detail.html
#	cps/templates/discover.html
#	cps/templates/index.html
#	cps/templates/layout.html
#	cps/templates/osd.xml
#	cps/templates/search.html
#	cps/templates/shelf.html
#	cps/translations/de/LC_MESSAGES/messages.mo
#	cps/translations/de/LC_MESSAGES/messages.po
#	cps/web.py
#	messages.pot
2019-03-10 08:31:10 +01:00
Ozzieisaacs 9144a7ceb9 Fix for sqlalchemy 1.3 2019-03-08 16:29:12 +01:00
Ozzieisaacs feb6a71f95 Fix uncompressed cbz files
merge from master -> file extension limitation
2019-03-05 20:59:30 +01:00
Ozzieisaacs 1561a4abdf Comic improvments 2019-03-05 20:19:02 +01:00
Ozzieisaacs f483ca3214 Code cosmetics
Bugfix uploadprogress
Bugfix mature content
Reenable read and unread feature
2019-03-05 17:34:51 +01:00
Ozzieisaacs 0224d45961 Code cosmetics 2019-03-04 20:03:09 +01:00
Ozzieisaacs 0be17ed157 Refactored sidebar (some parts are missing) 2019-03-04 19:34:29 +01:00
Ozzieisaacs f0de822ce7 Start refactor sidebar and view settings sidebar 2019-03-03 19:42:17 +01:00
Ozzieisaacs fb23db57b4 Added filtering of authors, series, categories, publishers 2019-03-03 15:37:53 +01:00
Ozzieisaacs fda977b155 Fix for users with umlauts 2019-03-03 08:38:36 +01:00
Ozzieisaacs 68a36597ab Fix opds login on python3 2019-03-03 07:37:15 +01:00
Ozzieisaacs de58d0a4d8 Merge remote-tracking branch 'metadata/Develop' into Develop
Update logger for updater
2019-03-01 19:09:37 +01:00
jianyun.zhao 54a006a420 [fix] Add a scroll bar to a long list of meta information 2019-03-01 10:57:27 +08:00
Ozzieisaacs 246d7673a9 Corrected file header with copyright information 2019-02-27 18:20:50 +01:00
Ozzieisaacs eef4787b79 Merge remote-tracking branch 'github/patch-1' into Develop
Oauth is optional again
2019-02-24 19:34:57 +01:00
Ozzieisaacs 1de3929988 Unicode 2019-02-24 19:08:24 +01:00
Ozzieisaacs cc3088c52f Merge branch 'master' into Develop
# Conflicts:
#	cps/book_formats.py
#	cps/static/js/libs/bootstrap.min.js
#	cps/templates/detail.html
#	cps/templates/layout.html
#	cps/web.py

Improvement updater (up to 100 releases are loaded at once)
Fix oauth pathes
Fix oauth without registering
2019-02-24 10:39:37 +01:00
Ozzieisaacs 0facb8fffa Fix #766 2019-02-23 18:28:25 +01:00
Ozzieisaacs 1a7052b287 Update pdf upload
Translation of uploadprogress dialog
2019-02-23 14:26:02 +01:00
AngelByDay 38307ececb Force namespace resolution of imports
The current import for some local modules causes errors when those already exist in site-packages on the target system.
Namely "import db" is ambiguous and may cause errors due to loading of the 'db' PyPI package instead of the module.
2019-02-22 12:24:51 -05:00
Ozzieisaacs e92497b34e Merge branch 'master' into Develop
# Conflicts:
#	cps/gdriveutils.py
#	cps/helper.py
2019-02-20 18:09:42 +01:00
Ozzieisaacs 3d5d95904a Oauth working somehow (?) 2019-02-17 19:10:16 +01:00
Ozzieisaacs a0be02e687 Ldap working 2019-02-17 09:09:20 +01:00
Ozzieisaacs 37007dafee Merge branch 'master' into Develop
# Conflicts:
#	cps/templates/layout.html
#	cps/web.py
#	readme.md
2019-02-16 10:17:46 +01:00
Ozzieisaacs 4230226716 Link fixes
Fixes reader button visible in detail view
Fix formats to convert (added htmlz)
Fix logger in updater
Added request "v3" of github api on update
Fix quotes parameter on external calls
E-Mail logger working more stable (also on python3)
Routing fixes
Change import in ub
2019-02-16 07:23:36 +01:00
Ozzieisaacs 1dc6f44828 Merge branch 'master' into Develop 2019-02-10 07:56:18 +01:00
Ozzieisaacs c1ef1bcd19 User and admin pages are working again 2019-02-09 21:26:17 +01:00
Ozzieisaacs 1fc4bc5204 Fix routes
Fix error page
2019-02-09 19:01:57 +01:00
Ozzieisaacs f5235b1d4c Uploader progress bar
Fixes imports and routes
Merge branch 'master' into Develop
Finished routing
2019-02-09 18:46:41 +01:00
Ozzieisaacs d6ee8f75e9 More refactoring 2019-02-08 20:12:16 +01:00
Ozzieisaacs a00d93a2d9 Working again (basically) 2019-02-06 21:52:32 +01:00
Ozzieisaacs 561d40f8ff Merge branch 'master' into Develop 2019-02-03 20:30:37 +01:00
Ozzieisaacs 36229076f7 Refactor subprocess calls 2019-02-03 18:32:27 +01:00
Ozzieisaacs 7f34073955 Merge branch 'master' into Develop
# Conflicts:
#	cps/web.py
#	readme.md
2019-02-03 17:33:54 +01:00
Ozzieisaacs b75b91606c Fix config oauth-UI 2019-01-27 11:32:16 +01:00
Ozzieisaacs 80582573f5 Merge remote-tracking branch 'oauth/oauth' into Develop
# Conflicts:
#	cps/templates/config_edit.html
#	cps/ub.py
#	cps/web.py
2019-01-27 11:22:22 +01:00
Ozzieisaacs 3683e4e7eb Merge remote-tracking branch 'ldap/master' into Develop 2019-01-27 11:18:08 +01:00
Ozzieisaacs 8ababf9f77 Merge remote-tracking branch 'simple_shelf/shelf-down' into Develop 2019-01-27 11:16:11 +01:00
Ozzieisaacs 5971194678 Merge remote-tracking branch 'audiobook/Branch_c27805b'
# Conflicts:
#	cps/templates/detail.html
#	cps/web.py
#	readme.md
2019-01-27 11:14:38 +01:00
Krakinou d48cdcc789 Correct authentication in case LDAP not activated 2019-01-13 11:21:11 +01:00
Krakinou d763168dec Merge branch 'master' of https://github.com/Krakinou/calibre-web 2019-01-13 11:04:32 +01:00
Krakinou 7ccc40cf5b Moving import LDAP
Correct optional-requirements-ldap.txt spelling
2019-01-13 11:02:03 +01:00
Krakinou aafb267787 Merge branch 'master' into master 2019-01-12 23:46:59 +01:00
Krakinou 82e4f11334 Forgot requirements :/ 2019-01-12 19:24:21 +01:00
Krakinou 2e37c14d94 Clean some comment 2019-01-12 18:40:32 +01:00
Krakinou 91f0908059 insert into db
connect via LDAP config
2019-01-12 18:07:03 +01:00
Krakinou 8d284b151d Edit html config 2019-01-12 12:52:27 +01:00
Krakinou 30954cc27f Initial LDAP support 2019-01-10 23:51:01 +01:00
Jim Ma 4b76b8400d Add OAuth link&unlink in user profile 2018-10-14 16:51:00 +08:00
Jim Ma 1abbcfa3c6 Add OAuth support: GitHub & Google 2018-10-14 16:51:00 +08:00
otapi 9b4ca22254 Update shelf.html 2018-10-11 18:39:31 +02:00
otapi c6d3613e57 Add UI link button to shelves 2018-10-11 18:20:38 +02:00
otapi e0229c917c Download only shelf
Show only titles and download button for specific shelf. Currently only direct link works, e.g: calibre-web/shelfdown/6
2018-10-10 23:01:05 +02:00
964 changed files with 197563 additions and 139415 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
updater.py ident export-subst
constants.py ident export-subst
/test export-ignore
cps/static/css/libs/* linguist-vendored
cps/static/js/libs/* linguist-vendored
+39
View File
@@ -0,0 +1,39 @@
---
name: Bug/Problem report
about: Create a report to help us improve Calibre-Web
title: ''
labels: ''
assignees: ''
---
<!-- Please have a look at our [Contributing Guidelines](https://github.com/janeczku/calibre-web/blob/master/CONTRIBUTING.md) -->
**Describe the bug/problem**
A clear and concise description of what the bug is. If you are asking for support, please check our [Wiki](https://github.com/janeczku/calibre-web/wiki) if your question is already answered there.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Logfile**
Add content of calibre-web.log file or the relevant error, try to reproduce your problem with "debug" log-level to get more output.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please complete the following information):**
- OS: [e.g. Windows 10/Raspberry Pi OS]
- Python version: [e.g. python2.7]
- Calibre-Web version: [e.g. 0.6.8 or 087c4c59 (git rev-parse --short HEAD)]:
- Docker container: [None/LinuxServer]:
- Special Hardware: [e.g. Rasperry Pi Zero]
- Browser: [e.g. Chrome 83.0.4103.97, Safari 13.3.7, Firefox 68.0.1 ESR]
**Additional context**
Add any other context about the problem here. [e.g. access via reverse proxy, database background sync, special database location]
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
+22
View File
@@ -0,0 +1,22 @@
---
name: Feature request
about: Suggest an idea for Calibre-Web
title: ''
labels: ''
assignees: ''
---
<!-- Please have a look at our [Contributing Guidelines](https://github.com/janeczku/calibre-web/blob/master/CONTRIBUTING.md) -->
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+8 -5
View File
@@ -6,26 +6,29 @@ __pycache__/
# Distribution / packaging
.Python
.python-version
env/
venv/
eggs/
dist/
executable/
build/
vendor/
.eggs/
*.egg-info/
.installed.cfg
*.egg
.pylint.d
# calibre-web
*.db
*.log
config.ini
cps/static/[0-9]*
.idea/
*.bak
*.log.*
tags
settings.yaml
gdrive_credentials
vendor
client_secrets.json
gmail.json
+46
View File
@@ -0,0 +1,46 @@
## How to contribute to Calibre-Web
First of all, we would like to thank you for reading this text. We are happy you are willing to contribute to Calibre-Web.
### **General**
**Communication language** is English. Google translated texts are not as bad as you might think, they are usually understandable, so don't worry if you generate your post that way.
**Calibre-Web** is not **Calibre**. If you are having a question regarding Calibre please post this at their [repository](https://github.com/kovidgoyal/calibre).
**Docker-Containers** of Calibre-Web are maintained by different persons than the people who drive Calibre-Web. If we come to the conclusion during our analysis that the problem is related to Docker, we might ask you to open a new issue at the repository of the Docker Container.
If you are having **Basic Installation Problems** with python or its dependencies, please consider using your favorite search engine to find a solution. In case you can't find a solution, we are happy to help you.
We can offer only very limited support regarding configuration of **Reverse-Proxy Installations**, **OPDS-Reader** or other programs in combination with Calibre-Web.
### **Translation**
Some of the user languages in Calibre-Web having missing translations. We are happy to add the missing texts if you translate them. Create a Pull Request, create an issue with the .po file attached, or write an email to "ozzie.fernandez.isaacs@googlemail.com" with attached translation file. To display all book languages in your native language an additional file is used (iso_language_names.py). The content of this file is auto-generated with the corresponding translations of Calibre, please do not edit this file on your own.
### **Documentation**
The Calibre-Web documentation is hosted in the Github [Wiki](https://github.com/janeczku/calibre-web/wiki). The Wiki is open to everybody, if you find a problem, feel free to correct it. If information is missing, you are welcome to add it. The content will be reviewed time by time. Please try to be consistent with the form with the other Wiki pages (e.g. the project name is Calibre-Web with 2 capital letters and a dash in between).
### **Reporting a bug**
Do not open up a GitHub issue if the bug is a **security vulnerability** in Calibre-Web. Instead, please write an email to "ozzie.fernandez.isaacs@googlemail.com".
Ensure the ***bug was not already reported** by searching on GitHub under [Issues](https://github.com/janeczku/calibre-web/issues). Please also check if a solution for your problem can be found in the [wiki](https://github.com/janeczku/calibre-web/wiki).
If you're unable to find an **open issue** addressing the problem, open a [new one](https://github.com/janeczku/calibre-web/issues/new?assignees=&labels=&template=bug_report.md&title=). Be sure to include a **title** and **clear description**, as much relevant information as possible, the **issue form** helps you providing the right information. Deleting the form and just pasting the stack trace doesn't speed up fixing the problem. If your issue could be resolved, consider closing the issue.
### **Feature Request**
If there is a feature missing in Calibre-Web and you can't find a feature request in the [Issues](https://github.com/janeczku/calibre-web/issues) section, you could create a [feature request](https://github.com/janeczku/calibre-web/issues/new?assignees=&labels=&template=feature_request.md&title=).
We will not extend Calibre-Web with any more login abilities or add further files storages, or file syncing ability. Furthermore Calibre-Web is made for home usage for company in-house usage, so requests regarding any sorts of social interaction capability, payment routines, search engine or web site analytics integration will not be implemented.
### **Contributing code to Calibre-Web**
Open a new GitHub pull request with the patch. Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
In case your code enhances features of Calibre-Web: Create your pull request for the development branch if your enhancement consists of more than some lines of code in a local section of Calibre-Webs code. This makes it easier to test it and check all implication before it's made public.
Please check if your code runs with python 3, python 2 is no longer supported. If possible and the feature is related to operating system functions, try to check it on Windows and Linux.
Calibre-Web is automatically tested on Linux in combination with python 3.8. The code for testing is in a [separate repo](https://github.com/OzzieIsaacs/calibre-web-test) on Github. It uses unit tests and performs real system tests with selenium; it would be great if you could consider also writing some tests.
A static code analysis is done by Codacy, but it's partly broken and doesn't run automatically. You could check your code with ESLint before contributing, a configuration file can be found in the projects root folder.
+1 -3
View File
@@ -1,3 +1 @@
include cps/static/*
include cps/templates/*
include cps/translations/*
graft src/calibreweb
+101
View File
@@ -0,0 +1,101 @@
# About
Calibre-Web is a web app providing a clean interface for browsing, reading and downloading eBooks using an existing [Calibre](https://calibre-ebook.com) database.
[![GitHub License](https://img.shields.io/github/license/janeczku/calibre-web?style=flat-square)](https://github.com/janeczku/calibre-web/blob/master/LICENSE)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/w/janeczku/calibre-web?logo=github&style=flat-square&label=commits)]()
[![GitHub all releases](https://img.shields.io/github/downloads/janeczku/calibre-web/total?logo=github&style=flat-square)](https://github.com/janeczku/calibre-web/releases)
[![PyPI](https://img.shields.io/pypi/v/calibreweb?logo=pypi&logoColor=fff&style=flat-square)](https://pypi.org/project/calibreweb/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/calibreweb?logo=pypi&logoColor=fff&style=flat-square)](https://pypi.org/project/calibreweb/)
[![Discord](https://img.shields.io/discord/838810113564344381?label=Discord&logo=discord&style=flat-square)](https://discord.gg/h2VsJ2NEfB)
*This software is a fork of [library](https://github.com/mutschler/calibreserver) and licensed under the GPL v3 License.*
![Main screen](https://github.com/janeczku/calibre-web/wiki/images/main_screen.png)
## Features
- Bootstrap 3 HTML5 interface
- full graphical setup
- User management with fine-grained per-user permissions
- Admin interface
- User Interface in brazilian, czech, dutch, english, finnish, french, german, greek, hungarian, italian, japanese, khmer, korean, polish, russian, simplified and traditional chinese, spanish, swedish, turkish, ukrainian
- OPDS feed for eBook reader apps
- Filter and search by titles, authors, tags, series and language
- Create a custom book collection (shelves)
- Support for editing eBook metadata and deleting eBooks from Calibre library
- Support for converting eBooks through Calibre binaries
- Restrict eBook download to logged-in users
- Support for public user registration
- Send eBooks to Kindle devices with the click of a button
- Sync your Kobo devices through Calibre-Web with your Calibre library
- Support for reading eBooks directly in the browser (.txt, .epub, .pdf, .cbr, .cbt, .cbz, .djvu)
- Upload new books in many formats, including audio formats (.mp3, .m4a, .m4b)
- Support for Calibre Custom Columns
- Ability to hide content based on categories and Custom Column content per user
- Self-update capability
- "Magic Link" login to make it easy to log on eReaders
- Login via LDAP, google/github oauth and via proxy authentication
## Installation
#### Installation via pip (recommended)
1. Install calibre web via pip with the command `pip install calibreweb` (Depending on your OS and or distro the command could also be `pip3`).
2. Optional features can also be installed via pip, please refer to [this page](https://github.com/janeczku/calibre-web/wiki/Dependencies-in-Calibre-Web-Linux-Windows) for details
3. Calibre-Web can be started afterwards by typing `cps` or `python3 -m cps`
#### Manual installation
1. Install dependencies by running `pip3 install --target vendor -r requirements.txt` (python3.x). Alternativly set up a python virtual environment.
2. Execute the command: `python3 cps.py` (or `nohup python3 cps.py` - recommended if you want to exit the terminal window)
Issues with Ubuntu:
Please note that running the above install command can fail on some versions of Ubuntu, saying `"can't combine user with prefix"`. This is a [known bug](https://github.com/pypa/pip/issues/3826) and can be remedied by using the command `pip install --system --target vendor -r requirements.txt` instead.
## Quick start
Point your browser to `http://localhost:8083` or `http://localhost:8083/opds` for the OPDS catalog
Set `Location of Calibre database` to the path of the folder where your Calibre library (metadata.db) lives, push "submit" button\
Optionally a Google Drive can be used to host the calibre library [-> Using Google Drive integration](https://github.com/janeczku/calibre-web/wiki/Configuration#using-google-drive-integration)
Go to Login page
#### Default admin login:
*Username:* admin\
*Password:* admin123
## Requirements
python 3.5+
Optionally, to enable on-the-fly conversion from one ebook format to another when using the send-to-kindle feature, or during editing of ebooks metadata:
[Download and install](https://calibre-ebook.com/download) the Calibre desktop program for your platform and enter the folder including program name (normally /opt/calibre/ebook-convert, or C:\Program Files\calibre\ebook-convert.exe) in the field "calibre's converter tool" on the setup page.
[Download](https://github.com/pgaskin/kepubify/releases/latest) Kepubify tool for your platform and place the binary starting with `kepubify` in Linux: `\opt\kepubify` Windows: `C:\Program Files\kepubify`.
## Docker Images
A pre-built Docker image is available in these Docker Hub repository (maintained by the LinuxServer team):
#### **LinuxServer - x64, armhf, aarch64**
+ Docker Hub - [https://hub.docker.com/r/linuxserver/calibre-web](https://hub.docker.com/r/linuxserver/calibre-web)
+ Github - [https://github.com/linuxserver/docker-calibre-web](https://github.com/linuxserver/docker-calibre-web)
+ Github - (Optional Calibre layer) - [https://github.com/linuxserver/docker-calibre-web/tree/calibre](https://github.com/linuxserver/docker-calibre-web/tree/calibre)
This image has the option to pull in an extra docker manifest layer to include the Calibre `ebook-convert` binary. Just include the environmental variable `DOCKER_MODS=linuxserver/calibre-web:calibre` in your docker run/docker compose file. **(x64 only)**
If you do not need this functionality then this can be omitted, keeping the image as lightweight as possible.
Both the Calibre-Web and Calibre-Mod images are rebuilt automatically on new releases of Calibre-Web and Calibre respectively, and on updates to any included base image packages on a weekly basis if required.
+ The "path to convertertool" should be set to `/usr/bin/ebook-convert`
+ The "path to unrar" should be set to `/usr/bin/unrar`
# Contact
Just reach us out on [Discord](https://discord.gg/h2VsJ2NEfB)
For further information, How To's and FAQ please check the [Wiki](https://github.com/janeczku/calibre-web/wiki)
# Contributing to Calibre-Web
Please have a look at our [Contributing Guidelines](https://github.com/janeczku/calibre-web/blob/master/CONTRIBUTING.md)
+39
View File
@@ -0,0 +1,39 @@
# Security Policy
## Reporting a Vulnerability
Please report security issues to ozzie.fernandez.isaacs@googlemail.com
## Supported Versions
To receive fixes for security vulnerabilities it is required to always upgrade to the latest version of Calibre-Web. See https://github.com/janeczku/calibre-web/releases/latest for the latest release.
## History
| Fixed in | Description |CVE number |
|---------------|--------------------------------------------------------------------------------------------------------------------|---------|
| 3rd July 2018 | Guest access acts as a backdoor ||
| V 0.6.7 | Hardcoded secret key for sessions |CVE-2020-12627 |
| V 0.6.13 | Calibre-Web Metadata cross site scripting |CVE-2021-25964|
| V 0.6.13 | Name of Shelves are only visible to users who can access the corresponding shelf Thanks to @ibarrionuevo ||
| V 0.6.13 | JavaScript could get executed in the description field. Thanks to @ranjit-git and Hagai Wechsler (WhiteSource) ||
| V 0.6.13 | JavaScript could get executed in a custom column of type "comment" field ||
| V 0.6.13 | JavaScript could get executed after converting a book to another format with a title containing javascript code ||
| V 0.6.13 | JavaScript could get executed after converting a book to another format with a username containing javascript code ||
| V 0.6.13 | JavaScript could get executed in the description series, categories or publishers title ||
| V 0.6.13 | JavaScript could get executed in the shelf title ||
| V 0.6.13 | Login with the old session cookie after logout. Thanks to @ibarrionuevo ||
| V 0.6.14 | CSRF was possible. Thanks to @mik317 and Hagai Wechsler (WhiteSource) |CVE-2021-25965|
| V 0.6.14 | Migrated some routes to POST-requests (CSRF protection). Thanks to @scara31 ||
| V 0.6.15 | Fix for "javascript:" script links in identifier. Thanks to @scara31 ||
| V 0.6.15 | Cross-Site Scripting vulnerability on uploaded cover file names. Thanks to @ibarrionuevo ||
| V 0.6.15 | Creating public shelfs is now denied if user is missing the edit public shelf right. Thanks to @ibarrionuevo ||
| V 0.6.15 | Changed error message in case of trying to delete a shelf unauthorized. Thanks to @ibarrionuevo ||
| V 0.6.16 | JavaScript could get executed on authors page. Thanks to @alicaz ||
| V 0.6.16 | Localhost can no longer be used to upload covers. Thanks to @scara31 ||
| V 0.6.16 | Another case where public shelfs could be created without permission is prevented. Thanks to @ibarrionuevo ||
## Staement regarding Log4j (CVE-2021-44228 and related)
Calibre-web is not affected by bugs related to Log4j. Calibre-Web is a python program, therefore not using Java, and not using the Java logging feature log4j.
+73 -12
View File
@@ -1,21 +1,82 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2012-2019 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
base_path = os.path.dirname(os.path.abspath(__file__))
# Insert local directories into path
sys.path.append(base_path)
sys.path.append(os.path.join(base_path, 'cps'))
sys.path.append(os.path.join(base_path, 'vendor'))
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'vendor'))
from cps import create_app
from cps import web_server
from cps.opds import opds
from cps.web import web
from cps.jinjia import jinjia
from cps.about import about
from cps.shelf import shelf
from cps.admin import admi
from cps.gdrive import gdrive
from cps.editbooks import editbook
from cps.remotelogin import remotelogin
from cps.search_metadata import meta
from cps.error_handler import init_errorhandler
try:
from cps.kobo import kobo, get_kobo_activated
from cps.kobo_auth import kobo_auth
kobo_available = get_kobo_activated()
except (ImportError, AttributeError): # Catch also error for not installed flask-WTF (missing csrf decorator)
kobo_available = False
try:
from cps.oauth_bb import oauth
oauth_available = True
except ImportError:
oauth_available = False
def main():
app = create_app()
init_errorhandler()
app.register_blueprint(web)
app.register_blueprint(opds)
app.register_blueprint(jinjia)
app.register_blueprint(about)
app.register_blueprint(shelf)
app.register_blueprint(admi)
app.register_blueprint(remotelogin)
app.register_blueprint(meta)
app.register_blueprint(gdrive)
app.register_blueprint(editbook)
if kobo_available:
app.register_blueprint(kobo)
app.register_blueprint(kobo_auth)
if oauth_available:
app.register_blueprint(oauth)
success = web_server.start()
sys.exit(0 if success else 1)
from cps.server import Server
if __name__ == '__main__':
Server.startServer()
main()
+34
View File
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11,
# andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh,
# falgh1, grunjol, csitko, ytils, xybydy, trasba, vrabe,
# ruben-herold, marblepebble, JackED42, SiphonSquirrel,
# apetresc, nanu-c, mutschler, GammaC0de, vuolter
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from flask_login import LoginManager
from flask import session
class MyLoginManager(LoginManager):
def _session_protection_failed(self):
sess = session._get_current_object()
ident = self._session_identifier_generator()
if(sess and not (len(sess) == 1 and sess.get('csrf_token', None))) and ident != sess.get('_id', None):
return super(). _session_protection_failed()
return False
Executable → Regular
+188 -1
View File
@@ -1,2 +1,189 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11,
# andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh,
# falgh1, grunjol, csitko, ytils, xybydy, trasba, vrabe,
# ruben-herold, marblepebble, JackED42, SiphonSquirrel,
# apetresc, nanu-c, mutschler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
__package__ = "cps"
import sys
import os
import mimetypes
from babel import Locale as LC
from babel import negotiate_locale
from babel.core import UnknownLocaleError
from flask import Flask, request, g
from .MyLoginManager import MyLoginManager
from flask_babel import Babel
from flask_principal import Principal
from . import config_sql, logger, cache_buster, cli, ub, db
from .reverseproxy import ReverseProxied
from .server import WebServer
from .dep_check import dependency_check
try:
import lxml
lxml_present = True
except ImportError:
lxml_present = False
try:
from flask_wtf.csrf import CSRFProtect
wtf_present = True
except ImportError:
wtf_present = False
mimetypes.init()
mimetypes.add_type('application/xhtml+xml', '.xhtml')
mimetypes.add_type('application/epub+zip', '.epub')
mimetypes.add_type('application/fb2+zip', '.fb2')
mimetypes.add_type('application/x-mobipocket-ebook', '.mobi')
mimetypes.add_type('application/x-mobipocket-ebook', '.prc')
mimetypes.add_type('application/vnd.amazon.ebook', '.azw')
mimetypes.add_type('application/x-mobi8-ebook', '.azw3')
mimetypes.add_type('application/x-cbr', '.cbr')
mimetypes.add_type('application/x-cbz', '.cbz')
mimetypes.add_type('application/x-cbt', '.cbt')
mimetypes.add_type('image/vnd.djvu', '.djvu')
mimetypes.add_type('application/mpeg', '.mpeg')
mimetypes.add_type('application/mpeg', '.mp3')
mimetypes.add_type('application/mp4', '.m4a')
mimetypes.add_type('application/mp4', '.m4b')
mimetypes.add_type('application/ogg', '.ogg')
mimetypes.add_type('application/ogg', '.oga')
mimetypes.add_type('text/css', '.css')
mimetypes.add_type('text/javascript; charset=UTF-8', '.js')
app = Flask(__name__)
app.config.update(
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE='Lax',
REMEMBER_COOKIE_SAMESITE='Lax', # will be available in flask-login 0.5.1 earliest
WTF_CSRF_SSL_STRICT=False
)
lm = MyLoginManager()
lm.login_view = 'web.login'
lm.anonymous_user = ub.Anonymous
lm.session_protection = 'strong'
if wtf_present:
csrf = CSRFProtect()
csrf.init_app(app)
else:
csrf = None
ub.init_db(cli.settingspath)
# pylint: disable=no-member
config = config_sql.load_configuration(ub.session)
web_server = WebServer()
babel = Babel()
_BABEL_TRANSLATIONS = set()
log = logger.create()
from . import services
db.CalibreDB.update_config(config)
db.CalibreDB.setup_db(config.config_calibre_dir, cli.settingspath)
calibre_db = db.CalibreDB()
def create_app():
if sys.version_info < (3, 0):
log.info(
'*** Python2 is EOL since end of 2019, this version of Calibre-Web is no longer supporting Python2, please update your installation to Python3 ***')
print(
'*** Python2 is EOL since end of 2019, this version of Calibre-Web is no longer supporting Python2, please update your installation to Python3 ***')
web_server.stop(True)
sys.exit(5)
if not lxml_present:
log.info('*** "lxml" is needed for calibre-web to run. Please install it using pip: "pip install lxml" ***')
print('*** "lxml" is needed for calibre-web to run. Please install it using pip: "pip install lxml" ***')
web_server.stop(True)
sys.exit(6)
if not wtf_present:
log.info('*** "flask-WTF" is needed for calibre-web to run. Please install it using pip: "pip install flask-WTF" ***')
print('*** "flask-WTF" is needed for calibre-web to run. Please install it using pip: "pip install flask-WTF" ***')
web_server.stop(True)
sys.exit(7)
for res in dependency_check() + dependency_check(True):
log.info('*** "{}" version does not fit the requirements. Should: {}, Found: {}, please consider installing required version ***'
.format(res['name'],
res['target'],
res['found']))
app.wsgi_app = ReverseProxied(app.wsgi_app)
if os.environ.get('FLASK_DEBUG'):
cache_buster.init_cache_busting(app)
log.info('Starting Calibre Web...')
Principal(app)
lm.init_app(app)
app.secret_key = os.getenv('SECRET_KEY', config_sql.get_flask_session_key(ub.session))
web_server.init_app(app, config)
babel.init_app(app)
_BABEL_TRANSLATIONS.update(str(item) for item in babel.list_translations())
_BABEL_TRANSLATIONS.add('en')
if services.ldap:
services.ldap.init_app(app, config)
if services.goodreads_support:
services.goodreads_support.connect(config.config_goodreads_api_key,
config.config_goodreads_api_secret,
config.config_use_goodreads)
return app
@babel.localeselector
def get_locale():
# if a user is logged in, use the locale from the user settings
user = getattr(g, 'user', None)
if user is not None and hasattr(user, "locale"):
if user.name != 'Guest': # if the account is the guest account bypass the config lang settings
return user.locale
preferred = list()
if request.accept_languages:
for x in request.accept_languages.values():
try:
preferred.append(str(LC.parse(x.replace('-', '_'))))
except (UnknownLocaleError, ValueError) as e:
log.debug('Could not parse locale "%s": %s', x, e)
return negotiate_locale(preferred or ['en'], _BABEL_TRANSLATIONS)
@babel.timezoneselector
def get_timezone():
user = getattr(g, 'user', None)
return user.timezone if user else None
from .updater import Updater
updater_thread = Updater()
updater_thread.start()
+145
View File
@@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11,
# andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh,
# falgh1, grunjol, csitko, ytils, xybydy, trasba, vrabe,
# ruben-herold, marblepebble, JackED42, SiphonSquirrel,
# apetresc, nanu-c, mutschler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import platform
import sqlite3
from collections import OrderedDict
import babel, pytz, requests, sqlalchemy
import werkzeug, flask, flask_login, flask_principal, jinja2
from flask_babel import gettext as _
try:
from flask_wtf import __version__ as flaskwtf_version
except ImportError:
flaskwtf_version = _(u'not installed')
from . import db, calibre_db, converter, uploader, server, isoLanguages, constants, gdriveutils, dep_check
from .render_template import render_title_template
try:
from flask_login import __version__ as flask_loginVersion
except ImportError:
from flask_login.__about__ import __version__ as flask_loginVersion
try:
# pylint: disable=unused-import
import unidecode
# _() necessary to make babel aware of string for translation
unidecode_version = _(u'installed')
except ImportError:
unidecode_version = _(u'not installed')
try:
from flask_dance import __version__ as flask_danceVersion
except ImportError:
flask_danceVersion = None
try:
from greenlet import __version__ as greenlet_Version
except ImportError:
greenlet_Version = None
try:
from scholarly import scholarly
scholarly_version = _(u'installed')
except ImportError:
scholarly_version = _(u'not installed')
from . import services
about = flask.Blueprint('about', __name__)
ret = dict()
req = dep_check.load_dependencys(False)
opt = dep_check.load_dependencys(True)
for i in (req + opt):
ret[i[1]] = i[0]
if constants.NIGHTLY_VERSION[0] == "$Format:%H$":
calibre_web_version = constants.STABLE_VERSION['version']
else:
calibre_web_version = (constants.STABLE_VERSION['version'] + ' - '
+ constants.NIGHTLY_VERSION[0].replace('%','%%') + ' - '
+ constants.NIGHTLY_VERSION[1].replace('%','%%'))
if getattr(sys, 'frozen', False):
calibre_web_version += " - Exe-Version"
elif constants.HOME_CONFIG:
calibre_web_version += " - pyPi"
if not ret:
_VERSIONS = OrderedDict(
Platform = '{0[0]} {0[2]} {0[3]} {0[4]} {0[5]}'.format(platform.uname()),
Python=sys.version,
Calibre_Web=calibre_web_version,
WebServer=server.VERSION,
Flask=flask.__version__,
Flask_Login=flask_loginVersion,
Flask_Principal=flask_principal.__version__,
Flask_WTF=flaskwtf_version,
Werkzeug=werkzeug.__version__,
Babel=babel.__version__,
Jinja2=jinja2.__version__,
Requests=requests.__version__,
SqlAlchemy=sqlalchemy.__version__,
pySqlite=sqlite3.version,
SQLite=sqlite3.sqlite_version,
iso639=isoLanguages.__version__,
pytz=pytz.__version__,
Unidecode=unidecode_version,
Scholarly=scholarly_version,
Flask_SimpleLDAP=u'installed' if bool(services.ldap) else None,
python_LDAP=services.ldapVersion if bool(services.ldapVersion) else None,
Goodreads=u'installed' if bool(services.goodreads_support) else None,
jsonschema=services.SyncToken.__version__ if bool(services.SyncToken) else None,
flask_dance=flask_danceVersion,
greenlet=greenlet_Version
)
_VERSIONS.update(gdriveutils.get_versions())
_VERSIONS.update(uploader.get_versions(True))
else:
_VERSIONS = OrderedDict(
Platform = '{0[0]} {0[2]} {0[3]} {0[4]} {0[5]}'.format(platform.uname()),
Python = sys.version,
Calibre_Web=calibre_web_version,
Werkzeug = werkzeug.__version__,
Jinja2=jinja2.__version__,
pySqlite = sqlite3.version,
SQLite = sqlite3.sqlite_version,
)
_VERSIONS.update(ret)
_VERSIONS.update(uploader.get_versions(False))
def collect_stats():
_VERSIONS['ebook converter'] = _(converter.get_calibre_version())
_VERSIONS['unrar'] = _(converter.get_unrar_version())
_VERSIONS['kepubify'] = _(converter.get_kepubify_version())
return _VERSIONS
@about.route("/stats")
@flask_login.login_required
def stats():
counter = calibre_db.session.query(db.Books).count()
authors = calibre_db.session.query(db.Authors).count()
categorys = calibre_db.session.query(db.Tags).count()
series = calibre_db.session.query(db.Series).count()
return render_title_template('stats.html', bookcounter=counter, authorcounter=authors, versions=collect_stats(),
categorycounter=categorys, seriecounter=series, title=_(u"Statistics"), page="stat")
+1884
View File
File diff suppressed because it is too large Load Diff
-217
View File
@@ -1,217 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2016-2019 lemmsh cervinko Kennyl matthazinski OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
import uploader
import os
from flask_babel import gettext as _
import comic
try:
from lxml.etree import LXML_VERSION as lxmlversion
except ImportError:
lxmlversion = None
__author__ = 'lemmsh'
logger = logging.getLogger("book_formats")
try:
from wand.image import Image
from wand import version as ImageVersion
from wand.exceptions import PolicyError
use_generic_pdf_cover = False
except (ImportError, RuntimeError) as e:
logger.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e)
use_generic_pdf_cover = True
try:
from PyPDF2 import PdfFileReader
from PyPDF2 import __version__ as PyPdfVersion
use_pdf_meta = True
except ImportError as e:
logger.warning('cannot import PyPDF2, extracting pdf metadata will not work: %s', e)
use_pdf_meta = False
try:
import epub
use_epub_meta = True
except ImportError as e:
logger.warning('cannot import epub, extracting epub metadata will not work: %s', e)
use_epub_meta = False
try:
import fb2
use_fb2_meta = True
except ImportError as e:
logger.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e)
use_fb2_meta = False
try:
from PIL import Image
from PIL import __version__ as PILversion
use_PIL = True
except ImportError:
use_PIL = False
def process(tmp_file_path, original_file_name, original_file_extension):
meta = None
try:
if ".PDF" == original_file_extension.upper():
meta = pdf_meta(tmp_file_path, original_file_name, original_file_extension)
if ".EPUB" == original_file_extension.upper() and use_epub_meta is True:
meta = epub.get_epub_info(tmp_file_path, original_file_name, original_file_extension)
if ".FB2" == original_file_extension.upper() and use_fb2_meta is True:
meta = fb2.get_fb2_info(tmp_file_path, original_file_extension)
if original_file_extension.upper() in ['.CBZ', '.CBT']:
meta = comic.get_comic_info(tmp_file_path, original_file_name, original_file_extension)
except Exception as ex:
logger.warning('cannot parse metadata, using default: %s', ex)
if meta and meta.title.strip() and meta.author.strip():
return meta
else:
return default_meta(tmp_file_path, original_file_name, original_file_extension)
def default_meta(tmp_file_path, original_file_name, original_file_extension):
return uploader.BookMeta(
file_path=tmp_file_path,
extension=original_file_extension,
title=original_file_name,
author=u"Unknown",
cover=None,
description="",
tags="",
series="",
series_id="",
languages="")
def pdf_meta(tmp_file_path, original_file_name, original_file_extension):
if use_pdf_meta:
pdf = PdfFileReader(open(tmp_file_path, 'rb'), strict=False)
doc_info = pdf.getDocumentInfo()
else:
doc_info = None
if doc_info is not None:
author = doc_info.author if doc_info.author else u"Unknown"
title = doc_info.title if doc_info.title else original_file_name
subject = doc_info.subject
else:
author = u"Unknown"
title = original_file_name
subject = ""
return uploader.BookMeta(
file_path=tmp_file_path,
extension=original_file_extension,
title=title,
author=author,
cover=pdf_preview(tmp_file_path, original_file_name),
description=subject,
tags="",
series="",
series_id="",
languages="")
def pdf_preview(tmp_file_path, tmp_dir):
if use_generic_pdf_cover:
return None
else:
if use_PIL:
try:
input1 = PdfFileReader(open(tmp_file_path, 'rb'), strict=False)
page0 = input1.getPage(0)
xObject = page0['/Resources']['/XObject'].getObject()
for obj in xObject:
if xObject[obj]['/Subtype'] == '/Image':
size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
data = xObject[obj]._data # xObject[obj].getData()
if xObject[obj]['/ColorSpace'] == '/DeviceRGB':
mode = "RGB"
else:
mode = "P"
if '/Filter' in xObject[obj]:
if xObject[obj]['/Filter'] == '/FlateDecode':
img = Image.frombytes(mode, size, data)
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.png"
img.save(filename=os.path.join(tmp_dir, cover_file_name))
return cover_file_name
# img.save(obj[1:] + ".png")
elif xObject[obj]['/Filter'] == '/DCTDecode':
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
img = open(cover_file_name, "wb")
img.write(data)
img.close()
return cover_file_name
elif xObject[obj]['/Filter'] == '/JPXDecode':
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jp2"
img = open(cover_file_name, "wb")
img.write(data)
img.close()
return cover_file_name
else:
img = Image.frombytes(mode, size, data)
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.png"
img.save(filename=os.path.join(tmp_dir, cover_file_name))
return cover_file_name
except Exception as ex:
print(ex)
try:
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
with Image(filename=tmp_file_path + "[0]", resolution=150) as img:
img.compression_quality = 88
img.save(filename=os.path.join(tmp_dir, cover_file_name))
return cover_file_name
except PolicyError as ex:
logger.warning('Pdf extraction forbidden by Imagemagick policy: %s', ex)
return None
except Exception as ex:
logger.warning('Cannot extract cover image, using default: %s', ex)
return None
def get_versions():
if not use_generic_pdf_cover:
IVersion = ImageVersion.MAGICK_VERSION
WVersion = ImageVersion.VERSION
else:
IVersion = _(u'not installed')
WVersion = _(u'not installed')
if use_pdf_meta:
PVersion='v'+PyPdfVersion
else:
PVersion=_(u'not installed')
if lxmlversion:
XVersion = 'v'+'.'.join(map(str, lxmlversion))
else:
XVersion = _(u'not installed')
if use_PIL:
PILVersion = 'v' + PILversion
else:
PILVersion = _(u'not installed')
return {'Image Magick': IVersion,
'PyPdf': PVersion,
'lxml':XVersion,
'Wand': WVersion,
'Pillow': PILVersion}
+12 -4
View File
@@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2016-2019 jkrehm andy29485 OzzieIsaacs
#
@@ -17,8 +19,13 @@
# Inspired by https://github.com/ChrisTM/Flask-CacheBust
# Uses query strings so CSS font files are found without having to resort to absolute URLs
import hashlib
import os
import hashlib
from . import logger
log = logger.create()
def init_cache_busting(app):
@@ -34,20 +41,20 @@ def init_cache_busting(app):
hash_table = {} # map of file hashes
app.logger.debug('Computing cache-busting values...')
log.debug('Computing cache-busting values...')
# compute file hashes
for dirpath, __, filenames in os.walk(static_folder):
for filename in filenames:
# compute version component
rooted_filename = os.path.join(dirpath, filename)
with open(rooted_filename, 'rb') as f:
file_hash = hashlib.md5(f.read()).hexdigest()[:7]
file_hash = hashlib.md5(f.read()).hexdigest()[:7] # nosec
# save version to tables
file_path = rooted_filename.replace(static_folder, "")
file_path = file_path.replace("\\", "/") # Convert Windows path to web path
hash_table[file_path] = file_hash
app.logger.debug('Finished computing cache-busting values')
log.debug('Finished computing cache-busting values')
def bust_filename(filename):
return hash_table.get(filename, "")
@@ -56,6 +63,7 @@ def init_cache_busting(app):
return filename.split("?", 1)[0]
@app.url_defaults
# pylint: disable=unused-variable
def reverse_to_cache_busted_url(endpoint, values):
"""
Make `url_for` produce busted filenames when using the 'static' endpoint.
+61 -22
View File
@@ -1,7 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018 OzzieIsaacs
#
@@ -18,52 +16,93 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import argparse
import os
import sys
import os
import argparse
import socket
from .constants import CONFIG_DIR as _CONFIG_DIR
from .constants import STABLE_VERSION as _STABLE_VERSION
from .constants import NIGHTLY_VERSION as _NIGHTLY_VERSION
def version_info():
if _NIGHTLY_VERSION[1].startswith('$Format'):
return "Calibre-Web version: %s - unkown git-clone" % _STABLE_VERSION['version']
return "Calibre-Web version: %s -%s" % (_STABLE_VERSION['version'], _NIGHTLY_VERSION[1])
parser = argparse.ArgumentParser(description='Calibre Web is a web app'
' providing a interface for browsing, reading and downloading eBooks\n', prog='cps.py')
' providing a interface for browsing, reading and downloading eBooks\n', prog='cps.py')
parser.add_argument('-p', metavar='path', help='path and name to settings db, e.g. /opt/cw.db')
parser.add_argument('-g', metavar='path', help='path and name to gdrive db, e.g. /opt/gd.db')
parser.add_argument('-c', metavar='path', help='path and name to SSL certfile, e.g. /opt/test.cert, works only in combination with keyfile')
parser.add_argument('-k', metavar='path', help='path and name to SSL keyfile, e.g. /opt/test.key, works only in combination with certfile')
parser.add_argument('-c', metavar='path',
help='path and name to SSL certfile, e.g. /opt/test.cert, works only in combination with keyfile')
parser.add_argument('-k', metavar='path',
help='path and name to SSL keyfile, e.g. /opt/test.key, works only in combination with certfile')
parser.add_argument('-v', '--version', action='version', help='Shows version number and exits Calibre-web',
version=version_info())
parser.add_argument('-i', metavar='ip-address', help='Server IP-Address to listen')
parser.add_argument('-s', metavar='user:pass', help='Sets specific username to new password')
parser.add_argument('-f', action='store_true', help='Flag is depreciated and will be removed in next version')
parser.add_argument('-l', action='store_true', help='Allow loading covers from localhost')
args = parser.parse_args()
generalPath = os.path.normpath(os.getenv("CALIBRE_DBPATH",
os.path.dirname(os.path.realpath(__file__)) + os.sep + ".." + os.sep))
if args.p:
settingspath = args.p
else:
settingspath = os.path.join(generalPath, "app.db")
if args.g:
gdpath = args.g
else:
gdpath = os.path.join(generalPath, "gdrive.db")
settingspath = args.p or os.path.join(_CONFIG_DIR, "app.db")
gdpath = args.g or os.path.join(_CONFIG_DIR, "gdrive.db")
# handle and check parameter for ssl encryption
certfilepath = None
keyfilepath = None
if args.c:
if os.path.isfile(args.c):
certfilepath = args.c
else:
print("Certfilepath is invalid. Exiting...")
print("Certfile path is invalid. Exiting...")
sys.exit(1)
if args.c is "":
if args.c == "":
certfilepath = ""
if args.k:
if os.path.isfile(args.k):
keyfilepath = args.k
else:
print("Keyfilepath is invalid. Exiting...")
print("Keyfile path is invalid. Exiting...")
sys.exit(1)
if (args.k and not args.c) or (not args.k and args.c):
print("Certfile and Keyfile have to be used together. Exiting...")
sys.exit(1)
if args.k is "":
if args.k == "":
keyfilepath = ""
# load covers from localhost
allow_localhost = args.l or None
# handle and check ip address argument
ip_address = args.i or None
if ip_address:
try:
# try to parse the given ip address with socket
if hasattr(socket, 'inet_pton'):
if ':' in ip_address:
socket.inet_pton(socket.AF_INET6, ip_address)
else:
socket.inet_pton(socket.AF_INET, ip_address)
else:
# on windows python < 3.4, inet_pton is not available
# inet_atom only handles IPv4 addresses
socket.inet_aton(ip_address)
except socket.error as err:
print(ip_address, ':', err)
sys.exit(1)
# handle and check user password argument
user_credentials = args.s or None
if user_credentials and ":" not in user_credentials:
print("No valid 'username:password' format")
sys.exit(3)
if args.f:
print("Warning: -f flag is depreciated and will be removed in next version")
Executable → Regular
+113 -65
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
@@ -18,65 +17,117 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import uploader
import logging
from iso639 import languages as isoLanguages
from . import logger, isoLanguages
from .constants import BookMeta
logger = logging.getLogger("book_formats")
log = logger.create()
try:
from wand.image import Image
use_IM = True
except (ImportError, RuntimeError) as e:
use_IM = False
try:
from comicapi.comicarchive import ComicArchive, MetaDataStyle
use_comic_meta = True
except ImportError as e:
logger.warning('cannot import comicapi, extracting comic metadata will not work: %s', e)
try:
from comicapi import __version__ as comic_version
except ImportError:
comic_version = ''
except (ImportError, LookupError) as e:
log.debug('Cannot import comicapi, extracting comic metadata will not work: %s', e)
import zipfile
import tarfile
try:
import rarfile
use_rarfile = True
except (ImportError, SyntaxError) as e:
log.debug('Cannot import rarfile, extracting cover files from rar files will not work: %s', e)
use_rarfile = False
use_comic_meta = False
NO_JPEG_EXTENSIONS = ['.png', '.webp', '.bmp']
COVER_EXTENSIONS = ['.png', '.webp', '.bmp', '.jpg', '.jpeg']
def extractCover(tmp_file_name, original_file_extension):
if use_comic_meta:
archive = ComicArchive(tmp_file_name)
cover_data = None
ext = os.path.splitext(archive.getPageName(0))
if len(ext) > 1:
extension = ext[1].lower()
if extension == '.jpg' or extension == '.jpeg':
cover_data = archive.getPage(0)
def _cover_processing(tmp_file_name, img, extension):
tmp_cover_name = os.path.join(os.path.dirname(tmp_file_name), 'cover.jpg')
if extension in NO_JPEG_EXTENSIONS:
if use_IM:
with Image(blob=img) as imgc:
imgc.format = 'jpeg'
imgc.transform_colorspace('rgb')
imgc.save(filename=tmp_cover_name)
return tmp_cover_name
else:
return None
if img:
with open(tmp_cover_name, 'wb') as f:
f.write(img)
return tmp_cover_name
else:
if original_file_extension.upper() == '.CBZ':
cf = zipfile.ZipFile(tmp_file_name)
for name in cf.namelist():
ext = os.path.splitext(name)
if len(ext) > 1:
extension = ext[1].lower()
if extension == '.jpg':
cover_data = cf.read(name)
break
elif original_file_extension.upper() == '.CBT':
cf = tarfile.TarFile(tmp_file_name)
return None
def _extract_Cover_from_archive(original_file_extension, tmp_file_name, rarExecutable):
cover_data = extension = None
if original_file_extension.upper() == '.CBZ':
cf = zipfile.ZipFile(tmp_file_name)
for name in cf.namelist():
ext = os.path.splitext(name)
if len(ext) > 1:
extension = ext[1].lower()
if extension in COVER_EXTENSIONS:
cover_data = cf.read(name)
break
elif original_file_extension.upper() == '.CBT':
cf = tarfile.TarFile(tmp_file_name)
for name in cf.getnames():
ext = os.path.splitext(name)
if len(ext) > 1:
extension = ext[1].lower()
if extension in COVER_EXTENSIONS:
cover_data = cf.extractfile(name).read()
break
elif original_file_extension.upper() == '.CBR' and use_rarfile:
try:
rarfile.UNRAR_TOOL = rarExecutable
cf = rarfile.RarFile(tmp_file_name)
for name in cf.getnames():
ext = os.path.splitext(name)
if len(ext) > 1:
extension = ext[1].lower()
if extension == '.jpg':
cover_data = cf.extractfile(name).read()
if extension in COVER_EXTENSIONS:
cover_data = cf.read(name)
break
prefix = os.path.dirname(tmp_file_name)
if cover_data:
tmp_cover_name = prefix + '/cover' + extension
image = open(tmp_cover_name, 'wb')
image.write(cover_data)
image.close()
else:
tmp_cover_name = None
return tmp_cover_name
except Exception as ex:
log.debug('Rarfile failed with error: %s', ex)
return cover_data, extension
def get_comic_info(tmp_file_path, original_file_name, original_file_extension):
def _extractCover(tmp_file_name, original_file_extension, rarExecutable):
cover_data = extension = None
if use_comic_meta:
archive = ComicArchive(tmp_file_path)
archive = ComicArchive(tmp_file_name, rar_exe_path=rarExecutable)
for index, name in enumerate(archive.getPageNameList()):
ext = os.path.splitext(name)
if len(ext) > 1:
extension = ext[1].lower()
if extension in COVER_EXTENSIONS:
cover_data = archive.getPage(index)
break
else:
cover_data, extension = _extract_Cover_from_archive(original_file_extension, tmp_file_name, rarExecutable)
return _cover_processing(tmp_file_name, cover_data, extension)
def get_comic_info(tmp_file_path, original_file_name, original_file_extension, rarExecutable):
if use_comic_meta:
archive = ComicArchive(tmp_file_path, rar_exe_path=rarExecutable)
if archive.seemsToBeAComicArchive():
if archive.hasMetadata(MetaDataStyle.CIX):
style = MetaDataStyle.CIX
@@ -85,38 +136,35 @@ def get_comic_info(tmp_file_path, original_file_name, original_file_extension):
else:
style = None
if style is not None:
loadedMetadata = archive.readMetadata(style)
# if style is not None:
loadedMetadata = archive.readMetadata(style)
lang = loadedMetadata.language
if len(lang) == 2:
loadedMetadata.language = isoLanguages.get(part1=lang).name
elif len(lang) == 3:
loadedMetadata.language = isoLanguages.get(part3=lang).name
else:
loadedMetadata.language = ""
lang = loadedMetadata.language or ""
loadedMetadata.language = isoLanguages.get_lang3(lang)
return uploader.BookMeta(
return BookMeta(
file_path=tmp_file_path,
extension=original_file_extension,
title=loadedMetadata.title or original_file_name,
author=" & ".join([credit["person"] for credit in loadedMetadata.credits if credit["role"] == "Writer"]) or u"Unknown",
cover=extractCover(tmp_file_path, original_file_extension),
author=" & ".join([credit["person"]
for credit in loadedMetadata.credits if credit["role"] == "Writer"]) or u'Unknown',
cover=_extractCover(tmp_file_path, original_file_extension, rarExecutable),
description=loadedMetadata.comments or "",
tags="",
series=loadedMetadata.series or "",
series_id=loadedMetadata.issue or "",
languages=loadedMetadata.language)
else:
languages=loadedMetadata.language,
publisher="")
return uploader.BookMeta(
file_path=tmp_file_path,
extension=original_file_extension,
title=original_file_name,
author=u"Unknown",
cover=extractCover(tmp_file_path, original_file_extension),
description="",
tags="",
series="",
series_id="",
languages="")
return BookMeta(
file_path=tmp_file_path,
extension=original_file_extension,
title=original_file_name,
author=u'Unknown',
cover=_extractCover(tmp_file_path, original_file_extension, rarExecutable),
description="",
tags="",
series="",
series_id="",
languages="",
publisher="")
+457
View File
@@ -0,0 +1,457 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2019 OzzieIsaacs, pwr
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import json
from sqlalchemy import Column, String, Integer, SmallInteger, Boolean, BLOB, JSON
from sqlalchemy.exc import OperationalError
from sqlalchemy.sql.expression import text
try:
# Compatibility with sqlalchemy 2.0
from sqlalchemy.orm import declarative_base
except ImportError:
from sqlalchemy.ext.declarative import declarative_base
from . import constants, cli, logger
log = logger.create()
_Base = declarative_base()
class _Flask_Settings(_Base):
__tablename__ = 'flask_settings'
id = Column(Integer, primary_key=True)
flask_session_key = Column(BLOB, default=b"")
def __init__(self, key):
self.flask_session_key = key
# Baseclass for representing settings in app.db with email server settings and Calibre database settings
# (application settings)
class _Settings(_Base):
__tablename__ = 'settings'
id = Column(Integer, primary_key=True)
mail_server = Column(String, default=constants.DEFAULT_MAIL_SERVER)
mail_port = Column(Integer, default=25)
mail_use_ssl = Column(SmallInteger, default=0)
mail_login = Column(String, default='mail@example.com')
mail_password = Column(String, default='mypassword')
mail_from = Column(String, default='automailer <mail@example.com>')
mail_size = Column(Integer, default=25*1024*1024)
mail_server_type = Column(SmallInteger, default=0)
mail_gmail_token = Column(JSON, default={})
config_calibre_dir = Column(String)
config_port = Column(Integer, default=constants.DEFAULT_PORT)
config_external_port = Column(Integer, default=constants.DEFAULT_PORT)
config_certfile = Column(String)
config_keyfile = Column(String)
config_trustedhosts = Column(String,default='')
config_calibre_web_title = Column(String, default=u'Calibre-Web')
config_books_per_page = Column(Integer, default=60)
config_random_books = Column(Integer, default=4)
config_authors_max = Column(Integer, default=0)
config_read_column = Column(Integer, default=0)
config_title_regex = Column(String, default=r'^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines)\s+')
config_mature_content_tags = Column(String, default='')
config_theme = Column(Integer, default=0)
config_log_level = Column(SmallInteger, default=logger.DEFAULT_LOG_LEVEL)
config_logfile = Column(String)
config_access_log = Column(SmallInteger, default=0)
config_access_logfile = Column(String)
config_uploading = Column(SmallInteger, default=0)
config_anonbrowse = Column(SmallInteger, default=0)
config_public_reg = Column(SmallInteger, default=0)
config_remote_login = Column(Boolean, default=False)
config_kobo_sync = Column(Boolean, default=False)
config_default_role = Column(SmallInteger, default=0)
config_default_show = Column(SmallInteger, default=constants.ADMIN_USER_SIDEBAR)
config_default_language = Column(String(3), default="all")
config_default_locale = Column(String(2), default="en")
config_columns_to_ignore = Column(String)
config_denied_tags = Column(String, default="")
config_allowed_tags = Column(String, default="")
config_restricted_column = Column(SmallInteger, default=0)
config_denied_column_value = Column(String, default="")
config_allowed_column_value = Column(String, default="")
config_use_google_drive = Column(Boolean, default=False)
config_google_drive_folder = Column(String)
config_google_drive_watch_changes_response = Column(JSON, default={})
config_use_goodreads = Column(Boolean, default=False)
config_goodreads_api_key = Column(String)
config_goodreads_api_secret = Column(String)
config_register_email = Column(Boolean, default=False)
config_login_type = Column(Integer, default=0)
config_kobo_proxy = Column(Boolean, default=False)
config_ldap_provider_url = Column(String, default='example.org')
config_ldap_port = Column(SmallInteger, default=389)
config_ldap_authentication = Column(SmallInteger, default=constants.LDAP_AUTH_SIMPLE)
config_ldap_serv_username = Column(String, default='cn=admin,dc=example,dc=org')
config_ldap_serv_password = Column(String, default="")
config_ldap_encryption = Column(SmallInteger, default=0)
config_ldap_cacert_path = Column(String, default="")
config_ldap_cert_path = Column(String, default="")
config_ldap_key_path = Column(String, default="")
config_ldap_dn = Column(String, default='dc=example,dc=org')
config_ldap_user_object = Column(String, default='uid=%s')
config_ldap_member_user_object = Column(String, default='') #
config_ldap_openldap = Column(Boolean, default=True)
config_ldap_group_object_filter = Column(String, default='(&(objectclass=posixGroup)(cn=%s))')
config_ldap_group_members_field = Column(String, default='memberUid')
config_ldap_group_name = Column(String, default='calibreweb')
config_kepubifypath = Column(String, default=None)
config_converterpath = Column(String, default=None)
config_calibre = Column(String)
config_rarfile_location = Column(String, default=None)
config_upload_formats = Column(String, default=','.join(constants.EXTENSIONS_UPLOAD))
config_unicode_filename =Column(Boolean, default=False)
config_updatechannel = Column(Integer, default=constants.UPDATE_STABLE)
config_reverse_proxy_login_header_name = Column(String)
config_allow_reverse_proxy_header_login = Column(Boolean, default=False)
def __repr__(self):
return self.__class__.__name__
# Class holds all application specific settings in calibre-web
class _ConfigSQL(object):
# pylint: disable=no-member
def __init__(self, session):
self._session = session
self._settings = None
self.db_configured = None
self.config_calibre_dir = None
self.load()
change = False
if self.config_converterpath == None: # pylint: disable=access-member-before-definition
change = True
self.config_converterpath = autodetect_calibre_binary()
if self.config_kepubifypath == None: # pylint: disable=access-member-before-definition
change = True
self.config_kepubifypath = autodetect_kepubify_binary()
if self.config_rarfile_location == None: # pylint: disable=access-member-before-definition
change = True
self.config_rarfile_location = autodetect_unrar_binary()
if change:
self.save()
def _read_from_storage(self):
if self._settings is None:
log.debug("_ConfigSQL._read_from_storage")
self._settings = self._session.query(_Settings).first()
return self._settings
def get_config_certfile(self):
if cli.certfilepath:
return cli.certfilepath
if cli.certfilepath == "":
return None
return self.config_certfile
def get_config_keyfile(self):
if cli.keyfilepath:
return cli.keyfilepath
if cli.certfilepath == "":
return None
return self.config_keyfile
@staticmethod
def get_config_ipaddress():
return cli.ip_address or ""
def _has_role(self, role_flag):
return constants.has_flag(self.config_default_role, role_flag)
def role_admin(self):
return self._has_role(constants.ROLE_ADMIN)
def role_download(self):
return self._has_role(constants.ROLE_DOWNLOAD)
def role_viewer(self):
return self._has_role(constants.ROLE_VIEWER)
def role_upload(self):
return self._has_role(constants.ROLE_UPLOAD)
def role_edit(self):
return self._has_role(constants.ROLE_EDIT)
def role_passwd(self):
return self._has_role(constants.ROLE_PASSWD)
def role_edit_shelfs(self):
return self._has_role(constants.ROLE_EDIT_SHELFS)
def role_delete_books(self):
return self._has_role(constants.ROLE_DELETE_BOOKS)
def show_element_new_user(self, value):
return constants.has_flag(self.config_default_show, value)
def show_detail_random(self):
return self.show_element_new_user(constants.DETAIL_RANDOM)
def list_denied_tags(self):
mct = self.config_denied_tags or ""
return [t.strip() for t in mct.split(",")]
def list_allowed_tags(self):
mct = self.config_allowed_tags or ""
return [t.strip() for t in mct.split(",")]
def list_denied_column_values(self):
mct = self.config_denied_column_value or ""
return [t.strip() for t in mct.split(",")]
def list_allowed_column_values(self):
mct = self.config_allowed_column_value or ""
return [t.strip() for t in mct.split(",")]
def get_log_level(self):
return logger.get_level_name(self.config_log_level)
def get_mail_settings(self):
return {k:v for k, v in self.__dict__.items() if k.startswith('mail_')}
def get_mail_server_configured(self):
return bool((self.mail_server != constants.DEFAULT_MAIL_SERVER and self.mail_server_type == 0)
or (self.mail_gmail_token != {} and self.mail_server_type == 1))
def set_from_dictionary(self, dictionary, field, convertor=None, default=None, encode=None):
"""Possibly updates a field of this object.
The new value, if present, is grabbed from the given dictionary, and optionally passed through a convertor.
:returns: `True` if the field has changed value
"""
new_value = dictionary.get(field, default)
if new_value is None:
return False
if field not in self.__dict__:
log.warning("_ConfigSQL trying to set unknown field '%s' = %r", field, new_value)
return False
if convertor is not None:
if encode:
new_value = convertor(new_value.encode(encode))
else:
new_value = convertor(new_value)
current_value = self.__dict__.get(field)
if current_value == new_value:
return False
setattr(self, field, new_value)
return True
def toDict(self):
storage = {}
for k, v in self.__dict__.items():
if k[0] != '_' and not k.endswith("password") and not k.endswith("secret"):
storage[k] = v
return storage
def load(self):
'''Load all configuration values from the underlying storage.'''
s = self._read_from_storage() # type: _Settings
for k, v in s.__dict__.items():
if k[0] != '_':
if v is None:
# if the storage column has no value, apply the (possible) default
column = s.__class__.__dict__.get(k)
if column.default is not None:
v = column.default.arg
setattr(self, k, v)
have_metadata_db = bool(self.config_calibre_dir)
if have_metadata_db:
if not self.config_use_google_drive:
db_file = os.path.join(self.config_calibre_dir, 'metadata.db')
have_metadata_db = os.path.isfile(db_file)
self.db_configured = have_metadata_db
constants.EXTENSIONS_UPLOAD = [x.lstrip().rstrip().lower() for x in self.config_upload_formats.split(',')]
if os.environ.get('FLASK_DEBUG'):
logfile = logger.setup(logger.LOG_TO_STDOUT, logger.logging.DEBUG)
else:
# pylint: disable=access-member-before-definition
logfile = logger.setup(self.config_logfile, self.config_log_level)
if logfile != self.config_logfile:
log.warning("Log path %s not valid, falling back to default", self.config_logfile)
self.config_logfile = logfile
self._session.merge(s)
try:
self._session.commit()
except OperationalError as e:
log.error('Database error: %s', e)
self._session.rollback()
def save(self):
'''Apply all configuration values to the underlying storage.'''
s = self._read_from_storage() # type: _Settings
for k, v in self.__dict__.items():
if k[0] == '_':
continue
if hasattr(s, k):
setattr(s, k, v)
log.debug("_ConfigSQL updating storage")
self._session.merge(s)
try:
self._session.commit()
except OperationalError as e:
log.error('Database error: %s', e)
self._session.rollback()
self.load()
def invalidate(self, error=None):
if error:
log.error(error)
log.warning("invalidating configuration")
self.db_configured = False
# self.config_calibre_dir = None
self.save()
def _migrate_table(session, orm_class):
changed = False
for column_name, column in orm_class.__dict__.items():
if column_name[0] != '_':
try:
session.query(column).first()
except OperationalError as err:
log.debug("%s: %s", column_name, err.args[0])
if column.default is None:
column_default = ""
else:
if isinstance(column.default.arg, bool):
column_default = "DEFAULT {}".format(int(column.default.arg))
else:
column_default = "DEFAULT `{}`".format(column.default.arg)
if isinstance(column.type, JSON):
column_type = "JSON"
else:
column_type = column.type
alter_table = text("ALTER TABLE %s ADD COLUMN `%s` %s %s" % (orm_class.__tablename__,
column_name,
column_type,
column_default))
log.debug(alter_table)
session.execute(alter_table)
changed = True
except json.decoder.JSONDecodeError as e:
log.error("Database corrupt column: {}".format(column_name))
log.debug(e)
if changed:
try:
session.commit()
except OperationalError:
session.rollback()
def autodetect_calibre_binary():
if sys.platform == "win32":
calibre_path = ["C:\\program files\\calibre\\ebook-convert.exe",
"C:\\program files(x86)\\calibre\\ebook-convert.exe",
"C:\\program files(x86)\\calibre2\\ebook-convert.exe",
"C:\\program files\\calibre2\\ebook-convert.exe"]
else:
calibre_path = ["/opt/calibre/ebook-convert"]
for element in calibre_path:
if os.path.isfile(element) and os.access(element, os.X_OK):
return element
return ""
def autodetect_unrar_binary():
if sys.platform == "win32":
calibre_path = ["C:\\program files\\WinRar\\unRAR.exe",
"C:\\program files(x86)\\WinRar\\unRAR.exe"]
else:
calibre_path = ["/usr/bin/unrar"]
for element in calibre_path:
if os.path.isfile(element) and os.access(element, os.X_OK):
return element
return ""
def autodetect_kepubify_binary():
if sys.platform == "win32":
calibre_path = ["C:\\program files\\kepubify\\kepubify-windows-64Bit.exe",
"C:\\program files(x86)\\kepubify\\kepubify-windows-64Bit.exe"]
else:
calibre_path = ["/opt/kepubify/kepubify-linux-64bit", "/opt/kepubify/kepubify-linux-32bit"]
for element in calibre_path:
if os.path.isfile(element) and os.access(element, os.X_OK):
return element
return ""
def _migrate_database(session):
# make sure the table is created, if it does not exist
_Base.metadata.create_all(session.bind)
_migrate_table(session, _Settings)
_migrate_table(session, _Flask_Settings)
def load_configuration(session):
_migrate_database(session)
if not session.query(_Settings).count():
session.add(_Settings())
session.commit()
conf = _ConfigSQL(session)
# Migrate from global restrictions to user based restrictions
#if bool(conf.config_default_show & constants.MATURE_CONTENT) and conf.config_denied_tags == "":
# conf.config_denied_tags = conf.config_mature_content_tags
# conf.save()
# session.query(ub.User).filter(ub.User.mature_content != True). \
# update({"denied_tags": conf.config_mature_content_tags}, synchronize_session=False)
# session.commit()
return conf
def get_flask_session_key(session):
flask_settings = session.query(_Flask_Settings).one_or_none()
if flask_settings == None:
flask_settings = _Flask_Settings(os.urandom(32))
session.add(flask_settings)
session.commit()
return flask_settings.flask_session_key
+164
View File
@@ -0,0 +1,164 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2019 OzzieIsaacs, pwr
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
from collections import namedtuple
from sqlalchemy import __version__ as sql_version
sqlalchemy_version2 = ([int(x) for x in sql_version.split('.')] >= [2,0,0])
# if installed via pip this variable is set to true (empty file with name .HOMEDIR present)
HOME_CONFIG = os.path.isfile(os.path.join(os.path.dirname(os.path.abspath(__file__)), '.HOMEDIR'))
#In executables updater is not available, so variable is set to False there
UPDATER_AVAILABLE = True
# Base dir is parent of current file, necessary if called from different folder
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)),os.pardir))
STATIC_DIR = os.path.join(BASE_DIR, 'cps', 'static')
TEMPLATES_DIR = os.path.join(BASE_DIR, 'cps', 'templates')
TRANSLATIONS_DIR = os.path.join(BASE_DIR, 'cps', 'translations')
if HOME_CONFIG:
home_dir = os.path.join(os.path.expanduser("~"),".calibre-web")
if not os.path.exists(home_dir):
os.makedirs(home_dir)
CONFIG_DIR = os.environ.get('CALIBRE_DBPATH', home_dir)
else:
CONFIG_DIR = os.environ.get('CALIBRE_DBPATH', BASE_DIR)
ROLE_USER = 0 << 0
ROLE_ADMIN = 1 << 0
ROLE_DOWNLOAD = 1 << 1
ROLE_UPLOAD = 1 << 2
ROLE_EDIT = 1 << 3
ROLE_PASSWD = 1 << 4
ROLE_ANONYMOUS = 1 << 5
ROLE_EDIT_SHELFS = 1 << 6
ROLE_DELETE_BOOKS = 1 << 7
ROLE_VIEWER = 1 << 8
ALL_ROLES = {
"admin_role": ROLE_ADMIN,
"download_role": ROLE_DOWNLOAD,
"upload_role": ROLE_UPLOAD,
"edit_role": ROLE_EDIT,
"passwd_role": ROLE_PASSWD,
"edit_shelf_role": ROLE_EDIT_SHELFS,
"delete_role": ROLE_DELETE_BOOKS,
"viewer_role": ROLE_VIEWER,
}
DETAIL_RANDOM = 1 << 0
SIDEBAR_LANGUAGE = 1 << 1
SIDEBAR_SERIES = 1 << 2
SIDEBAR_CATEGORY = 1 << 3
SIDEBAR_HOT = 1 << 4
SIDEBAR_RANDOM = 1 << 5
SIDEBAR_AUTHOR = 1 << 6
SIDEBAR_BEST_RATED = 1 << 7
SIDEBAR_READ_AND_UNREAD = 1 << 8
SIDEBAR_RECENT = 1 << 9
SIDEBAR_SORTED = 1 << 10
MATURE_CONTENT = 1 << 11
SIDEBAR_PUBLISHER = 1 << 12
SIDEBAR_RATING = 1 << 13
SIDEBAR_FORMAT = 1 << 14
SIDEBAR_ARCHIVED = 1 << 15
SIDEBAR_DOWNLOAD = 1 << 16
SIDEBAR_LIST = 1 << 17
sidebar_settings = {
"detail_random": DETAIL_RANDOM,
"sidebar_language": SIDEBAR_LANGUAGE,
"sidebar_series": SIDEBAR_SERIES,
"sidebar_category": SIDEBAR_CATEGORY,
"sidebar_random": SIDEBAR_RANDOM,
"sidebar_author": SIDEBAR_AUTHOR,
"sidebar_best_rated": SIDEBAR_BEST_RATED,
"sidebar_read_and_unread": SIDEBAR_READ_AND_UNREAD,
"sidebar_recent": SIDEBAR_RECENT,
"sidebar_sorted": SIDEBAR_SORTED,
"sidebar_publisher": SIDEBAR_PUBLISHER,
"sidebar_rating": SIDEBAR_RATING,
"sidebar_format": SIDEBAR_FORMAT,
"sidebar_archived": SIDEBAR_ARCHIVED,
"sidebar_download": SIDEBAR_DOWNLOAD,
"sidebar_list": SIDEBAR_LIST,
}
ADMIN_USER_ROLES = sum(r for r in ALL_ROLES.values()) & ~ROLE_ANONYMOUS
ADMIN_USER_SIDEBAR = (SIDEBAR_LIST << 1) - 1
UPDATE_STABLE = 0 << 0
AUTO_UPDATE_STABLE = 1 << 0
UPDATE_NIGHTLY = 1 << 1
AUTO_UPDATE_NIGHTLY = 1 << 2
LOGIN_STANDARD = 0
LOGIN_LDAP = 1
LOGIN_OAUTH = 2
LDAP_AUTH_ANONYMOUS = 0
LDAP_AUTH_UNAUTHENTICATE = 1
LDAP_AUTH_SIMPLE = 0
DEFAULT_MAIL_SERVER = "mail.example.org"
DEFAULT_PASSWORD = "admin123" # nosec
DEFAULT_PORT = 8083
env_CALIBRE_PORT = os.environ.get("CALIBRE_PORT", DEFAULT_PORT)
try:
DEFAULT_PORT = int(env_CALIBRE_PORT)
except ValueError:
print('Environment variable CALIBRE_PORT has invalid value (%s), faling back to default (8083)' % env_CALIBRE_PORT)
del env_CALIBRE_PORT
EXTENSIONS_AUDIO = {'mp3', 'mp4', 'ogg', 'opus', 'wav', 'flac', 'm4a', 'm4b'}
EXTENSIONS_CONVERT_FROM = ['pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', 'lit', 'lrf', 'txt', 'htmlz', 'rtf', 'odt','cbz','cbr']
EXTENSIONS_CONVERT_TO = ['pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', 'lit', 'lrf', 'txt', 'htmlz', 'rtf', 'odt']
EXTENSIONS_UPLOAD = {'txt', 'pdf', 'epub', 'kepub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx',
'fb2', 'html', 'rtf', 'lit', 'odt', 'mp3', 'mp4', 'ogg', 'opus', 'wav', 'flac', 'm4a', 'm4b'}
def has_flag(value, bit_flag):
return bit_flag == (bit_flag & (value or 0))
def selected_roles(dictionary):
return sum(v for k, v in ALL_ROLES.items() if k in dictionary)
# :rtype: BookMeta
BookMeta = namedtuple('BookMeta', 'file_path, extension, title, author, cover, description, tags, series, '
'series_id, languages, publisher')
STABLE_VERSION = {'version': '0.6.16'}
NIGHTLY_VERSION = {}
NIGHTLY_VERSION[0] = '$Format:%H$'
NIGHTLY_VERSION[1] = '$Format:%cI$'
# NIGHTLY_VERSION[0] = 'bb7d2c6273ae4560e83950d36d64533343623a57'
# NIGHTLY_VERSION[1] = '2018-09-09T10:13:08+02:00'
# clean-up the module namespace
del sys, os, namedtuple
+32 -38
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
@@ -17,51 +16,46 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import subprocess
import ub
import re
from flask_babel import gettext as _
from . import config, logger
from .subproc_wrapper import process_wait
def versionKindle():
versions = _(u'not installed')
if os.path.exists(ub.config.config_converterpath):
log = logger.create()
# _() necessary to make babel aware of string for translation
_NOT_CONFIGURED = _('not configured')
_NOT_INSTALLED = _('not installed')
_EXECUTION_ERROR = _('Execution permissions missing')
def _get_command_version(path, pattern, argument=None):
if os.path.exists(path):
command = [path]
if argument:
command.append(argument)
try:
p = subprocess.Popen(ub.config.config_converterpath, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.wait()
for lines in p.stdout.readlines():
if isinstance(lines, bytes):
lines = lines.decode('utf-8')
if re.search('Amazon kindlegen\(', lines):
versions = lines
except Exception:
versions = _(u'Excecution permissions missing')
return {'kindlegen' : versions}
match = process_wait(command, pattern=pattern)
if isinstance(match, re.Match):
return match.string
except Exception as ex:
log.warning("%s: %s", path, ex)
return _EXECUTION_ERROR
return _NOT_INSTALLED
def versionCalibre():
versions = _(u'not installed')
if os.path.exists(ub.config.config_converterpath):
try:
p = subprocess.Popen([ub.config.config_converterpath, '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.wait()
for lines in p.stdout.readlines():
if isinstance(lines, bytes):
lines = lines.decode('utf-8')
if re.search('ebook-convert.*\(calibre', lines):
versions = lines
except Exception:
versions = _(u'Excecution permissions missing')
return {'Calibre converter' : versions}
def get_calibre_version():
return _get_command_version(config.config_converterpath, r'ebook-convert.*\(calibre', '--version') \
or _NOT_CONFIGURED
def versioncheck():
if ub.config.config_ebookconverter == 1:
return versionKindle()
elif ub.config.config_ebookconverter == 2:
return versionCalibre()
else:
return {'ebook_converter':_(u'not configured')}
def get_unrar_version():
return _get_command_version(config.config_rarfile_location, r'UNRAR.*\d') or _NOT_CONFIGURED
def get_kepubify_version():
return _get_command_version(config.config_kepubifypath, r'kepubify\s','--version') or _NOT_CONFIGURED
Executable → Regular
+638 -170
View File
File diff suppressed because it is too large Load Diff
+72
View File
@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2012-2019 cervinko, idalin, SiphonSquirrel, ouzklcn, akushsky,
# OzzieIsaacs, bodybybuddha, jkrehm, matthazinski, janeczku
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import shutil
import glob
import zipfile
import json
from io import BytesIO
import os
from flask import send_file, __version__
from . import logger, config
from .about import collect_stats
log = logger.create()
def assemble_logfiles(file_name):
log_list = sorted(glob.glob(file_name + '*'), reverse=True)
wfd = BytesIO()
for f in log_list:
with open(f, 'rb') as fd:
shutil.copyfileobj(fd, wfd)
wfd.seek(0)
if int(__version__.split('.')[0]) < 2:
return send_file(wfd,
as_attachment=True,
attachment_filename=os.path.basename(file_name))
else:
return send_file(wfd,
as_attachment=True,
download_name=os.path.basename(file_name))
def send_debug():
file_list = glob.glob(logger.get_logfile(config.config_logfile) + '*')
file_list.extend(glob.glob(logger.get_accesslogfile(config.config_access_logfile) + '*'))
for element in [logger.LOG_TO_STDOUT, logger.LOG_TO_STDERR]:
if element in file_list:
file_list.remove(element)
memory_zip = BytesIO()
with zipfile.ZipFile(memory_zip, 'w', compression=zipfile.ZIP_DEFLATED) as zf:
zf.writestr('settings.txt', json.dumps(config.toDict()))
zf.writestr('libs.txt', json.dumps(collect_stats()))
for fp in file_list:
zf.write(fp, os.path.basename(fp))
memory_zip.seek(0)
if int(__version__.split('.')[0]) < 2:
return send_file(memory_zip,
as_attachment=True,
attachment_filename="Calibre-Web-debug-pack.zip")
else:
return send_file(memory_zip,
as_attachment=True,
download_name="Calibre-Web-debug-pack.zip")
+96
View File
@@ -0,0 +1,96 @@
import os
import re
from .constants import BASE_DIR
try:
from importlib_metadata import version
importlib = True
ImportNotFound = BaseException
except ImportError:
importlib = False
if not importlib:
try:
import pkg_resources
from pkg_resources import DistributionNotFound as ImportNotFound
pkgresources = True
except ImportError as e:
pkgresources = False
def load_dependencys(optional=False):
deps = list()
if importlib or pkgresources:
if optional:
req_path = os.path.join(BASE_DIR, "optional-requirements.txt")
else:
req_path = os.path.join(BASE_DIR, "requirements.txt")
if os.path.exists(req_path):
with open(req_path, 'r') as f:
for line in f:
if not line.startswith('#') and not line == '\n' and not line.startswith('git'):
res = re.match(r'(.*?)([<=>\s]+)([\d\.]+),?\s?([<=>\s]+)?([\d\.]+)?', line.strip())
try:
if importlib:
dep_version = version(res.group(1))
else:
dep_version = pkg_resources.get_distribution(res.group(1)).version
except ImportNotFound:
if optional:
continue
dep_version = "not installed"
deps.append([dep_version, res.group(1), res.group(2), res.group(3), res.group(4), res.group(5)])
return deps
def dependency_check(optional=False):
d = list()
deps = load_dependencys(optional)
for dep in deps:
try:
dep_version_int = [int(x) for x in dep[0].split('.')]
low_check = [int(x) for x in dep[3].split('.')]
high_check = [int(x) for x in dep[5].split('.')]
except AttributeError:
high_check = None
except ValueError:
d.append({'name': dep[1],
'target': "available",
'found': "Not available"
})
continue
if dep[2].strip() == "==":
if dep_version_int != low_check:
d.append({'name': dep[1],
'found': dep[0],
"target": dep[2] + dep[3]})
continue
elif dep[2].strip() == ">=":
if dep_version_int < low_check:
d.append({'name': dep[1],
'found': dep[0],
"target": dep[2] + dep[3]})
continue
elif dep[2].strip() == ">":
if dep_version_int <= low_check:
d.append({'name': dep[1],
'found': dep[0],
"target": dep[2] + dep[3]})
continue
if dep[4] and dep[5]:
if dep[4].strip() == "<":
if dep_version_int >= high_check:
d.append(
{'name': dep[1],
'found': dep[0],
"target": dep[4] + dep[5]})
continue
elif dep[4].strip() == "<=":
if dep_version_int > high_check:
d.append(
{'name': dep[1],
'found': dep[0],
"target": dep[4] + dep[5]})
continue
return d
+1305
View File
File diff suppressed because it is too large Load Diff
+71 -56
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
@@ -17,11 +16,14 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import zipfile
from lxml import etree
import os
import uploader
import isoLanguages
from . import isoLanguages
from .helper import split_authors
from .constants import BookMeta
def extractCover(zipFile, coverFile, coverpath, tmp_file_name):
@@ -62,31 +64,81 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension):
for s in ['title', 'description', 'creator', 'language', 'subject']:
tmp = p.xpath('dc:%s/text()' % s, namespaces=ns)
if len(tmp) > 0:
epub_metadata[s] = p.xpath('dc:%s/text()' % s, namespaces=ns)[0]
if s == 'creator':
epub_metadata[s] = ' & '.join(split_authors(tmp))
elif s == 'subject':
epub_metadata[s] = ', '.join(tmp)
else:
epub_metadata[s] = tmp[0]
else:
epub_metadata[s] = "Unknown"
epub_metadata[s] = u'Unknown'
if epub_metadata['subject'] == "Unknown":
if epub_metadata['subject'] == u'Unknown':
epub_metadata['subject'] = ''
if epub_metadata['description'] == "Unknown":
if epub_metadata['description'] == u'Unknown':
description = tree.xpath("//*[local-name() = 'description']/text()")
if len(description) > 0:
epub_metadata['description'] = description
else:
epub_metadata['description'] = ""
if epub_metadata['language'] == "Unknown":
epub_metadata['language'] = ""
else:
lang = epub_metadata['language'].split('-', 1)[0].lower()
if len(lang) == 2:
epub_metadata['language'] = isoLanguages.get(part1=lang).name
elif len(lang) == 3:
epub_metadata['language'] = isoLanguages.get(part3=lang).name
else:
epub_metadata['language'] = ""
lang = epub_metadata['language'].split('-', 1)[0].lower()
epub_metadata['language'] = isoLanguages.get_lang3(lang)
epub_metadata = parse_epbub_series(ns, tree, epub_metadata)
coverfile = parse_ebpub_cover(ns, tree, epubZip, coverpath, tmp_file_path)
if not epub_metadata['title']:
title = original_file_name
else:
title = epub_metadata['title']
return BookMeta(
file_path=tmp_file_path,
extension=original_file_extension,
title=title.encode('utf-8').decode('utf-8'),
author=epub_metadata['creator'].encode('utf-8').decode('utf-8'),
cover=coverfile,
description=epub_metadata['description'],
tags=epub_metadata['subject'].encode('utf-8').decode('utf-8'),
series=epub_metadata['series'].encode('utf-8').decode('utf-8'),
series_id=epub_metadata['series_id'].encode('utf-8').decode('utf-8'),
languages=epub_metadata['language'],
publisher="")
def parse_ebpub_cover(ns, tree, epubZip, coverpath, tmp_file_path):
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover-image']/@href", namespaces=ns)
coverfile = None
if len(coversection) > 0:
coverfile = extractCover(epubZip, coversection[0], coverpath, tmp_file_path)
else:
meta_cover = tree.xpath("/pkg:package/pkg:metadata/pkg:meta[@name='cover']/@content", namespaces=ns)
if len(meta_cover) > 0:
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='"+meta_cover[0]+"']/@href", namespaces=ns)
else:
coversection = tree.xpath("/pkg:package/pkg:guide/pkg:reference/@href", namespaces=ns)
if len(coversection) > 0:
filetype = coversection[0].rsplit('.', 1)[-1]
if filetype == "xhtml" or filetype == "html": # if cover is (x)html format
markup = epubZip.read(os.path.join(coverpath, coversection[0]))
markupTree = etree.fromstring(markup)
# no matter xhtml or html with no namespace
imgsrc = markupTree.xpath("//*[local-name() = 'img']/@src")
# Alternative image source
if not len(imgsrc):
imgsrc = markupTree.xpath("//attribute::*[contains(local-name(), 'href')]")
if len(imgsrc):
# imgsrc maybe startwith "../"" so fullpath join then relpath to cwd
filename = os.path.relpath(os.path.join(os.path.dirname(os.path.join(coverpath, coversection[0])),
imgsrc[0]))
coverfile = extractCover(epubZip, filename, "", tmp_file_path)
else:
coverfile = extractCover(epubZip, coversection[0], coverpath, tmp_file_path)
return coverfile
def parse_epbub_series(ns, tree, epub_metadata):
series = tree.xpath("/pkg:package/pkg:metadata/pkg:meta[@name='calibre:series']/@content", namespaces=ns)
if len(series) > 0:
epub_metadata['series'] = series[0]
@@ -98,41 +150,4 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension):
epub_metadata['series_id'] = series_id[0]
else:
epub_metadata['series_id'] = '1'
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover-image']/@href", namespaces=ns)
coverfile = None
if len(coversection) > 0:
coverfile = extractCover(epubZip, coversection[0], coverpath, tmp_file_path)
else:
meta_cover = tree.xpath("/pkg:package/pkg:metadata/pkg:meta[@name='cover']/@content", namespaces=ns)
if len(meta_cover) > 0:
coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='"+meta_cover[0]+"']/@href", namespaces=ns)
if len(coversection) > 0:
filetype = coversection[0].rsplit('.', 1)[-1]
if filetype == "xhtml" or filetype == "html": # if cover is (x)html format
markup = epubZip.read(os.path.join(coverpath, coversection[0]))
markupTree = etree.fromstring(markup)
# no matter xhtml or html with no namespace
imgsrc = markupTree.xpath("//*[local-name() = 'img']/@src")
# imgsrc maybe startwith "../"" so fullpath join then relpath to cwd
filename = os.path.relpath(os.path.join(os.path.dirname(os.path.join(coverpath, coversection[0])), imgsrc[0]))
coverfile = extractCover(epubZip, filename, "", tmp_file_path)
else:
coverfile = extractCover(epubZip, coversection[0], coverpath, tmp_file_path)
if not epub_metadata['title']:
title = original_file_name
else:
title = epub_metadata['title']
return uploader.BookMeta(
file_path=tmp_file_path,
extension=original_file_extension,
title=title.encode('utf-8').decode('utf-8'),
author=epub_metadata['creator'].encode('utf-8').decode('utf-8'),
cover=coverfile,
description=epub_metadata['description'],
tags=epub_metadata['subject'].encode('utf-8').decode('utf-8'),
series=epub_metadata['series'].encode('utf-8').decode('utf-8'),
series_id=epub_metadata['series_id'].encode('utf-8').decode('utf-8'),
languages=epub_metadata['language'])
return epub_metadata
+69
View File
@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2020 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import traceback
from flask import render_template
from werkzeug.exceptions import default_exceptions
try:
from werkzeug.exceptions import FailedDependency
except ImportError:
from werkzeug.exceptions import UnprocessableEntity as FailedDependency
from . import config, app, logger, services
log = logger.create()
# custom error page
def error_http(error):
return render_template('http_error.html',
error_code="Error {0}".format(error.code),
error_name=error.name,
issue=False,
unconfigured=not config.db_configured,
instance=config.config_calibre_web_title
), error.code
def internal_error(error):
return render_template('http_error.html',
error_code="Internal Server Error",
error_name=str(error),
issue=True,
unconfigured=False,
error_stack=traceback.format_exc().split("\n"),
instance=config.config_calibre_web_title
), 500
def init_errorhandler():
# http error handling
for ex in default_exceptions:
if ex < 500:
app.register_error_handler(ex, error_http)
elif ex == 500:
app.register_error_handler(ex, internal_error)
if services.ldap:
# Only way of catching the LDAPException upon logging in with LDAP server down
@app.errorhandler(services.ldap.LDAPException)
# pylint: disable=unused-variable
def handle_exception(e):
log.debug('LDAP server not accessible while trying to login to opds feed')
return error_http(FailedDependency())
+18 -17
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
@@ -18,7 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from lxml import etree
import uploader
from .constants import BookMeta
def get_fb2_info(tmp_file_path, original_file_extension):
@@ -28,52 +28,53 @@ def get_fb2_info(tmp_file_path, original_file_extension):
'l': 'http://www.w3.org/1999/xlink',
}
fb2_file = open(tmp_file_path)
tree = etree.fromstring(fb2_file.read())
fb2_file = open(tmp_file_path, encoding="utf-8")
tree = etree.fromstring(fb2_file.read().encode())
authors = tree.xpath('/fb:FictionBook/fb:description/fb:title-info/fb:author', namespaces=ns)
def get_author(element):
last_name = element.xpath('fb:last-name/text()', namespaces=ns)
if len(last_name):
last_name = last_name[0].encode('utf-8')
last_name = last_name[0]
else:
last_name = u''
middle_name = element.xpath('fb:middle-name/text()', namespaces=ns)
if len(middle_name):
middle_name = middle_name[0].encode('utf-8')
middle_name = middle_name[0]
else:
middle_name = u''
first_name = element.xpath('fb:first-name/text()', namespaces=ns)
if len(first_name):
first_name = first_name[0].encode('utf-8')
first_name = first_name[0]
else:
first_name = u''
return (first_name.decode('utf-8') + u' '
+ middle_name.decode('utf-8') + u' '
+ last_name.decode('utf-8')).encode('utf-8')
return (first_name + u' '
+ middle_name + u' '
+ last_name)
author = str(", ".join(map(get_author, authors)))
title = tree.xpath('/fb:FictionBook/fb:description/fb:title-info/fb:book-title/text()', namespaces=ns)
if len(title):
title = str(title[0].encode('utf-8'))
title = str(title[0])
else:
title = u''
description = tree.xpath('/fb:FictionBook/fb:description/fb:publish-info/fb:book-name/text()', namespaces=ns)
if len(description):
description = str(description[0].encode('utf-8'))
description = str(description[0])
else:
description = u''
return uploader.BookMeta(
return BookMeta(
file_path=tmp_file_path,
extension=original_file_extension,
title=title.decode('utf-8'),
author=author.decode('utf-8'),
title=title,
author=author,
cover=None,
description=description.decode('utf-8'),
description=description,
tags="",
series="",
series_id="",
languages="")
languages="",
publisher="")
+158
View File
@@ -0,0 +1,158 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11,
# andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh,
# falgh1, grunjol, csitko, ytils, xybydy, trasba, vrabe,
# ruben-herold, marblepebble, JackED42, SiphonSquirrel,
# apetresc, nanu-c, mutschler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import hashlib
import json
import tempfile
from uuid import uuid4
from time import time
from shutil import move, copyfile
from flask import Blueprint, flash, request, redirect, url_for, abort
from flask_babel import gettext as _
from flask_login import login_required
from . import logger, gdriveutils, config, ub, calibre_db, csrf
from .admin import admin_required
gdrive = Blueprint('gdrive', __name__, url_prefix='/gdrive')
log = logger.create()
try:
from googleapiclient.errors import HttpError
except ImportError as err:
log.debug("Cannot import googleapiclient, using GDrive will not work: %s", err)
current_milli_time = lambda: int(round(time() * 1000))
gdrive_watch_callback_token = 'target=calibreweb-watch_files' #nosec
@gdrive.route("/authenticate")
@login_required
@admin_required
def authenticate_google_drive():
try:
authUrl = gdriveutils.Gauth.Instance().auth.GetAuthUrl()
except gdriveutils.InvalidConfigError:
flash(_(u'Google Drive setup not completed, try to deactivate and activate Google Drive again'),
category="error")
return redirect(url_for('web.index'))
return redirect(authUrl)
@gdrive.route("/callback")
def google_drive_callback():
auth_code = request.args.get('code')
if not auth_code:
abort(403)
try:
credentials = gdriveutils.Gauth.Instance().auth.flow.step2_exchange(auth_code)
with open(gdriveutils.CREDENTIALS, 'w') as f:
f.write(credentials.to_json())
except (ValueError, AttributeError) as error:
log.error(error)
return redirect(url_for('admin.db_configuration'))
@gdrive.route("/watch/subscribe")
@login_required
@admin_required
def watch_gdrive():
if not config.config_google_drive_watch_changes_response:
with open(gdriveutils.CLIENT_SECRETS, 'r') as settings:
filedata = json.load(settings)
address = filedata['web']['redirect_uris'][0].rstrip('/').replace('/gdrive/callback', '/gdrive/watch/callback')
notification_id = str(uuid4())
try:
result = gdriveutils.watchChange(gdriveutils.Gdrive.Instance().drive, notification_id,
'web_hook', address, gdrive_watch_callback_token, current_milli_time() + 604800*1000)
config.config_google_drive_watch_changes_response = result
config.save()
except HttpError as e:
reason=json.loads(e.content)['error']['errors'][0]
if reason['reason'] == u'push.webhookUrlUnauthorized':
flash(_(u'Callback domain is not verified, '
u'please follow steps to verify domain in google developer console'), category="error")
else:
flash(reason['message'], category="error")
return redirect(url_for('admin.db_configuration'))
@gdrive.route("/watch/revoke")
@login_required
@admin_required
def revoke_watch_gdrive():
last_watch_response = config.config_google_drive_watch_changes_response
if last_watch_response:
try:
gdriveutils.stopChannel(gdriveutils.Gdrive.Instance().drive, last_watch_response['id'],
last_watch_response['resourceId'])
except (HttpError, AttributeError):
pass
config.config_google_drive_watch_changes_response = {}
config.save()
return redirect(url_for('admin.db_configuration'))
try:
@csrf.exempt
@gdrive.route("/watch/callback", methods=['GET', 'POST'])
def on_received_watch_confirmation():
if not config.config_google_drive_watch_changes_response:
return ''
if request.headers.get('X-Goog-Channel-Token') != gdrive_watch_callback_token \
or request.headers.get('X-Goog-Resource-State') != 'change' \
or not request.data:
return ''
log.debug('%r', request.headers)
log.debug('%r', request.data)
log.info('Change received from gdrive')
try:
j = json.loads(request.data)
log.info('Getting change details')
response = gdriveutils.getChangeById(gdriveutils.Gdrive.Instance().drive, j['id'])
log.debug('%r', response)
if response:
dbpath = os.path.join(config.config_calibre_dir, "metadata.db").encode()
if not response['deleted'] and response['file']['title'] == 'metadata.db' \
and response['file']['md5Checksum'] != hashlib.md5(dbpath): # nosec
tmp_dir = os.path.join(tempfile.gettempdir(), 'calibre_web')
if not os.path.isdir(tmp_dir):
os.mkdir(tmp_dir)
log.info('Database file updated')
copyfile(dbpath, os.path.join(tmp_dir, "metadata.db_" + str(current_milli_time())))
log.info('Backing up existing and downloading updated metadata.db')
gdriveutils.downloadFile(None, "metadata.db", os.path.join(tmp_dir, "tmp_metadata.db"))
log.info('Setting up new DB')
# prevent error on windows, as os.rename does on existing files, also allow cross hdd move
move(os.path.join(tmp_dir, "tmp_metadata.db"), dbpath)
calibre_db.reconnect_db(config, ub.app_DB_path)
except Exception as ex:
log.debug_or_exception(ex)
return ''
except AttributeError:
pass
+235 -74
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
@@ -17,24 +16,73 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
try:
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from pydrive.auth import RefreshError, InvalidConfigError
from apiclient import errors
gdrive_support = True
except ImportError:
gdrive_support = False
import os
from ub import config
import cli
import json
import shutil
import chardet
import ssl
from flask import Response, stream_with_context
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *
import web
from sqlalchemy import create_engine
from sqlalchemy import Column, UniqueConstraint
from sqlalchemy import String, Integer
from sqlalchemy.orm import sessionmaker, scoped_session
try:
# Compatibility with sqlalchemy 2.0
from sqlalchemy.orm import declarative_base
except ImportError:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.exc import OperationalError, InvalidRequestError
from sqlalchemy.sql.expression import text
try:
from six import __version__ as six_version
except ImportError:
six_version = "not installed"
try:
from httplib2 import __version__ as httplib2_version
except ImportError:
httplib2_version = "not installed"
try:
from apiclient import errors
from httplib2 import ServerNotFoundError
importError = None
gdrive_support = True
except ImportError as e:
importError = e
gdrive_support = False
try:
from pydrive2.auth import GoogleAuth
from pydrive2.drive import GoogleDrive
from pydrive2.auth import RefreshError
from pydrive2.files import ApiRequestError
except ImportError as err:
try:
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from pydrive.auth import RefreshError
from pydrive.files import ApiRequestError
except ImportError as err:
importError = err
gdrive_support = False
from . import logger, cli, config
from .constants import CONFIG_DIR as _CONFIG_DIR
SETTINGS_YAML = os.path.join(_CONFIG_DIR, 'settings.yaml')
CREDENTIALS = os.path.join(_CONFIG_DIR, 'gdrive_credentials')
CLIENT_SECRETS = os.path.join(_CONFIG_DIR, 'client_secrets.json')
log = logger.create()
if gdrive_support:
logger.get('googleapiclient.discovery_cache').setLevel(logger.logging.ERROR)
if not logger.is_debug_enabled():
logger.get('googleapiclient.discovery').setLevel(logger.logging.ERROR)
else:
log.debug("Cannot import pydrive,httplib2, using gdrive will not work: %s", importError)
class Singleton:
"""
@@ -67,6 +115,9 @@ class Singleton:
except AttributeError:
self._instance = self._decorated()
return self._instance
except (ImportError, NameError) as e:
log.debug(e)
return None
def __call__(self):
raise TypeError('Singletons must be accessed through `Instance()`.')
@@ -78,7 +129,11 @@ class Singleton:
@Singleton
class Gauth:
def __init__(self):
self.auth = GoogleAuth(settings_file=os.path.join(config.get_main_dir,'settings.yaml'))
try:
self.auth = GoogleAuth(settings_file=SETTINGS_YAML)
except NameError as error:
log.error(error)
self.auth = None
@Singleton
@@ -86,6 +141,9 @@ class Gdrive:
def __init__(self):
self.drive = getDrive(gauth=Gauth.Instance().auth)
def is_gdrive_ready():
return os.path.exists(SETTINGS_YAML) and os.path.exists(CREDENTIALS)
engine = create_engine('sqlite:///{0}'.format(cli.gdpath), echo=False)
Base = declarative_base()
@@ -121,7 +179,7 @@ class PermissionAdded(Base):
def migrate():
if not engine.dialect.has_table(engine.connect(), "permissions_added"):
PermissionAdded.__table__.create(bind = engine)
for sql in session.execute("select sql from sqlite_master where type='table'"):
for sql in session.execute(text("select sql from sqlite_master where type='table'")):
if 'CREATE TABLE gdrive_ids' in sql[0]:
currUniqueConstraint = 'UNIQUE (gdrive_id)'
if currUniqueConstraint in sql[0]:
@@ -146,17 +204,17 @@ migrate()
def getDrive(drive=None, gauth=None):
if not drive:
if not gauth:
gauth = GoogleAuth(settings_file=os.path.join(config.get_main_dir,'settings.yaml'))
gauth = GoogleAuth(settings_file=SETTINGS_YAML)
# Try to load saved client credentials
gauth.LoadCredentialsFile(os.path.join(config.get_main_dir,'gdrive_credentials'))
gauth.LoadCredentialsFile(CREDENTIALS)
if gauth.access_token_expired:
# Refresh them if expired
try:
gauth.Refresh()
except RefreshError as e:
web.app.logger.error("Google Drive error: " + e.message)
except Exception as e:
web.app.logger.exception(e)
log.error("Google Drive error: %s", e)
except Exception as ex:
log.debug_or_exception(ex)
else:
# Initialize the saved creds
gauth.Authorize()
@@ -166,18 +224,22 @@ def getDrive(drive=None, gauth=None):
try:
drive.auth.Refresh()
except RefreshError as e:
web.app.logger.error("Google Drive error: " + e.message)
log.error("Google Drive error: %s", e)
return drive
def listRootFolders():
drive = getDrive(Gdrive.Instance().drive)
folder = "'root' in parents and mimeType = 'application/vnd.google-apps.folder' and trashed = false"
fileList = drive.ListFile({'q': folder}).GetList()
try:
drive = getDrive(Gdrive.Instance().drive)
folder = "'root' in parents and mimeType = 'application/vnd.google-apps.folder' and trashed = false"
fileList = drive.ListFile({'q': folder}).GetList()
except (ServerNotFoundError, ssl.SSLError, RefreshError) as e:
log.info("GDrive Error %s" % e)
fileList = []
return fileList
def getEbooksFolder(drive):
return getFolderInFolder('root',config.config_google_drive_folder,drive)
return getFolderInFolder('root', config.config_google_drive_folder, drive)
def getFolderInFolder(parentId, folderName, drive):
@@ -203,11 +265,16 @@ def getEbooksFolderId(drive=None):
try:
gDriveId.gdrive_id = getEbooksFolder(drive)['id']
except Exception:
web.app.logger.error('Error gDrive, root ID not found')
log.error('Error gDrive, root ID not found')
gDriveId.path = '/'
session.merge(gDriveId)
session.commit()
return
try:
session.commit()
except OperationalError as ex:
log.error("gdrive.db DB is not Writeable")
log.debug('Database error: %s', ex)
session.rollback()
return gDriveId.gdrive_id
def getFile(pathId, fileName, drive):
@@ -221,37 +288,47 @@ def getFile(pathId, fileName, drive):
def getFolderId(path, drive):
# drive = getDrive(drive)
currentFolderId = getEbooksFolderId(drive)
sqlCheckPath = path if path[-1] == '/' else path + '/'
storedPathName = session.query(GdriveId).filter(GdriveId.path == sqlCheckPath).first()
try:
currentFolderId = getEbooksFolderId(drive)
sqlCheckPath = path if path[-1] == '/' else path + '/'
storedPathName = session.query(GdriveId).filter(GdriveId.path == sqlCheckPath).first()
if not storedPathName:
dbChange = False
s = path.split('/')
for i, x in enumerate(s):
if len(x) > 0:
currentPath = "/".join(s[:i+1])
if currentPath[-1] != '/':
currentPath = currentPath + '/'
storedPathName = session.query(GdriveId).filter(GdriveId.path == currentPath).first()
if storedPathName:
currentFolderId = storedPathName.gdrive_id
else:
currentFolder = getFolderInFolder(currentFolderId, x, drive)
if currentFolder:
gDriveId = GdriveId()
gDriveId.gdrive_id = currentFolder['id']
gDriveId.path = currentPath
session.merge(gDriveId)
dbChange = True
currentFolderId = currentFolder['id']
if not storedPathName:
dbChange = False
s = path.split('/')
for i, x in enumerate(s):
if len(x) > 0:
currentPath = "/".join(s[:i+1])
if currentPath[-1] != '/':
currentPath = currentPath + '/'
storedPathName = session.query(GdriveId).filter(GdriveId.path == currentPath).first()
if storedPathName:
currentFolderId = storedPathName.gdrive_id
else:
currentFolderId = None
break
if dbChange:
session.commit()
else:
currentFolderId = storedPathName.gdrive_id
currentFolder = getFolderInFolder(currentFolderId, x, drive)
if currentFolder:
gDriveId = GdriveId()
gDriveId.gdrive_id = currentFolder['id']
gDriveId.path = currentPath
session.merge(gDriveId)
dbChange = True
currentFolderId = currentFolder['id']
else:
currentFolderId = None
break
if dbChange:
session.commit()
else:
currentFolderId = storedPathName.gdrive_id
except OperationalError as ex:
log.error("gdrive.db DB is not Writeable")
log.debug('Database error: %s', ex)
session.rollback()
except ApiRequestError as ex:
log.error('{} {}'.format(ex.error['message'], path))
session.rollback()
except RefreshError as ex:
log.error(ex)
return currentFolderId
@@ -295,7 +372,7 @@ def moveGdriveFolderRemote(origin_file, target_folder):
addParents=gFileTargetDir['id'],
removeParents=previous_parents,
fields='id, parents').execute()
# if previous_parents has no childs anymore, delete original fileparent
# if previous_parents has no children anymore, delete original fileparent
if len(children['items']) == 1:
deleteDatabaseEntry(previous_parents)
drive.auth.service.files().delete(fileId=previous_parents).execute()
@@ -347,7 +424,8 @@ def uploadFileToEbooksFolder(destFile, f):
if len(existingFiles) > 0:
driveFile = existingFiles[0]
else:
driveFile = drive.CreateFile({'title': x, 'parents': [{"kind": "drive#fileLink", 'id': parent['id']}],})
driveFile = drive.CreateFile({'title': x,
'parents': [{"kind": "drive#fileLink", 'id': parent['id']}], })
driveFile.SetContentFile(f)
driveFile.Upload()
else:
@@ -443,17 +521,23 @@ def getChangeById (drive, change_id):
change = drive.auth.service.changes().get(changeId=change_id).execute()
return change
except (errors.HttpError) as error:
web.app.logger.info(error.message)
log.error(error)
return None
except Exception as e:
web.app.logger.info(e)
except Exception as ex:
log.error(ex)
return None
# Deletes the local hashes database to force search for new folder names
def deleteDatabaseOnChange():
session.query(GdriveId).delete()
session.commit()
try:
session.query(GdriveId).delete()
session.commit()
except (OperationalError, InvalidRequestError) as ex:
session.rollback()
log.debug('Database error: %s', ex)
log.error(u"GDrive DB is not Writeable")
def updateGdriveCalibreFromLocal():
copyToDrive(Gdrive.Instance().drive, config.config_calibre_dir, False, True)
@@ -467,13 +551,23 @@ def updateDatabaseOnEdit(ID,newPath):
storedPathName = session.query(GdriveId).filter(GdriveId.gdrive_id == ID).first()
if storedPathName:
storedPathName.path = sqlCheckPath
session.commit()
try:
session.commit()
except OperationalError as ex:
log.error("gdrive.db DB is not Writeable")
log.debug('Database error: %s', ex)
session.rollback()
# Deletes the hashes in database of deleted book
def deleteDatabaseEntry(ID):
session.query(GdriveId).filter(GdriveId.gdrive_id == ID).delete()
session.commit()
try:
session.commit()
except OperationalError as ex:
log.error("gdrive.db DB is not Writeable")
log.debug('Database error: %s', ex)
session.rollback()
# Gets cover file from gdrive
@@ -490,7 +584,12 @@ def get_cover_via_gdrive(cover_path):
permissionAdded = PermissionAdded()
permissionAdded.gdrive_id = df['id']
session.add(permissionAdded)
session.commit()
try:
session.commit()
except OperationalError as ex:
log.error("gdrive.db DB is not Writeable")
log.debug('Database error: %s', ex)
session.rollback()
return df.metadata.get('webContentLink')
else:
return None
@@ -504,18 +603,80 @@ def partial(total_byte_len, part_size_limit):
return s
# downloads files in chunks from gdrive
def do_gdrive_download(df, headers):
def do_gdrive_download(df, headers, convert_encoding=False):
total_size = int(df.metadata.get('fileSize'))
download_url = df.metadata.get('downloadUrl')
s = partial(total_size, 1024 * 1024) # I'm downloading BIG files, so 100M chunk size is fine for me
def stream():
def stream(convert_encoding):
for byte in s:
headers = {"Range": 'bytes=%s-%s' % (byte[0], byte[1])}
resp, content = df.auth.Get_Http_Object().request(download_url, headers=headers)
if resp.status == 206:
if convert_encoding:
result = chardet.detect(content)
content = content.decode(result['encoding']).encode('utf-8')
yield content
else:
web.app.logger.info('An error occurred: %s' % resp)
log.warning('An error occurred: %s', resp)
return
return Response(stream_with_context(stream()), headers=headers)
return Response(stream_with_context(stream(convert_encoding)), headers=headers)
_SETTINGS_YAML_TEMPLATE = """
client_config_backend: settings
client_config_file: %(client_file)s
client_config:
client_id: %(client_id)s
client_secret: %(client_secret)s
redirect_uri: %(redirect_uri)s
save_credentials: True
save_credentials_backend: file
save_credentials_file: %(credential)s
get_refresh_token: True
oauth_scope:
- https://www.googleapis.com/auth/drive
"""
def update_settings(client_id, client_secret, redirect_uri):
if redirect_uri.endswith('/'):
redirect_uri = redirect_uri[:-1]
config_params = {
'client_file': CLIENT_SECRETS,
'client_id': client_id,
'client_secret': client_secret,
'redirect_uri': redirect_uri,
'credential': CREDENTIALS
}
with open(SETTINGS_YAML, 'w') as f:
f.write(_SETTINGS_YAML_TEMPLATE % config_params)
def get_error_text(client_secrets=None):
if not gdrive_support:
return 'Import of optional Google Drive requirements missing'
if not os.path.isfile(CLIENT_SECRETS):
return 'client_secrets.json is missing or not readable'
try:
with open(CLIENT_SECRETS, 'r') as settings:
filedata = json.load(settings)
except PermissionError:
return 'client_secrets.json is missing or not readable'
if 'web' not in filedata:
return 'client_secrets.json is not configured for web application'
if 'redirect_uris' not in filedata['web']:
return 'Callback url (redirect url) is missing in client_secrets.json'
if client_secrets:
client_secrets.update(filedata['web'])
def get_versions():
return {'six': six_version,
'httplib2': httplib2_version}
+552 -344
View File
File diff suppressed because it is too large Load Diff
+63 -6
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
@@ -17,6 +16,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .iso_language_names import LANGUAGE_NAMES as _LANGUAGE_NAMES
from . import logger
log = logger.create()
try:
from iso639 import languages, __version__
get = languages.get
@@ -30,14 +35,66 @@ except ImportError:
__version__ = "? (PyCountry)"
def _copy_fields(l):
l.part1 = l.alpha_2
l.part3 = l.alpha_3
l.part1 = getattr(l, 'alpha_2', None)
l.part3 = getattr(l, 'alpha_3', None)
return l
def get(name=None, part1=None, part3=None):
if (part3 is not None):
if part3 is not None:
return _copy_fields(pyc_languages.get(alpha_3=part3))
if (part1 is not None):
if part1 is not None:
return _copy_fields(pyc_languages.get(alpha_2=part1))
if (name is not None):
if name is not None:
return _copy_fields(pyc_languages.get(name=name))
def get_language_names(locale):
return _LANGUAGE_NAMES.get(locale)
def get_language_name(locale, lang_code):
try:
return get_language_names(locale)[lang_code]
except KeyError:
log.error('Missing translation for language name: {}'.format(lang_code))
return "Unknown"
def get_language_codes(locale, language_names, remainder=None):
language_names = set(x.strip().lower() for x in language_names if x)
lang = list()
for k, v in get_language_names(locale).items():
v = v.lower()
if v in language_names:
lang.append(k)
language_names.remove(v)
if remainder is not None and language_names:
remainder.extend(language_names)
return lang
def get_valid_language_codes(locale, language_names, remainder=None):
lang = list()
if "" in language_names:
language_names.remove("")
for k, __ in get_language_names(locale).items():
if k in language_names:
lang.append(k)
language_names.remove(k)
if remainder is not None and len(language_names):
remainder.extend(language_names)
return lang
def get_lang3(lang):
try:
if len(lang) == 2:
ret_value = get(part1=lang).part3
elif len(lang) == 3:
ret_value = lang
else:
ret_value = ""
except KeyError:
ret_value = lang
return ret_value
File diff suppressed because it is too large Load Diff
+139
View File
@@ -0,0 +1,139 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11,
# andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh,
# falgh1, grunjol, csitko, ytils, xybydy, trasba, vrabe,
# ruben-herold, marblepebble, JackED42, SiphonSquirrel,
# apetresc, nanu-c, mutschler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# custom jinja filters
import datetime
import mimetypes
from uuid import uuid4
from babel.dates import format_date
from flask import Blueprint, request, url_for
from flask_babel import get_locale
from flask_login import current_user
from markupsafe import escape
from . import logger
jinjia = Blueprint('jinjia', __name__)
log = logger.create()
# pagination links in jinja
@jinjia.app_template_filter('url_for_other_page')
def url_for_other_page(page):
args = request.view_args.copy()
args['page'] = page
for get, val in request.args.items():
args[get] = val
return url_for(request.endpoint, **args)
# shortentitles to at longest nchar, shorten longer words if necessary
@jinjia.app_template_filter('shortentitle')
def shortentitle_filter(s, nchar=20):
text = s.split()
res = "" # result
suml = 0 # overall length
for line in text:
if suml >= 60:
res += '...'
break
# if word longer than 20 chars truncate line and append '...', otherwise add whole word to result
# string, and summarize total length to stop at chars given by nchar
if len(line) > nchar:
res += line[:(nchar-3)] + '[..] '
suml += nchar+3
else:
res += line + ' '
suml += len(line) + 1
return res.strip()
@jinjia.app_template_filter('mimetype')
def mimetype_filter(val):
return mimetypes.types_map.get('.' + val, 'application/octet-stream')
@jinjia.app_template_filter('formatdate')
def formatdate_filter(val):
try:
return format_date(val, format='medium', locale=get_locale())
except AttributeError as e:
log.error('Babel error: %s, Current user locale: %s, Current User: %s', e,
current_user.locale,
current_user.name
)
return val
@jinjia.app_template_filter('formatdateinput')
def format_date_input(val):
input_date = val.isoformat().split('T', 1)[0] # Hack to support dates <1900
return '' if input_date == "0101-01-01" else input_date
@jinjia.app_template_filter('strftime')
def timestamptodate(date, fmt=None):
date = datetime.datetime.fromtimestamp(
int(date)/1000
)
native = date.replace(tzinfo=None)
if fmt:
time_format = fmt
else:
time_format = '%d %m %Y - %H:%S'
return native.strftime(time_format)
@jinjia.app_template_filter('yesno')
def yesno(value, yes, no):
return yes if value else no
@jinjia.app_template_filter('formatfloat')
def formatfloat(value, decimals=1):
value = 0 if not value else value
return ('{0:.' + str(decimals) + 'f}').format(value).rstrip('0').rstrip('.')
@jinjia.app_template_filter('formatseriesindex')
def formatseriesindex_filter(series_index):
if series_index:
try:
if int(series_index) - series_index == 0:
return int(series_index)
else:
return series_index
except ValueError:
return series_index
return 0
@jinjia.app_template_filter('escapedlink')
def escapedlink_filter(url, text):
return "<a href='{}'>{}</a>".format(url, escape(text))
@jinjia.app_template_filter('uuidfilter')
def uuidfilter(var):
return uuid4()
+1262
View File
File diff suppressed because it is too large Load Diff
+167
View File
@@ -0,0 +1,167 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 shavitmichael, OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""This module is used to control authentication/authorization of Kobo sync requests.
This module also includes research notes into the auth protocol used by Kobo devices.
Log-in:
When first booting a Kobo device the user must sign into a Kobo (or affiliate) account.
Upon successful sign-in, the user is redirected to
https://auth.kobobooks.com/CrossDomainSignIn?id=<some id>
which serves the following response:
<script type='text/javascript'>
location.href='kobo://UserAuthenticated?userId=<redacted>&userKey<redacted>&email=<redacted>&returnUrl=https%3a%2f%2fwww.kobo.com';
</script>
And triggers the insertion of a userKey into the device's User table.
Together, the device's DeviceId and UserKey act as an *irrevocable* authentication
token to most (if not all) Kobo APIs. In fact, in most cases only the UserKey is
required to authorize the API call.
Changing Kobo password *does not* invalidate user keys! This is apparently a known
issue for a few years now https://www.mobileread.com/forums/showpost.php?p=3476851&postcount=13
(although this poster hypothesised that Kobo could blacklist a DeviceId, many endpoints
will still grant access given the userkey.)
Official Kobo Store Api authorization:
* For most of the endpoints we care about (sync, metadata, tags, etc), the userKey is
passed in the x-kobo-userkey header, and is sufficient to authorize the API call.
* Some endpoints (e.g: AnnotationService) instead make use of Bearer tokens pass through
an authorization header. To get a BearerToken, the device makes a POST request to the
v1/auth/device endpoint with the secret UserKey and the device's DeviceId.
* The book download endpoint passes an auth token as a URL param instead of a header.
Our implementation:
We pretty much ignore all of the above. To authenticate the user, we generate a random
and unique token that they append to the CalibreWeb Url when setting up the api_store
setting on the device.
Thus, every request from the device to the api_store will hit CalibreWeb with the
auth_token in the url (e.g: https://mylibrary.com/<auth_token>/v1/library/sync).
In addition, once authenticated we also set the login cookie on the response that will
be sent back for the duration of the session to authorize subsequent API calls (in
particular calls to non-Kobo specific endpoints such as the CalibreWeb book download).
"""
from binascii import hexlify
from datetime import datetime
from os import urandom
from functools import wraps
from flask import g, Blueprint, url_for, abort, request
from flask_login import login_user, current_user, login_required
from flask_babel import gettext as _
from . import logger, config, calibre_db, db, helper, ub, lm
from .render_template import render_title_template
log = logger.create()
def register_url_value_preprocessor(kobo):
@kobo.url_value_preprocessor
# pylint: disable=unused-variable
def pop_auth_token(__, values):
g.auth_token = values.pop("auth_token")
def disable_failed_auth_redirect_for_blueprint(bp):
lm.blueprint_login_views[bp.name] = None
def get_auth_token():
if "auth_token" in g:
return g.get("auth_token")
else:
return None
def requires_kobo_auth(f):
@wraps(f)
def inner(*args, **kwargs):
auth_token = get_auth_token()
if auth_token is not None:
user = (
ub.session.query(ub.User)
.join(ub.RemoteAuthToken)
.filter(ub.RemoteAuthToken.auth_token == auth_token).filter(ub.RemoteAuthToken.token_type==1)
.first()
)
if user is not None:
login_user(user)
return f(*args, **kwargs)
log.debug("Received Kobo request without a recognizable auth token.")
return abort(401)
return inner
kobo_auth = Blueprint("kobo_auth", __name__, url_prefix="/kobo_auth")
@kobo_auth.route("/generate_auth_token/<int:user_id>")
@login_required
def generate_auth_token(user_id):
warning = False
host_list = request.host.rsplit(':')
if len(host_list) == 1:
host = ':'.join(host_list)
else:
host = ':'.join(host_list[0:-1])
if host.startswith('127.') or host.lower() == 'localhost' or host.startswith('[::ffff:7f') or host == "[::1]":
warning = _('Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device')
# Generate auth token if none is existing for this user
auth_token = ub.session.query(ub.RemoteAuthToken).filter(
ub.RemoteAuthToken.user_id == user_id
).filter(ub.RemoteAuthToken.token_type==1).first()
if not auth_token:
auth_token = ub.RemoteAuthToken()
auth_token.user_id = user_id
auth_token.expiration = datetime.max
auth_token.auth_token = (hexlify(urandom(16))).decode("utf-8")
auth_token.token_type = 1
ub.session.add(auth_token)
ub.session_commit()
books = calibre_db.session.query(db.Books).join(db.Data).all()
for book in books:
formats = [data.format for data in book.data]
if not 'KEPUB' in formats and config.config_kepubifypath and 'EPUB' in formats:
helper.convert_book_format(book.id, config.config_calibre_dir, 'EPUB', 'KEPUB', current_user.name)
return render_title_template(
"generate_kobo_auth_url.html",
title=_(u"Kobo Setup"),
auth_token=auth_token.auth_token,
warning = warning
)
@kobo_auth.route("/deleteauthtoken/<int:user_id>", methods=["POST"])
@login_required
def delete_auth_token(user_id):
# Invalidate any previously generated Kobo Auth token for this user
ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.user_id == user_id)\
.filter(ub.RemoteAuthToken.token_type==1).delete()
return ub.session_commit()
+88
View File
@@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2021 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from flask_login import current_user
from . import ub
import datetime
from sqlalchemy.sql.expression import or_, and_, true
from sqlalchemy import exc
# Add the current book id to kobo_synced_books table for current user, if entry is already present,
# do nothing (safety precaution)
def add_synced_books(book_id):
is_present = ub.session.query(ub.KoboSyncedBooks).filter(ub.KoboSyncedBooks.book_id == book_id)\
.filter(ub.KoboSyncedBooks.user_id == current_user.id).count()
if not is_present:
synced_book = ub.KoboSyncedBooks()
synced_book.user_id = current_user.id
synced_book.book_id = book_id
ub.session.add(synced_book)
ub.session_commit()
# Select all entries of current book in kobo_synced_books table, which are from current user and delete them
def remove_synced_book(book_id, all=False, session=None):
if not all:
user = ub.KoboSyncedBooks.user_id == current_user.id
else:
user = true()
if not session:
ub.session.query(ub.KoboSyncedBooks).filter(ub.KoboSyncedBooks.book_id == book_id).filter(user).delete()
ub.session_commit()
else:
session.query(ub.KoboSyncedBooks).filter(ub.KoboSyncedBooks.book_id == book_id).filter(user).delete()
ub.session_commit(sess=session)
def change_archived_books(book_id, state=None, message=None):
archived_book = ub.session.query(ub.ArchivedBook).filter(and_(ub.ArchivedBook.user_id == int(current_user.id),
ub.ArchivedBook.book_id == book_id)).first()
if not archived_book:
archived_book = ub.ArchivedBook(user_id=current_user.id, book_id=book_id)
archived_book.is_archived = state if state else not archived_book.is_archived
archived_book.last_modified = datetime.datetime.utcnow()
ub.session.merge(archived_book)
ub.session_commit(message)
return archived_book.is_archived
# select all books which are synced by the current user and do not belong to a synced shelf and set them to archive
# select all shelves from current user which are synced and do not belong to the "only sync" shelves
def update_on_sync_shelfs(user_id):
books_to_archive = (ub.session.query(ub.KoboSyncedBooks)
.join(ub.BookShelf, ub.KoboSyncedBooks.book_id == ub.BookShelf.book_id, isouter=True)
.join(ub.Shelf, ub.Shelf.user_id == user_id, isouter=True)
.filter(or_(ub.Shelf.kobo_sync == 0, ub.Shelf.kobo_sync == None))
.filter(ub.KoboSyncedBooks.user_id == user_id).all())
for b in books_to_archive:
change_archived_books(b.book_id, True)
ub.session.query(ub.KoboSyncedBooks) \
.filter(ub.KoboSyncedBooks.book_id == b.book_id) \
.filter(ub.KoboSyncedBooks.user_id == user_id).delete()
ub.session_commit()
# Search all shelf which are currently not synced
shelves_to_archive = ub.session.query(ub.Shelf).filter(ub.Shelf.user_id == user_id).filter(
ub.Shelf.kobo_sync == 0).all()
for a in shelves_to_archive:
ub.session.add(ub.ShelfArchive(uuid=a.uuid, user_id=user_id))
ub.session_commit()
+207
View File
@@ -0,0 +1,207 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2019 pwr
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import inspect
import logging
from logging import Formatter, StreamHandler
from logging.handlers import RotatingFileHandler
from .constants import CONFIG_DIR as _CONFIG_DIR
ACCESS_FORMATTER_GEVENT = Formatter("%(message)s")
ACCESS_FORMATTER_TORNADO = Formatter("[%(asctime)s] %(message)s")
FORMATTER = Formatter("[%(asctime)s] %(levelname)5s {%(name)s:%(lineno)d} %(message)s")
DEFAULT_LOG_LEVEL = logging.INFO
DEFAULT_LOG_FILE = os.path.join(_CONFIG_DIR, "calibre-web.log")
DEFAULT_ACCESS_LOG = os.path.join(_CONFIG_DIR, "access.log")
LOG_TO_STDERR = '/dev/stderr'
LOG_TO_STDOUT = '/dev/stdout'
logging.addLevelName(logging.WARNING, "WARN")
logging.addLevelName(logging.CRITICAL, "CRIT")
class _Logger(logging.Logger):
def debug_or_exception(self, message, stacklevel=2, *args, **kwargs):
if sys.version_info > (3, 7):
if is_debug_enabled():
self.exception(message, stacklevel=stacklevel, *args, **kwargs)
else:
self.error(message, stacklevel=stacklevel, *args, **kwargs)
else:
if is_debug_enabled():
self.exception(message, stack_info=True, *args, **kwargs)
else:
self.error(message, *args, **kwargs)
def debug_no_auth(self, message, *args, **kwargs):
message = message.strip("\r\n")
if message.startswith("send: AUTH"):
self.debug(message[:16], *args, **kwargs)
else:
self.debug(message, *args, **kwargs)
def get(name=None):
return logging.getLogger(name)
def create():
parent_frame = inspect.stack(0)[1]
if hasattr(parent_frame, 'frame'):
parent_frame = parent_frame.frame
else:
parent_frame = parent_frame[0]
parent_module = inspect.getmodule(parent_frame)
return get(parent_module.__name__)
def is_debug_enabled():
return logging.root.level <= logging.DEBUG
def is_info_enabled(logger):
return logging.getLogger(logger).level <= logging.INFO
def get_level_name(level):
return logging.getLevelName(level)
def is_valid_logfile(file_path):
if file_path == LOG_TO_STDERR or file_path == LOG_TO_STDOUT:
return True
if not file_path:
return True
if os.path.isdir(file_path):
return False
log_dir = os.path.dirname(file_path)
return (not log_dir) or os.path.isdir(log_dir)
def _absolute_log_file(log_file, default_log_file):
if log_file:
if not os.path.dirname(log_file):
log_file = os.path.join(_CONFIG_DIR, log_file)
return os.path.abspath(log_file)
return default_log_file
def get_logfile(log_file):
return _absolute_log_file(log_file, DEFAULT_LOG_FILE)
def get_accesslogfile(log_file):
return _absolute_log_file(log_file, DEFAULT_ACCESS_LOG)
def setup(log_file, log_level=None):
'''
Configure the logging output.
May be called multiple times.
'''
log_level = log_level or DEFAULT_LOG_LEVEL
logging.setLoggerClass(_Logger)
logging.getLogger(__package__).setLevel(log_level)
r = logging.root
if log_level >= logging.INFO or os.environ.get('FLASK_DEBUG'):
# avoid spamming the log with debug messages from libraries
r.setLevel(log_level)
# Otherwise name get's destroyed on windows
if log_file != LOG_TO_STDERR and log_file != LOG_TO_STDOUT:
log_file = _absolute_log_file(log_file, DEFAULT_LOG_FILE)
previous_handler = r.handlers[0] if r.handlers else None
if previous_handler:
# if the log_file has not changed, don't create a new handler
if getattr(previous_handler, 'baseFilename', None) == log_file:
return "" if log_file == DEFAULT_LOG_FILE else log_file
logging.debug("logging to %s level %s", log_file, r.level)
if log_file == LOG_TO_STDERR or log_file == LOG_TO_STDOUT:
if log_file == LOG_TO_STDOUT:
file_handler = StreamHandler(sys.stdout)
file_handler.baseFilename = log_file
else:
file_handler = StreamHandler(sys.stderr)
file_handler.baseFilename = log_file
else:
try:
file_handler = RotatingFileHandler(log_file, maxBytes=100000, backupCount=2, encoding='utf-8')
except IOError:
if log_file == DEFAULT_LOG_FILE:
raise
file_handler = RotatingFileHandler(DEFAULT_LOG_FILE, maxBytes=100000, backupCount=2, encoding='utf-8')
log_file = ""
file_handler.setFormatter(FORMATTER)
for h in r.handlers:
r.removeHandler(h)
h.close()
r.addHandler(file_handler)
return "" if log_file == DEFAULT_LOG_FILE else log_file
def create_access_log(log_file, log_name, formatter):
'''
One-time configuration for the web server's access log.
'''
log_file = _absolute_log_file(log_file, DEFAULT_ACCESS_LOG)
logging.debug("access log: %s", log_file)
access_log = logging.getLogger(log_name)
access_log.propagate = False
access_log.setLevel(logging.INFO)
try:
file_handler = RotatingFileHandler(log_file, maxBytes=50000, backupCount=2, encoding='utf-8')
except IOError:
if log_file == DEFAULT_ACCESS_LOG:
raise
file_handler = RotatingFileHandler(DEFAULT_ACCESS_LOG, maxBytes=50000, backupCount=2, encoding='utf-8')
log_file = ""
file_handler.setFormatter(formatter)
access_log.addHandler(file_handler)
return access_log, \
"" if _absolute_log_file(log_file, DEFAULT_ACCESS_LOG) == DEFAULT_ACCESS_LOG else log_file
# Enable logging of smtp lib debug output
class StderrLogger(object):
def __init__(self, name=None):
self.log = get(name or self.__class__.__name__)
self.buffer = ''
def write(self, message):
try:
if message == '\n':
self.log.debug(self.buffer.replace('\n', '\\n'))
self.buffer = ''
else:
self.buffer += message
except Exception:
self.log.debug("Logging Error")
# default configuration, before application settings are applied
setup(LOG_TO_STDERR, logging.DEBUG if os.environ.get('FLASK_DEBUG') else DEFAULT_LOG_LEVEL)
+65
View File
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2021 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# ComicVine api document: https://comicvine.gamespot.com/api/documentation
import requests
from cps.services.Metadata import Metadata
class ComicVine(Metadata):
__name__ = "ComicVine"
__id__ = "comicvine"
def search(self, query, generic_cover=""):
val = list()
apikey = "57558043c53943d5d1e96a9ad425b0eb85532ee6"
if self.active:
headers = {
'User-Agent': 'Not Evil Browser'
}
result = requests.get("https://comicvine.gamespot.com/api/search?api_key="
+ apikey + "&resources=issue&query=" + query + "&sort=name:desc&format=json", headers=headers)
for r in result.json().get('results'):
seriesTitle = r['volume'].get('name', "")
if r.get('store_date'):
dateFomers = r.get('store_date')
else:
dateFomers = r.get('date_added')
v = dict()
v['id'] = r['id']
v['title'] = seriesTitle + " #" + r.get('issue_number', "0") + " - " + ( r.get('name', "") or "")
v['authors'] = r.get('authors', [])
v['description'] = r.get('description', "")
v['publisher'] = ""
v['publishedDate'] = dateFomers
v['tags'] = ["Comics", seriesTitle]
v['rating'] = 0
v['series'] = seriesTitle
v['cover'] = r['image'].get('original_url')
v['source'] = {
"id": self.__id__,
"description": "ComicVine Books",
"link": "https://comicvine.gamespot.com/"
}
v['url'] = r.get('site_detail_url', "")
val.append(v)
return val
+55
View File
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2021 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Google Books api document: https://developers.google.com/books/docs/v1/using
import requests
from cps.services.Metadata import Metadata
class Google(Metadata):
__name__ = "Google"
__id__ = "google"
def search(self, query, generic_cover=""):
if self.active:
val = list()
result = requests.get("https://www.googleapis.com/books/v1/volumes?q="+query.replace(" ","+"))
for r in result.json().get('items'):
v = dict()
v['id'] = r['id']
v['title'] = r['volumeInfo'].get('title',"")
v['authors'] = r['volumeInfo'].get('authors', [])
v['description'] = r['volumeInfo'].get('description', "")
v['publisher'] = r['volumeInfo'].get('publisher', "")
v['publishedDate'] = r['volumeInfo'].get('publishedDate', "")
v['tags'] = r['volumeInfo'].get('categories', [])
v['rating'] = r['volumeInfo'].get('averageRating', 0)
if r['volumeInfo'].get('imageLinks'):
v['cover'] = r['volumeInfo']['imageLinks']['thumbnail'].replace("http://", "https://")
else:
v['cover'] = "/../../../static/generic_cover.jpg"
v['source'] = {
"id": self.__id__,
"description": "Google Books",
"link": "https://books.google.com/"}
v['url'] = "https://books.google.com/books?id=" + r['id']
val.append(v)
return val
+60
View File
@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2021 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from scholarly import scholarly
from cps.services.Metadata import Metadata
class scholar(Metadata):
__name__ = "Google Scholar"
__id__ = "googlescholar"
def search(self, query, generic_cover=""):
val = list()
if self.active:
scholar_gen = scholarly.search_pubs(' '.join(query.split('+')))
i = 0
for publication in scholar_gen:
v = dict()
v['id'] = publication['url_scholarbib'].split(':')[1]
v['title'] = publication['bib'].get('title')
v['authors'] = publication['bib'].get('author', [])
v['description'] = publication['bib'].get('abstract', "")
v['publisher'] = publication['bib'].get('venue', "")
if publication['bib'].get('pub_year'):
v['publishedDate'] = publication['bib'].get('pub_year')+"-01-01"
else:
v['publishedDate'] = ""
v['tags'] = []
v['rating'] = 0
v['series'] = ""
v['cover'] = ""
v['url'] = publication.get('pub_url') or publication.get('eprint_url') or "",
v['source'] = {
"id": self.__id__,
"description": "Google Scholar",
"link": "https://scholar.google.com/"
}
val.append(v)
i += 1
if (i >= 10):
break
return val
+162
View File
@@ -0,0 +1,162 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 jim3ma
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
from flask import session
try:
from flask_dance.consumer.backend.sqla import SQLAlchemyBackend, first, _get_real_user
from sqlalchemy.orm.exc import NoResultFound
backend_resultcode = False # prevent storing values with this resultcode
except ImportError:
# fails on flask-dance >1.3, due to renaming
try:
from flask_dance.consumer.storage.sqla import SQLAlchemyStorage as SQLAlchemyBackend
from flask_dance.consumer.storage.sqla import first, _get_real_user
from sqlalchemy.orm.exc import NoResultFound
backend_resultcode = True # prevent storing values with this resultcode
except ImportError:
pass
class OAuthBackend(SQLAlchemyBackend):
"""
Stores and retrieves OAuth tokens using a relational database through
the `SQLAlchemy`_ ORM.
.. _SQLAlchemy: https://www.sqlalchemy.org/
"""
def __init__(self, model, session, provider_id,
user=None, user_id=None, user_required=None, anon_user=None,
cache=None):
self.provider_id = provider_id
super(OAuthBackend, self).__init__(model, session, user, user_id, user_required, anon_user, cache)
def get(self, blueprint, user=None, user_id=None):
if self.provider_id + '_oauth_token' in session and session[self.provider_id + '_oauth_token'] != '':
return session[self.provider_id + '_oauth_token']
# check cache
cache_key = self.make_cache_key(blueprint=blueprint, user=user, user_id=user_id)
token = self.cache.get(cache_key)
if token:
return token
# if not cached, make database queries
query = (
self.session.query(self.model)
.filter_by(provider=self.provider_id)
)
uid = first([user_id, self.user_id, blueprint.config.get("user_id")])
u = first(_get_real_user(ref, self.anon_user)
for ref in (user, self.user, blueprint.config.get("user")))
use_provider_user_id = False
if self.provider_id + '_oauth_user_id' in session and session[self.provider_id + '_oauth_user_id'] != '':
query = query.filter_by(provider_user_id=session[self.provider_id + '_oauth_user_id'])
use_provider_user_id = True
if self.user_required and not u and not uid and not use_provider_user_id:
# raise ValueError("Cannot get OAuth token without an associated user")
return None
# check for user ID
if hasattr(self.model, "user_id") and uid:
query = query.filter_by(user_id=uid)
# check for user (relationship property)
elif hasattr(self.model, "user") and u:
query = query.filter_by(user=u)
# if we have the property, but not value, filter by None
elif hasattr(self.model, "user_id"):
query = query.filter_by(user_id=None)
# run query
try:
token = query.one().token
except NoResultFound:
token = None
# cache the result
self.cache.set(cache_key, token)
return token
def set(self, blueprint, token, user=None, user_id=None):
uid = first([user_id, self.user_id, blueprint.config.get("user_id")])
u = first(_get_real_user(ref, self.anon_user)
for ref in (user, self.user, blueprint.config.get("user")))
if self.user_required and not u and not uid:
raise ValueError("Cannot set OAuth token without an associated user")
# if there was an existing model, delete it
existing_query = (
self.session.query(self.model)
.filter_by(provider=self.provider_id)
)
# check for user ID
has_user_id = hasattr(self.model, "user_id")
if has_user_id and uid:
existing_query = existing_query.filter_by(user_id=uid)
# check for user (relationship property)
has_user = hasattr(self.model, "user")
if has_user and u:
existing_query = existing_query.filter_by(user=u)
# queue up delete query -- won't be run until commit()
existing_query.delete()
# create a new model for this token
kwargs = {
"provider": self.provider_id,
"token": token,
}
if has_user_id and uid:
kwargs["user_id"] = uid
if has_user and u:
kwargs["user"] = u
self.session.add(self.model(**kwargs))
# commit to delete and add simultaneously
self.session.commit()
# invalidate cache
self.cache.delete(self.make_cache_key(
blueprint=blueprint, user=user, user_id=user_id
))
def delete(self, blueprint, user=None, user_id=None):
query = (
self.session.query(self.model)
.filter_by(provider=self.provider_id)
)
uid = first([user_id, self.user_id, blueprint.config.get("user_id")])
u = first(_get_real_user(ref, self.anon_user)
for ref in (user, self.user, blueprint.config.get("user")))
if self.user_required and not u and not uid:
raise ValueError("Cannot delete OAuth token without an associated user")
# check for user ID
if hasattr(self.model, "user_id") and uid:
query = query.filter_by(user_id=uid)
# check for user (relationship property)
elif hasattr(self.model, "user") and u:
query = query.filter_by(user=u)
# if we have the property, but not value, filter by None
elif hasattr(self.model, "user_id"):
query = query.filter_by(user_id=None)
# run query
query.delete()
self.session.commit()
# invalidate cache
self.cache.delete(self.make_cache_key(
blueprint=blueprint, user=user, user_id=user_id,
))
+367
View File
@@ -0,0 +1,367 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11,
# andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh,
# falgh1, grunjol, csitko, ytils, xybydy, trasba, vrabe,
# ruben-herold, marblepebble, JackED42, SiphonSquirrel,
# apetresc, nanu-c, mutschler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
import json
from functools import wraps
from flask import session, request, make_response, abort
from flask import Blueprint, flash, redirect, url_for
from flask_babel import gettext as _
from flask_dance.consumer import oauth_authorized, oauth_error
from flask_dance.contrib.github import make_github_blueprint, github
from flask_dance.contrib.google import make_google_blueprint, google
from oauthlib.oauth2 import TokenExpiredError, InvalidGrantError
from flask_login import login_user, current_user, login_required
from sqlalchemy.orm.exc import NoResultFound
from . import constants, logger, config, app, ub
try:
from .oauth import OAuthBackend, backend_resultcode
except NameError:
pass
oauth_check = {}
oauthblueprints = []
oauth = Blueprint('oauth', __name__)
log = logger.create()
def oauth_required(f):
@wraps(f)
def inner(*args, **kwargs):
if config.config_login_type == constants.LOGIN_OAUTH:
return f(*args, **kwargs)
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
data = {'status': 'error', 'message': 'Not Found'}
response = make_response(json.dumps(data, ensure_ascii=False))
response.headers["Content-Type"] = "application/json; charset=utf-8"
return response, 404
abort(404)
return inner
def register_oauth_blueprint(cid, show_name):
oauth_check[cid] = show_name
def register_user_with_oauth(user=None):
all_oauth = {}
for oauth_key in oauth_check.keys():
if str(oauth_key) + '_oauth_user_id' in session and session[str(oauth_key) + '_oauth_user_id'] != '':
all_oauth[oauth_key] = oauth_check[oauth_key]
if len(all_oauth.keys()) == 0:
return
if user is None:
flash(_(u"Register with %(provider)s", provider=", ".join(list(all_oauth.values()))), category="success")
else:
for oauth_key in all_oauth.keys():
# Find this OAuth token in the database, or create it
query = ub.session.query(ub.OAuth).filter_by(
provider=oauth_key,
provider_user_id=session[str(oauth_key) + "_oauth_user_id"],
)
try:
oauth_key = query.one()
oauth_key.user_id = user.id
except NoResultFound:
# no found, return error
return
ub.session_commit("User {} with OAuth for provider {} registered".format(user.name, oauth_key))
def logout_oauth_user():
for oauth_key in oauth_check.keys():
if str(oauth_key) + '_oauth_user_id' in session:
session.pop(str(oauth_key) + '_oauth_user_id')
def oauth_update_token(provider_id, token, provider_user_id):
session[provider_id + "_oauth_user_id"] = provider_user_id
session[provider_id + "_oauth_token"] = token
# Find this OAuth token in the database, or create it
query = ub.session.query(ub.OAuth).filter_by(
provider=provider_id,
provider_user_id=provider_user_id,
)
try:
oauth_entry = query.one()
# update token
oauth_entry.token = token
except NoResultFound:
oauth_entry = ub.OAuth(
provider=provider_id,
provider_user_id=provider_user_id,
token=token,
)
ub.session.add(oauth_entry)
ub.session_commit()
# Disable Flask-Dance's default behavior for saving the OAuth token
# Value differrs depending on flask-dance version
return backend_resultcode
def bind_oauth_or_register(provider_id, provider_user_id, redirect_url, provider_name):
query = ub.session.query(ub.OAuth).filter_by(
provider=provider_id,
provider_user_id=provider_user_id,
)
try:
oauth_entry = query.first()
# already bind with user, just login
if oauth_entry.user:
login_user(oauth_entry.user)
log.debug(u"You are now logged in as: '%s'", oauth_entry.user.name)
flash(_(u"you are now logged in as: '%(nickname)s'", nickname= oauth_entry.user.name),
category="success")
return redirect(url_for('web.index'))
else:
# bind to current user
if current_user and current_user.is_authenticated:
oauth_entry.user = current_user
try:
ub.session.add(oauth_entry)
ub.session.commit()
flash(_(u"Link to %(oauth)s Succeeded", oauth=provider_name), category="success")
log.info("Link to {} Succeeded".format(provider_name))
return redirect(url_for('web.profile'))
except Exception as ex:
log.debug_or_exception(ex)
ub.session.rollback()
else:
flash(_(u"Login failed, No User Linked With OAuth Account"), category="error")
log.info('Login failed, No User Linked With OAuth Account')
return redirect(url_for('web.login'))
# return redirect(url_for('web.login'))
# if config.config_public_reg:
# return redirect(url_for('web.register'))
# else:
# flash(_(u"Public registration is not enabled"), category="error")
# return redirect(url_for(redirect_url))
except (NoResultFound, AttributeError):
return redirect(url_for(redirect_url))
def get_oauth_status():
status = []
query = ub.session.query(ub.OAuth).filter_by(
user_id=current_user.id,
)
try:
oauths = query.all()
for oauth_entry in oauths:
status.append(int(oauth_entry.provider))
return status
except NoResultFound:
return None
def unlink_oauth(provider):
if request.host_url + 'me' != request.referrer:
pass
query = ub.session.query(ub.OAuth).filter_by(
provider=provider,
user_id=current_user.id,
)
try:
oauth_entry = query.one()
if current_user and current_user.is_authenticated:
oauth_entry.user = current_user
try:
ub.session.delete(oauth_entry)
ub.session.commit()
logout_oauth_user()
flash(_(u"Unlink to %(oauth)s Succeeded", oauth=oauth_check[provider]), category="success")
log.info("Unlink to {} Succeeded".format(oauth_check[provider]))
except Exception as ex:
log.debug_or_exception(ex)
ub.session.rollback()
flash(_(u"Unlink to %(oauth)s Failed", oauth=oauth_check[provider]), category="error")
except NoResultFound:
log.warning("oauth %s for user %d not found", provider, current_user.id)
flash(_(u"Not Linked to %(oauth)s", oauth=provider), category="error")
return redirect(url_for('web.profile'))
def generate_oauth_blueprints():
if not ub.session.query(ub.OAuthProvider).count():
for provider in ("github", "google"):
oauthProvider = ub.OAuthProvider()
oauthProvider.provider_name = provider
oauthProvider.active = False
ub.session.add(oauthProvider)
ub.session_commit("{} Blueprint Created".format(provider))
oauth_ids = ub.session.query(ub.OAuthProvider).all()
ele1 = dict(provider_name='github',
id=oauth_ids[0].id,
active=oauth_ids[0].active,
oauth_client_id=oauth_ids[0].oauth_client_id,
scope=None,
oauth_client_secret=oauth_ids[0].oauth_client_secret,
obtain_link='https://github.com/settings/developers')
ele2 = dict(provider_name='google',
id=oauth_ids[1].id,
active=oauth_ids[1].active,
scope=["https://www.googleapis.com/auth/userinfo.email"],
oauth_client_id=oauth_ids[1].oauth_client_id,
oauth_client_secret=oauth_ids[1].oauth_client_secret,
obtain_link='https://console.developers.google.com/apis/credentials')
oauthblueprints.append(ele1)
oauthblueprints.append(ele2)
for element in oauthblueprints:
if element['provider_name'] == 'github':
blueprint_func = make_github_blueprint
else:
blueprint_func = make_google_blueprint
blueprint = blueprint_func(
client_id=element['oauth_client_id'],
client_secret=element['oauth_client_secret'],
redirect_to="oauth."+element['provider_name']+"_login",
scope=element['scope']
)
element['blueprint'] = blueprint
element['blueprint'].backend = OAuthBackend(ub.OAuth, ub.session, str(element['id']),
user=current_user, user_required=True)
app.register_blueprint(blueprint, url_prefix="/login")
if element['active']:
register_oauth_blueprint(element['id'], element['provider_name'])
return oauthblueprints
if ub.oauth_support:
oauthblueprints = generate_oauth_blueprints()
@oauth_authorized.connect_via(oauthblueprints[0]['blueprint'])
def github_logged_in(blueprint, token):
if not token:
flash(_(u"Failed to log in with GitHub."), category="error")
log.error("Failed to log in with GitHub")
return False
resp = blueprint.session.get("/user")
if not resp.ok:
flash(_(u"Failed to fetch user info from GitHub."), category="error")
log.error("Failed to fetch user info from GitHub")
return False
github_info = resp.json()
github_user_id = str(github_info["id"])
return oauth_update_token(str(oauthblueprints[0]['id']), token, github_user_id)
@oauth_authorized.connect_via(oauthblueprints[1]['blueprint'])
def google_logged_in(blueprint, token):
if not token:
flash(_(u"Failed to log in with Google."), category="error")
log.error("Failed to log in with Google")
return False
resp = blueprint.session.get("/oauth2/v2/userinfo")
if not resp.ok:
flash(_(u"Failed to fetch user info from Google."), category="error")
log.error("Failed to fetch user info from Google")
return False
google_info = resp.json()
google_user_id = str(google_info["id"])
return oauth_update_token(str(oauthblueprints[1]['id']), token, google_user_id)
# notify on OAuth provider error
@oauth_error.connect_via(oauthblueprints[0]['blueprint'])
def github_error(blueprint, error, error_description=None, error_uri=None):
msg = (
u"OAuth error from {name}! "
u"error={error} description={description} uri={uri}"
).format(
name=blueprint.name,
error=error,
description=error_description,
uri=error_uri,
) # ToDo: Translate
flash(msg, category="error")
@oauth_error.connect_via(oauthblueprints[1]['blueprint'])
def google_error(blueprint, error, error_description=None, error_uri=None):
msg = (
u"OAuth error from {name}! "
u"error={error} description={description} uri={uri}"
).format(
name=blueprint.name,
error=error,
description=error_description,
uri=error_uri,
) # ToDo: Translate
flash(msg, category="error")
@oauth.route('/link/github')
@oauth_required
def github_login():
if not github.authorized:
return redirect(url_for('github.login'))
try:
account_info = github.get('/user')
if account_info.ok:
account_info_json = account_info.json()
return bind_oauth_or_register(oauthblueprints[0]['id'], account_info_json['id'], 'github.login', 'github')
flash(_(u"GitHub Oauth error, please retry later."), category="error")
log.error("GitHub Oauth error, please retry later")
except (InvalidGrantError, TokenExpiredError) as e:
flash(_(u"GitHub Oauth error: {}").format(e), category="error")
log.error(e)
return redirect(url_for('web.login'))
@oauth.route('/unlink/github', methods=["GET"])
@login_required
def github_login_unlink():
return unlink_oauth(oauthblueprints[0]['id'])
@oauth.route('/link/google')
@oauth_required
def google_login():
if not google.authorized:
return redirect(url_for("google.login"))
try:
resp = google.get("/oauth2/v2/userinfo")
if resp.ok:
account_info_json = resp.json()
return bind_oauth_or_register(oauthblueprints[1]['id'], account_info_json['id'], 'google.login', 'google')
flash(_(u"Google Oauth error, please retry later."), category="error")
log.error("Google Oauth error, please retry later")
except (InvalidGrantError, TokenExpiredError) as e:
flash(_(u"Google Oauth error: {}").format(e), category="error")
log.error(e)
return redirect(url_for('web.login'))
@oauth.route('/unlink/google', methods=["GET"])
@login_required
def google_login_unlink():
return unlink_oauth(oauthblueprints[1]['id'])
+588
View File
@@ -0,0 +1,588 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11,
# andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh,
# falgh1, grunjol, csitko, ytils, xybydy, trasba, vrabe,
# ruben-herold, marblepebble, JackED42, SiphonSquirrel,
# apetresc, nanu-c, mutschler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import datetime
from functools import wraps
from flask import Blueprint, request, render_template, Response, g, make_response, abort
from flask_login import current_user
from sqlalchemy.sql.expression import func, text, or_, and_, true
from werkzeug.security import check_password_hash
from . import constants, logger, config, db, calibre_db, ub, services, get_locale, isoLanguages
from .helper import get_download_link, get_book_cover
from .pagination import Pagination
from .web import render_read_books
from .usermanagement import load_user_from_request
from flask_babel import gettext as _
opds = Blueprint('opds', __name__)
log = logger.create()
def requires_basic_auth_if_no_ano(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if config.config_anonbrowse != 1:
if not auth or auth.type != 'basic' or not check_auth(auth.username, auth.password):
return authenticate()
return f(*args, **kwargs)
if config.config_login_type == constants.LOGIN_LDAP and services.ldap and config.config_anonbrowse != 1:
return services.ldap.basic_auth_required(f)
return decorated
class FeedObject:
def __init__(self, rating_id, rating_name):
self.rating_id = rating_id
self.rating_name = rating_name
@property
def id(self):
return self.rating_id
@property
def name(self):
return self.rating_name
@opds.route("/opds/")
@opds.route("/opds")
@requires_basic_auth_if_no_ano
def feed_index():
return render_xml_template('index.xml')
@opds.route("/opds/osd")
@requires_basic_auth_if_no_ano
def feed_osd():
return render_xml_template('osd.xml', lang='en-EN')
@opds.route("/opds/search", defaults={'query': ""})
@opds.route("/opds/search/<query>")
@requires_basic_auth_if_no_ano
def feed_cc_search(query):
return feed_search(query.strip())
@opds.route("/opds/search", methods=["GET"])
@requires_basic_auth_if_no_ano
def feed_normal_search():
return feed_search(request.args.get("query", "").strip())
@opds.route("/opds/books")
@requires_basic_auth_if_no_ano
def feed_booksindex():
shift = 0
off = int(request.args.get("offset") or 0)
entries = calibre_db.session.query(func.upper(func.substr(db.Books.sort, 1, 1)).label('id'))\
.filter(calibre_db.common_filters()).group_by(func.upper(func.substr(db.Books.sort, 1, 1))).all()
elements = []
if off == 0:
elements.append({'id': "00", 'name':_("All")})
shift = 1
for entry in entries[
off + shift - 1:
int(off + int(config.config_books_per_page) - shift)]:
elements.append({'id': entry.id, 'name': entry.id})
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(entries) + 1)
return render_xml_template('feed.xml',
letterelements=elements,
folder='opds.feed_letter_books',
pagination=pagination)
@opds.route("/opds/books/letter/<book_id>")
@requires_basic_auth_if_no_ano
def feed_letter_books(book_id):
off = request.args.get("offset") or 0
letter = true() if book_id == "00" else func.upper(db.Books.sort).startswith(book_id)
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
db.Books,
letter,
[db.Books.sort])
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/new")
@requires_basic_auth_if_no_ano
def feed_new():
off = request.args.get("offset") or 0
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
db.Books, True, [db.Books.timestamp.desc()])
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/discover")
@requires_basic_auth_if_no_ano
def feed_discover():
entries = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()).order_by(func.random())\
.limit(config.config_books_per_page)
pagination = Pagination(1, config.config_books_per_page, int(config.config_books_per_page))
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/rated")
@requires_basic_auth_if_no_ano
def feed_best_rated():
off = request.args.get("offset") or 0
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
db.Books, db.Books.ratings.any(db.Ratings.rating > 9),
[db.Books.timestamp.desc()])
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/hot")
@requires_basic_auth_if_no_ano
def feed_hot():
off = request.args.get("offset") or 0
all_books = ub.session.query(ub.Downloads, func.count(ub.Downloads.book_id)).order_by(
func.count(ub.Downloads.book_id).desc()).group_by(ub.Downloads.book_id)
hot_books = all_books.offset(off).limit(config.config_books_per_page)
entries = list()
for book in hot_books:
downloadBook = calibre_db.get_book(book.Downloads.book_id)
if downloadBook:
entries.append(
calibre_db.get_filtered_book(book.Downloads.book_id)
)
else:
ub.delete_download(book.Downloads.book_id)
numBooks = entries.__len__()
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1),
config.config_books_per_page, numBooks)
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/author")
@requires_basic_auth_if_no_ano
def feed_authorindex():
shift = 0
off = int(request.args.get("offset") or 0)
entries = calibre_db.session.query(func.upper(func.substr(db.Authors.sort, 1, 1)).label('id'))\
.join(db.books_authors_link).join(db.Books).filter(calibre_db.common_filters())\
.group_by(func.upper(func.substr(db.Authors.sort, 1, 1))).all()
elements = []
if off == 0:
elements.append({'id': "00", 'name':_("All")})
shift = 1
for entry in entries[
off + shift - 1:
int(off + int(config.config_books_per_page) - shift)]:
elements.append({'id': entry.id, 'name': entry.id})
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(entries) + 1)
return render_xml_template('feed.xml',
letterelements=elements,
folder='opds.feed_letter_author',
pagination=pagination)
@opds.route("/opds/author/letter/<book_id>")
@requires_basic_auth_if_no_ano
def feed_letter_author(book_id):
off = request.args.get("offset") or 0
letter = true() if book_id == "00" else func.upper(db.Authors.sort).startswith(book_id)
entries = calibre_db.session.query(db.Authors).join(db.books_authors_link).join(db.Books)\
.filter(calibre_db.common_filters()).filter(letter)\
.group_by(text('books_authors_link.author'))\
.order_by(db.Authors.sort)
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
entries.count())
entries = entries.limit(config.config_books_per_page).offset(off).all()
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_author', pagination=pagination)
@opds.route("/opds/author/<int:book_id>")
@requires_basic_auth_if_no_ano
def feed_author(book_id):
off = request.args.get("offset") or 0
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
db.Books,
db.Books.authors.any(db.Authors.id == book_id),
[db.Books.timestamp.desc()])
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/publisher")
@requires_basic_auth_if_no_ano
def feed_publisherindex():
off = request.args.get("offset") or 0
entries = calibre_db.session.query(db.Publishers)\
.join(db.books_publishers_link)\
.join(db.Books).filter(calibre_db.common_filters())\
.group_by(text('books_publishers_link.publisher'))\
.order_by(db.Publishers.sort)\
.limit(config.config_books_per_page).offset(off)
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(calibre_db.session.query(db.Publishers).all()))
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_publisher', pagination=pagination)
@opds.route("/opds/publisher/<int:book_id>")
@requires_basic_auth_if_no_ano
def feed_publisher(book_id):
off = request.args.get("offset") or 0
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
db.Books,
db.Books.publishers.any(db.Publishers.id == book_id),
[db.Books.timestamp.desc()])
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/category")
@requires_basic_auth_if_no_ano
def feed_categoryindex():
shift = 0
off = int(request.args.get("offset") or 0)
entries = calibre_db.session.query(func.upper(func.substr(db.Tags.name, 1, 1)).label('id'))\
.join(db.books_tags_link).join(db.Books).filter(calibre_db.common_filters())\
.group_by(func.upper(func.substr(db.Tags.name, 1, 1))).all()
elements = []
if off == 0:
elements.append({'id': "00", 'name':_("All")})
shift = 1
for entry in entries[
off + shift - 1:
int(off + int(config.config_books_per_page) - shift)]:
elements.append({'id': entry.id, 'name': entry.id})
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(entries) + 1)
return render_xml_template('feed.xml',
letterelements=elements,
folder='opds.feed_letter_category',
pagination=pagination)
@opds.route("/opds/category/letter/<book_id>")
@requires_basic_auth_if_no_ano
def feed_letter_category(book_id):
off = request.args.get("offset") or 0
letter = true() if book_id == "00" else func.upper(db.Tags.name).startswith(book_id)
entries = calibre_db.session.query(db.Tags)\
.join(db.books_tags_link)\
.join(db.Books)\
.filter(calibre_db.common_filters()).filter(letter)\
.group_by(text('books_tags_link.tag'))\
.order_by(db.Tags.name)
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
entries.count())
entries = entries.offset(off).limit(config.config_books_per_page).all()
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_category', pagination=pagination)
@opds.route("/opds/category/<int:book_id>")
@requires_basic_auth_if_no_ano
def feed_category(book_id):
off = request.args.get("offset") or 0
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
db.Books,
db.Books.tags.any(db.Tags.id == book_id),
[db.Books.timestamp.desc()])
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/series")
@requires_basic_auth_if_no_ano
def feed_seriesindex():
shift = 0
off = int(request.args.get("offset") or 0)
entries = calibre_db.session.query(func.upper(func.substr(db.Series.sort, 1, 1)).label('id'))\
.join(db.books_series_link).join(db.Books).filter(calibre_db.common_filters())\
.group_by(func.upper(func.substr(db.Series.sort, 1, 1))).all()
elements = []
if off == 0:
elements.append({'id': "00", 'name':_("All")})
shift = 1
for entry in entries[
off + shift - 1:
int(off + int(config.config_books_per_page) - shift)]:
elements.append({'id': entry.id, 'name': entry.id})
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(entries) + 1)
return render_xml_template('feed.xml',
letterelements=elements,
folder='opds.feed_letter_series',
pagination=pagination)
@opds.route("/opds/series/letter/<book_id>")
@requires_basic_auth_if_no_ano
def feed_letter_series(book_id):
off = request.args.get("offset") or 0
letter = true() if book_id == "00" else func.upper(db.Series.sort).startswith(book_id)
entries = calibre_db.session.query(db.Series)\
.join(db.books_series_link)\
.join(db.Books)\
.filter(calibre_db.common_filters()).filter(letter)\
.group_by(text('books_series_link.series'))\
.order_by(db.Series.sort)
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
entries.count())
entries = entries.offset(off).limit(config.config_books_per_page).all()
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_series', pagination=pagination)
@opds.route("/opds/series/<int:book_id>")
@requires_basic_auth_if_no_ano
def feed_series(book_id):
off = request.args.get("offset") or 0
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
db.Books,
db.Books.series.any(db.Series.id == book_id),
[db.Books.series_index])
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/ratings")
@requires_basic_auth_if_no_ano
def feed_ratingindex():
off = request.args.get("offset") or 0
entries = calibre_db.session.query(db.Ratings, func.count('books_ratings_link.book').label('count'),
(db.Ratings.rating / 2).label('name')) \
.join(db.books_ratings_link)\
.join(db.Books)\
.filter(calibre_db.common_filters()) \
.group_by(text('books_ratings_link.rating'))\
.order_by(db.Ratings.rating).all()
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(entries))
element = list()
for entry in entries:
element.append(FeedObject(entry[0].id, _("{} Stars").format(entry.name)))
return render_xml_template('feed.xml', listelements=element, folder='opds.feed_ratings', pagination=pagination)
@opds.route("/opds/ratings/<book_id>")
@requires_basic_auth_if_no_ano
def feed_ratings(book_id):
off = request.args.get("offset") or 0
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
db.Books,
db.Books.ratings.any(db.Ratings.id == book_id),
[db.Books.timestamp.desc()])
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/formats")
@requires_basic_auth_if_no_ano
def feed_formatindex():
off = request.args.get("offset") or 0
entries = calibre_db.session.query(db.Data).join(db.Books)\
.filter(calibre_db.common_filters()) \
.group_by(db.Data.format)\
.order_by(db.Data.format).all()
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(entries))
element = list()
for entry in entries:
element.append(FeedObject(entry.format, entry.format))
return render_xml_template('feed.xml', listelements=element, folder='opds.feed_format', pagination=pagination)
@opds.route("/opds/formats/<book_id>")
@requires_basic_auth_if_no_ano
def feed_format(book_id):
off = request.args.get("offset") or 0
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
db.Books,
db.Books.data.any(db.Data.format == book_id.upper()),
[db.Books.timestamp.desc()])
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/language")
@opds.route("/opds/language/")
@requires_basic_auth_if_no_ano
def feed_languagesindex():
off = request.args.get("offset") or 0
if current_user.filter_language() == u"all":
languages = calibre_db.speaking_language()
else:
#try:
# cur_l = LC.parse(current_user.filter_language())
#except UnknownLocaleError:
# cur_l = None
languages = calibre_db.session.query(db.Languages).filter(
db.Languages.lang_code == current_user.filter_language()).all()
languages[0].name = isoLanguages.get_language_name(get_locale(), languages[0].lang_code)
#if cur_l:
# languages[0].name = cur_l.get_language_name(get_locale())
#else:
# languages[0].name = _(isoLanguages.get(part3=languages[0].lang_code).name)
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(languages))
return render_xml_template('feed.xml', listelements=languages, folder='opds.feed_languages', pagination=pagination)
@opds.route("/opds/language/<int:book_id>")
@requires_basic_auth_if_no_ano
def feed_languages(book_id):
off = request.args.get("offset") or 0
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
db.Books,
db.Books.languages.any(db.Languages.id == book_id),
[db.Books.timestamp.desc()])
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@opds.route("/opds/shelfindex")
@requires_basic_auth_if_no_ano
def feed_shelfindex():
off = request.args.get("offset") or 0
shelf = g.shelves_access
number = len(shelf)
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
number)
return render_xml_template('feed.xml', listelements=shelf, folder='opds.feed_shelf', pagination=pagination)
@opds.route("/opds/shelf/<int:book_id>")
@requires_basic_auth_if_no_ano
def feed_shelf(book_id):
off = request.args.get("offset") or 0
if current_user.is_anonymous:
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.is_public == 1,
ub.Shelf.id == book_id).first()
else:
shelf = ub.session.query(ub.Shelf).filter(or_(and_(ub.Shelf.user_id == int(current_user.id),
ub.Shelf.id == book_id),
and_(ub.Shelf.is_public == 1,
ub.Shelf.id == book_id))).first()
result = list()
# user is allowed to access shelf
if shelf:
books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == book_id).order_by(
ub.BookShelf.order.asc()).all()
for book in books_in_shelf:
cur_book = calibre_db.get_book(book.book_id)
result.append(cur_book)
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(result))
return render_xml_template('feed.xml', entries=result, pagination=pagination)
@opds.route("/opds/download/<book_id>/<book_format>/")
@requires_basic_auth_if_no_ano
def opds_download_link(book_id, book_format):
# I gave up with this: With enabled ldap login, the user doesn't get logged in, therefore it's always guest
# workaround, loading the user from the request and checking it's download rights here
# in case of anonymous browsing user is None
user = load_user_from_request(request) or current_user
if not user.role_download():
return abort(403)
if "Kobo" in request.headers.get('User-Agent'):
client = "kobo"
else:
client = ""
return get_download_link(book_id, book_format.lower(), client)
@opds.route("/ajax/book/<string:uuid>/<library>")
@opds.route("/ajax/book/<string:uuid>", defaults={'library': ""})
@requires_basic_auth_if_no_ano
def get_metadata_calibre_companion(uuid, library):
entry = calibre_db.session.query(db.Books).filter(db.Books.uuid.like("%" + uuid + "%")).first()
if entry is not None:
js = render_template('json.txt', entry=entry)
response = make_response(js)
response.headers["Content-Type"] = "application/json; charset=utf-8"
return response
else:
return ""
def feed_search(term):
if term:
entries, __, ___ = calibre_db.get_search_results(term)
entriescount = len(entries) if len(entries) > 0 else 1
pagination = Pagination(1, entriescount, entriescount)
return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination)
else:
return render_xml_template('feed.xml', searchterm="")
def check_auth(username, password):
try:
username = username.encode('windows-1252')
except UnicodeEncodeError:
username = username.encode('utf-8')
user = ub.session.query(ub.User).filter(func.lower(ub.User.name) ==
username.decode('utf-8').lower()).first()
if bool(user and check_password_hash(str(user.password), password)):
return True
else:
ip_Address = request.headers.get('X-Forwarded-For', request.remote_addr)
log.warning('OPDS Login failed for user "%s" IP-address: %s', username.decode('utf-8'), ip_Address)
return False
def authenticate():
return Response(
'Could not verify your access level for that URL.\n'
'You have to login with proper credentials', 401,
{'WWW-Authenticate': 'Basic realm="Login Required"'})
def render_xml_template(*args, **kwargs):
# ToDo: return time in current timezone similar to %z
currtime = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S+00:00")
xml = render_template(current_time=currtime, instance=config.config_calibre_web_title, *args, **kwargs)
response = make_response(xml)
response.headers["Content-Type"] = "application/atom+xml; charset=utf-8"
return response
@opds.route("/opds/thumb_240_240/<book_id>")
@opds.route("/opds/cover_240_240/<book_id>")
@opds.route("/opds/cover_90_90/<book_id>")
@opds.route("/opds/cover/<book_id>")
@requires_basic_auth_if_no_ano
def feed_get_cover(book_id):
return get_book_cover(book_id)
@opds.route("/opds/readbooks")
@requires_basic_auth_if_no_ano
def feed_read_books():
off = request.args.get("offset") or 0
result, pagination = render_read_books(int(off) / (int(config.config_books_per_page)) + 1, True, True)
return render_xml_template('feed.xml', entries=result, pagination=pagination)
@opds.route("/opds/unreadbooks")
@requires_basic_auth_if_no_ano
def feed_unread_books():
off = request.args.get("offset") or 0
result, pagination = render_read_books(int(off) / (int(config.config_books_per_page)) + 1, False, True)
return render_xml_template('feed.xml', entries=result, pagination=pagination)
+75
View File
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11,
# andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh,
# falgh1, grunjol, csitko, ytils, xybydy, trasba, vrabe,
# ruben-herold, marblepebble, JackED42, SiphonSquirrel,
# apetresc, nanu-c, mutschler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from math import ceil
# simple pagination for the feed
class Pagination(object):
def __init__(self, page, per_page, total_count):
self.page = int(page)
self.per_page = int(per_page)
self.total_count = int(total_count)
@property
def next_offset(self):
return int(self.page * self.per_page)
@property
def previous_offset(self):
return int((self.page - 2) * self.per_page)
@property
def last_offset(self):
last = int(self.total_count) - int(self.per_page)
if last < 0:
last = 0
return int(last)
@property
def pages(self):
return int(ceil(self.total_count / float(self.per_page)))
@property
def has_prev(self):
return self.page > 1
@property
def has_next(self):
return self.page < self.pages
# right_edge: last right_edges count of all pages are shown as number, means, if 10 pages are paginated -> 9,10 shwn
# left_edge: first left_edges count of all pages are shown as number -> 1,2 shwn
# left_current: left_current count below current page are shown as number, means if current page 5 -> 3,4 shwn
# left_current: right_current count above current page are shown as number, means if current page 5 -> 6,7 shwn
def iter_pages(self, left_edge=2, left_current=2,
right_current=4, right_edge=2):
last = 0
left_current = self.page - left_current - 1
right_current = self.page + right_current + 1
right_edge = self.pages - right_edge
for num in range(1, (self.pages + 1)):
if num <= left_edge or (left_current < num < right_current) or num > right_edge:
if last + 1 != num:
yield None
yield num
last = num
+3 -5
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Flask License
@@ -28,10 +27,9 @@
# http://flask.pocoo.org/snippets/62/
try:
from urllib.parse import urlparse, urljoin
except ImportError:
from urlparse import urlparse, urljoin
from urllib.parse import urlparse, urljoin
from flask import request, url_for, redirect
+138
View File
@@ -0,0 +1,138 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11,
# andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh,
# falgh1, grunjol, csitko, ytils, xybydy, trasba, vrabe,
# ruben-herold, marblepebble, JackED42, SiphonSquirrel,
# apetresc, nanu-c, mutschler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
from datetime import datetime
from flask import Blueprint, request, make_response, abort, url_for, flash, redirect
from flask_login import login_required, current_user, login_user
from flask_babel import gettext as _
from sqlalchemy.sql.expression import true
from . import config, logger, ub
from .render_template import render_title_template
try:
from functools import wraps
except ImportError:
pass # We're not using Python 3
remotelogin = Blueprint('remotelogin', __name__)
log = logger.create()
def remote_login_required(f):
@wraps(f)
def inner(*args, **kwargs):
if config.config_remote_login:
return f(*args, **kwargs)
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
data = {'status': 'error', 'message': 'Forbidden'}
response = make_response(json.dumps(data, ensure_ascii=False))
response.headers["Content-Type"] = "application/json; charset=utf-8"
return response, 403
abort(403)
return inner
@remotelogin.route('/remote/login')
@remote_login_required
def remote_login():
auth_token = ub.RemoteAuthToken()
ub.session.add(auth_token)
ub.session_commit()
verify_url = url_for('remotelogin.verify_token', token=auth_token.auth_token, _external=true)
log.debug(u"Remot Login request with token: %s", auth_token.auth_token)
return render_title_template('remote_login.html', title=_(u"Login"), token=auth_token.auth_token,
verify_url=verify_url, page="remotelogin")
@remotelogin.route('/verify/<token>')
@remote_login_required
@login_required
def verify_token(token):
auth_token = ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.auth_token == token).first()
# Token not found
if auth_token is None:
flash(_(u"Token not found"), category="error")
log.error(u"Remote Login token not found")
return redirect(url_for('web.index'))
# Token expired
elif datetime.now() > auth_token.expiration:
ub.session.delete(auth_token)
ub.session_commit()
flash(_(u"Token has expired"), category="error")
log.error(u"Remote Login token expired")
return redirect(url_for('web.index'))
# Update token with user information
auth_token.user_id = current_user.id
auth_token.verified = True
ub.session_commit()
flash(_(u"Success! Please return to your device"), category="success")
log.debug(u"Remote Login token for userid %s verified", auth_token.user_id)
return redirect(url_for('web.index'))
@remotelogin.route('/ajax/verify_token', methods=['POST'])
@remote_login_required
def token_verified():
token = request.form['token']
auth_token = ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.auth_token == token).first()
data = {}
# Token not found
if auth_token is None:
data['status'] = 'error'
data['message'] = _(u"Token not found")
# Token expired
elif datetime.now() > auth_token.expiration:
ub.session.delete(auth_token)
ub.session_commit()
data['status'] = 'error'
data['message'] = _(u"Token has expired")
elif not auth_token.verified:
data['status'] = 'not_verified'
else:
user = ub.session.query(ub.User).filter(ub.User.id == auth_token.user_id).first()
login_user(user)
ub.session.delete(auth_token)
ub.session_commit("User {} logged in via remotelogin, token deleted".format(user.name))
data['status'] = 'success'
log.debug(u"Remote Login for userid %s succeded", user.id)
flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.name), category="success")
response = make_response(json.dumps(data, ensure_ascii=False))
response.headers["Content-Type"] = "application/json; charset=utf-8"
return response
+122
View File
@@ -0,0 +1,122 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2020 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from flask import render_template
from flask_babel import gettext as _
from flask import g
from werkzeug.local import LocalProxy
from flask_login import current_user
from . import config, constants, ub, logger, db, calibre_db
from .ub import User
log = logger.create()
def get_sidebar_config(kwargs=None):
kwargs = kwargs or []
if 'content' in kwargs:
content = kwargs['content']
content = isinstance(content, (User, LocalProxy)) and not content.role_anonymous()
else:
content = 'conf' in kwargs
sidebar = list()
sidebar.append({"glyph": "glyphicon-book", "text": _('Books'), "link": 'web.index', "id": "new",
"visibility": constants.SIDEBAR_RECENT, 'public': True, "page": "root",
"show_text": _('Show recent books'), "config_show":False})
sidebar.append({"glyph": "glyphicon-fire", "text": _('Hot Books'), "link": 'web.books_list', "id": "hot",
"visibility": constants.SIDEBAR_HOT, 'public': True, "page": "hot",
"show_text": _('Show Hot Books'), "config_show": True})
if current_user.role_admin():
sidebar.append({"glyph": "glyphicon-download", "text": _('Downloaded Books'), "link": 'web.download_list',
"id": "download", "visibility": constants.SIDEBAR_DOWNLOAD, 'public': (not g.user.is_anonymous),
"page": "download", "show_text": _('Show Downloaded Books'),
"config_show": content})
else:
sidebar.append({"glyph": "glyphicon-download", "text": _('Downloaded Books'), "link": 'web.books_list',
"id": "download", "visibility": constants.SIDEBAR_DOWNLOAD, 'public': (not g.user.is_anonymous),
"page": "download", "show_text": _('Show Downloaded Books'),
"config_show": content})
sidebar.append(
{"glyph": "glyphicon-star", "text": _('Top Rated Books'), "link": 'web.books_list', "id": "rated",
"visibility": constants.SIDEBAR_BEST_RATED, 'public': True, "page": "rated",
"show_text": _('Show Top Rated Books'), "config_show": True})
sidebar.append({"glyph": "glyphicon-eye-open", "text": _('Read Books'), "link": 'web.books_list', "id": "read",
"visibility": constants.SIDEBAR_READ_AND_UNREAD, 'public': (not g.user.is_anonymous),
"page": "read", "show_text": _('Show read and unread'), "config_show": content})
sidebar.append(
{"glyph": "glyphicon-eye-close", "text": _('Unread Books'), "link": 'web.books_list', "id": "unread",
"visibility": constants.SIDEBAR_READ_AND_UNREAD, 'public': (not g.user.is_anonymous), "page": "unread",
"show_text": _('Show unread'), "config_show": False})
sidebar.append({"glyph": "glyphicon-random", "text": _('Discover'), "link": 'web.books_list', "id": "rand",
"visibility": constants.SIDEBAR_RANDOM, 'public': True, "page": "discover",
"show_text": _('Show Random Books'), "config_show": True})
sidebar.append({"glyph": "glyphicon-inbox", "text": _('Categories'), "link": 'web.category_list', "id": "cat",
"visibility": constants.SIDEBAR_CATEGORY, 'public': True, "page": "category",
"show_text": _('Show category selection'), "config_show": True})
sidebar.append({"glyph": "glyphicon-bookmark", "text": _('Series'), "link": 'web.series_list', "id": "serie",
"visibility": constants.SIDEBAR_SERIES, 'public': True, "page": "series",
"show_text": _('Show series selection'), "config_show": True})
sidebar.append({"glyph": "glyphicon-user", "text": _('Authors'), "link": 'web.author_list', "id": "author",
"visibility": constants.SIDEBAR_AUTHOR, 'public': True, "page": "author",
"show_text": _('Show author selection'), "config_show": True})
sidebar.append(
{"glyph": "glyphicon-text-size", "text": _('Publishers'), "link": 'web.publisher_list', "id": "publisher",
"visibility": constants.SIDEBAR_PUBLISHER, 'public': True, "page": "publisher",
"show_text": _('Show publisher selection'), "config_show":True})
sidebar.append({"glyph": "glyphicon-flag", "text": _('Languages'), "link": 'web.language_overview', "id": "lang",
"visibility": constants.SIDEBAR_LANGUAGE, 'public': (g.user.filter_language() == 'all'),
"page": "language",
"show_text": _('Show language selection'), "config_show": True})
sidebar.append({"glyph": "glyphicon-star-empty", "text": _('Ratings'), "link": 'web.ratings_list', "id": "rate",
"visibility": constants.SIDEBAR_RATING, 'public': True,
"page": "rating", "show_text": _('Show ratings selection'), "config_show": True})
sidebar.append({"glyph": "glyphicon-file", "text": _('File formats'), "link": 'web.formats_list', "id": "format",
"visibility": constants.SIDEBAR_FORMAT, 'public': True,
"page": "format", "show_text": _('Show file formats selection'), "config_show": True})
sidebar.append(
{"glyph": "glyphicon-trash", "text": _('Archived Books'), "link": 'web.books_list', "id": "archived",
"visibility": constants.SIDEBAR_ARCHIVED, 'public': (not g.user.is_anonymous), "page": "archived",
"show_text": _('Show archived books'), "config_show": content})
sidebar.append(
{"glyph": "glyphicon-th-list", "text": _('Books List'), "link": 'web.books_table', "id": "list",
"visibility": constants.SIDEBAR_LIST, 'public': (not g.user.is_anonymous), "page": "list",
"show_text": _('Show Books List'), "config_show": content})
return sidebar
def get_readbooks_ids():
if not config.config_read_column:
readBooks = ub.session.query(ub.ReadBook).filter(ub.ReadBook.user_id == int(current_user.id))\
.filter(ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED).all()
return frozenset([x.book_id for x in readBooks])
else:
try:
readBooks = calibre_db.session.query(db.cc_classes[config.config_read_column])\
.filter(db.cc_classes[config.config_read_column].value == True).all()
return frozenset([x.book for x in readBooks])
except (KeyError, AttributeError):
log.error("Custom Column No.%d is not existing in calibre database", config.config_read_column)
return []
# Returns the template for rendering and includes the instance name
def render_title_template(*args, **kwargs):
sidebar = get_sidebar_config(kwargs)
return render_template(instance=config.config_calibre_web_title, sidebar=sidebar,
accept=constants.EXTENSIONS_UPLOAD, read_book_ids=get_readbooks_ids(),
*args, **kwargs)
+9 -1
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Flask License
@@ -37,6 +36,7 @@
#
# Inspired by http://flask.pocoo.org/snippets/35/
class ReverseProxied(object):
"""Wrap the application in this middleware and configure the
front-end server to add these headers, to let you quietly bind
@@ -57,10 +57,13 @@ class ReverseProxied(object):
def __init__(self, application):
self.app = application
self.proxied = False
def __call__(self, environ, start_response):
self.proxied = False
script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
if script_name:
self.proxied = True
environ['SCRIPT_NAME'] = script_name
path_info = environ.get('PATH_INFO', '')
if path_info and path_info.startswith(script_name):
@@ -72,4 +75,9 @@ class ReverseProxied(object):
servr = environ.get('HTTP_X_FORWARDED_HOST', '')
if servr:
environ['HTTP_HOST'] = servr
self.proxied = True
return self.app(environ, start_response)
@property
def is_proxied(self):
return self.proxied
+117
View File
@@ -0,0 +1,117 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2021 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import json
import importlib
import sys
import inspect
import datetime
import concurrent.futures
from flask import Blueprint, request, Response, url_for
from flask_login import current_user
from flask_login import login_required
from sqlalchemy.orm.attributes import flag_modified
from sqlalchemy.exc import OperationalError, InvalidRequestError
from . import constants, logger, ub
from cps.services.Metadata import Metadata
meta = Blueprint('metadata', __name__)
log = logger.create()
new_list = list()
meta_dir = os.path.join(constants.BASE_DIR, "cps", "metadata_provider")
modules = os.listdir(os.path.join(constants.BASE_DIR, "cps", "metadata_provider"))
for f in modules:
if os.path.isfile(os.path.join(meta_dir, f)) and not f.endswith('__init__.py'):
a = os.path.basename(f)[:-3]
try:
importlib.import_module("cps.metadata_provider." + a)
new_list.append(a)
except ImportError:
log.error("Import error for metadata source: {}".format(a))
pass
def list_classes(provider_list):
classes = list()
for element in provider_list:
for name, obj in inspect.getmembers(sys.modules["cps.metadata_provider." + element]):
if inspect.isclass(obj) and name != "Metadata" and issubclass(obj, Metadata):
classes.append(obj())
return classes
cl = list_classes(new_list)
@meta.route("/metadata/provider")
@login_required
def metadata_provider():
active = current_user.view_settings.get('metadata', {})
provider = list()
for c in cl:
ac = active.get(c.__id__, True)
provider.append({"name": c.__name__, "active": ac, "initial": ac, "id": c.__id__})
return Response(json.dumps(provider), mimetype='application/json')
@meta.route("/metadata/provider", methods=['POST'])
@meta.route("/metadata/provider/<prov_name>", methods=['POST'])
@login_required
def metadata_change_active_provider(prov_name):
new_state = request.get_json()
active = current_user.view_settings.get('metadata', {})
active[new_state['id']] = new_state['value']
current_user.view_settings['metadata'] = active
try:
try:
flag_modified(current_user, "view_settings")
except AttributeError:
pass
ub.session.commit()
except (InvalidRequestError, OperationalError):
log.error("Invalid request received: {}".format(request))
return "Invalid request", 400
if "initial" in new_state and prov_name:
for c in cl:
if c.__id__ == prov_name:
data = c.search(new_state.get('query', ""))
break
return Response(json.dumps(data), mimetype='application/json')
return ""
@meta.route("/metadata/search", methods=['POST'])
@login_required
def metadata_search():
query = request.form.to_dict().get('query')
data = list()
active = current_user.view_settings.get('metadata', {})
if query:
generic_cover = ""
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
meta = {executor.submit(c.search, query, generic_cover): c for c in cl if active.get(c.__id__, True)}
for future in concurrent.futures.as_completed(meta):
data.extend(future.result())
return Response(json.dumps(data), mimetype='application/json')
+235 -122
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
@@ -17,149 +16,263 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from socket import error as SocketError
import sys
import os
import errno
import signal
import web
import socket
import subprocess # nosec
try:
from gevent.pywsgi import WSGIServer
from gevent.pool import Pool
from gevent import __version__ as geventVersion
gevent_present = True
from gevent import __version__ as _version
from greenlet import GreenletExit
import ssl
VERSION = 'Gevent ' + _version
_GEVENT = True
except ImportError:
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado import version as tornadoVersion
gevent_present = False
from tornado import version as _version
VERSION = 'Tornado ' + _version
_GEVENT = False
from . import logger
log = logger.create()
class server:
wsgiserver = None
restart= False
def _readable_listen_address(address, port):
if ':' in address:
address = "[" + address + "]"
return '%s:%s' % (address, port)
class WebServer(object):
def __init__(self):
signal.signal(signal.SIGINT, self.killServer)
signal.signal(signal.SIGTERM, self.killServer)
signal.signal(signal.SIGINT, self._killServer)
signal.signal(signal.SIGTERM, self._killServer)
self.wsgiserver = None
self.access_logger = None
self.restart = False
self.app = None
self.listen_address = None
self.listen_port = None
self.unix_socket_file = None
self.ssl_args = None
def init_app(self, application, config):
self.app = application
self.listen_address = config.get_config_ipaddress()
self.listen_port = config.config_port
if config.config_access_log:
log_name = "gevent.access" if _GEVENT else "tornado.access"
formatter = logger.ACCESS_FORMATTER_GEVENT if _GEVENT else logger.ACCESS_FORMATTER_TORNADO
self.access_logger, logfile = logger.create_access_log(config.config_access_logfile, log_name, formatter)
if logfile != config.config_access_logfile:
log.warning("Accesslog path %s not valid, falling back to default", config.config_access_logfile)
config.config_access_logfile = logfile
config.save()
else:
if not _GEVENT:
logger.get('tornado.access').disabled = True
certfile_path = config.get_config_certfile()
keyfile_path = config.get_config_keyfile()
if certfile_path and keyfile_path:
if os.path.isfile(certfile_path) and os.path.isfile(keyfile_path):
self.ssl_args = dict(certfile=certfile_path, keyfile=keyfile_path)
else:
log.warning('The specified paths for the ssl certificate file and/or key file seem to be broken. '
'Ignoring ssl.')
log.warning('Cert path: %s', certfile_path)
log.warning('Key path: %s', keyfile_path)
def _make_gevent_unix_socket(self, socket_file):
# the socket file must not exist prior to bind()
if os.path.exists(socket_file):
# avoid nuking regular files and symbolic links (could be a mistype or security issue)
if os.path.isfile(socket_file) or os.path.islink(socket_file):
raise OSError(errno.EEXIST, os.strerror(errno.EEXIST), socket_file)
os.remove(socket_file)
unix_sock = WSGIServer.get_listener(socket_file, family=socket.AF_UNIX)
self.unix_socket_file = socket_file
# ensure current user and group have r/w permissions, no permissions for other users
# this way the socket can be shared in a semi-secure manner
# between the user running calibre-web and the user running the fronting webserver
os.chmod(socket_file, 0o660)
return unix_sock
def _make_gevent_socket(self):
if os.name != 'nt':
unix_socket_file = os.environ.get("CALIBRE_UNIX_SOCKET")
if unix_socket_file:
return self._make_gevent_unix_socket(unix_socket_file), "unix:" + unix_socket_file
if self.listen_address:
return (self.listen_address, self.listen_port), None
if os.name == 'nt':
self.listen_address = '0.0.0.0'
return (self.listen_address, self.listen_port), None
def start_gevent(self):
try:
ssl_args = dict()
certfile_path = web.ub.config.get_config_certfile()
keyfile_path = web.ub.config.get_config_keyfile()
if certfile_path and keyfile_path:
if os.path.isfile(certfile_path) and os.path.isfile(keyfile_path):
ssl_args = {"certfile": certfile_path,
"keyfile": keyfile_path}
else:
web.app.logger.info('The specified paths for the ssl certificate file and/or key file seem to be broken. Ignoring ssl. Cert path: %s | Key path: %s' % (certfile_path, keyfile_path))
if os.name == 'nt':
self.wsgiserver= WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
else:
self.wsgiserver = WSGIServer(('', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
web.py3_gevent_link = self.wsgiserver
self.wsgiserver.serve_forever()
address = ('::', self.listen_port)
sock = WSGIServer.get_listener(address, family=socket.AF_INET6)
except socket.error as ex:
log.error('%s', ex)
log.warning('Unable to listen on "", trying on IPv4 only...')
address = ('', self.listen_port)
sock = WSGIServer.get_listener(address, family=socket.AF_INET)
except SocketError:
try:
web.app.logger.info('Unable to listen on \'\', trying on IPv4 only...')
self.wsgiserver = WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
web.py3_gevent_link = self.wsgiserver
self.wsgiserver.serve_forever()
except (OSError, SocketError) as e:
web.app.logger.info("Error starting server: %s" % e.strerror)
print("Error starting server: %s" % e.strerror)
web.helper.global_WorkerThread.stop()
sys.exit(1)
except Exception:
web.app.logger.info("Unknown error while starting gevent")
def startServer(self):
if gevent_present:
web.app.logger.info('Starting Gevent server')
# leave subprocess out to allow forking for fetchers and processors
self.start_gevent()
else:
try:
ssl = None
web.app.logger.info('Starting Tornado server')
certfile_path = web.ub.config.get_config_certfile()
keyfile_path = web.ub.config.get_config_keyfile()
if certfile_path and keyfile_path:
if os.path.isfile(certfile_path) and os.path.isfile(keyfile_path):
ssl = {"certfile": certfile_path,
"keyfile": keyfile_path}
else:
web.app.logger.info('The specified paths for the ssl certificate file and/or key file seem to be broken. Ignoring ssl. Cert path: %s | Key path: %s' % (certfile_path, keyfile_path))
# Max Buffersize set to 200MB
http_server = HTTPServer(WSGIContainer(web.app),
max_buffer_size = 209700000,
ssl_options=ssl)
http_server.listen(web.ub.config.config_port)
self.wsgiserver=IOLoop.instance()
web.py3_gevent_link = self.wsgiserver
self.wsgiserver.start()
# wait for stop signal
self.wsgiserver.close(True)
except SocketError as e:
web.app.logger.info("Error starting server: %s" % e.strerror)
print("Error starting server: %s" % e.strerror)
web.helper.global_WorkerThread.stop()
sys.exit(1)
# ToDo: Somehow caused by circular import under python3 refactor
if sys.version_info > (3, 0):
self.restart = web.py3_restart_Typ
if self.restart == True:
web.app.logger.info("Performing restart of Calibre-Web")
web.helper.global_WorkerThread.stop()
if os.name == 'nt':
arguments = ["\"" + sys.executable + "\""]
for e in sys.argv:
arguments.append("\"" + e + "\"")
os.execv(sys.executable, arguments)
else:
os.execl(sys.executable, sys.executable, *sys.argv)
else:
web.app.logger.info("Performing shutdown of Calibre-Web")
web.helper.global_WorkerThread.stop()
sys.exit(0)
def setRestartTyp(self,starttyp):
self.restart = starttyp
# ToDo: Somehow caused by circular import under python3 refactor
web.py3_restart_Typ = starttyp
def killServer(self, signum, frame):
self.stopServer()
def stopServer(self):
# ToDo: Somehow caused by circular import under python3 refactor
if sys.version_info > (3, 0):
if not self.wsgiserver:
# if gevent_present:
self.wsgiserver = web.py3_gevent_link
#else:
# self.wsgiserver = IOLoop.instance()
if self.wsgiserver:
if gevent_present:
self.wsgiserver.close()
else:
self.wsgiserver.add_callback(self.wsgiserver.stop)
return sock, _readable_listen_address(*address)
@staticmethod
def getNameVersion():
if gevent_present:
return {'Gevent':'v'+geventVersion}
def _get_args_for_reloading():
"""Determine how the script was executed, and return the args needed
to execute it again in a new process.
Code from https://github.com/pyload/pyload. Author GammaC0de, voulter
"""
rv = [sys.executable]
py_script = sys.argv[0]
args = sys.argv[1:]
# Need to look at main module to determine how it was executed.
__main__ = sys.modules["__main__"]
# The value of __package__ indicates how Python was called. It may
# not exist if a setuptools script is installed as an egg. It may be
# set incorrectly for entry points created with pip on Windows.
if getattr(__main__, "__package__", None) is None or (
os.name == "nt"
and __main__.__package__ == ""
and not os.path.exists(py_script)
and os.path.exists("{}.exe".format(py_script))
):
# Executed a file, like "python app.py".
py_script = os.path.abspath(py_script)
if os.name == "nt":
# Windows entry points have ".exe" extension and should be
# called directly.
if not os.path.exists(py_script) and os.path.exists("{}.exe".format(py_script)):
py_script += ".exe"
if (
os.path.splitext(sys.executable)[1] == ".exe"
and os.path.splitext(py_script)[1] == ".exe"
):
rv.pop(0)
rv.append(py_script)
else:
return {'Tornado':'v'+tornadoVersion}
# Executed a module, like "python -m module".
if sys.argv[0] == "-m":
args = sys.argv
else:
if os.path.isfile(py_script):
# Rewritten by Python from "-m script" to "/path/to/script.py".
py_module = __main__.__package__
name = os.path.splitext(os.path.basename(py_script))[0]
if name != "__main__":
py_module += ".{}".format(name)
else:
# Incorrectly rewritten by pydevd debugger from "-m script" to "script".
py_module = py_script
# Start Instance of Server
Server=server()
rv.extend(("-m", py_module.lstrip(".")))
rv.extend(args)
return rv
def _start_gevent(self):
ssl_args = self.ssl_args or {}
try:
sock, output = self._make_gevent_socket()
if output is None:
output = _readable_listen_address(self.listen_address, self.listen_port)
log.info('Starting Gevent server on %s', output)
self.wsgiserver = WSGIServer(sock, self.app, log=self.access_logger, spawn=Pool(), **ssl_args)
if ssl_args:
wrap_socket = self.wsgiserver.wrap_socket
def my_wrap_socket(*args, **kwargs):
try:
return wrap_socket(*args, **kwargs)
except (ssl.SSLError, OSError) as ex:
log.warning('Gevent SSL Error: %s', ex)
raise GreenletExit
self.wsgiserver.wrap_socket = my_wrap_socket
self.wsgiserver.serve_forever()
finally:
if self.unix_socket_file:
os.remove(self.unix_socket_file)
self.unix_socket_file = None
def _start_tornado(self):
if os.name == 'nt' and sys.version_info > (3, 7):
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
log.info('Starting Tornado server on %s', _readable_listen_address(self.listen_address, self.listen_port))
# Max Buffersize set to 200MB )
http_server = HTTPServer(WSGIContainer(self.app),
max_buffer_size=209700000,
ssl_options=self.ssl_args)
http_server.listen(self.listen_port, self.listen_address)
self.wsgiserver = IOLoop.current()
self.wsgiserver.start()
# wait for stop signal
self.wsgiserver.close(True)
def start(self):
try:
if _GEVENT:
# leave subprocess out to allow forking for fetchers and processors
self._start_gevent()
else:
self._start_tornado()
except Exception as ex:
log.error("Error starting server: %s", ex)
print("Error starting server: %s" % ex)
self.stop()
return False
finally:
self.wsgiserver = None
# prevent irritating log of pending tasks message from asyncio
logger.get('asyncio').setLevel(logger.logging.CRITICAL)
if not self.restart:
log.info("Performing shutdown of Calibre-Web")
return True
log.info("Performing restart of Calibre-Web")
args = self._get_args_for_reloading()
subprocess.call(args, close_fds=True) # nosec
return True
def _killServer(self, __, ___):
self.stop()
def stop(self, restart=False):
from . import updater_thread
updater_thread.stop()
log.info("webserver stop (restart=%s)", restart)
self.restart = restart
if self.wsgiserver:
if _GEVENT:
self.wsgiserver.close()
else:
self.wsgiserver.add_callback_from_signal(self.wsgiserver.stop)
+27
View File
@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2021 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class Metadata():
__name__ = "Generic"
def __init__(self):
self.active = True
def set_status(self, state):
self.active = state
+187
View File
@@ -0,0 +1,187 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 shavitmichael, OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from base64 import b64decode, b64encode
from jsonschema import validate, exceptions, __version__
from datetime import datetime
from urllib.parse import unquote
from flask import json
from .. import logger
log = logger.create()
def b64encode_json(json_data):
return b64encode(json.dumps(json_data).encode())
# Python3 has a timestamp() method we could be calling, however it's not avaiable in python2.
def to_epoch_timestamp(datetime_object):
return (datetime_object - datetime(1970, 1, 1)).total_seconds()
def get_datetime_from_json(json_object, field_name):
try:
return datetime.utcfromtimestamp(json_object[field_name])
except (KeyError, OSError, OverflowError):
# OSError is thrown on Windows if timestamp is <1970 or >2038
return datetime.min
class SyncToken:
""" The SyncToken is used to persist state accross requests.
When serialized over the response headers, the Kobo device will propagate the token onto following
requests to the service. As an example use-case, the SyncToken is used to detect books that have been added
to the library since the last time the device synced to the server.
Attributes:
books_last_created: Datetime representing the newest book that the device knows about.
books_last_modified: Datetime representing the last modified book that the device knows about.
"""
SYNC_TOKEN_HEADER = "x-kobo-synctoken" # nosec
VERSION = "1-1-0"
LAST_MODIFIED_ADDED_VERSION = "1-1-0"
MIN_VERSION = "1-0-0"
token_schema = {
"type": "object",
"properties": {"version": {"type": "string"}, "data": {"type": "object"}, },
}
# This Schema doesn't contain enough information to detect and propagate book deletions from Calibre to the device.
# A potential solution might be to keep a list of all known book uuids in the token, and look for any missing
# from the db.
data_schema_v1 = {
"type": "object",
"properties": {
"raw_kobo_store_token": {"type": "string"},
"books_last_modified": {"type": "string"},
"books_last_created": {"type": "string"},
"archive_last_modified": {"type": "string"},
"reading_state_last_modified": {"type": "string"},
"tags_last_modified": {"type": "string"}
# "books_last_id": {"type": "integer", "optional": True}
},
}
def __init__(
self,
raw_kobo_store_token="",
books_last_created=datetime.min,
books_last_modified=datetime.min,
archive_last_modified=datetime.min,
reading_state_last_modified=datetime.min,
tags_last_modified=datetime.min
# books_last_id=-1
): # nosec
self.raw_kobo_store_token = raw_kobo_store_token
self.books_last_created = books_last_created
self.books_last_modified = books_last_modified
self.archive_last_modified = archive_last_modified
self.reading_state_last_modified = reading_state_last_modified
self.tags_last_modified = tags_last_modified
# self.books_last_id = books_last_id
@staticmethod
def from_headers(headers):
sync_token_header = headers.get(SyncToken.SYNC_TOKEN_HEADER, "")
if sync_token_header == "": # nosec
return SyncToken()
# On the first sync from a Kobo device, we may receive the SyncToken
# from the official Kobo store. Without digging too deep into it, that
# token is of the form [b64encoded blob].[b64encoded blob 2]
if "." in sync_token_header:
return SyncToken(raw_kobo_store_token=sync_token_header)
try:
sync_token_json = json.loads(
b64decode(sync_token_header + "=" * (-len(sync_token_header) % 4))
)
validate(sync_token_json, SyncToken.token_schema)
if sync_token_json["version"] < SyncToken.MIN_VERSION:
raise ValueError
data_json = sync_token_json["data"]
validate(sync_token_json, SyncToken.data_schema_v1)
except (exceptions.ValidationError, ValueError):
log.error("Sync token contents do not follow the expected json schema.")
return SyncToken()
raw_kobo_store_token = data_json["raw_kobo_store_token"]
try:
books_last_modified = get_datetime_from_json(data_json, "books_last_modified")
books_last_created = get_datetime_from_json(data_json, "books_last_created")
archive_last_modified = get_datetime_from_json(data_json, "archive_last_modified")
reading_state_last_modified = get_datetime_from_json(data_json, "reading_state_last_modified")
tags_last_modified = get_datetime_from_json(data_json, "tags_last_modified")
# books_last_id = data_json["books_last_id"]
except TypeError:
log.error("SyncToken timestamps don't parse to a datetime.")
return SyncToken(raw_kobo_store_token=raw_kobo_store_token)
#except KeyError:
# books_last_id = -1
return SyncToken(
raw_kobo_store_token=raw_kobo_store_token,
books_last_created=books_last_created,
books_last_modified=books_last_modified,
archive_last_modified=archive_last_modified,
reading_state_last_modified=reading_state_last_modified,
tags_last_modified=tags_last_modified,
#books_last_id=books_last_id
)
def set_kobo_store_header(self, store_headers):
store_headers.set(SyncToken.SYNC_TOKEN_HEADER, self.raw_kobo_store_token)
def merge_from_store_response(self, store_response):
self.raw_kobo_store_token = store_response.headers.get(
SyncToken.SYNC_TOKEN_HEADER, ""
)
def to_headers(self, headers):
headers[SyncToken.SYNC_TOKEN_HEADER] = self.build_sync_token()
def build_sync_token(self):
token = {
"version": SyncToken.VERSION,
"data": {
"raw_kobo_store_token": self.raw_kobo_store_token,
"books_last_modified": to_epoch_timestamp(self.books_last_modified),
"books_last_created": to_epoch_timestamp(self.books_last_created),
"archive_last_modified": to_epoch_timestamp(self.archive_last_modified),
"reading_state_last_modified": to_epoch_timestamp(self.reading_state_last_modified),
"tags_last_modified": to_epoch_timestamp(self.tags_last_modified),
#"books_last_id":self.books_last_id
},
}
return b64encode_json(token)
def __str__(self):
return "{},{},{},{},{},{}".format(self.books_last_created,
self.books_last_modified,
self.archive_last_modified,
self.reading_state_last_modified,
self.tags_last_modified, self.raw_kobo_store_token)
#self.books_last_id)
+51
View File
@@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2019 pwr
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .. import logger
log = logger.create()
try: from . import goodreads_support
except ImportError as err:
log.debug("Cannot import goodreads, showing authors-metadata will not work: %s", err)
goodreads_support = None
try:
from . import simpleldap as ldap
from .simpleldap import ldapVersion
except ImportError as err:
log.debug("Cannot import simpleldap, logging in with ldap will not work: %s", err)
ldap = None
ldapVersion = None
try:
from . import SyncToken as SyncToken
kobo = True
except ImportError as err:
log.debug("Cannot import SyncToken, syncing books with Kobo Devices will not work: %s", err)
kobo = None
SyncToken = None
try:
from . import gmail
except ImportError as err:
log.debug("Cannot import gmail, sending books via Gmail Oauth2 Verification will not work: %s", err)
gmail = None
+100
View File
@@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2021 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os.path
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
from datetime import datetime
import base64
from flask_babel import gettext as _
from ..constants import BASE_DIR
from .. import logger
log = logger.create()
SCOPES = ['openid', 'https://www.googleapis.com/auth/gmail.send', 'https://www.googleapis.com/auth/userinfo.email']
def setup_gmail(token):
# If there are no (valid) credentials available, let the user log in.
creds = None
if "token" in token:
creds = Credentials(
token=token['token'],
refresh_token=token['refresh_token'],
token_uri=token['token_uri'],
client_id=token['client_id'],
client_secret=token['client_secret'],
scopes=token['scopes'],
)
creds.expiry = datetime.fromisoformat(token['expiry'])
if not creds or not creds.valid:
# don't forget to dump one more time after the refresh
# also, some file-locking routines wouldn't be needless
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
cred_file = os.path.join(BASE_DIR, 'gmail.json')
if not os.path.exists(cred_file):
raise Exception(_("Found no valid gmail.json file with OAuth information"))
flow = InstalledAppFlow.from_client_secrets_file(
os.path.join(BASE_DIR, 'gmail.json'), SCOPES)
creds = flow.run_local_server(port=0)
user_info = get_user_info(creds)
return {
'token': creds.token,
'refresh_token': creds.refresh_token,
'token_uri': creds.token_uri,
'client_id': creds.client_id,
'client_secret': creds.client_secret,
'scopes': creds.scopes,
'expiry': creds.expiry.isoformat(),
'email': user_info
}
return {}
def get_user_info(credentials):
user_info_service = build(serviceName='oauth2', version='v2',credentials=credentials)
user_info = user_info_service.userinfo().get().execute()
return user_info.get('email', "")
def send_messsage(token, msg):
log.debug("Start sending e-mail via Gmail")
creds = Credentials(
token=token['token'],
refresh_token=token['refresh_token'],
token_uri=token['token_uri'],
client_id=token['client_id'],
client_secret=token['client_secret'],
scopes=token['scopes'],
)
creds.expiry = datetime.fromisoformat(token['expiry'])
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
service = build('gmail', 'v1', credentials=creds)
message_as_bytes = msg.as_bytes() # the message should converted from string to bytes.
message_as_base64 = base64.urlsafe_b64encode(message_as_bytes) # encode in base64 (printable letters coding)
raw = message_as_base64.decode() # convert to something JSON serializable
body = {'raw': raw}
(service.users().messages().send(userId='me', body=body).execute())
log.debug("E-mail send successfully via Gmail")
+112
View File
@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, pwr
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import time
from functools import reduce
try:
from goodreads.client import GoodreadsClient
except ImportError:
from betterreads.client import GoodreadsClient
try: import Levenshtein
except ImportError: Levenshtein = False
from .. import logger
log = logger.create()
_client = None # type: GoodreadsClient
# GoodReads TOS allows for 24h caching of data
_CACHE_TIMEOUT = 23 * 60 * 60 # 23 hours (in seconds)
_AUTHORS_CACHE = {}
def connect(key=None, secret=None, enabled=True):
global _client
if not enabled or not key or not secret:
_client = None
return
if _client:
# make sure the configuration has not changed since last we used the client
if _client.client_key != key or _client.client_secret != secret:
_client = None
if not _client:
_client = GoodreadsClient(key, secret)
def get_author_info(author_name):
now = time.time()
author_info = _AUTHORS_CACHE.get(author_name, None)
if author_info:
if now < author_info._timestamp + _CACHE_TIMEOUT:
return author_info
# clear expired entries
del _AUTHORS_CACHE[author_name]
if not _client:
log.warning("failed to get a Goodreads client")
return
try:
author_info = _client.find_author(author_name=author_name)
except Exception as ex:
# Skip goodreads, if site is down/inaccessible
log.warning('Goodreads website is down/inaccessible? %s', ex.__str__())
return
if author_info:
author_info._timestamp = now
_AUTHORS_CACHE[author_name] = author_info
return author_info
def get_other_books(author_info, library_books=None):
# Get all identifiers (ISBN, Goodreads, etc) and filter author's books by that list so we show fewer duplicates
# Note: Not all images will be shown, even though they're available on Goodreads.com.
# See https://www.goodreads.com/topic/show/18213769-goodreads-book-images
if not author_info:
return
identifiers = []
library_titles = []
if library_books:
identifiers = list(reduce(lambda acc, book: acc + [i.val for i in book.identifiers if i.val], library_books, []))
library_titles = [book.title for book in library_books]
for book in author_info.books:
if book.isbn in identifiers:
continue
if isinstance(book.gid, int):
if book.gid in identifiers:
continue
else:
if book.gid["#text"] in identifiers:
continue
if Levenshtein and library_titles:
goodreads_title = book._book_dict['title_without_series']
if any(Levenshtein.ratio(goodreads_title, title) > 0.7 for title in library_titles):
continue
yield book
+127
View File
@@ -0,0 +1,127 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, pwr
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import base64
from flask_simpleldap import LDAP, LDAPException
from flask_simpleldap import ldap as pyLDAP
from .. import constants, logger
try:
from ldap.pkginfo import __version__ as ldapVersion
except ImportError:
pass
log = logger.create()
_ldap = LDAP()
def init_app(app, config):
if config.config_login_type != constants.LOGIN_LDAP:
return
app.config['LDAP_HOST'] = config.config_ldap_provider_url
app.config['LDAP_PORT'] = config.config_ldap_port
app.config['LDAP_CUSTOM_OPTIONS'] = {pyLDAP.OPT_REFERRALS: 0}
if config.config_ldap_encryption == 2:
app.config['LDAP_SCHEMA'] = 'ldaps'
else:
app.config['LDAP_SCHEMA'] = 'ldap'
if config.config_ldap_authentication > constants.LDAP_AUTH_ANONYMOUS:
if config.config_ldap_authentication > constants.LDAP_AUTH_UNAUTHENTICATE:
if config.config_ldap_serv_password is None:
config.config_ldap_serv_password = ''
app.config['LDAP_PASSWORD'] = base64.b64decode(config.config_ldap_serv_password)
else:
app.config['LDAP_PASSWORD'] = base64.b64decode("")
app.config['LDAP_USERNAME'] = config.config_ldap_serv_username
else:
app.config['LDAP_USERNAME'] = ""
app.config['LDAP_PASSWORD'] = base64.b64decode("")
if bool(config.config_ldap_cert_path):
app.config['LDAP_CUSTOM_OPTIONS'].update({
pyLDAP.OPT_X_TLS_REQUIRE_CERT: pyLDAP.OPT_X_TLS_DEMAND,
pyLDAP.OPT_X_TLS_CACERTFILE: config.config_ldap_cacert_path,
pyLDAP.OPT_X_TLS_CERTFILE: config.config_ldap_cert_path,
pyLDAP.OPT_X_TLS_KEYFILE: config.config_ldap_key_path,
pyLDAP.OPT_X_TLS_NEWCTX: 0
})
app.config['LDAP_BASE_DN'] = config.config_ldap_dn
app.config['LDAP_USER_OBJECT_FILTER'] = config.config_ldap_user_object
app.config['LDAP_USE_TLS'] = bool(config.config_ldap_encryption == 1)
app.config['LDAP_USE_SSL'] = bool(config.config_ldap_encryption == 2)
app.config['LDAP_OPENLDAP'] = bool(config.config_ldap_openldap)
app.config['LDAP_GROUP_OBJECT_FILTER'] = config.config_ldap_group_object_filter
app.config['LDAP_GROUP_MEMBERS_FIELD'] = config.config_ldap_group_members_field
try:
_ldap.init_app(app)
except ValueError:
if bool(config.config_ldap_cert_path):
app.config['LDAP_CUSTOM_OPTIONS'].pop(pyLDAP.OPT_X_TLS_NEWCTX)
try:
_ldap.init_app(app)
except RuntimeError as e:
log.error(e)
except RuntimeError as e:
log.error(e)
def get_object_details(user=None,query_filter=None):
return _ldap.get_object_details(user, query_filter=query_filter)
def bind():
return _ldap.bind()
def get_group_members(group):
return _ldap.get_group_members(group)
def basic_auth_required(func):
return _ldap.basic_auth_required(func)
def bind_user(username, password):
'''Attempts a LDAP login.
:returns: True if login succeeded, False if login failed, None if server unavailable.
'''
try:
if _ldap.get_object_details(username):
result = _ldap.bind_user(username, password)
log.debug("LDAP login '%s': %r", username, result)
return result is not None, None
return None, None # User not found
except (TypeError, AttributeError, KeyError) as ex:
error = ("LDAP bind_user: %s" % ex)
return None, error
except LDAPException as ex:
if ex.message == 'Invalid credentials':
error = "LDAP admin login failed"
return None, error
if ex.message == "Can't contact LDAP server":
# log.warning('LDAP Server down: %s', ex)
error = ('LDAP Server down: %s' % ex)
return None, error
else:
error = ('LDAP Server error: %s' % ex.message)
return None, error
+239
View File
@@ -0,0 +1,239 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2020 pwr
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import threading
import abc
import uuid
import time
try:
import queue
except ImportError:
import Queue as queue
from datetime import datetime
from collections import namedtuple
from cps import logger
log = logger.create()
# task 'status' consts
STAT_WAITING = 0
STAT_FAIL = 1
STAT_STARTED = 2
STAT_FINISH_SUCCESS = 3
# Only retain this many tasks in dequeued list
TASK_CLEANUP_TRIGGER = 20
QueuedTask = namedtuple('QueuedTask', 'num, user, added, task')
def _get_main_thread():
for t in threading.enumerate():
if t.__class__.__name__ == '_MainThread':
return t
raise Exception("main thread not found?!")
class ImprovedQueue(queue.Queue):
def to_list(self):
"""
Returns a copy of all items in the queue without removing them.
"""
with self.mutex:
return list(self.queue)
# Class for all worker tasks in the background
class WorkerThread(threading.Thread):
_instance = None
@classmethod
def getInstance(cls):
if cls._instance is None:
cls._instance = WorkerThread()
return cls._instance
def __init__(self):
threading.Thread.__init__(self)
self.dequeued = list()
self.doLock = threading.Lock()
self.queue = ImprovedQueue()
self.num = 0
self.start()
@classmethod
def add(cls, user, task):
ins = cls.getInstance()
ins.num += 1
log.debug("Add Task for user: {} - {}".format(user, task))
ins.queue.put(QueuedTask(
num=ins.num,
user=user,
added=datetime.now(),
task=task,
))
@property
def tasks(self):
with self.doLock:
tasks = self.queue.to_list() + self.dequeued
return sorted(tasks, key=lambda x: x.num)
def cleanup_tasks(self):
with self.doLock:
dead = []
alive = []
for x in self.dequeued:
(dead if x.task.dead else alive).append(x)
# if the ones that we need to keep are within the trigger, do nothing else
delta = len(self.dequeued) - len(dead)
if delta > TASK_CLEANUP_TRIGGER:
ret = alive
else:
# otherwise, lop off the oldest dead tasks until we hit the target trigger
ret = sorted(dead, key=lambda x: x.task.end_time)[-TASK_CLEANUP_TRIGGER:] + alive
self.dequeued = sorted(ret, key=lambda x: x.num)
# Main thread loop starting the different tasks
def run(self):
main_thread = _get_main_thread()
while main_thread.is_alive():
try:
# this blocks until something is available. This can cause issues when the main thread dies - this
# thread will remain alive. We implement a timeout to unblock every second which allows us to check if
# the main thread is still alive.
# We don't use a daemon here because we don't want the tasks to just be abruptly halted, leading to
# possible file / database corruption
item = self.queue.get(timeout=1)
except queue.Empty:
time.sleep(1)
continue
with self.doLock:
# add to list so that in-progress tasks show up
self.dequeued.append(item)
# once we hit our trigger, start cleaning up dead tasks
if len(self.dequeued) > TASK_CLEANUP_TRIGGER:
self.cleanup_tasks()
# sometimes tasks (like Upload) don't actually have work to do and are created as already finished
if item.task.stat is STAT_WAITING:
# CalibreTask.start() should wrap all exceptions in it's own error handling
item.task.start(self)
self.queue.task_done()
class CalibreTask:
__metaclass__ = abc.ABCMeta
def __init__(self, message):
self._progress = 0
self.stat = STAT_WAITING
self.error = None
self.start_time = None
self.end_time = None
self.message = message
self.id = uuid.uuid4()
@abc.abstractmethod
def run(self, worker_thread):
"""Provides the caller some human-readable name for this class"""
raise NotImplementedError
@abc.abstractmethod
def name(self):
"""Provides the caller some human-readable name for this class"""
raise NotImplementedError
def start(self, *args):
self.start_time = datetime.now()
self.stat = STAT_STARTED
# catch any unhandled exceptions in a task and automatically fail it
try:
self.run(*args)
except Exception as ex:
self._handleError(str(ex))
log.debug_or_exception(ex)
self.end_time = datetime.now()
@property
def stat(self):
return self._stat
@stat.setter
def stat(self, x):
self._stat = x
@property
def progress(self):
return self._progress
@progress.setter
def progress(self, x):
if not 0 <= x <= 1:
raise ValueError("Task progress should within [0, 1] range")
self._progress = x
@property
def error(self):
return self._error
@error.setter
def error(self, x):
self._error = x
@property
def runtime(self):
return (self.end_time or datetime.now()) - self.start_time
@property
def dead(self):
"""Determines whether or not this task can be garbage collected
We have a separate dictating this because there may be certain tasks that want to override this
"""
# By default, we're good to clean a task if it's "Done"
return self.stat in (STAT_FINISH_SUCCESS, STAT_FAIL)
'''@progress.setter
def progress(self, x):
if x > 1:
x = 1
if x < 0:
x = 0
self._progress = x'''
def _handleError(self, error_message):
self.stat = STAT_FAIL
self.progress = 1
self.error = error_message
def _handleSuccess(self):
self.stat = STAT_FINISH_SUCCESS
self.progress = 1
+461
View File
@@ -0,0 +1,461 @@
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11,
# andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh,
# falgh1, grunjol, csitko, ytils, xybydy, trasba, vrabe,
# ruben-herold, marblepebble, JackED42, SiphonSquirrel,
# apetresc, nanu-c, mutschler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from datetime import datetime
from flask import Blueprint, flash, redirect, request, url_for
from flask_babel import gettext as _
from flask_login import current_user, login_required
from sqlalchemy.exc import InvalidRequestError, OperationalError
from sqlalchemy.sql.expression import func, true
from . import calibre_db, config, db, logger, ub
from .render_template import render_title_template
from .usermanagement import login_required_if_no_ano
shelf = Blueprint('shelf', __name__)
log = logger.create()
def check_shelf_edit_permissions(cur_shelf):
if not cur_shelf.is_public and not cur_shelf.user_id == int(current_user.id):
log.error("User %s not allowed to edit shelf %s", current_user, cur_shelf)
return False
if cur_shelf.is_public and not current_user.role_edit_shelfs():
log.info("User %s not allowed to edit public shelves", current_user)
return False
return True
def check_shelf_view_permissions(cur_shelf):
if cur_shelf.is_public:
return True
if current_user.is_anonymous or cur_shelf.user_id != current_user.id:
log.error("User is unauthorized to view non-public shelf: %s", cur_shelf)
return False
return True
@shelf.route("/shelf/add/<int:shelf_id>/<int:book_id>", methods=["POST"])
@login_required
def add_to_shelf(shelf_id, book_id):
xhr = request.headers.get('X-Requested-With') == 'XMLHttpRequest'
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
if shelf is None:
log.error("Invalid shelf specified: %s", shelf_id)
if not xhr:
flash(_(u"Invalid shelf specified"), category="error")
return redirect(url_for('web.index'))
return "Invalid shelf specified", 400
if not check_shelf_edit_permissions(shelf):
if not xhr:
flash(_(u"Sorry you are not allowed to add a book to that shelf"), category="error")
return redirect(url_for('web.index'))
return "Sorry you are not allowed to add a book to the that shelf", 403
book_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id,
ub.BookShelf.book_id == book_id).first()
if book_in_shelf:
log.error("Book %s is already part of %s", book_id, shelf)
if not xhr:
flash(_(u"Book is already part of the shelf: %(shelfname)s", shelfname=shelf.name), category="error")
return redirect(url_for('web.index'))
return "Book is already part of the shelf: %s" % shelf.name, 400
maxOrder = ub.session.query(func.max(ub.BookShelf.order)).filter(ub.BookShelf.shelf == shelf_id).first()
if maxOrder[0] is None:
maxOrder = 0
else:
maxOrder = maxOrder[0]
shelf.books.append(ub.BookShelf(shelf=shelf.id, book_id=book_id, order=maxOrder + 1))
shelf.last_modified = datetime.utcnow()
try:
ub.session.merge(shelf)
ub.session.commit()
except (OperationalError, InvalidRequestError):
ub.session.rollback()
log.error("Settings DB is not Writeable")
flash(_(u"Settings DB is not Writeable"), category="error")
if "HTTP_REFERER" in request.environ:
return redirect(request.environ["HTTP_REFERER"])
else:
return redirect(url_for('web.index'))
if not xhr:
log.debug("Book has been added to shelf: {}".format(shelf.name))
flash(_(u"Book has been added to shelf: %(sname)s", sname=shelf.name), category="success")
if "HTTP_REFERER" in request.environ:
return redirect(request.environ["HTTP_REFERER"])
else:
return redirect(url_for('web.index'))
return "", 204
@shelf.route("/shelf/massadd/<int:shelf_id>", methods=["POST"])
@login_required
def search_to_shelf(shelf_id):
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
if shelf is None:
log.error("Invalid shelf specified: %s", shelf_id)
flash(_(u"Invalid shelf specified"), category="error")
return redirect(url_for('web.index'))
if not check_shelf_edit_permissions(shelf):
log.warning("You are not allowed to add a book to the shelf".format(shelf.name))
flash(_(u"You are not allowed to add a book to the shelf"), category="error")
return redirect(url_for('web.index'))
if current_user.id in ub.searched_ids and ub.searched_ids[current_user.id]:
books_for_shelf = list()
books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).all()
if books_in_shelf:
book_ids = list()
for book_id in books_in_shelf:
book_ids.append(book_id.book_id)
for searchid in ub.searched_ids[current_user.id]:
if searchid not in book_ids:
books_for_shelf.append(searchid)
else:
books_for_shelf = ub.searched_ids[current_user.id]
if not books_for_shelf:
log.error("Books are already part of {}".format(shelf.name))
flash(_(u"Books are already part of the shelf: %(name)s", name=shelf.name), category="error")
return redirect(url_for('web.index'))
maxOrder = ub.session.query(func.max(ub.BookShelf.order)).filter(ub.BookShelf.shelf == shelf_id).first()[0] or 0
for book in books_for_shelf:
maxOrder += 1
shelf.books.append(ub.BookShelf(shelf=shelf.id, book_id=book, order=maxOrder))
shelf.last_modified = datetime.utcnow()
try:
ub.session.merge(shelf)
ub.session.commit()
flash(_(u"Books have been added to shelf: %(sname)s", sname=shelf.name), category="success")
except (OperationalError, InvalidRequestError):
ub.session.rollback()
log.error("Settings DB is not Writeable")
flash(_("Settings DB is not Writeable"), category="error")
else:
log.error("Could not add books to shelf: {}".format(shelf.name))
flash(_(u"Could not add books to shelf: %(sname)s", sname=shelf.name), category="error")
return redirect(url_for('web.index'))
@shelf.route("/shelf/remove/<int:shelf_id>/<int:book_id>", methods=["POST"])
@login_required
def remove_from_shelf(shelf_id, book_id):
xhr = request.headers.get('X-Requested-With') == 'XMLHttpRequest'
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
if shelf is None:
log.error("Invalid shelf specified: {}".format(shelf_id))
if not xhr:
return redirect(url_for('web.index'))
return "Invalid shelf specified", 400
# if shelf is public and use is allowed to edit shelfs, or if shelf is private and user is owner
# allow editing shelfs
# result shelf public user allowed user owner
# false 1 0 x
# true 1 1 x
# true 0 x 1
# false 0 x 0
if check_shelf_edit_permissions(shelf):
book_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id,
ub.BookShelf.book_id == book_id).first()
if book_shelf is None:
log.error("Book %s already removed from %s", book_id, shelf)
if not xhr:
return redirect(url_for('web.index'))
return "Book already removed from shelf", 410
try:
ub.session.delete(book_shelf)
shelf.last_modified = datetime.utcnow()
ub.session.commit()
except (OperationalError, InvalidRequestError):
ub.session.rollback()
log.error("Settings DB is not Writeable")
flash(_("Settings DB is not Writeable"), category="error")
if "HTTP_REFERER" in request.environ:
return redirect(request.environ["HTTP_REFERER"])
else:
return redirect(url_for('web.index'))
if not xhr:
flash(_(u"Book has been removed from shelf: %(sname)s", sname=shelf.name), category="success")
if "HTTP_REFERER" in request.environ:
return redirect(request.environ["HTTP_REFERER"])
else:
return redirect(url_for('web.index'))
return "", 204
else:
if not xhr:
log.warning("You are not allowed to remove a book from shelf: {}".format(shelf.name))
flash(_(u"Sorry you are not allowed to remove a book from this shelf"),
category="error")
return redirect(url_for('web.index'))
return "Sorry you are not allowed to remove a book from this shelf", 403
@shelf.route("/shelf/create", methods=["GET", "POST"])
@login_required
def create_shelf():
shelf = ub.Shelf()
return create_edit_shelf(shelf, page_title=_(u"Create a Shelf"), page="shelfcreate")
@shelf.route("/shelf/edit/<int:shelf_id>", methods=["GET", "POST"])
@login_required
def edit_shelf(shelf_id):
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
if not check_shelf_edit_permissions(shelf):
flash(_(u"Sorry you are not allowed to edit this shelf"), category="error")
return redirect(url_for('web.index'))
return create_edit_shelf(shelf, page_title=_(u"Edit a shelf"), page="shelfedit", shelf_id=shelf_id)
# if shelf ID is set, we are editing a shelf
def create_edit_shelf(shelf, page_title, page, shelf_id=False):
sync_only_selected_shelves = current_user.kobo_only_shelves_sync
# calibre_db.session.query(ub.Shelf).filter(ub.Shelf.user_id == current_user.id).filter(ub.Shelf.kobo_sync).count()
if request.method == "POST":
to_save = request.form.to_dict()
if not current_user.role_edit_shelfs() and to_save.get("is_public") == "on":
flash(_(u"Sorry you are not allowed to create a public shelf"), category="error")
return redirect(url_for('web.index'))
is_public = 1 if to_save.get("is_public") == "on" else 0
if config.config_kobo_sync:
shelf.kobo_sync = True if to_save.get("kobo_sync") else False
if shelf.kobo_sync:
ub.session.query(ub.ShelfArchive).filter(ub.ShelfArchive.user_id == current_user.id).filter(
ub.ShelfArchive.uuid == shelf.uuid).delete()
ub.session_commit()
shelf_title = to_save.get("title", "")
if check_shelf_is_unique(shelf, shelf_title, is_public, shelf_id):
shelf.name = shelf_title
shelf.is_public = is_public
if not shelf_id:
shelf.user_id = int(current_user.id)
ub.session.add(shelf)
shelf_action = "created"
flash_text = _(u"Shelf %(title)s created", title=shelf_title)
else:
shelf_action = "changed"
flash_text = _(u"Shelf %(title)s changed", title=shelf_title)
try:
ub.session.commit()
log.info(u"Shelf {} {}".format(shelf_title, shelf_action))
flash(flash_text, category="success")
return redirect(url_for('shelf.show_shelf', shelf_id=shelf.id))
except (OperationalError, InvalidRequestError) as ex:
ub.session.rollback()
log.debug_or_exception(ex)
log.error("Settings DB is not Writeable")
flash(_("Settings DB is not Writeable"), category="error")
except Exception as ex:
ub.session.rollback()
log.debug_or_exception(ex)
flash(_(u"There was an error"), category="error")
return render_title_template('shelf_edit.html',
shelf=shelf,
title=page_title,
page=page,
kobo_sync_enabled=config.config_kobo_sync,
sync_only_selected_shelves=sync_only_selected_shelves)
def check_shelf_is_unique(shelf, title, is_public, shelf_id=False):
if shelf_id:
ident = ub.Shelf.id != shelf_id
else:
ident = true()
if is_public == 1:
is_shelf_name_unique = ub.session.query(ub.Shelf) \
.filter((ub.Shelf.name == title) & (ub.Shelf.is_public == 1)) \
.filter(ident) \
.first() is None
if not is_shelf_name_unique:
log.error("A public shelf with the name '{}' already exists.".format(title))
flash(_(u"A public shelf with the name '%(title)s' already exists.", title=title),
category="error")
else:
is_shelf_name_unique = ub.session.query(ub.Shelf) \
.filter((ub.Shelf.name == title) & (ub.Shelf.is_public == 0) &
(ub.Shelf.user_id == int(current_user.id))) \
.filter(ident) \
.first() is None
if not is_shelf_name_unique:
log.error("A private shelf with the name '{}' already exists.".format(title))
flash(_(u"A private shelf with the name '%(title)s' already exists.", title=title),
category="error")
return is_shelf_name_unique
def delete_shelf_helper(cur_shelf):
if not cur_shelf or not check_shelf_edit_permissions(cur_shelf):
return
shelf_id = cur_shelf.id
ub.session.delete(cur_shelf)
ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).delete()
ub.session.add(ub.ShelfArchive(uuid=cur_shelf.uuid, user_id=cur_shelf.user_id))
ub.session_commit("successfully deleted Shelf {}".format(cur_shelf.name))
@shelf.route("/shelf/delete/<int:shelf_id>", methods=["POST"])
@login_required
def delete_shelf(shelf_id):
cur_shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
try:
delete_shelf_helper(cur_shelf)
flash(_("Shelf successfully deleted"), category="success")
except InvalidRequestError:
ub.session.rollback()
log.error("Settings DB is not Writeable")
flash(_("Settings DB is not Writeable"), category="error")
return redirect(url_for('web.index'))
@shelf.route("/simpleshelf/<int:shelf_id>")
@login_required_if_no_ano
def show_simpleshelf(shelf_id):
return render_show_shelf(2, shelf_id, 1, None)
@shelf.route("/shelf/<int:shelf_id>", defaults={"sort_param": "order", 'page': 1})
@shelf.route("/shelf/<int:shelf_id>/<sort_param>", defaults={'page': 1})
@shelf.route("/shelf/<int:shelf_id>/<sort_param>/<int:page>")
@login_required_if_no_ano
def show_shelf(shelf_id, sort_param, page):
return render_show_shelf(1, shelf_id, page, sort_param)
@shelf.route("/shelf/order/<int:shelf_id>", methods=["GET", "POST"])
@login_required
def order_shelf(shelf_id):
if request.method == "POST":
to_save = request.form.to_dict()
books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).order_by(
ub.BookShelf.order.asc()).all()
counter = 0
for book in books_in_shelf:
setattr(book, 'order', to_save[str(book.book_id)])
counter += 1
# if order diffrent from before -> shelf.last_modified = datetime.utcnow()
try:
ub.session.commit()
except (OperationalError, InvalidRequestError):
ub.session.rollback()
log.error("Settings DB is not Writeable")
flash(_("Settings DB is not Writeable"), category="error")
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
result = list()
if shelf and check_shelf_view_permissions(shelf):
result = calibre_db.session.query(db.Books) \
.join(ub.BookShelf, ub.BookShelf.book_id == db.Books.id, isouter=True) \
.add_columns(calibre_db.common_filters().label("visible")) \
.filter(ub.BookShelf.shelf == shelf_id).order_by(ub.BookShelf.order.asc()).all()
return render_title_template('shelf_order.html', entries=result,
title=_(u"Change order of Shelf: '%(name)s'", name=shelf.name),
shelf=shelf, page="shelforder")
def change_shelf_order(shelf_id, order):
result = calibre_db.session.query(db.Books).outerjoin(db.books_series_link,
db.Books.id == db.books_series_link.c.book)\
.outerjoin(db.Series).join(ub.BookShelf, ub.BookShelf.book_id == db.Books.id) \
.filter(ub.BookShelf.shelf == shelf_id).order_by(*order).all()
for index, entry in enumerate(result):
book = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id) \
.filter(ub.BookShelf.book_id == entry.id).first()
book.order = index
ub.session_commit("Shelf-id:{} - Order changed".format(shelf_id))
def render_show_shelf(shelf_type, shelf_id, page_no, sort_param):
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
# check user is allowed to access shelf
if shelf and check_shelf_view_permissions(shelf):
if shelf_type == 1:
# order = [ub.BookShelf.order.asc()]
if sort_param == 'pubnew':
change_shelf_order(shelf_id, [db.Books.pubdate.desc()])
if sort_param == 'pubold':
change_shelf_order(shelf_id, [db.Books.pubdate])
if sort_param == 'abc':
change_shelf_order(shelf_id, [db.Books.sort])
if sort_param == 'zyx':
change_shelf_order(shelf_id, [db.Books.sort.desc()])
if sort_param == 'new':
change_shelf_order(shelf_id, [db.Books.timestamp.desc()])
if sort_param == 'old':
change_shelf_order(shelf_id, [db.Books.timestamp])
if sort_param == 'authaz':
change_shelf_order(shelf_id, [db.Books.author_sort.asc(), db.Series.name, db.Books.series_index])
if sort_param == 'authza':
change_shelf_order(shelf_id, [db.Books.author_sort.desc(),
db.Series.name.desc(),
db.Books.series_index.desc()])
page = "shelf.html"
pagesize = 0
else:
pagesize = sys.maxsize
page = 'shelfdown.html'
result, __, pagination = calibre_db.fill_indexpage(page_no, pagesize,
db.Books,
ub.BookShelf.shelf == shelf_id,
[ub.BookShelf.order.asc()],
ub.BookShelf, ub.BookShelf.book_id == db.Books.id)
# delete chelf entries where book is not existent anymore, can happen if book is deleted outside calibre-web
wrong_entries = calibre_db.session.query(ub.BookShelf) \
.join(db.Books, ub.BookShelf.book_id == db.Books.id, isouter=True) \
.filter(db.Books.id == None).all()
for entry in wrong_entries:
log.info('Not existing book {} in {} deleted'.format(entry.book_id, shelf))
try:
ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == entry.book_id).delete()
ub.session.commit()
except (OperationalError, InvalidRequestError):
ub.session.rollback()
log.error("Settings DB is not Writeable")
flash(_("Settings DB is not Writeable"), category="error")
return render_title_template(page,
entries=result,
pagination=pagination,
title=_(u"Shelf: '%(name)s'", name=shelf.name),
shelf=shelf,
page="shelf")
else:
flash(_(u"Error opening shelf. Shelf does not exist or is not accessible"), category="error")
return redirect(url_for("web.index"))
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More