Skip to content

Conversation

@bblhd
Copy link

@bblhd bblhd commented Nov 16, 2025

Closes #10120

This pull request adds support for cover images which can display in the preview of entries. It also allows new entries to automatically download cover images from either "https://bookcover.longitood.com" or "https://covers.openlibrary.org", and preferences to control downloading behaviour. Key changes are:

  • The ability for PreviewViewer to display images
  • A new BookCoverFetcher class to download cover images
  • Hooks in NewEntryViewModel to do cover fetching
  • New options in FilePreferences and LinkedFilesTab

Steps to test

  1. Add a new entry using the ISBN "978-1449310509", if you open the preview for the new entry, the cover image should be visible.
  2. Under File > Preferences, in the Linked Files tab, disable the "Automatically download cover images" setting.
  3. Add a new entry using the ISBN "978-1449373320", there should be no cover image if you open the preview.

Mandatory checks

Images

jabref-book-covers-preview jabref-book-covers-preferences

@github-actions
Copy link
Contributor

Hey @bblhd!

Thank you for contributing to JabRef! Your help is truly appreciated ❤️.

We have automatic checks in place, based on which you will soon get automated feedback if any of them are failing. We also use TragBot with custom rules that scans your changes and provides some preliminary comments, before a maintainer takes a look. TragBot is still learning, and may not always be accurate. In the "Files changed" tab, you can go through its comments and just click on "Resolve conversation" if you are sure that it is incorrect, or comment on the conversation if you are doubtful.

Please re-check our contribution guide in case of any other doubts related to our contribution workflow.

@bblhd
Copy link
Author

bblhd commented Nov 17, 2025

I have attempted to unmodify submodules without success, both in the past and currently, though I was unaware how much of a problem it was.

I've tried all suggested fixes unsuccessfully, either commit ids are not found or the commands have no effect at all. It seems to be something wrong with my version of git or my repository. For context, I'm using git version 2.51.2_1, on linux, with a basic command line and no IDE.

In theory, this could be fixed by creating a new branch and pull request, but the contributors guide specifically requests not to.

Does anyone know how to solve this?

Commit: bb58664
Diffs: csl-locales, csl-styles

@bblhd
Copy link
Author

bblhd commented Nov 17, 2025

I have attempted to unmodify submodules without success, both in the past and currently, though I was unaware how much of a problem it was.

I've tried all suggested fixes unsuccessfully, either commit ids are not found or the commands have no effect at all. It seems to be something wrong with my version of git or my repository. For context, I'm using git version 2.51.2_1, on linux, with a basic command line and no IDE.

In theory, this could be fixed by creating a new branch and pull request, but the contributors guide specifically requests not to.

Does anyone know how to solve this?

Commit: bb58664 Diffs: csl-locales, csl-styles

Fixed this by doing submodule checkout in IntelliJ IDEA, unsure what exactly the issue was, but submodules are now unmodified from main.

@bblhd bblhd force-pushed the feature/book-front-cover-10120 branch from 0b644fd to 2c61ef3 Compare November 17, 2025 13:55
@bblhd
Copy link
Author

bblhd commented Nov 17, 2025

I apologise for force pushing, the only difference was a single incorrect author email in the previous commit I pushed.

@InAnYan
Copy link
Member

InAnYan commented Nov 17, 2025

Hi, bblhd! Thank you for looking into this feature. This is a very good issue for the first contribution!

Copy link
Member

@koppor koppor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understood:

  1. The approach only supports isbn-based pictures (which is OK)
  2. All files are named isbn-xyz
  3. Covers are only downloaded for new entries
  4. Covers are attached to an entry - and thus displayed as attached file in the main table
  5. Existing covers are not re-used across different libraries (unless the configured directories match)

I think step 4 is a really big issue and hampering usability of JabRef. I cannot open an attached PDF any more with a single click.


For this PR, I propose a radical different approach:

  1. Add method getCoverDirectory to org.jabref.logic.util.Directories
  2. Store all covers there
  3. Lookup covers there

No storing in BibEntry any more.

Just using ISBN and that directory for lookup

No re-download if cover already exists.

Reasons:

  • ISBN and DOIs are unique identifiers of papers. The links are implicit and do not need to be written down explicitly. (Because these are more technical things and a user seldomly interacts with the covers; in comparison to PDF files, which also could be stored using the DOI as name, but users tend to use more self-descriptive names).
  • Collecting all cover images in a single directory allows for seamless use across multiple bib files and I want to have the images displayed in all .bib files without the need to modify it. It should be "knob-less"
  • I as researcher have 100+ different bib files. I do not want to swamp colleague's libraries with images

Alternatives

  • One could introduce another field coverimage with a link. But then, we are back in the old days with pdf, ps fields, which we migrated away
  • One could add explicit handling in the main table to NOT show #cover links... This seems to be too much code there

  • Moreover, there should be a button next to the ISBN field to download the cover image if it does not exist. (This can be done in a follow-up, but we should be aware)

