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
8bc2fddf
Commit
8bc2fddf
authored
Dec 16, 2015
by
Hugo Beauzée-Luyssen
Browse files
Propagate device removal to files & folders
parent
69be8ef7
Changes
8
Hide whitespace changes
Inline
Side-by-side
include/factory/IFileSystem.h
View file @
8bc2fddf
...
...
@@ -54,6 +54,5 @@ namespace factory
/// \return A representation of the device, or nullptr if the device is currently unavailable.
///
virtual
std
::
shared_ptr
<
fs
::
IDevice
>
createDevice
(
const
std
::
string
&
uuid
)
=
0
;
};
}
src/Folder.cpp
View file @
8bc2fddf
...
...
@@ -42,7 +42,8 @@ Folder::Folder(DBConnection dbConnection, sqlite::Row& row )
>>
m_parent
>>
m_lastModificationDate
>>
m_isBlacklisted
>>
m_deviceId
;
>>
m_deviceId
>>
m_isPresent
;
}
Folder
::
Folder
(
const
std
::
string
&
path
,
time_t
lastModificationDate
,
unsigned
int
parent
,
unsigned
int
deviceId
)
...
...
@@ -52,6 +53,7 @@ Folder::Folder( const std::string& path, time_t lastModificationDate, unsigned i
,
m_lastModificationDate
(
lastModificationDate
)
,
m_isBlacklisted
(
false
)
,
m_deviceId
(
deviceId
)
,
m_isPresent
(
true
)
{
}
...
...
@@ -65,10 +67,19 @@ bool Folder::createTable(DBConnection connection)
"last_modification_date UNSIGNED INTEGER,"
"is_blacklisted INTEGER,"
"device_id UNSIGNED INTEGER,"
"is_present BOOLEAN NOT NULL DEFAULT 1,"
"FOREIGN KEY (id_parent) REFERENCES "
+
policy
::
FolderTable
::
Name
+
"(id_folder) ON DELETE CASCADE"
"(id_folder) ON DELETE CASCADE,"
"FOREIGN KEY (device_id) REFERENCES "
+
policy
::
DeviceTable
::
Name
+
"(id_device) ON DELETE CASCADE"
")"
;
return
sqlite
::
Tools
::
executeRequest
(
connection
,
req
);
std
::
string
triggerReq
=
"CREATE TRIGGER IF NOT EXISTS is_device_present AFTER UPDATE OF is_present ON "
+
policy
::
DeviceTable
::
Name
+
" BEGIN"
" UPDATE "
+
policy
::
FolderTable
::
Name
+
" SET is_present = new.is_present WHERE device_id = new.id_device;"
" END"
;
return
sqlite
::
Tools
::
executeRequest
(
connection
,
req
)
&&
sqlite
::
Tools
::
executeRequest
(
connection
,
triggerReq
);
}
std
::
shared_ptr
<
Folder
>
Folder
::
create
(
DBConnection
connection
,
const
std
::
string
&
path
,
time_t
lastModificationDate
,
unsigned
int
parentId
,
Device
&
device
)
...
...
src/Folder.h
View file @
8bc2fddf
...
...
@@ -76,6 +76,7 @@ private:
unsigned
int
m_lastModificationDate
;
bool
m_isBlacklisted
;
unsigned
int
m_deviceId
;
bool
m_isPresent
;
friend
struct
policy
::
FolderTable
;
};
src/Media.cpp
View file @
8bc2fddf
...
...
@@ -60,7 +60,8 @@ Media::Media( DBConnection dbConnection, sqlite::Row& row )
>>
m_insertionDate
>>
m_snapshot
>>
m_isParsed
>>
m_title
;
>>
m_title
>>
m_isPresent
;
}
Media
::
Media
(
const
fs
::
IFile
*
file
,
unsigned
int
folderId
,
const
std
::
string
&
title
,
Type
type
)
...
...
@@ -76,6 +77,7 @@ Media::Media( const fs::IFile* file, unsigned int folderId, const std::string& t
,
m_insertionDate
(
time
(
nullptr
)
)
,
m_isParsed
(
false
)
,
m_title
(
title
)
,
m_isPresent
(
true
)
,
m_changed
(
false
)
{
}
...
...
@@ -330,6 +332,7 @@ bool Media::createTable( DBConnection connection )
"snapshot TEXT,"
"parsed BOOLEAN NOT NULL DEFAULT 0,"
"title TEXT,"
"is_present BOOLEAN NOT NULL DEFAULT 1,"
"FOREIGN KEY (show_episode_id) REFERENCES "
+
policy
::
ShowEpisodeTable
::
Name
+
"(id_episode) ON DELETE CASCADE,"
"FOREIGN KEY (movie_id) REFERENCES "
+
policy
::
MovieTable
::
Name
...
...
@@ -337,7 +340,13 @@ bool Media::createTable( DBConnection connection )
"FOREIGN KEY (folder_id) REFERENCES "
+
policy
::
FolderTable
::
Name
+
"(id_folder) ON DELETE CASCADE"
")"
;
return
sqlite
::
Tools
::
executeRequest
(
connection
,
req
);
std
::
string
triggerReq
=
"CREATE TRIGGER IF NOT EXISTS is_folder_present AFTER UPDATE OF is_present ON "
+
policy
::
FolderTable
::
Name
+
" BEGIN"
" UPDATE "
+
policy
::
MediaTable
::
Name
+
" SET is_present = new.is_present WHERE folder_id = new.id_folder;"
" END"
;
return
sqlite
::
Tools
::
executeRequest
(
connection
,
req
)
&&
sqlite
::
Tools
::
executeRequest
(
connection
,
triggerReq
);
}
bool
Media
::
addLabel
(
LabelPtr
label
)
...
...
src/Media.h
View file @
8bc2fddf
...
...
@@ -118,6 +118,7 @@ class Media : public IMedia, public DatabaseHelpers<Media, policy::MediaTable>
std
::
string
m_snapshot
;
bool
m_isParsed
;
std
::
string
m_title
;
bool
m_isPresent
;
// Auto fetched related properties
AlbumTrackPtr
m_albumTrack
;
...
...
src/MediaLibrary.cpp
View file @
8bc2fddf
...
...
@@ -143,8 +143,13 @@ bool MediaLibrary::initialize( const std::string& dbPath, const std::string& sna
}
auto
t
=
m_dbConnection
->
newTransaction
();
if
(
(
Media
::
createTable
(
m_dbConnection
.
get
()
)
&&
// We need to create the tables in order of triggers creation
// Device is the "root of all evil". When a device is modified,
// we will trigger an update on folder, which will trigger
// an update on files, and so on.
if
(
(
Device
::
createTable
(
m_dbConnection
.
get
()
)
&&
Folder
::
createTable
(
m_dbConnection
.
get
()
)
&&
Media
::
createTable
(
m_dbConnection
.
get
()
)
&&
Label
::
createTable
(
m_dbConnection
.
get
()
)
&&
Album
::
createTable
(
m_dbConnection
.
get
()
)
&&
AlbumTrack
::
createTable
(
m_dbConnection
.
get
()
)
&&
...
...
@@ -155,8 +160,7 @@ bool MediaLibrary::initialize( const std::string& dbPath, const std::string& sna
AudioTrack
::
createTable
(
m_dbConnection
.
get
()
)
&&
Artist
::
createTable
(
m_dbConnection
.
get
()
)
&&
Artist
::
createDefaultArtists
(
m_dbConnection
.
get
()
)
&&
Settings
::
createTable
(
m_dbConnection
.
get
()
)
&&
Device
::
createTable
(
m_dbConnection
.
get
()
)
)
==
false
)
Settings
::
createTable
(
m_dbConnection
.
get
()
)
)
==
false
)
{
LOG_ERROR
(
"Failed to create database structure"
);
return
false
;
...
...
@@ -182,25 +186,26 @@ void MediaLibrary::setVerbosity(LogLevel v)
std
::
vector
<
MediaPtr
>
MediaLibrary
::
files
()
{
return
Media
::
fetchAll
<
IMedia
>
(
m_dbConnection
.
get
()
);
static
const
std
::
string
req
=
"SELECT * FROM "
+
policy
::
MediaTable
::
Name
+
" WHERE is_present = 1"
;
return
Media
::
fetchAll
<
IMedia
>
(
m_dbConnection
.
get
(),
req
);
}
std
::
vector
<
MediaPtr
>
MediaLibrary
::
audioFiles
()
{
static
const
std
::
string
req
=
"SELECT * FROM "
+
policy
::
MediaTable
::
Name
+
" WHERE type = ? ORDER BY title"
;
static
const
std
::
string
req
=
"SELECT * FROM "
+
policy
::
MediaTable
::
Name
+
" WHERE type = ?
AND is_present = 1
ORDER BY title"
;
return
Media
::
fetchAll
<
IMedia
>
(
m_dbConnection
.
get
(),
req
,
IMedia
::
Type
::
AudioType
);
}
std
::
vector
<
MediaPtr
>
MediaLibrary
::
videoFiles
()
{
static
const
std
::
string
req
=
"SELECT * FROM "
+
policy
::
MediaTable
::
Name
+
" WHERE type = ? ORDER BY title"
;
static
const
std
::
string
req
=
"SELECT * FROM "
+
policy
::
MediaTable
::
Name
+
" WHERE type = ?
AND is_present = 1
ORDER BY title"
;
return
Media
::
fetchAll
<
IMedia
>
(
m_dbConnection
.
get
(),
req
,
IMedia
::
Type
::
VideoType
);
}
MediaPtr
MediaLibrary
::
file
(
const
std
::
string
&
path
)
{
static
const
std
::
string
req
=
"SELECT * FROM "
+
policy
::
MediaTable
::
Name
+
" WHERE mrl = ?"
;
" WHERE mrl = ?
AND is_present = 1
"
;
return
Media
::
fetch
(
m_dbConnection
.
get
(),
req
,
path
);
}
...
...
src/Parser.cpp
View file @
8bc2fddf
...
...
@@ -143,7 +143,7 @@ void Parser::restore()
return
;
static
const
std
::
string
req
=
"SELECT * FROM "
+
policy
::
MediaTable
::
Name
+
" WHERE parsed = 0"
;
+
" WHERE parsed = 0
AND is_present = 1
"
;
auto
media
=
Media
::
fetchAll
<
Media
>
(
m_dbConnection
,
req
);
std
::
lock_guard
<
std
::
mutex
>
lock
(
m_lock
);
...
...
src/discoverer/FsDiscoverer.cpp
View file @
8bc2fddf
...
...
@@ -91,8 +91,6 @@ void FsDiscoverer::reload()
device
->
setPresent
(
false
);
continue
;
}
if
(
folder
->
lastModificationDate
()
==
f
->
lastModificationDate
()
)
continue
;
checkSubfolders
(
folder
.
get
(),
f
.
get
(),
blist
);
checkFiles
(
folder
.
get
(),
f
.
get
()
);
f
->
setLastModificationDate
(
folder
->
lastModificationDate
()
);
...
...
@@ -135,15 +133,25 @@ bool FsDiscoverer::checkSubfolders( fs::IDirectory* folder, Folder* parentFolder
continue
;
}
auto
folderInDb
=
*
it
;
if
(
subFolder
->
lastModificationDate
()
==
folderInDb
->
lastModificationDate
()
)
auto
deviceFs
=
subFolder
->
device
();
// If the device supposed to contain this folder is not present anymore, flag it as removed
if
(
deviceFs
==
nullptr
)
{
// Remove all folders that still exist in FS. That way, the list of folders that
// will still be in subFoldersInDB when we're done is the list of folders that have
// been deleted from the FS
auto
device
=
Device
::
fetch
(
m_dbConn
,
folderInDb
->
deviceId
()
);
if
(
device
==
nullptr
)
{
LOG_ERROR
(
"Failed to fetch device containing folder "
,
folderInDb
->
path
()
);
continue
;
}
LOG_INFO
(
"Device containing "
,
folderInDb
->
path
(),
" is not present anymore"
);
device
->
setPresent
(
false
);
// Don't let this folder be deleted after the main loop.
subFoldersInDB
.
erase
(
it
);
continue
;
}
// This folder was modified, let's recurse
// In any case, check for modifications, as a change related to a mountpoint might
// not update the folder modification date.
// Also, relying on the modification date probably isn't portable
checkSubfolders
(
subFolder
.
get
(),
folderInDb
.
get
(),
blacklist
);
checkFiles
(
subFolder
.
get
(),
folderInDb
.
get
()
);
folderInDb
->
setLastModificationDate
(
subFolder
->
lastModificationDate
()
);
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment