Commit 043cb8bc authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

Add chapter support.

Chapters are not yet analyzed or inserted by the medialibrary, but the
entity type is now supported.
refs #52
parent 8d54cd22
......@@ -24,6 +24,7 @@ libmedialibrary_la_HEADERS = \
include/medialibrary/IAlbumTrack.h \
include/medialibrary/IArtist.h \
include/medialibrary/IAudioTrack.h \
include/medialibrary/IChapter.h \
include/medialibrary/IFile.h \
include/medialibrary/IGenre.h \
include/medialibrary/ILabel.h \
......@@ -67,6 +68,7 @@ libmedialibrary_la_SOURCES = \
src/Device.cpp \
src/Factory.cpp \
src/File.cpp \
src/Chapter.cpp \
src/Folder.cpp \
src/Genre.cpp \
src/Label.cpp \
......@@ -141,6 +143,7 @@ noinst_HEADERS = \
src/filesystem/unix/DeviceLister.h \
src/filesystem/win32/Directory.h \
src/filesystem/win32/File.h \
src/Chapter.h \
src/Folder.h \
src/Genre.h \
src/Label.h \
......@@ -301,6 +304,7 @@ unittest_SOURCES = \
test/unittest/AlbumTrackTests.cpp \
test/unittest/ArtistTests.cpp \
test/unittest/AudioTrackTests.cpp \
test/unittest/ChapterTests.cpp \
test/unittest/DeviceTests.cpp \
test/unittest/FileTests.cpp \
test/unittest/FolderTests.cpp \
......
/*****************************************************************************
* Media Library
*****************************************************************************
* Copyright (C) 2018 Hugo Beauzée-Luyssen, Videolabs
*
* Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#pragma once
#include <string>
namespace medialibrary
{
class IChapter
{
public:
virtual ~IChapter() = default;
/**
* @brief name Returns the chapter name
*/
virtual const std::string& name() const = 0;
/**
* @brief offset Returns the offset from the start of the media in seconds
*/
virtual int64_t offset() const = 0;
/**
* @brief duration Returns the duration of this chapter in seconds
*/
virtual int64_t duration() const = 0;
};
}
......@@ -36,6 +36,7 @@ class IAlbumTrack;
class IShowEpisode;
class ITrackInformation;
class IMetadata;
struct QueryParameters;
class IMedia
{
......@@ -159,6 +160,16 @@ class IMedia
virtual Query<IAudioTrack> audioTracks() const = 0;
virtual Query<ISubtitleTrack> subtitleTracks() const = 0;
///
/// \brief chapters Returns the chapters for this media, if any
///
/// For this query, the default sorting parameter is by chapter offset.
/// Supported criteria are: Alpha, Duration, Default.
/// Any other criteria will fallback to default.
/// Default order for duration is from longer to shorter.
/// Passing desc = true will invert this default.
///
virtual Query<IChapter> chapters( const QueryParameters* params ) const = 0;
///
/// \brief thumbnail Returns the path of a thumbnail for this media
/// \return A path, relative to the thumbnailPath configured when initializing
/// The media library
......
......@@ -30,6 +30,7 @@ namespace medialibrary
class IAlbum;
class IAlbumTrack;
class IAudioTrack;
class IChapter;
class IFile;
class IGenre;
class IMedia;
......
/*****************************************************************************
* Media Library
*****************************************************************************
* Copyright (C) 2018 Hugo Beauzée-Luyssen, Videolabs
*
* Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "Chapter.h"
#include "database/SqliteTools.h"
#include "database/SqliteQuery.h"
#include "Media.h"
namespace medialibrary
{
const std::string Chapter::Table::Name = "Chapter";
const std::string Chapter::Table::PrimaryKeyColumn = "id_chapter";
int64_t Chapter::* const Chapter::Table::PrimaryKey = &Chapter::m_id;
void Chapter::createTable( sqlite::Connection* dbConn )
{
std::string req = "CREATE TABLE IF NOT EXISTS " + Table::Name +
"("
+ Table::PrimaryKeyColumn + " INTEGER PRIMARY KEY AUTOINCREMENT,"
"offset INTEGER NOT NULL,"
"duration INTEGER NOT NULL,"
"name TEXT,"
"media_id INTEGER,"
"FOREIGN KEY(media_id) REFERENCES " +
Media::Table::Name + "(" + Media::Table::PrimaryKeyColumn + ")"
"ON DELETE CASCADE"
")";
return sqlite::Tools::executeRequest( dbConn, req );
}
std::shared_ptr<Chapter> Chapter::create( MediaLibraryPtr ml, int64_t offset,
int64_t duration, std::string name,
int64_t mediaId )
{
static const std::string req = "INSERT INTO " + Table::Name +
"(offset, duration, name, media_id) VALUES(?, ?, ?, ?)";
auto self = std::make_shared<Chapter>( ml, offset, duration,
std::move( name ) );
if ( insert( ml, self, req, offset, duration, self->m_name, mediaId ) == false )
return nullptr;
return self;
}
Query<IChapter> Chapter::fromMedia( MediaLibraryPtr ml, int64_t mediaId,
const QueryParameters* params )
{
std::string req = "FROM " + Table::Name + " WHERE media_id = ?";
std::string orderBy = "ORDER BY ";
auto desc = params != nullptr ? params->desc : false;
auto sort = params != nullptr ? params->sort : SortingCriteria::Default;
switch ( sort )
{
case SortingCriteria::Alpha:
orderBy += "name";
break;
case SortingCriteria::Duration:
orderBy += "duration";
desc = !desc;
break;
default:
LOG_WARN( "Unsupported sorting criteria ",
static_cast<std::underlying_type<SortingCriteria>::type>( sort ),
" falling back to default (by offset)" );
/* fall-through */
case SortingCriteria::Default:
orderBy += "offset";
break;
}
if ( desc == true )
orderBy += " DESC";
return make_query<Chapter, IChapter>( ml, "*", req, orderBy, mediaId );
}
Chapter::Chapter( MediaLibraryPtr ml, sqlite::Row& row )
: m_ml( ml )
, m_id( row.extract<decltype(m_id)>() )
, m_offset( row.extract<decltype(m_offset)>() )
, m_duration( row.extract<decltype(m_offset)>() )
, m_name( row.extract<decltype(m_name)>() )
{
}
Chapter::Chapter( MediaLibraryPtr ml, int64_t offset, int64_t duration,
std::string name )
: m_ml( ml )
, m_id( 0 )
, m_offset( offset )
, m_duration( duration )
, m_name( std::move( name ) )
{
}
const std::string& Chapter::name() const
{
return m_name;
}
int64_t Chapter::offset() const
{
return m_offset;
}
int64_t Chapter::duration() const
{
return m_duration;
}
}
/*****************************************************************************
* Media Library
*****************************************************************************
* Copyright (C) 2018 Hugo Beauzée-Luyssen, Videolabs
*
* Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#pragma once
#include "medialibrary/IChapter.h"
#include "database/DatabaseHelpers.h"
#include "Types.h"
namespace medialibrary
{
class Chapter : public IChapter, public DatabaseHelpers<Chapter>
{
public:
struct Table
{
static const std::string Name;
static const std::string PrimaryKeyColumn;
static int64_t Chapter::*const PrimaryKey;
};
Chapter( MediaLibraryPtr ml, sqlite::Row& row );
Chapter( MediaLibraryPtr ml, int64_t offset, int64_t duration,
std::string name );
virtual const std::string& name() const override;
virtual int64_t offset() const override;
virtual int64_t duration() const override;
static void createTable( sqlite::Connection* dbConn );
static std::shared_ptr<Chapter> create( MediaLibraryPtr ml, int64_t offset,
int64_t duration, std::string name,
int64_t mediaId );
static Query<IChapter> fromMedia( MediaLibraryPtr ml, int64_t mediaId,
const QueryParameters* params );
private:
MediaLibraryPtr m_ml;
int64_t m_id;
int64_t m_offset;
int64_t m_duration;
std::string m_name;
friend Chapter::Table;
};
}
......@@ -34,6 +34,7 @@
#include "AlbumTrack.h"
#include "Artist.h"
#include "AudioTrack.h"
#include "Chapter.h"
#include "Device.h"
#include "Media.h"
#include "File.h"
......@@ -305,6 +306,17 @@ Query<ISubtitleTrack> Media::subtitleTracks() const
return make_query<SubtitleTrack, ISubtitleTrack>( m_ml, "*", req, "", m_id );
}
Query<IChapter> Media::chapters( const QueryParameters* params ) const
{
return Chapter::fromMedia( m_ml, m_id, params );
}
bool Media::addChapter(int64_t offset, int64_t duration, std::string name)
{
return Chapter::create( m_ml, offset, duration, std::move( name ),
m_id ) != nullptr;
}
const std::string& Media::thumbnail() const
{
if ( isThumbnailGenerated() == false )
......
......@@ -113,6 +113,8 @@ class Media : public IMedia, public DatabaseHelpers<Media>
std::string description, std::string encoding );
virtual Query<IAudioTrack> audioTracks() const override;
virtual Query<ISubtitleTrack> subtitleTracks() const override;
virtual Query<IChapter> chapters( const QueryParameters* params ) const override;
bool addChapter( int64_t offset, int64_t duration, std::string name );
virtual const std::string& thumbnail() const override;
virtual bool isThumbnailGenerated() const override;
virtual bool setThumbnail( const std::string &thumbnail ) override;
......
......@@ -37,6 +37,7 @@
#include "discoverer/DiscovererWorker.h"
#include "discoverer/probe/CrawlerProbe.h"
#include "utils/ModificationsNotifier.h"
#include "Chapter.h"
#include "Device.h"
#include "File.h"
#include "Folder.h"
......@@ -163,6 +164,7 @@ void MediaLibrary::createAllTables()
parser::Task::createTable( m_dbConnection.get() );
Metadata::createTable( m_dbConnection.get() );
SubtitleTrack::createTable( m_dbConnection.get() );
Chapter::createTable( m_dbConnection.get() );
}
void MediaLibrary::createAllTriggers()
......
/*****************************************************************************
* Media Library
*****************************************************************************
* Copyright (C) 2018 Hugo Beauzée-Luyssen, Videolabs
*
* Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include "Tests.h"
#include "Chapter.h"
#include "Media.h"
class ChapterTests : public Tests
{
protected:
std::shared_ptr<Media> m;
virtual void SetUp() override
{
Tests::SetUp();
m = std::static_pointer_cast<Media>( ml->addMedia( "media.avi" ) );
}
};
TEST_F( ChapterTests, Create )
{
auto res = m->addChapter( 0, 10, "chapter 1" );
ASSERT_TRUE( res );
auto chapters = m->chapters( nullptr )->all();
ASSERT_EQ( 1u, chapters.size() );
auto chapter = chapters[0];
ASSERT_EQ( 0, chapter->offset() );
ASSERT_EQ( 10, chapter->duration() );
ASSERT_EQ( "chapter 1", chapter->name() );
}
TEST_F( ChapterTests, Fetch )
{
m->addChapter( 0, 10, "chapter 1" );
m->addChapter( 11, 100, "chapter 2" );
m->addChapter( 111, 1, "A different chapter" );
auto query = m->chapters( nullptr );
ASSERT_EQ( 3u, query->count() );
auto chapters = query->all();
ASSERT_EQ( 3u, chapters.size() );
ASSERT_EQ( 0, chapters[0]->offset() );
ASSERT_EQ( 11, chapters[1]->offset() );
ASSERT_EQ( 111, chapters[2]->offset() );
QueryParameters params;
params.desc = false;
params.sort = SortingCriteria::Duration;
query = m->chapters( &params );
ASSERT_EQ( 3u, query->count() );
chapters = query->all();
ASSERT_EQ( 100, chapters[0]->duration() );
ASSERT_EQ( 10, chapters[1]->duration() );
ASSERT_EQ( 1, chapters[2]->duration() );
params.desc = true;
query = m->chapters( &params );
chapters = query->all();
ASSERT_EQ( 3u, chapters.size() );
ASSERT_EQ( 1, chapters[0]->duration() );
ASSERT_EQ( 10, chapters[1]->duration() );
ASSERT_EQ( 100, chapters[2]->duration() );
params.sort = SortingCriteria::Alpha;
params.desc = false;
query = m->chapters( &params );
chapters = query->all();
ASSERT_EQ( 3u, chapters.size() );
ASSERT_EQ( "A different chapter", chapters[0]->name() );
ASSERT_EQ( 111, chapters[0]->offset() );
ASSERT_EQ( "chapter 1", chapters[1]->name() );
ASSERT_EQ( 0, chapters[1]->offset() );
ASSERT_EQ( "chapter 2", chapters[2]->name() );
ASSERT_EQ( 11, chapters[2]->offset() );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment