-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Suggestions: show annotation in FM on long tap #5956
Comments
What do you call "a book's annotation"? Bookmarks/highlights you made, or the book description/metadata? |
The book’s short description. In fb2 books it is usually enclosed in tag somewhere in the beginning of the XML. |
For EPUB, you have it: long-press > Book information - or if you have any of the CoverBrowser mode: long-press > View book description directly (and among its option, you can set it to show an indicator, a small rectangle poping out on the right of the cover, for book that have a description). |
Unfortunately, for fb2 we have very short information. |
'Annotation' field is shown in the beginning of the book. Other fields (such as 'translator') are hidden by fb2.fss default settings. |
That's what we fetch and fill for EPUB: https://github.com/koreader/crengine/blob/c1700e3798d2563123b303485f3bcb340017f66b/crengine/src/epubfmt.cpp#L782-L827 That's what we fetch and fill for FB2 (and other formats that are parsed and made to look like a FB2 XML tree): So, we have the 2 slots we added for EPUBs (and didn't bother filling for other formats): "keywords" and "description" - that we could fill from FB2 fields, possibly multiple if we concatenate them. If you don't write C and can't tackle it yourself, I'm gonna need you to do the thinking :) and give me some pseudocode about what to parse, and what to put in which field, and in which order, and if they can be zero, 1 or more occurence, like: |
Also I think references to the relevant spec are always helpful. ;-) |
I meant a reference to the specific relevant section the way I did, not "the spec" as some abstract entity. ;-) (Although that too can be useful.) In this case, presumably http://www.fictionbook.org/index.php/%D0%AD%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82_annotation So that someone reading doesn't have to waste time trying to find that, even if it doesn't take long. |
I am not sure my writings are useful, anyway, I would be happy to see the following information from fb2 description section as Book information:
|
Regarding /FictionBook/description/title-info/annotation. |
Thanks for that reference.
We already have that for any long metadata (that gets a truncation ellipsis So, the length is not an issue. What's less complicated would be to merge/concatenate the metadata you list into the ones we already have:
with, possibly, no prefix to tell what they are (because of translations, unless you (and @Frenzie :) are fine with having them in english). Note that this little indicator tells you that the book has a "Description": |
It would be perfect. |
You can probably still concat translations? |
That would be build (annotation + publisher name + publisher city + ...) by crengine, and given to frontend as a single string: koreader/frontend/apps/filemanager/filemanagerbookinfo.lua Lines 173 to 184 in 4a5a2eb
I really don't want to have to put some tags ( |
Eh, should be fine. |
OK, pasting some code, that should hopefully be readable by non-programmers. lString16 extractDocKeywords( ldomDocument * doc )
{
lString16 res;
// Year
res << doc->createXPointer(L"/FictionBook/description/title-info/date").getText().trim();
// Genres
for ( int i=0; i<16; i++) {
lString16 path = cs16("/FictionBook/description/title-info/genre[") + fmt::decimal(i+1) + "]";
ldomXPointer genre = doc->createXPointer(path);
if ( !genre ) {
break;
}
if ( !res.empty() )
res << "\n";
res << genre.getText().trim();
}
return res;
}
lString16 extractDocDescription( ldomDocument * doc )
{
// We put all other FB2 meta info in this description
lString16 res;
// Annotation (description)
res << doc->createXPointer(L"/FictionBook/description/title-info/annotation").getText().trim();
// Translators
lString16 translators;
int nbTranslators = 0;
for ( int i=0; i<16; i++) {
lString16 path = cs16("/FictionBook/description/title-info/translator[") + fmt::decimal(i+1) + "]";
ldomXPointer ptranslator = doc->createXPointer(path);
if ( !ptranslator ) {
break;
}
lString16 firstName = ptranslator.relative( L"/first-name" ).getText().trim();
lString16 lastName = ptranslator.relative( L"/last-name" ).getText().trim();
lString16 middleName = ptranslator.relative( L"/middle-name" ).getText().trim();
lString16 translator = firstName;
if ( !translator.empty() )
translator += " ";
if ( !middleName.empty() )
translator += middleName;
if ( !lastName.empty() && !translator.empty() )
translator += " ";
translator += lastName;
if ( !translators.empty() )
translators << "\n";
translators << translator;
nbTranslators++;
}
if ( !translators.empty() ) {
if ( !res.empty() )
res << "\n\n";
if ( nbTranslators > 1 )
res << "Translators:\n" << translators;
else
res << "Translator: " << translators;
}
// Publication info & publisher
ldomXPointer publishInfo = doc->createXPointer(L"/FictionBook/description/publish-info");
if ( !publishInfo.isNull() ) {
lString16 publisher = publishInfo.relative( L"/publisher" ).getText().trim();
lString16 pubcity = publishInfo.relative( L"/city" ).getText().trim();
lString16 pubyear = publishInfo.relative( L"/year" ).getText().trim();
lString16 isbn = publishInfo.relative( L"/isbn" ).getText().trim();
lString16 bookName = publishInfo.relative( L"/book-name" ).getText().trim();
lString16 publication;
if ( !publisher.empty() || !pubcity.empty() ) {
if ( !publisher.empty() ) {
publication << publisher;
}
if ( !pubcity.empty() ) {
if ( !!publisher.empty() ) {
publication << ", ";
}
publication << pubcity;
}
}
if ( !pubyear.empty() || !isbn.empty() ) {
if ( !publication.empty() )
publication << "\n";
if ( !pubyear.empty() ) {
publication << pubyear;
}
if ( !isbn.empty() ) {
if ( !pubyear.empty() ) {
publication << ", ";
}
publication << isbn;
}
}
if ( !bookName.empty() ) {
if ( !publication.empty() )
publication << "\n";
publication << bookName;
}
if ( !publication.empty() ) {
if ( !res.empty() )
res << "\n\n";
res << "Publication:\n" << publication;
}
}
// Document info
ldomXPointer pDocInfo = doc->createXPointer(L"/FictionBook/description/document-info");
if ( !pDocInfo.isNull() ) {
lString16 docInfo;
lString16 docAuthors;
int nbAuthors = 0;
for ( int i=0; i<16; i++) {
lString16 path = cs16("/FictionBook/description/document-info/author[") + fmt::decimal(i+1) + "]";
ldomXPointer pdocAuthor = doc->createXPointer(path);
if ( !pdocAuthor ) {
break;
}
lString16 firstName = pdocAuthor.relative( L"/first-name" ).getText().trim();
lString16 lastName = pdocAuthor.relative( L"/last-name" ).getText().trim();
lString16 middleName = pdocAuthor.relative( L"/middle-name" ).getText().trim();
lString16 docAuthor = firstName;
if ( !docAuthor.empty() )
docAuthor += " ";
if ( !middleName.empty() )
docAuthor += middleName;
if ( !lastName.empty() && !docAuthor.empty() )
docAuthor += " ";
docAuthor += lastName;
if ( !docAuthors.empty() )
docAuthors << "\n";
docAuthors << docAuthor;
nbAuthors++;
}
if ( !docAuthors.empty() ) {
if ( nbAuthors > 1 )
docInfo << "Authors:\n" << docAuthors;
else
docInfo << "Author: " << docAuthors;
}
lString16 docPublisher = pDocInfo.relative( L"/publisher" ).getText().trim();
lString16 docId = pDocInfo.relative( L"/id" ).getText().trim();
lString16 docVersion = pDocInfo.relative( L"/version" ).getText().trim();
lString16 docDate = pDocInfo.relative( L"/date" ).getText().trim();
lString16 docHistory = pDocInfo.relative( L"/history" ).getText().trim();
lString16 docSrcUrl = pDocInfo.relative( L"/src-url" ).getText().trim();
lString16 docSrcOcr = pDocInfo.relative( L"/src-ocr" ).getText().trim();
lString16 docProgramUsed = pDocInfo.relative( L"/program-used" ).getText().trim();
if ( !docPublisher.empty() ) {
if ( !docInfo.empty() )
docInfo << "\n";
docInfo << "Publisher: " << docPublisher;
}
if ( !docId.empty() ) {
if ( !docInfo.empty() )
docInfo << "\n";
docInfo << "Id: " << docId;
}
if ( !docVersion.empty() ) {
if ( !docInfo.empty() )
docInfo << "\n";
docInfo << "Version: " << docVersion;
}
if ( !docDate.empty() ) {
if ( !docInfo.empty() )
docInfo << "\n";
docInfo << "Date: " << docDate;
}
if ( !docHistory.empty() ) {
if ( !docInfo.empty() )
docInfo << "\n";
docInfo << "History: " << docHistory;
}
if ( !docSrcUrl.empty() ) {
if ( !docInfo.empty() )
docInfo << "\n";
docInfo << "Url: " << docSrcUrl;
}
if ( !docSrcOcr.empty() ) {
if ( !docInfo.empty() )
docInfo << "\n";
docInfo << "OCR: " << docSrcOcr;
}
if ( !docProgramUsed.empty() ) {
if ( !docInfo.empty() )
docInfo << "\n";
docInfo << "Program: " << docProgramUsed;
}
if ( !docInfo.empty() ) {
if ( !res.empty() )
res << "\n\n";
res << "Document:\n" << docInfo;
}
}
return res;
} |
It's the best decision I dreamt of.
|
We have a field already named "keywords", and it will stay displayed "Keywords". I can put small stuff in it, or let it blank. But I guess it's good to put the date in it (and first), so you see it without having to open Description. The "genre" small words will be in there too, because they are there for other formats (would be strange to drop them for FB2 only). We have these fields Keywords and Description because some other book formats have slots for them (both PDF & EPUB). FB2 has a lot more metadata, but adding new fields is tedious (I don't want to add new columns in the cache database...), and these would be empty for most other book formats).
At least, its first words tell you if it is in a language you can read :) |
Thank you, I like it very much. |
This is great! Thank you for your kind consideration! |
Seems fine. Btw, I think PDF calls the program used the creator. |
My Acrobat Reader uses "Application", which feels a bit less rough than "program". |
Either way, it's a difference without distinction. An application is a program. A program is an application. Application's more French/Latin, program's more Greek. |
v2020.03.2-16 |
One more point: Book information for .fb2.zip shows Format: ZIP. |
It would be nice if there was an option to read a book's annotation (for epub, fb2 at least) via File Manager's long tap on a book. It would make it easier to choose a book without opening and rendering it.
What do you think guys?
The text was updated successfully, but these errors were encountered: