WIP. Restoring video playback
This commit is contained in:
@@ -23,7 +23,6 @@ lms_SOURCES = \
|
||||
$(top_srcdir)/database/Track.cpp \
|
||||
$(top_srcdir)/database/DatabaseHandler.cpp \
|
||||
$(top_srcdir)/database/SqlQuery.cpp \
|
||||
$(top_srcdir)/database/Path.cpp \
|
||||
$(top_srcdir)/database/Video.cpp \
|
||||
$(top_srcdir)/database/User.cpp \
|
||||
$(top_srcdir)/database-updater/DatabaseUpdater.cpp \
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
- Implement a video database cleanup
|
||||
- Group videos in "video groups". Each video may has sub groups (current "Path" class)
|
||||
-> Simplify the database and remove the Path class
|
||||
- Process only files whose extensions are well known in audio/video world (avoid useless parsing/errors)?
|
||||
- make a default admin/admin account of the very first connection?
|
||||
- count scan import errors
|
||||
|
||||
[Metadata]
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ ConfigReader::getDatabaseUpdateConfig(Service::DatabaseUpdateService::Config& co
|
||||
config.dbPath = _config.lookup("main.database.path");
|
||||
|
||||
std::string audioExtensions = _config.lookup("main.database.audio_extensions");
|
||||
std::string videoExtensions = _config.lookup("main.database.audio_extensions");
|
||||
std::string videoExtensions = _config.lookup("main.database.video_extensions");
|
||||
|
||||
splitStrings(audioExtensions, config.audioExtensions);
|
||||
splitStrings(videoExtensions, config.videoExtensions);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "database/MediaDirectory.hpp"
|
||||
#include "database/AudioTypes.hpp"
|
||||
#include "database/VideoTypes.hpp"
|
||||
|
||||
#include "Checksum.hpp"
|
||||
#include "DatabaseUpdater.hpp"
|
||||
@@ -200,8 +201,7 @@ Updater::process(boost::system::error_code err)
|
||||
Stats stats;
|
||||
|
||||
checkAudioFiles(stats);
|
||||
// TODO video files
|
||||
|
||||
checkVideoFiles(stats);
|
||||
|
||||
typedef std::pair<boost::filesystem::path, Database::MediaDirectory::Type> RootDirectory;
|
||||
std::vector<RootDirectory> rootDirectories;
|
||||
@@ -289,6 +289,7 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
|
||||
return;
|
||||
}
|
||||
|
||||
// ***** Title
|
||||
std::string title;
|
||||
if (items.find(MetaData::Title) != items.end()) {
|
||||
title = boost::any_cast<std::string>(items[MetaData::Title]);
|
||||
@@ -436,7 +437,8 @@ Updater::processDirectory(const boost::filesystem::path& rootDirectory,
|
||||
break;
|
||||
|
||||
case Database::MediaDirectory::Video:
|
||||
// processVideoFile( rootDirectory, *itPath, stats);
|
||||
if (isFileSupported(*itPath, _videoExtensions))
|
||||
processVideoFile( *itPath, stats);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -549,70 +551,33 @@ Updater::checkAudioFiles( Stats& stats )
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Check audio files done!";
|
||||
}
|
||||
|
||||
Path::pointer
|
||||
Updater::getAddPath(const boost::filesystem::path& path)
|
||||
{
|
||||
Path::pointer res;
|
||||
Path::pointer parentDirectory;
|
||||
|
||||
if (path.has_parent_path())
|
||||
parentDirectory = Path::getByPath(_db.getSession(), path.parent_path());
|
||||
|
||||
res = Path::getByPath(_db.getSession(), path);
|
||||
if (!res)
|
||||
res = Path::create(_db.getSession(), path, parentDirectory);
|
||||
else
|
||||
{
|
||||
// Make sure the parent directory owns the child
|
||||
if (parentDirectory && !res->getParent())
|
||||
parentDirectory.modify()->addChild( res );
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*void
|
||||
Updater::refreshVideoDirectory( const boost::filesystem::path& path)
|
||||
{
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Refreshing video directory " << path;
|
||||
if (boost::filesystem::exists(path) && boost::filesystem::is_directory(path))
|
||||
{
|
||||
|
||||
// Add this directory in the database
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
Path::pointer pathDirectory = getAddPath(path);
|
||||
assert( pathDirectory->isDirectory() );
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
// Now process all files/dirs in directory
|
||||
typedef std::vector<boost::filesystem::path> Paths; // store paths,
|
||||
|
||||
Paths pathChildren;
|
||||
std::copy(boost::filesystem::directory_iterator(path), boost::filesystem::directory_iterator(), std::back_inserter(pathChildren));
|
||||
|
||||
BOOST_FOREACH(const boost::filesystem::path& pathChild, pathChildren) {
|
||||
|
||||
if (boost::filesystem::is_directory(pathChild)) {
|
||||
refreshVideoDirectory( pathChild );
|
||||
}
|
||||
else if (boost::filesystem::is_regular(pathChild)) {
|
||||
processVideoFile( pathChild );
|
||||
}
|
||||
else {
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Skipped '" << pathChild << "' (not regular)";
|
||||
}
|
||||
}
|
||||
}
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Refreshing video directory " << path << ": DONE";
|
||||
}*/
|
||||
/*
|
||||
void
|
||||
Updater::processVideoFile( const boost::filesystem::path& file)
|
||||
Updater::checkVideoFiles( Stats& stats )
|
||||
{
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Checking video files...";
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
std::vector<boost::filesystem::path> rootDirs = getRootDirectoriesByType(_db.getSession(), Database::MediaDirectory::Video);
|
||||
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Checking videos...";
|
||||
typedef Wt::Dbo::collection< Wt::Dbo::ptr<Video> > Videos;
|
||||
Videos videos = Video::getAll(_db.getSession());
|
||||
|
||||
for (Videos::iterator it = videos.begin(); it != videos.end(); ++it)
|
||||
{
|
||||
Video::pointer video = (*it);
|
||||
|
||||
if (!checkFile(video->getPath(), rootDirs, _videoExtensions))
|
||||
{
|
||||
video.remove();
|
||||
stats.nbRemoved++;
|
||||
}
|
||||
}
|
||||
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Check video files done!";
|
||||
}
|
||||
void
|
||||
Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -622,15 +587,9 @@ Updater::processVideoFile( const boost::filesystem::path& file)
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
// Skip file if last write is the same
|
||||
Path::pointer dbPath = Path::getByPath(_db.getSession(), file);
|
||||
if (dbPath && dbPath->getLastWriteTime() == lastWriteTime)
|
||||
{
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_ERROR) << "Skipped '" << file << "' (last write time match)";
|
||||
Wt::Dbo::ptr<Video> video = Video::getByPath(_db.getSession(), file);
|
||||
if (video && video->getLastWriteTime() == lastWriteTime)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Video, parsing file " << file;
|
||||
|
||||
MetaData::Items items;
|
||||
_metadataParser.parse(file, items);
|
||||
@@ -643,51 +602,52 @@ Updater::processVideoFile( const boost::filesystem::path& file)
|
||||
{
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_ERROR) << "Skipped '" << file << "' (no video stream found)";
|
||||
|
||||
// If Track exists here, delete it!
|
||||
if (dbPath)
|
||||
dbPath.remove();
|
||||
// If the video exists here, delete it!
|
||||
if (video) {
|
||||
video.remove();
|
||||
stats.nbRemoved++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (items.find(MetaData::Duration) == items.end()
|
||||
if (items.find(MetaData::Duration) == items.end()
|
||||
|| boost::any_cast<boost::posix_time::time_duration>(items[MetaData::Duration]).total_seconds() == 0)
|
||||
{
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_ERROR) << "Skipped '" << file << "' (no duration or duration 0)";
|
||||
|
||||
// If Track exists here, delete it!
|
||||
if (dbPath)
|
||||
dbPath.remove();
|
||||
if (video) {
|
||||
video.remove();
|
||||
stats.nbRemoved++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If video already exist, update data
|
||||
// Otherwise, create it
|
||||
// Today we are very aggressive, but we could also guess names from path, etc.
|
||||
if (!video)
|
||||
{
|
||||
video = Video::create(_db.getSession(), file);
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Adding '" << file << "'";
|
||||
stats.nbAdded++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add Path if needed
|
||||
if (!dbPath)
|
||||
dbPath = getAddPath( file );
|
||||
|
||||
dbPath.modify()->setLastWriteTime( lastWriteTime );
|
||||
|
||||
assert(dbPath);
|
||||
|
||||
// Valid video here
|
||||
// Today we are very aggressive, but we could also guess names from path, etc.
|
||||
|
||||
Video::pointer video = dbPath.modify()->getVideo();
|
||||
if (!video) {
|
||||
video = Video::create(_db.getSession(), dbPath);
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Adding '" << file << "'";
|
||||
}
|
||||
else
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Updating '" << file << "'";
|
||||
|
||||
assert(video);
|
||||
|
||||
video.modify()->setName( file.filename().string() );
|
||||
video.modify()->setDuration( boost::any_cast<boost::posix_time::time_duration>(items[MetaData::Duration]) );
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Updating '" << file << "'";
|
||||
stats.nbModified++;
|
||||
}
|
||||
|
||||
assert(video);
|
||||
|
||||
video.modify()->setName( file.filename().string() );
|
||||
video.modify()->setDuration( boost::any_cast<boost::posix_time::time_duration>(items[MetaData::Duration]) );
|
||||
video.modify()->setLastWriteTime(lastWriteTime);
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
catch( std::exception& e ) {
|
||||
LMS_LOG(MOD_DBUPDATER, SEV_ERROR) << "Exception while parsing video file : '" << file << "': '" << e.what() << "' => skipping!";
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
} // namespace DatabaseUpdater
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "database/DatabaseHandler.hpp"
|
||||
#include "database/MediaDirectory.hpp"
|
||||
#include "database/FileTypes.hpp" // to remove
|
||||
#include "database/DatabaseHandler.hpp"
|
||||
|
||||
namespace DatabaseUpdater {
|
||||
@@ -51,20 +50,19 @@ class Updater
|
||||
const std::vector<boost::filesystem::path>& extensions);
|
||||
|
||||
|
||||
// Video
|
||||
|
||||
void processDirectory( const boost::filesystem::path& rootDirectory,
|
||||
const boost::filesystem::path& directory,
|
||||
Database::MediaDirectory::Type type,
|
||||
Stats& stats);
|
||||
|
||||
void processVideoFile( const boost::filesystem::path& file);
|
||||
|
||||
// Audio
|
||||
void checkAudioFiles( Stats& stats );
|
||||
void processAudioFile( const boost::filesystem::path& file, Stats& stats);
|
||||
|
||||
Database::Path::pointer getAddPath(const boost::filesystem::path& path);
|
||||
// Video
|
||||
void checkVideoFiles( Stats& stats );
|
||||
void processVideoFile( const boost::filesystem::path& file, Stats& stats);
|
||||
|
||||
bool _running;
|
||||
Wt::WIOService _ioService;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
// Db types
|
||||
#include "AudioTypes.hpp"
|
||||
#include "FileTypes.hpp"
|
||||
#include "VideoTypes.hpp"
|
||||
#include "MediaDirectory.hpp"
|
||||
#include "User.hpp"
|
||||
|
||||
@@ -67,7 +67,6 @@ _dbBackend( db.string() )
|
||||
_session.mapClass<Database::Artist>("artist");
|
||||
_session.mapClass<Database::Release>("release");
|
||||
_session.mapClass<Database::Release>("release");
|
||||
_session.mapClass<Database::Path>("path");
|
||||
_session.mapClass<Database::Video>("video");
|
||||
_session.mapClass<Database::MediaDirectory>("media_directory");
|
||||
_session.mapClass<Database::MediaDirectorySettings>("media_directory_settings");
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
#ifndef DATABASE_FILE_TYPES_HPP
|
||||
#define DATABASE_FILE_TYPES_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <Wt/Dbo/Dbo>
|
||||
#include <Wt/Dbo/WtSqlTraits>
|
||||
|
||||
#include <Wt/WDateTime>
|
||||
|
||||
#include "VideoTypes.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
class Path
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Wt::Dbo::ptr<Path> pointer;
|
||||
|
||||
Path();
|
||||
Path(boost::filesystem::path p);
|
||||
|
||||
// utility
|
||||
static pointer create(Wt::Dbo::Session& session, boost::filesystem::path p);
|
||||
static pointer create(Wt::Dbo::Session& session, boost::filesystem::path p, Path::pointer parent);
|
||||
static pointer getByPath(Wt::Dbo::Session& session, boost::filesystem::path p);
|
||||
static std::vector< pointer > getRoots(Wt::Dbo::Session& session); // get root pathes (no parent!)
|
||||
|
||||
// Modifiers
|
||||
void addChild( pointer child );
|
||||
void setLastWriteTime(boost::posix_time::ptime time) { _fileLastWrite = time; }
|
||||
void setChecksum(const std::vector<unsigned char>& checksum) { _fileChecksum = checksum; }
|
||||
void setCreationTime(const boost::posix_time::ptime& time) { _creationTime = time; }
|
||||
|
||||
// Accessors
|
||||
std::string getFileName(void) const;
|
||||
boost::filesystem::path getPath(void) const {return boost::filesystem::path(_filePath);}
|
||||
bool isDirectory() const {return _isDirectory;}
|
||||
std::vector< pointer > getChilds() const;
|
||||
pointer getParent() const;
|
||||
boost::posix_time::ptime getLastWriteTime(void) const { return _fileLastWrite; }
|
||||
const std::vector<unsigned char>& getChecksum(void) const { return _fileChecksum; }
|
||||
Wt::Dbo::ptr<Video> getVideo();
|
||||
const Wt::Dbo::ptr<Video> getVideo() const;
|
||||
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
{
|
||||
Wt::Dbo::field(a, _filePath, "path");
|
||||
Wt::Dbo::field(a, _isDirectory, "directory");
|
||||
Wt::Dbo::field(a, _creationTime, "creation_time");
|
||||
Wt::Dbo::field(a, _fileLastWrite, "last_write");
|
||||
Wt::Dbo::field(a, _fileChecksum, "checksum");
|
||||
Wt::Dbo::hasMany(a, _childPathes, Wt::Dbo::ManyToMany, "path_path", "child_path_id");
|
||||
Wt::Dbo::hasMany(a, _parentPathes, Wt::Dbo::ManyToMany, "path_path", "parent_path_id");
|
||||
Wt::Dbo::hasMany(a, _video, Wt::Dbo::ManyToOne, "path");
|
||||
}
|
||||
private:
|
||||
|
||||
std::string _filePath;
|
||||
bool _isDirectory;
|
||||
boost::posix_time::ptime _creationTime;
|
||||
std::vector<unsigned char> _fileChecksum;
|
||||
boost::posix_time::ptime _fileLastWrite;
|
||||
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<Video> > _video;
|
||||
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<Path> > _childPathes; // Child pathes
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<Path> > _parentPathes; // Parent pathes
|
||||
|
||||
};
|
||||
|
||||
} // namespace Database
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
|
||||
#include "FileTypes.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
Path::Path()
|
||||
{}
|
||||
|
||||
Path::Path(boost::filesystem::path p)
|
||||
: _filePath (p.string()),
|
||||
_isDirectory( boost::filesystem::is_directory( _filePath ) )
|
||||
{}
|
||||
|
||||
Path::pointer
|
||||
Path::create(Wt::Dbo::Session& session, boost::filesystem::path p)
|
||||
{
|
||||
return session.add(new Path(p));
|
||||
}
|
||||
|
||||
Path::pointer
|
||||
Path::create(Wt::Dbo::Session& session, boost::filesystem::path p, Path::pointer parent)
|
||||
{
|
||||
Path::pointer res = session.add(new Path(p));
|
||||
if (parent)
|
||||
parent.modify()->addChild( res );
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
Path::addChild( pointer child)
|
||||
{
|
||||
_childPathes.insert(child);
|
||||
}
|
||||
|
||||
Path::pointer
|
||||
Path::getByPath(Wt::Dbo::Session& session, boost::filesystem::path p)
|
||||
{
|
||||
return session.find<Path>().where("path = ?").bind( p.string() );
|
||||
}
|
||||
|
||||
std::vector<Path::pointer>
|
||||
Path::getChilds(void) const
|
||||
{
|
||||
std::vector< pointer > childs;
|
||||
|
||||
// Get childs in another way: order by type then name
|
||||
Wt::Dbo::Query< Path::pointer> query = _childPathes.find().orderBy("path.directory DESC, path.path");
|
||||
Wt::Dbo::collection< Path::pointer > res = query.resultList();
|
||||
|
||||
std::copy( res.begin(), res.end(), std::back_inserter( childs ));
|
||||
return childs;
|
||||
}
|
||||
|
||||
Path::pointer
|
||||
Path::getParent(void) const
|
||||
{
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<Path> >::const_iterator it = _parentPathes.begin();
|
||||
return it != _parentPathes.end() ? *it : Path::pointer();
|
||||
}
|
||||
|
||||
std::vector<Path::pointer>
|
||||
Path::getRoots(Wt::Dbo::Session& session)
|
||||
{
|
||||
std::vector<pointer> roots;
|
||||
|
||||
typedef Wt::Dbo::collection< pointer > Pathes;
|
||||
|
||||
Pathes pathes = session.find<Path>();
|
||||
|
||||
for (Pathes::const_iterator it = pathes.begin(); it != pathes.end(); ++it)
|
||||
{
|
||||
if (!(*it)->getParent())
|
||||
{
|
||||
std::cout << "path '" << (*it)->getPath() << "' has no parent!" << std::endl;
|
||||
roots.push_back( *it );
|
||||
}
|
||||
}
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
Wt::Dbo::ptr<Video>
|
||||
Path::getVideo()
|
||||
{
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<Video> >::const_iterator it = _video.begin();
|
||||
return it != _video.end() ? *it : Wt::Dbo::ptr<Video>();
|
||||
}
|
||||
|
||||
const Wt::Dbo::ptr<Video>
|
||||
Path::getVideo() const
|
||||
{
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<Video> >::const_iterator it = _video.begin();
|
||||
return it != _video.end() ? *it : Wt::Dbo::ptr<Video>();
|
||||
}
|
||||
|
||||
std::string
|
||||
Path::getFileName(void) const
|
||||
{
|
||||
if (isDirectory())
|
||||
return boost::filesystem::path(_filePath).string();
|
||||
else
|
||||
return boost::filesystem::path(_filePath).filename().string();
|
||||
}
|
||||
|
||||
} // namespace Database
|
||||
+16
-6
@@ -1,22 +1,32 @@
|
||||
#include "VideoTypes.hpp"
|
||||
|
||||
#include "FileTypes.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
Video::Video()
|
||||
{
|
||||
}
|
||||
|
||||
Video::Video(Wt::Dbo::ptr<Path> path)
|
||||
: _path(path)
|
||||
Video::Video(const boost::filesystem::path& p)
|
||||
: _filePath(p.string())
|
||||
{
|
||||
}
|
||||
|
||||
Video::pointer
|
||||
Video::create(Wt::Dbo::Session& session, Wt::Dbo::ptr<Path> path)
|
||||
Video::create(Wt::Dbo::Session& session, const boost::filesystem::path& p)
|
||||
{
|
||||
return session.add(new Video(path));
|
||||
return session.add(new Video(p));
|
||||
}
|
||||
|
||||
Wt::Dbo::collection< Video::pointer >
|
||||
Video::getAll(Wt::Dbo::Session& session)
|
||||
{
|
||||
return session.find<Video>();
|
||||
}
|
||||
|
||||
Video::pointer
|
||||
Video::getByPath(Wt::Dbo::Session& session, const boost::filesystem::path& p)
|
||||
{
|
||||
return session.find<Video>().where("path = ?").bind(p.string());
|
||||
}
|
||||
|
||||
} // namespace Video
|
||||
|
||||
+12
-9
@@ -12,8 +12,6 @@
|
||||
|
||||
namespace Database {
|
||||
|
||||
class Path;
|
||||
|
||||
class Video
|
||||
{
|
||||
public:
|
||||
@@ -21,37 +19,42 @@ class Video
|
||||
typedef Wt::Dbo::ptr<Video> pointer;
|
||||
|
||||
Video();
|
||||
Video( Wt::Dbo::ptr<Path> path);
|
||||
Video( const boost::filesystem::path& p);
|
||||
|
||||
// Find utilities
|
||||
static pointer getByPath(Wt::Dbo::Session& session, Wt::Dbo::ptr<Path> path);
|
||||
static pointer getByPath(Wt::Dbo::Session& session, const boost::filesystem::path& p);
|
||||
static Wt::Dbo::collection< pointer > getAll(Wt::Dbo::Session& session);
|
||||
static Wt::Dbo::collection< pointer > getByParentPath(Wt::Dbo::Session& session, const boost::filesystem::path& p);
|
||||
|
||||
// Create utility
|
||||
static pointer create(Wt::Dbo::Session& session, Wt::Dbo::ptr<Path> path);
|
||||
static pointer create(Wt::Dbo::Session& session, const boost::filesystem::path& p);
|
||||
|
||||
// Modifiers
|
||||
void setName(const std::string& name) { _name = name; }
|
||||
void setDuration(boost::posix_time::time_duration duration) { _duration = duration; }
|
||||
void setLastWriteTime(boost::posix_time::ptime time) { _fileLastWrite = time; }
|
||||
|
||||
// Accessors
|
||||
std::string getName(void) const { return _name; }
|
||||
Wt::Dbo::ptr<Path> getPath(void) { return _path; }
|
||||
std::string getName(void) const { return _name; }
|
||||
boost::posix_time::time_duration getDuration(void) const { return _duration; }
|
||||
boost::filesystem::path getPath(void) const { return _filePath; }
|
||||
boost::posix_time::ptime getLastWriteTime(void) const { return _fileLastWrite; }
|
||||
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
{
|
||||
Wt::Dbo::field(a, _name, "name");
|
||||
Wt::Dbo::field(a, _duration, "duration");
|
||||
Wt::Dbo::belongsTo(a, _path, "path");
|
||||
Wt::Dbo::field(a, _fileLastWrite, "last_write");
|
||||
Wt::Dbo::field(a, _filePath, "path");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Wt::Dbo::ptr<Path> _path;
|
||||
std::string _name;
|
||||
boost::posix_time::time_duration _duration;
|
||||
std::string _filePath;
|
||||
boost::posix_time::ptime _fileLastWrite;
|
||||
|
||||
}; // Video
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
|
||||
#include <Wt/WMediaPlayer>
|
||||
#include <Wt/WFileResource>
|
||||
#include "transcode/Parameters.hpp"
|
||||
|
||||
#include "resource/AvConvTranscodeStreamResource.hpp"
|
||||
#include "transcode/Parameters.hpp"
|
||||
#include "database/VideoTypes.hpp"
|
||||
#include "database/MediaDirectory.hpp"
|
||||
|
||||
#include "VideoDatabaseWidget.hpp"
|
||||
|
||||
@@ -20,15 +21,12 @@ VideoDatabaseWidget::VideoDatabaseWidget(Database::Handler& db, Wt::WContainerW
|
||||
_table = new Wt::WTable( this );
|
||||
_table->setHeaderCount(1);
|
||||
|
||||
Wt::Dbo::Transaction transaction ( _db.getSession() );
|
||||
|
||||
updateView( Database::Path::pointer() );
|
||||
|
||||
_table->addStyleClass("table form-inline");
|
||||
|
||||
_table->toggleStyleClass("table-hover", true);
|
||||
_table->toggleStyleClass("table-striped", true);
|
||||
|
||||
updateView( boost::filesystem::path(), 0);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -40,18 +38,20 @@ VideoDatabaseWidget::addHeader(void)
|
||||
}
|
||||
|
||||
void
|
||||
VideoDatabaseWidget::addDirectory(const std::string& name, const boost::filesystem::path& path)
|
||||
VideoDatabaseWidget::addDirectory(const std::string& name, boost::filesystem::path path, size_t depth)
|
||||
{
|
||||
|
||||
int row = _table->rowCount();
|
||||
|
||||
std::cout << "Adding DIR at row " << row << ", path = '" << path << "'" << std::endl;
|
||||
|
||||
new Wt::WText(Wt::WString::fromUTF8( name ), _table->elementAt(row, 0));
|
||||
new Wt::WText(Wt::WString::fromUTF8( " " ), _table->elementAt(row, 1));
|
||||
|
||||
Wt::WPushButton* btn = new Wt::WPushButton(Wt::WString::fromUTF8( "Open"), _table->elementAt(row, 2));
|
||||
btn->clicked().connect( boost::bind(&VideoDatabaseWidget::handleOpenDirectory, this, path) );
|
||||
|
||||
btn->clicked().connect(std::bind([=] () {
|
||||
updateView(path, depth);
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -61,82 +61,67 @@ VideoDatabaseWidget::addVideo(const std::string& name, const boost::posix_time::
|
||||
|
||||
int row = _table->rowCount();
|
||||
|
||||
std::cout << "Adding VIDEO at row " << row << ", path = '" << path << "'" << std::endl;
|
||||
|
||||
new Wt::WText(Wt::WString::fromUTF8( name ), _table->elementAt(row, 0));
|
||||
new Wt::WText(Wt::WString::fromUTF8( boost::posix_time::to_simple_string( duration )), _table->elementAt(row, 1));
|
||||
|
||||
Wt::WPushButton* btn = new Wt::WPushButton(Wt::WString::fromUTF8( "Play"), _table->elementAt(row, 2));
|
||||
btn->clicked().connect( boost::bind(&VideoDatabaseWidget::handlePlayVideo, this, path) );
|
||||
|
||||
btn->clicked().connect(std::bind([=] () {
|
||||
playVideo().emit(path);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VideoDatabaseWidget::updateView(Database::Path::pointer directory)
|
||||
VideoDatabaseWidget::updateView(boost::filesystem::path directory, size_t depth)
|
||||
{
|
||||
// Clear table from row 1 to end
|
||||
// while(_table->rowCount() > 2)
|
||||
// _table->deleteRow( _table->rowCount() - 1);
|
||||
|
||||
_table->clear();
|
||||
|
||||
addHeader();
|
||||
|
||||
std::vector< Database::Path::pointer > pathes;
|
||||
if(directory)
|
||||
// If directory is not valid, add the root Media Directories
|
||||
if (depth == 0)
|
||||
{
|
||||
pathes = directory->getChilds();
|
||||
// Add parent directory
|
||||
addDirectory("<Parent>", directory->getParent() ? directory->getParent() ->getPath() : boost::filesystem::path());
|
||||
Wt::Dbo::Transaction transaction ( _db.getSession() );
|
||||
|
||||
std::vector<Database::MediaDirectory::pointer> dirs
|
||||
= Database::MediaDirectory::getByType(_db.getSession(), Database::MediaDirectory::Video);
|
||||
|
||||
BOOST_FOREACH(Database::MediaDirectory::pointer dir, dirs)
|
||||
{
|
||||
addDirectory( dir->getPath().filename().string(),
|
||||
dir->getPath(),
|
||||
depth + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
pathes = Database::Path::getRoots(_db.getSession() );
|
||||
|
||||
// Add childs
|
||||
BOOST_FOREACH(Database::Path::pointer path, pathes)
|
||||
{
|
||||
std::cout << "Adding path " << path->getPath() << std::endl;
|
||||
if (path->isDirectory())
|
||||
addDirectory( path->getFileName(), path->getPath());
|
||||
else if (path->getVideo())
|
||||
addVideo( path->getFileName(), path->getVideo()->getDuration(), path->getPath());
|
||||
else
|
||||
std::cerr << "Bad type??" << std::endl;
|
||||
addDirectory( "..", directory.parent_path(), depth - 1);
|
||||
|
||||
// Iterators over files in the directory
|
||||
// If directory, add a directory entry
|
||||
// If video, add a video entry
|
||||
std::vector<boost::filesystem::path> paths;
|
||||
std::copy(boost::filesystem::directory_iterator(directory), boost::filesystem::directory_iterator(), std::back_inserter(paths));
|
||||
|
||||
std::sort(paths.begin(), paths.end());
|
||||
|
||||
BOOST_FOREACH(const boost::filesystem::path& path, paths)
|
||||
{
|
||||
if (boost::filesystem::is_directory(path))
|
||||
addDirectory( path.filename().string(), path, depth + 1);
|
||||
else if (boost::filesystem::is_regular(path) )
|
||||
{
|
||||
Wt::Dbo::Transaction transaction ( _db.getSession() );
|
||||
|
||||
Database::Video::pointer video = Database::Video::getByPath( _db.getSession(), path);
|
||||
if (video)
|
||||
addVideo( video->getName(), video->getDuration(), path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
VideoDatabaseWidget::handleOpenDirectory(boost::filesystem::path path)
|
||||
{
|
||||
Wt::Dbo::Transaction transaction ( _db.getSession() );
|
||||
|
||||
Database::Path::pointer directory = Database::Path::getByPath(_db.getSession(), path);
|
||||
updateView(directory);
|
||||
}
|
||||
|
||||
void
|
||||
VideoDatabaseWidget::handlePlayVideo(const boost::filesystem::path& videoFilePath)
|
||||
{
|
||||
std::cout << "Wants to play video " << videoFilePath << std::endl;
|
||||
|
||||
Wt::Dbo::Transaction transaction ( _db.getSession() );
|
||||
|
||||
Database::Path::pointer path = Database::Path::getByPath(_db.getSession(), videoFilePath);
|
||||
Database::Video::pointer video;
|
||||
if (path)
|
||||
video = path->getVideo();
|
||||
|
||||
if (!video)
|
||||
{
|
||||
std::cerr << "Cannot find video for this path '" << videoFilePath << "'" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Emit signal
|
||||
playVideo().emit(videoFilePath);
|
||||
|
||||
}
|
||||
|
||||
} // namespace UserInterface
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <Wt/WContainerWidget>
|
||||
|
||||
#include "common/SessionData.hpp"
|
||||
#include "database/FileTypes.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
|
||||
@@ -19,15 +18,12 @@ class VideoDatabaseWidget : public Wt::WContainerWidget
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void updateView(Database::Path::pointer directory);
|
||||
void handleOpenDirectory(boost::filesystem::path directory);
|
||||
void handlePlayVideo(const boost::filesystem::path& path);
|
||||
|
||||
void addHeader(void);
|
||||
void addDirectory(const std::string& name, const boost::filesystem::path& path);
|
||||
void addDirectory(const std::string& name, boost::filesystem::path path, size_t depth);
|
||||
void addVideo(const std::string& name, const boost::posix_time::time_duration& duration, const boost::filesystem::path& path);
|
||||
|
||||
void updateView(boost::filesystem::path directory, size_t depth);
|
||||
|
||||
Database::Handler& _db;
|
||||
|
||||
Wt::Signal< boost::filesystem::path > _playVideo;
|
||||
|
||||
Reference in New Issue
Block a user