Commit 07ed5d5f authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

IMediaLibrary: Add a MRL based media getter

parent 952385af
......@@ -156,6 +156,7 @@ class IMediaLibrary
virtual LabelPtr createLabel( const std::string& label ) = 0;
virtual bool deleteLabel( LabelPtr label ) = 0;
virtual MediaPtr media( int64_t mediaId ) const = 0;
virtual MediaPtr media( const std::string& mrl ) const = 0;
virtual std::vector<MediaPtr> audioFiles( SortingCriteria sort = SortingCriteria::Default, bool desc = false ) const = 0;
virtual std::vector<MediaPtr> videoFiles( SortingCriteria sort = SortingCriteria::Default, bool desc = false ) const = 0;
virtual AlbumPtr album( int64_t id ) const = 0;
......
......@@ -167,4 +167,28 @@ std::shared_ptr<File> File::create( MediaLibraryPtr ml, int64_t mediaId, Type ty
return self;
}
std::shared_ptr<File> File::fromPath( MediaLibraryPtr ml, const std::string& path )
{
static const std::string req = "SELECT * FROM " + policy::FileTable::Name + " WHERE mrl = ?";
auto file = fetch( ml, req, path );
if ( file == nullptr )
return nullptr;
// safety checks: since this only works for files on non removable devices, isPresent must be true
// and isRemovable must be false
assert( file->m_isPresent == true );
assert( file->m_isRemovable == false );
return file;
}
std::shared_ptr<File> File::fromFileName( MediaLibraryPtr ml, const std::string& fileName, int64_t folderId )
{
static const std::string req = "SELECT * FROM " + policy::FileTable::Name + " WHERE mrl = ? "
"AND folder_id = ?";
auto file = fetch( ml, req, fileName, folderId );
if ( file == nullptr )
return nullptr;
assert( file->m_isRemovable == true );
return file;
}
}
......@@ -64,6 +64,21 @@ public:
static bool createTable( DBConnection dbConnection );
static std::shared_ptr<File> create( MediaLibraryPtr ml, int64_t mediaId, Type type,
const fs::IFile& file, int64_t folderId, bool isRemovable );
/**
* @brief fromPath Attempts to fetch a file using its full path
* This will only work if the file was stored on a non removable device
* @param path The full path to the wanted file
* @return A pointer to the wanted file, or nullptr if it wasn't found
*/
static std::shared_ptr<File> fromPath( MediaLibraryPtr ml, const std::string& path );
/**
* @brief fromFileName Attemps to fetch a file based on its filename and folder id
* @param ml
* @param fileName
* @param folderId
* @return
*/
static std::shared_ptr<File> fromFileName( MediaLibraryPtr ml, const std::string& fileName, int64_t folderId );
private:
MediaLibraryPtr m_ml;
......
......@@ -64,6 +64,7 @@
// FileSystem
#include "factory/DeviceListerFactory.h"
#include "factory/FileSystemFactory.h"
#include "filesystem/IDevice.h"
namespace medialibrary
{
......@@ -257,6 +258,41 @@ MediaPtr MediaLibrary::media( int64_t mediaId ) const
return Media::fetch( this, mediaId );
}
MediaPtr MediaLibrary::media( const std::string& mrl ) const
{
auto device = m_fsFactory->createDeviceFromPath( mrl );
if ( device == nullptr )
{
LOG_WARN( "Failed to create a device associated with mrl ", mrl );
return nullptr;
}
std::shared_ptr<File> file;
if ( device->isRemovable() == false )
file = File::fromPath( this, mrl );
else
{
auto folder = Folder::fromPath( this, utils::file::directory( mrl ) );
if ( folder == nullptr )
{
LOG_WARN( "Failed to find folder containing ", mrl );
return nullptr;
}
if ( folder->isPresent() == false )
{
LOG_INFO( "Found a folder containing ", mrl, " but it is not present" );
return nullptr;
}
file = File::fromFileName( this, utils::file::fileName( mrl ), folder->id() );
}
if ( file == nullptr )
{
LOG_WARN( "Failed to fetch file for ", mrl, "(device ", device->uuid(), " was ",
device->isRemovable() ? "NOT" : "", "removable)");
return nullptr;
}
return file->media();
}
std::vector<MediaPtr> MediaLibrary::audioFiles( SortingCriteria sort, bool desc ) const
{
return Media::listAll( this, IMedia::Type::AudioType, sort, desc );
......
......@@ -66,6 +66,7 @@ class MediaLibrary : public IMediaLibrary, public IDeviceListerCb
virtual void setVerbosity( LogLevel v ) override;
virtual MediaPtr media( int64_t mediaId ) const override;
virtual MediaPtr media( const std::string& path ) const override;
virtual std::vector<MediaPtr> audioFiles( SortingCriteria sort, bool desc) const override;
virtual std::vector<MediaPtr> videoFiles( SortingCriteria sort, bool desc) const override;
......
......@@ -48,21 +48,6 @@ std::shared_ptr<Media> MediaLibraryTester::media( int64_t id )
return std::static_pointer_cast<Media>( MediaLibrary::media( id ) );
}
MediaPtr MediaLibraryTester::media( const std::string& path )
{
auto medias = files();
for ( auto& m : medias )
{
auto files = m->files();
for ( auto& f : files )
{
if ( f->mrl() == path )
return m;
}
}
return nullptr;
}
std::shared_ptr<Folder> MediaLibraryTester::folder( const std::string& path )
{
static const std::string req = "SELECT * FROM " + policy::FolderTable::Name +
......
......@@ -39,8 +39,10 @@ class MediaLibraryTester : public MediaLibrary
public:
MediaLibraryTester();
std::vector<MediaPtr> files();
// Use the filename getter
using MediaLibrary::media;
// And override the ID getter to return a Media instead of IMedia
std::shared_ptr<Media> media( int64_t id );
MediaPtr media( const std::string& path );
std::shared_ptr<Folder> folder( const std::string& path );
std::shared_ptr<Media> addFile( const std::string& path );
std::shared_ptr<Playlist> playlist( int64_t playlistId );
......
......@@ -33,6 +33,7 @@
#include "Album.h"
#include "AlbumTrack.h"
#include "mocks/FileSystem.h"
#include "mocks/DiscovererCbMock.h"
#include "compat/Thread.h"
class Medias : public Tests
......@@ -388,3 +389,77 @@ TEST_F( Medias, SortByLastModifDate )
ASSERT_EQ( m2->id(), media[1]->id() );
ASSERT_EQ( m1->id(), media[0]->id() );
}
class FetchMedia : public Tests
{
protected:
static const std::string RemovableDeviceUuid;
static const std::string RemovableDeviceMountpoint;
std::shared_ptr<mock::FileSystemFactory> fsMock;
std::unique_ptr<mock::WaitForDiscoveryComplete> cbMock;
virtual void SetUp() override
{
unlink( "test.db" );
fsMock.reset( new mock::FileSystemFactory );
cbMock.reset( new mock::WaitForDiscoveryComplete );
fsMock->addFolder( "/a/mnt/" );
auto device = fsMock->addDevice( RemovableDeviceMountpoint, RemovableDeviceUuid );
device->setRemovable( true );
fsMock->addFile( RemovableDeviceMountpoint + "removablefile.mp3" );
Reload();
}
virtual void InstantiateMediaLibrary() override
{
ml.reset( new MediaLibraryWithoutParser );
}
virtual void Reload()
{
Tests::Reload( fsMock, cbMock.get() );
}
};
const std::string FetchMedia::RemovableDeviceUuid = "{fake-removable-device}";
const std::string FetchMedia::RemovableDeviceMountpoint = "/a/mnt/fake-device/";
TEST_F( FetchMedia, FetchNonRemovable )
{
cbMock->prepareForWait();
ml->discover( mock::FileSystemFactory::Root );
bool discovered = cbMock->wait();
ASSERT_TRUE( discovered );
auto m = ml->media( mock::FileSystemFactory::SubFolder + "subfile.mp4" );
ASSERT_NE( nullptr, m );
}
TEST_F( FetchMedia, FetchRemovable )
{
cbMock->prepareForWait();
ml->discover( mock::FileSystemFactory::Root );
bool discovered = cbMock->wait();
ASSERT_TRUE( discovered );
auto m = ml->media( RemovableDeviceMountpoint + "removablefile.mp3" );
ASSERT_NE( nullptr, m );
}
TEST_F( FetchMedia, FetchRemovableUnplugged )
{
cbMock->prepareForWait();
ml->discover( mock::FileSystemFactory::Root );
bool discovered = cbMock->wait();
ASSERT_TRUE( discovered );
fsMock->unmountDevice( RemovableDeviceUuid );
cbMock->prepareForReload();
Reload();
bool reloaded = cbMock->wait();
ASSERT_TRUE( reloaded );
auto m = ml->media( RemovableDeviceMountpoint + "removablefile.mp3" );
ASSERT_EQ( nullptr, m );
}
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