Implement loading chapters from mpeg files
This commit is contained in:
parent
4c73f1c71c
commit
044dbf5f23
@ -36,6 +36,7 @@ ecm_setup_version(${PROJECT_VERSION}
|
|||||||
|
|
||||||
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Quick Test Gui QuickControls2 Sql Multimedia)
|
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Quick Test Gui QuickControls2 Sql Multimedia)
|
||||||
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS CoreAddons Syndication Config I18n)
|
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS CoreAddons Syndication Config I18n)
|
||||||
|
find_package(Taglib REQUIRED)
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Svg)
|
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Svg)
|
||||||
|
@ -18,6 +18,7 @@ Note: When using versions of kasts built from git-master, it's possible that the
|
|||||||
- KConfig
|
- KConfig
|
||||||
- Kirigami
|
- Kirigami
|
||||||
- Syndication
|
- Syndication
|
||||||
|
- TagLib
|
||||||
|
|
||||||
## Linux
|
## Linux
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ add_executable(kasts ${SRCS})
|
|||||||
kconfig_add_kcfg_files(kasts settingsmanager.kcfgc GENERATE_MOC)
|
kconfig_add_kcfg_files(kasts settingsmanager.kcfgc GENERATE_MOC)
|
||||||
|
|
||||||
target_include_directories(kasts PRIVATE ${CMAKE_BINARY_DIR})
|
target_include_directories(kasts PRIVATE ${CMAKE_BINARY_DIR})
|
||||||
target_link_libraries(kasts PRIVATE Qt::Core Qt::Qml Qt::Quick Qt::QuickControls2 Qt::Sql Qt::Multimedia KF5::Syndication KF5::CoreAddons KF5::ConfigGui KF5::I18n)
|
target_link_libraries(kasts PRIVATE Qt::Core Qt::Qml Qt::Quick Qt::QuickControls2 Qt::Sql Qt::Multimedia KF5::Syndication KF5::CoreAddons KF5::ConfigGui KF5::I18n Taglib::Taglib)
|
||||||
|
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
target_link_libraries(kasts PRIVATE
|
target_link_libraries(kasts PRIVATE
|
||||||
|
@ -7,9 +7,12 @@
|
|||||||
#include "models/chaptermodel.h"
|
#include "models/chaptermodel.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QMimeDatabase>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QSqlQuery>
|
#include <QSqlQuery>
|
||||||
|
|
||||||
|
#include <taglib/chapterframe.h>
|
||||||
|
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
|
||||||
ChapterModel::ChapterModel(QObject *parent)
|
ChapterModel::ChapterModel(QObject *parent)
|
||||||
@ -69,15 +72,24 @@ QString ChapterModel::enclosureId() const
|
|||||||
void ChapterModel::setEnclosureId(QString newEnclosureId)
|
void ChapterModel::setEnclosureId(QString newEnclosureId)
|
||||||
{
|
{
|
||||||
m_enclosureId = newEnclosureId;
|
m_enclosureId = newEnclosureId;
|
||||||
loadFromDatabase();
|
load();
|
||||||
Q_EMIT enclosureIdChanged();
|
Q_EMIT enclosureIdChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChapterModel::loadFromDatabase()
|
void ChapterModel::load()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
||||||
m_chapters = {};
|
m_chapters = {};
|
||||||
|
loadFromDatabase();
|
||||||
|
if (m_chapters.isEmpty()) {
|
||||||
|
loadChaptersFromFile();
|
||||||
|
}
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChapterModel::loadFromDatabase()
|
||||||
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare(QStringLiteral("SELECT * FROM Chapters WHERE id=:id"));
|
query.prepare(QStringLiteral("SELECT * FROM Chapters WHERE id=:id"));
|
||||||
query.bindValue(QStringLiteral(":id"), enclosureId());
|
query.bindValue(QStringLiteral(":id"), enclosureId());
|
||||||
@ -90,6 +102,48 @@ void ChapterModel::loadFromDatabase()
|
|||||||
chapter.start = query.value(QStringLiteral("start")).toInt();
|
chapter.start = query.value(QStringLiteral("start")).toInt();
|
||||||
m_chapters << chapter;
|
m_chapters << chapter;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
endResetModel();
|
|
||||||
|
void ChapterModel::loadMPEGChapters(TagLib::MPEG::File &f)
|
||||||
|
{
|
||||||
|
if (!f.hasID3v2Tag()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const auto &frame : f.ID3v2Tag()->frameListMap()["CHAP"]) {
|
||||||
|
auto chapterFrame = dynamic_cast<TagLib::ID3v2::ChapterFrame *>(frame);
|
||||||
|
|
||||||
|
ChapterEntry chapter{};
|
||||||
|
chapter.title = QString::fromStdString(chapterFrame->embeddedFrameListMap()["TIT2"].front()->toString().to8Bit(true));
|
||||||
|
chapter.link = QString();
|
||||||
|
chapter.image = QString();
|
||||||
|
chapter.start = chapterFrame->startTime() / 1000;
|
||||||
|
m_chapters << chapter;
|
||||||
|
}
|
||||||
|
std::sort(m_chapters.begin(), m_chapters.end(), [](const ChapterEntry &a, const ChapterEntry &b) {
|
||||||
|
return a.start < b.start;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChapterModel::loadChaptersFromFile()
|
||||||
|
{
|
||||||
|
if (m_enclosurePath.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto mime = QMimeDatabase().mimeTypeForFile(m_enclosurePath).name();
|
||||||
|
if (mime == QStringLiteral("audio/mpeg")) {
|
||||||
|
TagLib::MPEG::File f(m_enclosurePath.toLatin1().data());
|
||||||
|
loadMPEGChapters(f);
|
||||||
|
} // TODO else...
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChapterModel::setEnclosurePath(const QString &enclosurePath)
|
||||||
|
{
|
||||||
|
m_enclosurePath = enclosurePath;
|
||||||
|
Q_EMIT enclosureIdChanged();
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ChapterModel::enclosurePath() const
|
||||||
|
{
|
||||||
|
return m_enclosurePath;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#include <KFormat>
|
#include <KFormat>
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
#include <taglib/mpegfile.h>
|
||||||
|
|
||||||
struct ChapterEntry {
|
struct ChapterEntry {
|
||||||
QString title;
|
QString title;
|
||||||
QString link;
|
QString link;
|
||||||
@ -21,6 +23,7 @@ class ChapterModel : public QAbstractListModel
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(QString enclosureId READ enclosureId WRITE setEnclosureId NOTIFY enclosureIdChanged)
|
Q_PROPERTY(QString enclosureId READ enclosureId WRITE setEnclosureId NOTIFY enclosureIdChanged)
|
||||||
|
Q_PROPERTY(QString enclosurePath READ enclosurePath WRITE setEnclosurePath NOTIFY enclosurePathChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum RoleNames {
|
enum RoleNames {
|
||||||
@ -40,13 +43,21 @@ public:
|
|||||||
void setEnclosureId(QString newEnclosureId);
|
void setEnclosureId(QString newEnclosureId);
|
||||||
QString enclosureId() const;
|
QString enclosureId() const;
|
||||||
|
|
||||||
|
void setEnclosurePath(const QString &enclosurePath);
|
||||||
|
QString enclosurePath() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void enclosureIdChanged();
|
void enclosureIdChanged();
|
||||||
|
void enclosurePathChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void load();
|
||||||
void loadFromDatabase();
|
void loadFromDatabase();
|
||||||
|
void loadChaptersFromFile();
|
||||||
|
void loadMPEGChapters(TagLib::MPEG::File &f);
|
||||||
|
|
||||||
QString m_enclosureId;
|
QString m_enclosureId;
|
||||||
QVector<ChapterEntry> m_chapters;
|
QVector<ChapterEntry> m_chapters;
|
||||||
KFormat m_kformat;
|
KFormat m_kformat;
|
||||||
|
QString m_enclosurePath;
|
||||||
};
|
};
|
||||||
|
@ -97,6 +97,7 @@ Kirigami.ScrollablePage {
|
|||||||
Layout.bottomMargin: Kirigami.Units.gridUnit
|
Layout.bottomMargin: Kirigami.Units.gridUnit
|
||||||
model: ChapterModel {
|
model: ChapterModel {
|
||||||
enclosureId: entry.id
|
enclosureId: entry.id
|
||||||
|
enclosurePath: entry.enclosure.path
|
||||||
}
|
}
|
||||||
delegate: ChapterListDelegate {
|
delegate: ChapterListDelegate {
|
||||||
entry: page.entry
|
entry: page.entry
|
||||||
|
@ -123,6 +123,7 @@ Kirigami.Page {
|
|||||||
id: chapterList
|
id: chapterList
|
||||||
model: ChapterModel {
|
model: ChapterModel {
|
||||||
enclosureId: AudioManager.entry.id
|
enclosureId: AudioManager.entry.id
|
||||||
|
enclosurePath: AudioManager.entry.enclosure.path
|
||||||
}
|
}
|
||||||
clip: true
|
clip: true
|
||||||
visible: chapterList.count !== 0
|
visible: chapterList.count !== 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user