if (link.isEmpty()) {
when(filePreferences.getFileNamePattern()).thenReturn("[bibtexkey]");
} else {
when(filePreferences.getFileNamePattern()).thenReturn("[bibtexkey] - [title]");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is lost. I don't know the intention written here, but there is a test of an empty link - and then [title] is expected -- maybe, this is very strange and can really be removed, but we need to think :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To my understanding, in the previous version, when the test was successful the pattern was only used if the link was empty, so "[bibtexkey] - [title]", the default filename pattern, was used otherwise.

Comment on lines 366 to 368
if ("default".equals(fileNamePattern.trim())) {
return Optional.empty();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, there is a misunderstanding of the existing code. If there is NO target name generated and NO citation key generated THEN Optional.empty is returned.

Please keep this behavior and do not change it without reason! There is NEVER passed default as fileNamePattern...

Revert the changes in this method.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a specific test that when "default" is passed as pattern, then it should return Optional.empty. I thought this might've an over-fitted test case, but I wasn't sure, should I remove it as well?

""".formatted(text);
<html>
<body id="previewBody">
%s <div id="content"> %s </div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is OK for a quick hack.

One should introduce a LayoutFormatter here. And then use \begin{file}\format[CoverImage}\end{file}.

The default preview style needs to be adapted accordingly.

Not sure whether we should make exceptions of the general preview handling for this because of images. @InAnYan

// matches images that are either named according to the preferred file name format
// or images with case-insensitive "[cover]" in their description, to allow using any image regardless of name

if (file.getDescription().toLowerCase().contains("[cover]") || isFileTypeAValidCoverImage(file.getFileType()) && (FileUtil.getBaseName(file.getFileName()).equals(nameFromFormat))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tags are normally starting with #. I would prefer #cover. WDYT @InAnYan ?

@github-actions github-actions bot added the status: changes-required Pull requests that are not yet complete label Nov 20, 2025
@bblhd
Copy link
Author

bblhd commented Nov 20, 2025

I understood:

1. The approach only supports isbn-based pictures (which is OK)

2. All files are named `isbn-xyz`

3. Covers are only downloaded for new entries

4. **Covers are attached to an entry - and thus displayed as attached file in the main table**

5. Existing covers are not re-used across different libraries (unless the configured directories match)

I think step 4 is a really big issue and hampering usability of JabRef. I cannot open an attached PDF any more with a single click.

For this PR, I propose a radical different approach:

1. Add method `getCoverDirectory` to org.jabref.logic.util.Directories

2. Store all covers there

3. Lookup covers there

No storing in BibEntry any more.

Just using ISBN and that directory for lookup

No re-download if cover already exists.

Thank you for the thorough review, it is very much appreciated.

Seperating book covers from attached files is a good idea, my current method was based off of previous attempts and what I understood of the codebase at the time, but its flaws became more obvious as I worked on it and understood more of the way that JabRef is actually used. I was considering this type of approach, so confirmation and details is helpful, I will be implementing seperate covers going forward.

…java

Co-authored-by: Oliver Kopp <kopp.dev@gmail.com>
@github-actions github-actions bot removed the status: changes-required Pull requests that are not yet complete label Nov 20, 2025
@koppor
Copy link
Member

koppor commented Nov 20, 2025

Seperating book covers from attached files is a good idea, my current method was based off of previous attempts and what I understood of the codebase at the time, but its flaws became more obvious as I worked on it and understood more of the way that JabRef is actually used. I was considering this type of approach, so confirmation and details is helpful, I will be implementing seperate covers going forward.

Nice! - Yeah, we are hitting the trade-off between 100% crisp requirements (causing much time) and implementing a solution and needed to change based on feedback. -- Its always easier to see something when it is "tangible" than when it is written somehow vaguely.

Thank you for the endurance!


If you want, you can write down an ADR (docs/decisions), because you know have material for both options.

Comment on lines 57 to 62
if (isbn.isPresent()) {
final String name = "isbn-" + isbn.asString();
final String name = "isbn-" + isbn.get().asString();
if (findExistingImage(name, directory).isEmpty()) {
final String url = getSourceForIsbn(isbn);
final String url = getSourceForIsbn(isbn.get());
Optional<LinkedFile> file = downloadCoverImage(url, name, directory);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please get used to .map for optionals. At the end, you can do forEach as you don't need the resulting downloaded file at this place.

@jabref-machine
Copy link
Collaborator

JUnit tests of jablib are failing. You can see which checks are failing by locating the box "Some checks were not successful" on the pull request page. To see the test output, locate "Source Code Tests / Unit tests (pull_request)" and click on it.

You can then run these tests in IntelliJ to reproduce the failing tests locally. We offer a quick test running howto in the section Final build system checks in our setup guide.

@koppor koppor added the status: changes-required Pull requests that are not yet complete label Nov 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

first contrib status: changes-required Pull requests that are not yet complete

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feature request: book front cover feature

5 participants