Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bb4aa8c
Add CBL reading list parser
bsavage81 Sep 1, 2026
4274f51
Implement CBL reading list parser
bsavage81 Sep 1, 2026
2f96f8c
Add CBL import action declaration
bsavage81 Sep 1, 2026
c65950d
Add CBL import coordinator slot
bsavage81 Sep 1, 2026
4b3f858
Add initial CBL import preview
bsavage81 Sep 1, 2026
db1a22f
Make CBL parser header-only for initial integration
bsavage81 Sep 1, 2026
da8d7c3
Remove standalone CBL parser source for initial integration
bsavage81 Sep 1, 2026
e0809a4
Expose Phase 1 CBL importer with application shortcut
bsavage81 Sep 1, 2026
b3b07cb
Expose library database path for CBL matching
bsavage81 Sep 1, 2026
57d4618
Add native CBL matching preview against library metadata
bsavage81 Sep 1, 2026
64a75ea
Add transactional CBL reading list import storage
bsavage81 Sep 2, 2026
434564b
Fix folder grid delegate bindings on newer Qt
bsavage81 Sep 2, 2026
4dc9cc0
Revert folder delegate bound behavior experiment
bsavage81 Sep 2, 2026
6c6d732
Fix MSVC manifest embedding for Qt 6.9 builds
bsavage81 Sep 2, 2026
1f65ff3
Fix embedded manifest for library server
bsavage81 Sep 2, 2026
9067daf
Use CMake manifest source handling on Windows
bsavage81 Sep 2, 2026
84df14f
Use CMake manifest source handling for library server
bsavage81 Sep 2, 2026
07e7020
Add CBL reading list import and smart lists
bsavage81 Sep 11, 2026
120ee49
Make imported reading lists editable
bsavage81 Sep 17, 2026
6883b28
Allow removing comics from imported reading lists
bsavage81 Sep 17, 2026
27291e2
Update imported reading list icon
bsavage81 Sep 17, 2026
b6dc977
Match imported list icon details to list styling
bsavage81 Sep 17, 2026
e489dd0
Avoid relinking reading lists during load
bsavage81 Sep 17, 2026
8108e62
Match missing list warning to report logic
bsavage81 Sep 17, 2026
5f846c2
Show progress while rematching missing comics
bsavage81 Sep 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions YACReader/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,10 @@ target_link_libraries(YACReader PRIVATE

# Platform-specific
if(WIN32)
target_sources(YACReader PRIVATE icon.rc)
if(MSVC)
target_link_options(YACReader PRIVATE "/MANIFESTINPUT:${PROJECT_SOURCE_DIR}/cmake/windows/yacreader.manifest")
endif()
target_sources(YACReader PRIVATE
icon.rc
${PROJECT_SOURCE_DIR}/cmake/windows/yacreader.manifest
)
target_link_libraries(YACReader PRIVATE oleaut32 ole32 shell32 user32)
endif()

Expand Down Expand Up @@ -309,4 +309,4 @@ if(UNIX AND NOT APPLE)
install(FILES
"${PROJECT_SOURCE_DIR}/YACReader.svg"
DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps)
endif()
endif()
9 changes: 5 additions & 4 deletions YACReaderLibrary/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ set(yacreaderlibrary_image_files
${PROJECT_SOURCE_DIR}/images/lists/default_0.svg
${PROJECT_SOURCE_DIR}/images/lists/default_1.svg
${PROJECT_SOURCE_DIR}/images/lists/default_2.svg
${PROJECT_SOURCE_DIR}/images/lists/imported.svg
${PROJECT_SOURCE_DIR}/images/lists/label_template.svg
${PROJECT_SOURCE_DIR}/images/lists/list.svg
${PROJECT_SOURCE_DIR}/images/clearSearchNew.svg
Expand Down Expand Up @@ -577,10 +578,10 @@ endif()

# Platform-specific
if(WIN32)
target_sources(YACReaderLibrary PRIVATE icon.rc)
if(MSVC)
target_link_options(YACReaderLibrary PRIVATE "/MANIFESTINPUT:${PROJECT_SOURCE_DIR}/cmake/windows/yacreader.manifest")
endif()
target_sources(YACReaderLibrary PRIVATE
icon.rc
${PROJECT_SOURCE_DIR}/cmake/windows/yacreader.manifest
)
target_link_libraries(YACReaderLibrary PRIVATE oleaut32 ole32 shell32 user32)
endif()

Expand Down
128 changes: 128 additions & 0 deletions YACReaderLibrary/cbl_reader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#ifndef CBL_READER_H
#define CBL_READER_H

#include <QFile>
#include <QFileInfo>
#include <QList>
#include <QString>
#include <QXmlStreamReader>

struct CblBook
{
QString series;
QString number;
QString volume;
QString year;
QString format;
QString fileName;
QString id;
QString comicVineSeriesId;
QString comicVineIssueId;
int ordering = 0;
};

struct CblReadingList
{
QString name;
QList<CblBook> books;
};

struct CblReadResult
{
bool success = false;
CblReadingList readingList;
QString errorMessage;
qint64 errorLine = 0;
qint64 errorColumn = 0;
};

class CblReader
{
public:
static CblReadResult read(const QString &filePath)
{
CblReadResult result;

QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
result.errorMessage = file.errorString();
return result;
}

QXmlStreamReader xml(&file);
bool foundReadingList = false;
int ordering = 0;

while (!xml.atEnd()) {
xml.readNext();

if (!xml.isStartElement())
continue;

if (!foundReadingList) {
if (xml.name() != QLatin1String("ReadingList")) {
result.errorMessage = QStringLiteral("The selected file is not a CBL reading list.");
return result;
}
foundReadingList = true;
continue;
}

if (xml.name() == QLatin1String("Name")) {
result.readingList.name = xml.readElementText().trimmed();
} else if (xml.name() == QLatin1String("Book")) {
const auto attributes = xml.attributes();

CblBook book;
book.series = attributes.value(QLatin1String("Series")).toString().trimmed();
book.number = attributes.value(QLatin1String("Number")).toString().trimmed();
book.volume = attributes.value(QLatin1String("Volume")).toString().trimmed();
book.year = attributes.value(QLatin1String("Year")).toString().trimmed();
book.format = attributes.value(QLatin1String("Format")).toString().trimmed();
book.ordering = ordering++;

while (!(xml.isEndElement() && xml.name() == QLatin1String("Book")) && !xml.atEnd()) {
xml.readNext();
if (!xml.isStartElement())
continue;

if (xml.name() == QLatin1String("Id")) {
book.id = xml.readElementText().trimmed();
} else if (xml.name() == QLatin1String("FileName")) {
book.fileName = xml.readElementText().trimmed();
} else if (xml.name() == QLatin1String("Database")) {
const auto databaseAttributes = xml.attributes();
const auto databaseName = databaseAttributes.value(QLatin1String("Name")).toString().trimmed();
if (databaseName.compare(QLatin1String("cv"), Qt::CaseInsensitive) == 0
|| databaseName.compare(QLatin1String("comicvine"), Qt::CaseInsensitive) == 0) {
book.comicVineSeriesId = databaseAttributes.value(QLatin1String("Series")).toString().trimmed();
book.comicVineIssueId = databaseAttributes.value(QLatin1String("Issue")).toString().trimmed();
}
}
}

result.readingList.books.append(book);
}
}

if (xml.hasError()) {
result.errorMessage = xml.errorString();
result.errorLine = xml.lineNumber();
result.errorColumn = xml.columnNumber();
return result;
}

if (!foundReadingList) {
result.errorMessage = QStringLiteral("The selected file does not contain a ReadingList element.");
return result;
}

if (result.readingList.name.isEmpty())
result.readingList.name = QFileInfo(filePath).completeBaseName();

result.success = true;
return result;
}
};

#endif // CBL_READER_H
Loading
Loading