Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
VideoLAN
medialibrary
Commits
6dfa05cb
Commit
6dfa05cb
authored
Jan 11, 2016
by
Hugo Beauzée-Luyssen
Browse files
Add playlists support
parent
67a5fd3c
Changes
13
Hide whitespace changes
Inline
Side-by-side
include/IMediaLibrary.h
View file @
6dfa05cb
...
...
@@ -97,6 +97,13 @@ class IMediaLibrary
virtual
ArtistPtr
artist
(
unsigned
int
id
)
=
0
;
virtual
std
::
vector
<
ArtistPtr
>
artists
()
const
=
0
;
/***
* Playlists
*/
virtual
PlaylistPtr
createPlaylist
(
const
std
::
string
&
name
)
=
0
;
virtual
std
::
vector
<
PlaylistPtr
>
playlists
()
=
0
;
virtual
bool
deletePlaylist
(
unsigned
int
playlistId
)
=
0
;
/**
* @brief discover Launch a discovery on the provided entry point.
* The actuall discovery will run asynchronously, meaning this method will immediatly return.
...
...
include/IPlaylist.h
0 → 100644
View file @
6dfa05cb
/*****************************************************************************
* Media Library
*****************************************************************************
* Copyright (C) 2015 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
<vector>
#include
"Types.h"
class
IPlaylist
{
public:
virtual
~
IPlaylist
()
=
default
;
virtual
unsigned
int
id
()
const
=
0
;
virtual
const
std
::
string
&
name
()
const
=
0
;
virtual
bool
setName
(
const
std
::
string
&
name
)
=
0
;
virtual
std
::
vector
<
MediaPtr
>
media
()
const
=
0
;
///
/// \brief append Appends a media to a playlist
/// The media will be the last element of a subsequent call to media()
/// This is equivalent to calling add( media, 0 )
/// \param media The media to add
/// \return true on success, false on failure.
///
virtual
bool
append
(
unsigned
int
mediaId
)
=
0
;
///
/// \brief add Add a media to the playlist at the given position.
/// Valid positions start at 1. 0 means appending.
/// \param media The media to add
/// \param position The position of this new media
/// \return true on success, false on failure
///
virtual
bool
add
(
unsigned
int
mediaId
,
unsigned
int
position
)
=
0
;
///
/// \brief move Change the position of a media
/// \param mediaId The media to move reorder
/// \param position The new position within the playlist.
/// 0 is an invalid value when moving.
/// In case there is already a media at the given position, it will be placed after
/// the media being moved. This will cascade to any media placed afterward.
/// For instance, a playlist with <media,position> like
/// [<1,1>, <2,2>, <3,3>] on which move(1, 2) is called will result in the playlist
/// being changed to
/// [<1,2>, <2,3>, <3,4>]
/// \return true on success, false on failure
///
virtual
bool
move
(
unsigned
int
mediaId
,
unsigned
int
position
)
=
0
;
///
/// \brief remove Removes a media from the playlist
/// \param mediaId The media to remove.
/// \return true on success, false on failure
///
virtual
bool
remove
(
unsigned
int
mediaId
)
=
0
;
};
include/Types.h
View file @
6dfa05cb
...
...
@@ -39,6 +39,7 @@ class IShowEpisode;
class
IVideoTrack
;
class
ILogger
;
class
IArtist
;
class
IPlaylist
;
class
SqliteConnection
;
typedef
std
::
shared_ptr
<
IMedia
>
MediaPtr
;
...
...
@@ -52,6 +53,7 @@ typedef std::shared_ptr<IMovie> MoviePtr;
typedef
std
::
shared_ptr
<
IAudioTrack
>
AudioTrackPtr
;
typedef
std
::
shared_ptr
<
IVideoTrack
>
VideoTrackPtr
;
typedef
std
::
shared_ptr
<
IArtist
>
ArtistPtr
;
typedef
std
::
shared_ptr
<
IPlaylist
>
PlaylistPtr
;
typedef
SqliteConnection
*
DBConnection
;
...
...
src/CMakeLists.txt
View file @
6dfa05cb
...
...
@@ -34,6 +34,7 @@ list(APPEND HEADERS_LIST
${
CMAKE_SOURCE_DIR
}
/include/factory/IFileSystem.h
${
CMAKE_SOURCE_DIR
}
/include/ILogger.h
${
CMAKE_SOURCE_DIR
}
/include/IArtist.h
${
CMAKE_SOURCE_DIR
}
/include/IPlaylist.h
database/SqliteTools.h
...
...
@@ -67,6 +68,7 @@ list(APPEND SRC_LIST ${HEADERS_LIST}
Settings.cpp
Device.cpp
File.cpp
Playlist.cpp
factory/FileSystem.cpp
filesystem/common/CommonFile.cpp
...
...
src/MediaLibrary.cpp
View file @
6dfa05cb
...
...
@@ -40,6 +40,7 @@
#include
"logging/Logger.h"
#include
"Movie.h"
#include
"Parser.h"
#include
"Playlist.h"
#include
"Show.h"
#include
"ShowEpisode.h"
#include
"database/SqliteTools.h"
...
...
@@ -103,6 +104,7 @@ MediaLibrary::~MediaLibrary()
Artist
::
clear
();
Device
::
clear
();
File
::
clear
();
Playlist
::
clear
();
// Explicitely release the connection's TLS
if
(
m_dbConnection
!=
nullptr
)
m_dbConnection
->
release
();
...
...
@@ -122,6 +124,7 @@ bool MediaLibrary::createAllTables()
Media
::
createTable
(
m_dbConnection
.
get
()
)
&&
File
::
createTable
(
m_dbConnection
.
get
()
)
&&
Label
::
createTable
(
m_dbConnection
.
get
()
)
&&
Playlist
::
createTable
(
m_dbConnection
.
get
()
)
&&
Album
::
createTable
(
m_dbConnection
.
get
()
)
&&
AlbumTrack
::
createTable
(
m_dbConnection
.
get
()
)
&&
Album
::
createTriggers
(
m_dbConnection
.
get
()
)
&&
...
...
@@ -134,6 +137,7 @@ bool MediaLibrary::createAllTables()
Artist
::
createDefaultArtists
(
m_dbConnection
.
get
()
)
&&
Artist
::
createTriggers
(
m_dbConnection
.
get
()
)
&&
Media
::
createTriggers
(
m_dbConnection
.
get
()
)
&&
Playlist
::
createTriggers
(
m_dbConnection
.
get
()
)
&&
Settings
::
createTable
(
m_dbConnection
.
get
()
);
if
(
res
==
false
)
return
false
;
...
...
@@ -346,6 +350,21 @@ std::vector<ArtistPtr> MediaLibrary::artists() const
return
Artist
::
fetchAll
<
IArtist
>
(
m_dbConnection
.
get
(),
req
);
}
PlaylistPtr
MediaLibrary
::
createPlaylist
(
const
std
::
string
&
name
)
{
return
Playlist
::
create
(
m_dbConnection
.
get
(),
name
);
}
std
::
vector
<
PlaylistPtr
>
MediaLibrary
::
playlists
()
{
return
Playlist
::
fetchAll
<
IPlaylist
>
(
m_dbConnection
.
get
()
);
}
bool
MediaLibrary
::
deletePlaylist
(
unsigned
int
playlistId
)
{
return
Playlist
::
destroy
(
m_dbConnection
.
get
(),
playlistId
);
}
void
MediaLibrary
::
addMetadataService
(
std
::
unique_ptr
<
IMetadataService
>
service
)
{
if
(
service
->
initialize
(
m_parser
.
get
(),
this
)
==
false
)
...
...
src/MediaLibrary.h
View file @
6dfa05cb
...
...
@@ -77,6 +77,10 @@ class MediaLibrary : public IMediaLibrary
std
::
shared_ptr
<
Artist
>
createArtist
(
const
std
::
string
&
name
);
virtual
std
::
vector
<
ArtistPtr
>
artists
()
const
override
;
virtual
PlaylistPtr
createPlaylist
(
const
std
::
string
&
name
)
override
;
virtual
std
::
vector
<
PlaylistPtr
>
playlists
()
override
;
virtual
bool
deletePlaylist
(
unsigned
int
playlistId
)
override
;
virtual
void
discover
(
const
std
::
string
&
entryPoint
)
override
;
bool
ignoreFolder
(
const
std
::
string
&
path
)
override
;
...
...
src/Playlist.cpp
0 → 100644
View file @
6dfa05cb
/*****************************************************************************
* Media Library
*****************************************************************************
* Copyright (C) 2015 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.
*****************************************************************************/
#include
"Playlist.h"
#include
"Media.h"
namespace
policy
{
const
std
::
string
PlaylistTable
::
Name
=
"Playlist"
;
const
std
::
string
PlaylistTable
::
PrimaryKeyColumn
=
"id_playlist"
;
unsigned
int
Playlist
::*
const
PlaylistTable
::
PrimaryKey
=
&
Playlist
::
m_id
;
}
Playlist
::
Playlist
(
DBConnection
dbConn
,
sqlite
::
Row
&
row
)
:
m_dbConnection
(
dbConn
)
{
row
>>
m_id
>>
m_name
;
}
Playlist
::
Playlist
(
const
std
::
string
&
name
)
:
m_id
(
0
)
,
m_name
(
name
)
{
}
std
::
shared_ptr
<
Playlist
>
Playlist
::
create
(
DBConnection
dbConn
,
const
std
::
string
&
name
)
{
auto
self
=
std
::
make_shared
<
Playlist
>
(
name
);
static
const
std
::
string
req
=
"INSERT INTO "
+
policy
::
PlaylistTable
::
Name
+
"(name) VALUES(?)"
;
if
(
insert
(
dbConn
,
self
,
req
,
name
)
==
false
)
return
nullptr
;
self
->
m_dbConnection
=
dbConn
;
return
self
;
}
unsigned
int
Playlist
::
id
()
const
{
return
m_id
;
}
const
std
::
string
&
Playlist
::
name
()
const
{
return
m_name
;
}
bool
Playlist
::
setName
(
const
std
::
string
&
name
)
{
if
(
name
==
m_name
)
return
true
;
static
const
std
::
string
req
=
"UPDATE "
+
policy
::
PlaylistTable
::
Name
+
" SET name = ? WHERE id_playlist = ?"
;
if
(
sqlite
::
Tools
::
executeUpdate
(
m_dbConnection
,
req
,
name
,
m_id
)
==
false
)
return
false
;
m_name
=
name
;
return
true
;
}
std
::
vector
<
MediaPtr
>
Playlist
::
media
()
const
{
static
const
std
::
string
req
=
"SELECT m.* FROM "
+
policy
::
MediaTable
::
Name
+
" m "
"LEFT JOIN PlaylistMediaRelation pmr ON pmr.media_id = m.id_media "
"WHERE pmr.playlist_id = ? AND m.is_present = 1 "
"ORDER BY pmr.position"
;
return
Media
::
fetchAll
<
IMedia
>
(
m_dbConnection
,
req
,
m_id
);
}
bool
Playlist
::
append
(
unsigned
int
mediaId
)
{
return
add
(
mediaId
,
0
);
}
bool
Playlist
::
add
(
unsigned
int
mediaId
,
unsigned
int
position
)
{
static
const
std
::
string
req
=
"INSERT INTO PlaylistMediaRelation(media_id, playlist_id, position) VALUES(?, ?, ?)"
;
// position isn't a foreign key, but we want it to be passed as NULL if it equals to 0
// When the position is NULL, the insertion triggers takes care of counting the number of records to auto append.
return
sqlite
::
Tools
::
insert
(
m_dbConnection
,
req
,
mediaId
,
m_id
,
sqlite
::
ForeignKey
{
position
}
);
}
bool
Playlist
::
move
(
unsigned
int
mediaId
,
unsigned
int
position
)
{
if
(
position
==
0
)
return
false
;
static
const
std
::
string
req
=
"UPDATE PlaylistMediaRelation SET position = ? WHERE "
"playlist_id = ? AND media_id = ?"
;
return
sqlite
::
Tools
::
executeUpdate
(
m_dbConnection
,
req
,
position
,
m_id
,
mediaId
);
}
bool
Playlist
::
remove
(
unsigned
int
mediaId
)
{
static
const
std
::
string
req
=
"DELETE FROM PlaylistMediaRelation WHERE playlist_id = ? AND media_id = ?"
;
return
sqlite
::
Tools
::
executeDelete
(
m_dbConnection
,
req
,
m_id
,
mediaId
);
}
bool
Playlist
::
createTable
(
DBConnection
dbConn
)
{
static
const
std
::
string
req
=
"CREATE TABLE IF NOT EXISTS "
+
policy
::
PlaylistTable
::
Name
+
"("
+
policy
::
PlaylistTable
::
PrimaryKeyColumn
+
" INTEGER PRIMARY KEY AUTOINCREMENT,"
"name TEXT"
")"
;
static
const
std
::
string
relTableReq
=
"CREATE TABLE IF NOT EXISTS PlaylistMediaRelation("
"media_id INTEGER,"
"playlist_id INTEGER,"
"position INTEGER,"
"PRIMARY KEY(media_id, playlist_id),"
"FOREIGN KEY(media_id) REFERENCES "
+
policy
::
MediaTable
::
Name
+
"("
+
policy
::
MediaTable
::
PrimaryKeyColumn
+
") ON DELETE CASCADE,"
"FOREIGN KEY(playlist_id) REFERENCES "
+
policy
::
PlaylistTable
::
Name
+
"("
+
policy
::
PlaylistTable
::
PrimaryKeyColumn
+
") ON DELETE CASCADE"
")"
;
//FIXME Enforce (playlist_id,position) uniqueness
return
sqlite
::
Tools
::
executeRequest
(
dbConn
,
req
)
&&
sqlite
::
Tools
::
executeRequest
(
dbConn
,
relTableReq
);
}
bool
Playlist
::
createTriggers
(
DBConnection
dbConn
)
{
static
const
std
::
string
req
=
"CREATE TRIGGER IF NOT EXISTS update_playlist_order AFTER UPDATE OF position"
" ON PlaylistMediaRelation"
" BEGIN "
"UPDATE PlaylistMediaRelation SET position = position + 1"
" WHERE playlist_id = new.playlist_id"
" AND position = new.position"
// We don't to trigger a self-update when the insert trigger fires.
" AND media_id != new.media_id;"
" END"
;
static
const
std
::
string
autoAppendReq
=
"CREATE TRIGGER IF NOT EXISTS append_new_playlist_record AFTER INSERT"
" ON PlaylistMediaRelation"
" WHEN new.position IS NULL"
" BEGIN "
" UPDATE PlaylistMediaRelation SET position = ("
"SELECT COUNT(media_id) FROM PlaylistMediaRelation WHERE playlist_id = new.playlist_id"
") WHERE playlist_id=new.playlist_id AND media_id = new.media_id;"
" END"
;
static
const
std
::
string
autoShiftPosReq
=
"CREATE TRIGGER IF NOT EXISTS update_playlist_order_on_insert AFTER INSERT"
" ON PlaylistMediaRelation"
" WHEN new.position IS NOT NULL"
" BEGIN "
"UPDATE PlaylistMediaRelation SET position = position + 1"
" WHERE playlist_id = new.playlist_id"
" AND position = new.position"
" AND media_id != new.media_id;"
" END"
;
return
sqlite
::
Tools
::
executeRequest
(
dbConn
,
req
)
&&
sqlite
::
Tools
::
executeRequest
(
dbConn
,
autoAppendReq
)
&&
sqlite
::
Tools
::
executeRequest
(
dbConn
,
autoShiftPosReq
);
}
src/Playlist.h
0 → 100644
View file @
6dfa05cb
/*****************************************************************************
* Media Library
*****************************************************************************
* Copyright (C) 2015 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
"IPlaylist.h"
#include
"database/SqliteTools.h"
#include
"database/DatabaseHelpers.h"
#include
"utils/Cache.h"
class
Playlist
;
namespace
policy
{
struct
PlaylistTable
{
static
const
std
::
string
Name
;
static
const
std
::
string
PrimaryKeyColumn
;
static
unsigned
int
Playlist
::*
const
PrimaryKey
;
};
}
class
Playlist
:
public
IPlaylist
,
public
DatabaseHelpers
<
Playlist
,
policy
::
PlaylistTable
>
{
public:
Playlist
(
DBConnection
dbConn
,
sqlite
::
Row
&
row
);
Playlist
(
const
std
::
string
&
name
);
static
std
::
shared_ptr
<
Playlist
>
create
(
DBConnection
dbConn
,
const
std
::
string
&
name
);
virtual
unsigned
int
id
()
const
override
;
virtual
const
std
::
string
&
name
()
const
override
;
virtual
bool
setName
(
const
std
::
string
&
name
)
override
;
virtual
std
::
vector
<
MediaPtr
>
media
()
const
override
;
virtual
bool
append
(
unsigned
int
mediaId
)
override
;
virtual
bool
add
(
unsigned
int
mediaId
,
unsigned
int
position
)
override
;
virtual
bool
move
(
unsigned
int
mediaId
,
unsigned
int
position
)
override
;
virtual
bool
remove
(
unsigned
int
mediaId
)
override
;
static
bool
createTable
(
DBConnection
dbConn
);
static
bool
createTriggers
(
DBConnection
dbConn
);
private:
DBConnection
m_dbConnection
;
unsigned
int
m_id
;
std
::
string
m_name
;
friend
class
policy
::
PlaylistTable
;
};
src/database/SqliteConnection.cpp
View file @
6dfa05cb
...
...
@@ -50,6 +50,8 @@ sqlite3 *SqliteConnection::getConn()
lock
.
unlock
();
if
(
sqlite
::
Tools
::
executeRequestLocked
(
this
,
"PRAGMA foreign_keys = ON"
)
==
false
)
throw
std
::
runtime_error
(
"Failed to enable foreign keys"
);
if
(
sqlite
::
Tools
::
executeRequestLocked
(
this
,
"PRAGMA recursive_triggers = ON"
)
==
false
)
throw
std
::
runtime_error
(
"Failed to enable recursive triggers"
);
return
dbConnection
;
}
return
it
->
second
.
get
();
...
...
test/unittest/PlaylistTests.cpp
0 → 100644
View file @
6dfa05cb
/*****************************************************************************
* Media Library
*****************************************************************************
* Copyright (C) 2015 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.
*****************************************************************************/
#include
"Tests.h"
#include
"Playlist.h"
#include
"Media.h"
class
Playlists
:
public
Tests
{
protected:
std
::
shared_ptr
<
Playlist
>
pl
;
std
::
shared_ptr
<
Media
>
m
;
virtual
void
SetUp
()
override
{
Tests
::
SetUp
();
pl
=
std
::
static_pointer_cast
<
Playlist
>
(
ml
->
createPlaylist
(
"test playlist"
)
);
}
};
TEST_F
(
Playlists
,
Create
)
{
ASSERT_NE
(
nullptr
,
pl
);
ASSERT_NE
(
0u
,
pl
->
id
()
);
ASSERT_EQ
(
"test playlist"
,
pl
->
name
()
);
}
TEST_F
(
Playlists
,
Fetch
)
{
auto
pl2
=
ml
->
playlist
(
pl
->
id
()
);
ASSERT_NE
(
nullptr
,
pl2
);
ASSERT_EQ
(
pl
->
id
(),
pl2
->
id
()
);
auto
playlists
=
ml
->
playlists
();
ASSERT_EQ
(
1u
,
playlists
.
size
()
);
ASSERT_EQ
(
pl
->
id
(),
playlists
[
0
]
->
id
()
);
}
TEST_F
(
Playlists
,
DeletePlaylist
)
{
auto
res
=
ml
->
deletePlaylist
(
pl
->
id
()
);
ASSERT_TRUE
(
res
);
auto
playlists
=
ml
->
playlists
();
ASSERT_EQ
(
0u
,
playlists
.
size
()
);
}
TEST_F
(
Playlists
,
SetName
)
{
ASSERT_EQ
(
"test playlist"
,
pl
->
name
()
);
auto
newName
=
"new name"
;
auto
res
=
pl
->
setName
(
newName
);
ASSERT_TRUE
(
res
);
ASSERT_EQ
(
newName
,
pl
->
name
()
);
Reload
();
pl
=
ml
->
playlist
(
pl
->
id
()
);
ASSERT_EQ
(
newName
,
pl
->
name
()
);
}
TEST_F
(
Playlists
,
FetchAll
)
{
pl
->
setName
(
"pl 1"
);
ml
->
createPlaylist
(
"pl 2"
);
ml
->
createPlaylist
(
"pl 3"
);
ml
->
createPlaylist
(
"pl 4"
);
auto
playlists
=
ml
->
playlists
();
ASSERT_EQ
(
4u
,
playlists
.
size
()
);
for
(
auto
&
p
:
playlists
)
{
auto
name
=
std
::
string
{
"pl "
}
+
std
::
to_string
(
p
->
id
()
);
ASSERT_EQ
(
name
,
p
->
name
()
);
}
}
TEST_F
(
Playlists
,
Add
)
{
auto
m
=
ml
->
addFile
(
"file.mkv"
);
auto
res
=
pl
->
append
(
m
->
id
()
);
ASSERT_TRUE
(
res
);
auto
media
=
pl
->
media
();
ASSERT_EQ
(
1u
,
media
.
size
()
);
ASSERT_EQ
(
m
->
id
(),
media
[
0
]
->
id
()
);
}
TEST_F
(
Playlists
,
Append
)
{
for
(
auto
i
=
0
;
i
<
5
;
++
i
)
{
auto
m
=
ml
->
addFile
(
"media"
+
std
::
to_string
(
i
)
+
".mkv"
);
ASSERT_NE
(
nullptr
,
m
);
pl
->
append
(
m
->
id
()
);
}
auto
media
=
pl
->
media
();
ASSERT_EQ
(
5u
,
media
.
size
()
);
for
(
auto
i
=
0u
;
i
<
media
.
size
();
++
i
)
{
auto
name
=
"media"
+
std
::
to_string
(
i
)
+
".mkv"
;
ASSERT_EQ
(
media
[
i
]
->
title
(),
name
);
}
}
TEST_F
(
Playlists
,
Insert
)
{
for
(
auto
i
=
1
;
i
<
4
;
++
i
)
{
auto
m
=
ml
->
addFile
(
"media"
+
std
::
to_string
(
i
)
+
".mkv"
);
ASSERT_NE
(
nullptr
,
m
);
auto
res
=
pl
->
append
(
m
->
id
()
);
ASSERT_TRUE
(
res
);
}
// [<1,1>,<2,2>,<3,3>]
auto
firstMedia
=
ml
->
addFile
(
"first.mkv"
);
pl
->
add
(
firstMedia
->
id
(),
1
);
// [<4,1>,<1,2>,<2,3>,<3,4>]
auto
middleMedia
=
ml
->
addFile
(
"middle.mkv"
);
pl
->
add
(
middleMedia
->
id
(),
3
);
// [<4,1>,<1,2>,<5,3>,<2,4>,<3,5>]
auto
media
=
pl
->
media
();
ASSERT_EQ
(
5u
,
media
.
size
()
);
ASSERT_EQ
(
4u
,
media
[
0
]
->
id
()
);
ASSERT_EQ
(
1u
,
media
[
1
]
->
id
()
);
ASSERT_EQ
(
5u
,
media
[
2
]
->
id
()
);
ASSERT_EQ
(
2u
,
media
[
3
]
->
id
()
);
ASSERT_EQ
(
3u
,
media
[
4
]
->
id
()
);
}
TEST_F
(
Playlists
,
Move
)
{
for
(
auto
i
=
1
;
i
<
6
;
++
i
)
{
auto
m
=
ml
->
addFile
(
"media"
+
std
::
to_string
(
i
)
+
".mkv"
);
ASSERT_NE
(
nullptr
,
m
);
auto
res
=
pl
->
append
(
m
->
id
()
);
ASSERT_TRUE
(
res
);
}
// [<1,1>,<2,2>,<3,3>,<4,4>,<5,5>]
pl
->
move
(
5
,
1
);
// [<5,1>,<1,2>,<2,3>,<3,4>,<4,5>]
auto
media
=
pl
->
media
();
ASSERT_EQ
(
5u
,
media
.
size
()
);
ASSERT_EQ
(
5u
,
media
[
0
]
->
id
()
);
ASSERT_EQ
(
1u
,
media
[
1
]
->
id
()
);
ASSERT_EQ
(
2u
,
media
[
2
]
->
id
()
);
ASSERT_EQ
(
3u
,
media
[
3
]
->
id
()
);
ASSERT_EQ
(
4u
,
media
[
4
]
->
id
()
);
}
TEST_F
(
Playlists
,
Remove
)
{
for
(
auto
i
=
1
;
i
<
6
;
++
i
)
{
auto
m
=
ml
->
addFile
(
"media"
+
std
::
to_string
(
i
)
+
".mkv"
);
ASSERT_NE
(
nullptr
,
m
);
auto
res
=
pl
->
append
(
m
->
id
()
);
ASSERT_TRUE
(
res
);