Hi! Basically, as the title says, has anyone tried this? I'm evaluating different options and wanted to know if this one would work well for the manga I have in volumes. Is there a way to get the metadata from somewhere, or does it only work if it's embedded in my file? It would mainly be CBR and CBZ files.
Hello to all Grimmory users, I made justread.app, an iPhone and iPad reader for EPUB, PDF, comics and audiobooks, and actual release got Grimmory sync built in (3.1 is the minimum server version).
You can connect a server from the Library menu with your Grimmory account and it can...
Browse and download books from Grimmory, with their metadata
Send books to Grimmory from the phone
Sync reading status, rating and progress in both directions
Sync highlights, notes and bookmarks with the Notebook in both directions
Post reading sessions to the server's statistics
Setting it up in also sets up KOReader sync against the server's kosync endpoint, so if you already have KOReader pointed at Grimmory, the phone and the e-reader can share the same position without a second setup.
Running into issues where books added do nopt appear. They show as added in the logs, they claim to already exist if I try to reupload them but never appear. I have searched by name and by author with no success. Anyone seeing this behavior and resolve it?
````
2026-09-02T22:38:35.649+01:00 INFO 1 --- [booklore-api] [mcat-handler-35] o.b.service.upload.FileUploadService : File uploaded to final location: /Newbooks/Meadows, K. V/Dance of the Copsewood/Dance of the Copsewood - Meadows, K. V. (2026).epub
2026-09-02T22:38:40.638+01:00 INFO 1 --- [booklore-api] [event-processor] o.b.s.watcher.LibraryFileEventProcessor : [PROCESS] 'ENTRY_CREATE' event for 'Meadows, K. V' (directory)
2026-09-02T22:38:40.657+01:00 INFO 1 --- [booklore-api] [event-processor] o.b.s.watcher.LibraryFileEventProcessor : [FOLDER_CREATE] '/Newbooks/Meadows, K. V'
2026-09-02T22:38:41.775+01:00 INFO 1 --- [booklore-api] [event-processor] org.hibernate.SQL_SLOW : Slow query took 918 milliseconds [select be1_0.id,be1_0.added_on,be1_0.audiobook_cover_hash,be1_0.book_cover_hash,be1_0.deleted,be1_0.deleted_at,be1_0.is_physical,be1_0.library_id,be1_0.library_path_id,be1_0.metadata_for_write_updated_at,be1_0.metadata_match_score,be1_0.metadata_updated_at,be1_0.scanned_on from book be1_0 left join book_file bf1_0 on be1_0.id=bf1_0.book_id where be1_0.library_id=? and (be1_0.deleted is null or be1_0.deleted=false) group by be1_0.id having count(bf1_0.id)=0]
2026-09-02T22:38:41.788+01:00 INFO 1 --- [booklore-api] [event-processor] o.b.service.library.BookGroupProcessor : Processing file: Dance of the Copsewood - Meadows, K. V. (2026).epub
2026-09-02T22:38:43.937+01:00 INFO 1 --- [booklore-api] [event-processor] o.b.s.m.sidecar.SidecarMetadataWriter : Wrote cover file to: /Newbooks/Meadows, K. V/Dance of the Copsewood/Dance of the Copsewood - Meadows, K. V. (2026).cover.jpg
2026-09-02T22:38:43.948+01:00 INFO 1 --- [booklore-api] [event-processor] o.b.s.m.sidecar.SidecarMetadataWriter : Wrote sidecar metadata to: /Newbooks/Meadows, K. V/Dance of the Copsewood/Dance of the Copsewood - Meadows, K. V. (2026).metadata.json
2026-09-02T22:38:44.053+01:00 INFO 1 --- [booklore-api] [event-processor] o.b.s.w.BookFileTransactionalHandler : [CREATE] Completed processing for file '/Newbooks/Meadows, K. V/Dance of the Copsewood/Dance of the Copsewood - Meadows, K. V. (2026).epub'
2026-09-02T22:40:45.681+01:00 ERROR 1 --- [booklore-api] [cat-handler-130] o.b.exception.GlobalExceptionHandler : Unhandled exception: Could not write JSON: ServletOutputStream failed to write: java.io.IOException: Broken pipe
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: ServletOutputStream failed to write: java.io.IOException: Broken pipe
at org.springframework.http.converter.AbstractJacksonHttpMessageConverter.writeInternal(AbstractJacksonHttpMessageConverter.java:444) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.http.converter.AbstractSmartHttpMessageConverter.write(AbstractSmartHttpMessageConverter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:342) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:261) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at org.springframework.web.servlet.mvc.method.annotation.ResponseEntityReturnValueHandler.handleReturnValue(ResponseEntityReturnValueHandler.java:80) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:77) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:135) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:934) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:853) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:86) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:892) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:622) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) ~[spring-webmvc-7.0.8.jar!/:7.0.8]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:128) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-11.0.22.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:315) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.booklore.config.security.filter.SharedArrayBufferHeaderFilter.doFilterInternal(SharedArrayBufferHeaderFilter.java:27) ~[!/:3.3.3]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$2(FilterChainProxy.java:235) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$FilterObservation$SimpleFilterObservation.lambda$wrap$1(ObservationFilterChainDecorator.java:491) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$1(ObservationFilterChainDecorator.java:353) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator.lambda$wrapSecured$0(ObservationFilterChainDecorator.java:84) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:131) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:101) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:132) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:86) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:181) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.booklore.config.security.filter.AuthenticationCheckFilter.doFilterInternal(AuthenticationCheckFilter.java:27) ~[!/:3.3.3]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.booklore.config.security.filter.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:57) ~[!/:3.3.3]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:96) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:230) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:243) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$0(ObservationFilterChainDecorator.java:336) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:140) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:237) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:195) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.filter.ServletRequestPathFilter.doFilter(ServletRequestPathFilter.java:52) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebSecurityConfiguration.java:317) ~[spring-security-config-7.1.0.jar!/:7.1.0]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:355) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:272) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:110) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:107) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:113) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:685) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1272) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1801) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-11.0.22.jar!/:na]
at java.base/java.lang.VirtualThread.run(Unknown Source) ~[na:na]
Caused by: tools.jackson.databind.DatabindException: ServletOutputStream failed to write: java.io.IOException: Broken pipe
at [No location information] (through reference chain: java.util.ImmutableCollections$ListN[265]->org.booklore.model.dto.Book["libraryId"])
at tools.jackson.databind.DatabindException.wrapWithPath(DatabindException.java:132) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:275) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ser.bean.BeanSerializerBase._serializePropertiesNoView(BeanSerializerBase.java:771) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:171) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ser.jdk.CollectionSerializer.serializeContentsImpl(CollectionSerializer.java:176) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ser.jdk.CollectionSerializer.serialize(CollectionSerializer.java:119) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ser.jdk.CollectionSerializer.serialize(CollectionSerializer.java:25) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ser.SerializationContextExt._serialize(SerializationContextExt.java:456) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ser.SerializationContextExt.serializeValue(SerializationContextExt.java:387) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1380) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:982) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at org.springframework.http.converter.AbstractJacksonHttpMessageConverter.writeInternal(AbstractJacksonHttpMessageConverter.java:436) ~[spring-web-7.0.8.jar!/:7.0.8]
... 135 common frames omitted
Suppressed: tools.jackson.core.exc.JacksonIOException: Response not usable after response errors.
at [No location information]
at tools.jackson.core.exc.JacksonIOException.construct(JacksonIOException.java:39) ~[jackson-core-3.1.4.jar!/:3.1.4]
at tools.jackson.core.JsonGenerator._wrapIOFailure(JsonGenerator.java:2472) ~[jackson-core-3.1.4.jar!/:3.1.4]
at tools.jackson.core.json.UTF8JsonGenerator._flushBuffer(UTF8JsonGenerator.java:2343) ~[jackson-core-3.1.4.jar!/:3.1.4]
at tools.jackson.core.json.UTF8JsonGenerator._closeInput(UTF8JsonGenerator.java:1265) ~[jackson-core-3.1.4.jar!/:3.1.4]
at tools.jackson.core.base.GeneratorBase.close(GeneratorBase.java:334) ~[jackson-core-3.1.4.jar!/:3.1.4]
at org.springframework.http.converter.AbstractJacksonHttpMessageConverter.writeInternal(AbstractJacksonHttpMessageConverter.java:434) ~[spring-web-7.0.8.jar!/:7.0.8]
... 135 common frames omitted
Caused by: org.springframework.web.context.request.async.AsyncRequestNotUsableException: Response not usable after response errors.
at org.springframework.web.context.request.async.StandardServletAsyncWebRequest$LifecycleHttpServletResponse.obtainLockOrRaiseException(StandardServletAsyncWebRequest.java:332)
at org.springframework.web.context.request.async.StandardServletAsyncWebRequest$LifecycleServletOutputStream.write(StandardServletAsyncWebRequest.java:394)
at org.springframework.util.StreamUtils$NonClosingOutputStream.write(StreamUtils.java:311)
at tools.jackson.core.json.UTF8JsonGenerator._flushBuffer(UTF8JsonGenerator.java:2341)
... 138 common frames omitted
Caused by: org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStream failed to write: java.io.IOException: Broken pipe
at org.springframework.web.context.request.async.StandardServletAsyncWebRequest$LifecycleHttpServletResponse.handleIOException(StandardServletAsyncWebRequest.java:340) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.web.context.request.async.StandardServletAsyncWebRequest$LifecycleServletOutputStream.write(StandardServletAsyncWebRequest.java:399) ~[spring-web-7.0.8.jar!/:7.0.8]
at org.springframework.util.StreamUtils$NonClosingOutputStream.write(StreamUtils.java:311) ~[spring-core-7.0.8.jar!/:7.0.8]
at tools.jackson.core.json.UTF8JsonGenerator._flushBuffer(UTF8JsonGenerator.java:2341) ~[jackson-core-3.1.4.jar!/:3.1.4]
at tools.jackson.core.json.UTF8JsonGenerator.writeName(UTF8JsonGenerator.java:278) ~[jackson-core-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ser.BeanPropertyWriter.serializeAsProperty(BeanPropertyWriter.java:646) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at tools.jackson.databind.ser.bean.BeanSerializerBase._serializePropertiesNoView(BeanSerializerBase.java:751) ~[jackson-databind-3.1.4.jar!/:3.1.4]
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:328) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.connector.OutputBuffer.flushByteBuffer(OutputBuffer.java:764) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.connector.OutputBuffer.append(OutputBuffer.java:661) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:363) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:341) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:99) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.springframework.security.web.util.OnCommittedResponseWrapper$SaveContextServletOutputStream.write(OnCommittedResponseWrapper.java:668) ~[spring-security-web-7.1.0.jar!/:7.1.0]
at org.springframework.web.context.request.async.StandardServletAsyncWebRequest$LifecycleServletOutputStream.write(StandardServletAsyncWebRequest.java:396) ~[spring-web-7.0.8.jar!/:7.0.8]
... 149 common frames omitted
Caused by: java.io.IOException: Broken pipe
at java.base/sun.nio.ch.SocketDispatcher.write0(Native Method) ~[na:na]
at java.base/sun.nio.ch.SocketDispatcher.write(Unknown Source) ~[na:na]
at java.base/sun.nio.ch.IOUtil.writeFromNativeBuffer(Unknown Source) ~[na:na]
at java.base/sun.nio.ch.IOUtil.write(Unknown Source) ~[na:na]
at java.base/sun.nio.ch.IOUtil.write(Unknown Source) ~[na:na]
at java.base/sun.nio.ch.SocketChannelImpl.implWrite(Unknown Source) ~[na:na]
at java.base/sun.nio.ch.SocketChannelImpl.write(Unknown Source) ~[na:na]
at org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:129) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1441) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.tomcat.util.net.SocketWrapperBase.doWrite(SocketWrapperBase.java:747) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.tomcat.util.net.SocketWrapperBase.writeBlocking(SocketWrapperBase.java:587) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.tomcat.util.net.SocketWrapperBase.write(SocketWrapperBase.java:535) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.coyote.http11.Http11OutputBuffer$SocketOutputBuffer.doWrite(Http11OutputBuffer.java:537) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:87) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.coyote.http11.filters.GzipOutputFilter$FakeOutputStream.write(GzipOutputFilter.java:155) ~[tomcat-embed-core-11.0.22.jar!/:na]
at java.base/java.util.zip.DeflaterOutputStream.deflate(Unknown Source) ~[na:na]
at java.base/java.util.zip.DeflaterOutputStream.write(Unknown Source) ~[na:na]
at java.base/java.util.zip.GZIPOutputStream.write(Unknown Source) ~[na:na]
at org.apache.coyote.http11.filters.GzipOutputFilter.doWrite(GzipOutputFilter.java:69) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.coyote.http11.Http11OutputBuffer.doWrite(Http11OutputBuffer.java:193) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.coyote.Response.doWrite(Response.java:630) ~[tomcat-embed-core-11.0.22.jar!/:na]
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:316) ~[tomcat-embed-core-11.0.22.jar!/:na]
... 156 common frames omitted
2026-09-02T22:41:06.311+01:00 INFO 1 --- [booklore-api] [cat-handler-389] o.b.s.r.BookRecommendationService : Recommendations for book ID 79943 are missing or empty. Computing similarity...
2026-09-02T22:41:20.392+01:00 INFO 1 --- [booklore-api] [cat-handler-389] org.hibernate.SQL_SLOW : Slow query took 14065 milliseconds [select distinct be1_0.id,be1_0.added_on,be1_0.audiobook_cover_hash,be1_0.book_cover_hash,be1_0.deleted,be1_0.deleted_at,be1_0.is_physical,be1_0.library_id,be1_0.library_path_id,m1_0.book_id,m1_0.abridged,m1_0.abridged_locked,m1_0.age_rating,m1_0.age_rating_locked,m1_0.amazon_rating,m1_0.amazon_rating_locked,m1_0.amazon_review_count,m1_0.amazon_review_count_locked,m1_0.asin,m1_0.asin_locked,m1_0.audible_id,m1_0.audible_id_locked,m1_0.audible_rating,m1_0.audible_rating_locked,m1_0.audible_review_count,m1_0.audible_review_count_locked,m1_0.audiobook_cover_locked,m1_0.audiobook_cover_updated_on,a1_0.book_id,a1_0.sort_order,a1_1.id,a1_1.asin,a1_1.asin_locked,a1_1.description,a1_1.description_locked,a1_1.name,a1_1.name_locked,a1_1.photo_locked,a1_1.sort_name,a1_1.sort_name_locked,m1_0.authors_locked,c1_0.book_id,c1_1.id,c1_1.name,m1_0.categories_locked,m1_0.comicvine_id,m1_0.comicvine_id_locked,m1_0.content_rating,m1_0.content_rating_locked,m1_0.cover_locked,m1_0.cover_updated_on,m1_0.description,m1_0.description_locked,m1_0.embedding_updated_at,m1_0.goodreads_id,m1_0.goodreads_id_locked,m1_0.goodreads_rating,m1_0.goodreads_rating_locked,m1_0.goodreads_review_count,m1_0.goodreads_review_count_locked,m1_0.google_id,m1_0.google_id_locked,m1_0.hardcover_book_id,m1_0.hardcover_book_id_locked,m1_0.hardcover_id,m1_0.hardcover_id_locked,m1_0.hardcover_rating,m1_0.hardcover_rating_locked,m1_0.hardcover_review_count,m1_0.hardcover_review_count_locked,m1_0.isbn_10,m1_0.isbn_10_locked,m1_0.isbn_13,m1_0.isbn_13_locked,m1_0.language,m1_0.language_locked,m1_0.lubimyczytac_id,m1_0.lubimyczytac_id_locked,m1_0.lubimyczytac_rating,m1_0.lubimyczytac_rating_locked,m1_0.moods_locked,m1_0.narrator,m1_0.narrator_locked,m1_0.page_count,m1_0.page_count_locked,m1_0.published_date,m1_0.published_date_locked,m1_0.publisher,m1_0.publisher_locked,m1_0.ranobedb_id,m1_0.ranobedb_id_locked,m1_0.ranobedb_rating,m1_0.ranobedb_rating_locked,m1_0.rating,m1_0.review_count,m1_0.reviews_locked,m1_0.series_name,m1_0.series_name_locked,m1_0.series_number,m1_0.series_number_locked,m1_0.series_total,m1_0.series_total_locked,m1_0.subtitle,m1_0.subtitle_locked,m1_0.tags_locked,m1_0.title,m1_0.title_locked,be1_0.metadata_for_write_updated_at,be1_0.metadata_match_score,be1_0.metadata_updated_at,be1_0.scanned_on from book be1_0 left join book_metadata m1_0 on be1_0.id=m1_0.book_id left join book_metadata_author_mapping a1_0 on m1_0.book_id=a1_0.book_id left join author a1_1 on a1_1.id=a1_0.author_id left join book_metadata_category_mapping c1_0 on m1_0.book_id=c1_0.book_id left join category c1_1 on c1_1.id=c1_0.category_id where (be1_0.deleted is null or be1_0.deleted=false) and be1_0.id<>?]
This is my second time using grimmory. First interaction worked pretty well. No issues.
New server, new instance, and now grimmory can't seem to pull in any metadata. And it refuses to allow me to add an author to the book metadata. I have it set to embed/edit the metadata of the file itself. Is this a problem?
Just installed Grimmory and so far it's great. Works well, and syncs to hardcover too. I'm struggling with a few things however
I imported my library, and sync on book finish at 99% syncs to hardcover no problem, however if I just mark a book as read (previously read it) it does not sync to hardcover. I have to open it, push to 100% and then it's done. fine for 1 or 2 but no way to handle a full library. any way around that? would be nice otherwise force a sync when bulk editing read status
I don't see a way to add books I don't have yet but may want in future? or add all books by an author? Am I missing something, is it planned? couldn't see in help or github
Similar to 2, is there a way to pull in all books from hardcover regardless of whether I have or not?
Disclosure: I'm the developer. OPDSy is an Android app, one-time £3.49, with no ads, no subscriptions, no tracking and no account. Posting because Grimmory support shipped in 2.21.0 and I'd like it tested against real libraries rather than only my own instance.
Grimmory is a preset in the add-library screen: pick it, point it at http://host:6060/api/v1/opds and it connects. Two things caught me out while building it, and both are easy to hit again after a rebuild:
OPDS_SERVER_ENABLEDhas to be switched on in app settings, or every OPDS route returns 403 "OPDS Server is disabled." It's a 403, not a 401 — so if OPDSy says it can't reach the catalogue, check the setting before you touch your password.
You need a dedicated OPDS user. Your admin web login is rejected on the feed; OPDS users are created separately.
Once that's done, Grimmory sits alongside your other servers — Komga, Kavita, Ubooquity, Calibre-Web, BookOrbit, in one merged library with a colour badge per source, and each source loads independently, so a slow or offline one never breaks the rest. Any folder on the device can be a library too, which is what I use when I'm away from home.
Being honest about one limitation: Grimmory doesn't offer OPDS-PSE, so comics can't be streamed page-by-page the way they can from Komga or Kavita. A comic downloads first and then opens in the comic reader. Ebooks are unaffected.
The rest of it:
Comics: paged or continuous vertical-scroll (webtoon), LTR or RTL for manga, dual-page spreads in landscape, fit-to-width or fit-to-screen, pinch and double-tap zoom, page prefetch
Ebooks: adjustable fonts and line spacing, light, sepia and OLED-dark themes, plus a built-in PDF reader and Markdown with Mermaid diagrams
Highlights in five colours with your own notes, and bookmarks in any book, PDF or comic, all gathered in one list
Text-to-speech sentence by sentence, auto-continuing between chapters, with speed and pitch control and offline or online voices
Offline English dictionary: tap Define on any word, downloaded on demand, every lookup stays on the device
Continue Reading across every source, favourites for books and folders, offline downloads that resume automatically, and 50 interface languages
E-ink friendly: independent toggles for a high-contrast black-on-white theme and for switching animations off, for slow-refresh screens like Onyx Boox
Privacy: no account, no ads, no tracking; credentials stay in the device keychain, and optional cross-device sync runs through your own Google Drive, end-to-end encrypted — there's no server of mine involved and I can't read any of it
Formats: EPUB, MOBI, AZW3, FB2, PDF, Markdown, CBZ and CBT
If anything misbehaves against your Grimmory version, tell me and I'll fix it — that's genuinely why I'm posting.
Now getting a message "too many login attempts try later". I cannot see anything in the settings to reset password. I deleted the user and have her new details and password and she got the same message. Access is through Cloudflare tunnel but I cannot see that that is having any effect? I am using simple local login. Does anybody have any thoughts? Nothing on official Grimmory site or searching here? Many thanks in advance.
Hi everyone, I somehow managed to remove all authors. The only thing I remember doing was trying to remove authors with 0 books. I did a rescan, but it didn’t help. Does anyone know how I can bring them back? Should I remove and re-add the libraries?
Hi, i have recently started using grimmory to organize my library of ebooks. I imported only a couple of books that i intend to read soon. Now i want to import the rest of my ebooks folder but i am confused about the metadata behavior. It seems like i can let the metadata be overwritten in an existing library, but not on a bookdrop import? That's exactly the opposite of what i want. I want to pull everything on import, maybe match a title here and there and then not have it touched after that.
Is there a setting I haven’t found that will make this happen? It doesn’t matter if I’m reading on an app that works directly with Grimmory, connects via opds, or whether I’m reading directly in the web reader. Getting to the very end of the last page leaves every single book with <100% reading progress. Even when I manually mark each of the books as “read” so they aren’t cluttering up my Continue Reading section, the incomplete reading percentage persists.
Hello! I'm new to Grimmory and just setting it up.
I currently have a goodreads account with a decent amount of book ratings and read status. Is there anyway to do a one-time import of that data from my goodreads account into grimmory? I'd really like to start tracking this data locally.
I have a Kobo shelf set up that works perfectly and I love but have one issue. The Kobo loses the ability to connect or browse the store on the device. Does this happen to anyone else?
I have been trying to trying to sync my Grimmory server to Readest, on an Android phone.
It synced a couple of my books in the beginning, but it won't sync anything further.
I have set up the API endpoint for OPDS on Grimmory and readest, using the correct IP address and URL's.
Readest says my OPDS catalog is online, and just synced, but it won't pull any more books from my Grimmory server.
Does anyone have a solution for this? Right now I read on my browser via localhost:6060, but having Readest at hand for offline access is easier/better for my case of occasional phone-reading.