M CMakeLists.txt => CMakeLists.txt +7 -0
@@ 27,6 27,7 @@ include(ModuleUtils)
include(DiskImage)
include(AddPackage)
include(AutoModuleOption)
+include(AddDirectories)
message("Selected product: ${PRODUCT}")
message("Selected board: ${BOARD}")
@@ 167,6 168,12 @@ add_custom_target(
"Generating version info"
)
+add_directories(
+ TARGET user_directories_common
+ PREFIX ${CMAKE_BINARY_DIR}/sysroot/sys/user
+ DEPENDS assets
+ DIRECTORIES logs crash_dumps backup tmp storage audio
+)
add_library(version-header INTERFACE)
target_include_directories(version-header INTERFACE $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/source/include>)
add_dependencies(version-header version)
A cmake/modules/AddDirectories.cmake => cmake/modules/AddDirectories.cmake +31 -0
@@ 0,0 1,31 @@
+#[[
+Example of use:
+add_directories(
+ TARGET <target name>
+ PREFIX <paths prefix>
+ DEPENDS <dependencies list>
+ DIRECTORIES <dir1 dir2 dir3 dir_n>
+)
+]]#
+function(add_directories)
+ cmake_parse_arguments(
+ _ASSETS
+ ""
+ "TARGET;PREFIX"
+ "DEPENDS;DIRECTORIES"
+ ${ARGN}
+ )
+ set(command)
+ foreach (entry ${_ASSETS_DIRECTORIES})
+ list(APPEND command
+ COMMAND mkdir -p ${_ASSETS_PREFIX}/${entry})
+ endforeach ()
+
+ add_custom_target(
+ ${_ASSETS_TARGET}
+ DEPENDS ${_ASSETS_DEPENDS}
+ ${command}
+ COMMENT
+ "Adding directories: ${_ASSETS_DIRECTORIES}"
+ )
+endfunction()<
\ No newline at end of file
A doc/directories.md => doc/directories.md +77 -0
@@ 0,0 1,77 @@
+# PureOS directories structure
+
+## Audio
+
+Audio assets are split into two directories. Later, they are split further into subdirectories.
+Each subdirectory is exclusive to an application that uses it hence it is relatively easy to have specific assets tied
+to a specific application.
+
+### Internal partition
+Internal partition stores proprietary assets that can't be accessed/modified by a user. Its structure and contents are created
+at compile time. For technical info, please check the [CMake section](#CMake).
+
+Structure template:
+```
+assets/audio/
+ ├── app_1
+ ├── app_2
+ ├── app_3
+ └── app_n
+```
+
+For instance, Harmony directory:
+```
+assets/audio/
+ └── relaxation
+```
+
+Each product can have its structure freely defined. There are no restrictions applied. For instance, for the time being, there is no
+proprietary assets path in Pure as it is not required. It is because the Pure MusicPlayer application only loads assets from the user partition.
+
+### User partition
+User partition stores assets that may be accessed by using the Mudita Center. In contrast to the [Internal partition](#Internal partition),
+its permissions are set to write/read. It follows the same structure as the internal partition, i.e. each application has
+its subdirectory used exclusively. Its structure is also created at compile time, and its contents can be propagated with assets or not,
+it depends on the product. For technical info, please check the [CMake section](#CMake).
+
+Structure template:
+```
+user/
+└── audio
+ ├── app_1
+ ├── app_2
+ ├── app_3
+ └── app_n
+```
+For instance, Harmony directory:
+```
+user/
+└── audio
+ └── relaxation
+```
+and PurePhone:
+```
+user/
+└── audio
+ └── music_player
+```
+
+## Storage
+It is the directory accessible via MTP. Its purpose is to provide space for storing user files.
+
+```
+user/
+└── storage
+```
+
+## CMake
+
+Script used to create directories:
+[AddDirectories](../cmake/modules/AddDirectories.cmake)
+
+There are two targets created by using the script above,
+`user_directories_common` and `user_directories`. The first one creates common directories which are required for PureOS.
+The latter is used to create required product-related directories. They are both added as a dependency to both `BellHybrid-disk-img` and
+`PurePhone-disk-img` targets hence they will be invoked automatically upon generating the product image.
+
+
M module-apps/application-music-player/ApplicationMusicPlayer.cpp => module-apps/application-music-player/ApplicationMusicPlayer.cpp +3 -5
@@ 46,11 46,9 @@ namespace app
bus.channels.push_back(sys::BusChannel::ServiceAudioNotifications);
- auto tagsFetcher = std::make_unique<app::music::ServiceAudioTagsFetcher>(this);
-
- const auto musicPlayerFilesPath = purefs::createPath(purefs::dir::getUserDiskPath(), "music").string();
- auto songsRepository =
- std::make_unique<app::music::SongsRepository>(this, std::move(tagsFetcher), musicPlayerFilesPath);
+ const auto paths = std::vector<std::string>{purefs::dir::getUserAudioPath()};
+ auto tagsFetcher = std::make_unique<app::music::ServiceAudioTagsFetcher>(this);
+ auto songsRepository = std::make_unique<app::music::SongsRepository>(this, std::move(tagsFetcher), paths);
priv->songsModel = std::make_unique<app::music::SongsModel>(this, std::move(songsRepository));
auto audioOperations = std::make_unique<app::AsyncAudioOperations>(this);
M module-apps/apps-common/models/SongsRepository.cpp => module-apps/apps-common/models/SongsRepository.cpp +7 -6
@@ 32,15 32,16 @@ namespace app::music
SongsRepository::SongsRepository(ApplicationCommon *application,
std::unique_ptr<AbstractTagsFetcher> tagsFetcher,
- std::string pathPrefix)
+ const std::vector<std::string> &pathPrefixes)
: app::AsyncCallbackReceiver{application}, application{application},
- tagsFetcher(std::move(tagsFetcher)), pathPrefix{pathPrefix}
+ tagsFetcher(std::move(tagsFetcher)), pathPrefixes{pathPrefixes}
{}
void SongsRepository::initCache()
{
- auto query = std::make_unique<db::multimedia_files::query::GetLimited>(0, constants::cacheMaxSize);
- auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::MultimediaFiles);
+ auto query =
+ std::make_unique<db::multimedia_files::query::GetLimitedByPaths>(pathPrefixes, 0, constants::cacheMaxSize);
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::MultimediaFiles);
musicFilesModelCache.recordsOffset = 0;
task->setCallback([this](auto response) {
@@ 59,7 60,7 @@ namespace app::music
std::uint32_t limit,
const OnGetMusicFilesListCallback &callback)
{
- auto query = std::make_unique<db::multimedia_files::query::GetLimitedByPath>(pathPrefix, offset, limit);
+ auto query = std::make_unique<db::multimedia_files::query::GetLimitedByPaths>(pathPrefixes, offset, limit);
auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::MultimediaFiles);
task->setCallback([this, callback, offset](auto response) {
@@ 187,7 188,7 @@ namespace app::music
std::uint32_t limit,
const OnUpdateMusicFilesListCallback &callback)
{
- auto query = std::make_unique<db::multimedia_files::query::GetLimited>(offset, limit);
+ auto query = std::make_unique<db::multimedia_files::query::GetLimitedByPaths>(pathPrefixes, offset, limit);
auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::MultimediaFiles);
task->setCallback([offset, callback](auto response) {
M module-apps/apps-common/models/SongsRepository.hpp => module-apps/apps-common/models/SongsRepository.hpp +4 -4
@@ 64,9 64,9 @@ namespace app::music
class SongsRepository : public AbstractSongsRepository, public app::AsyncCallbackReceiver
{
public:
- explicit SongsRepository(ApplicationCommon *application,
- std::unique_ptr<AbstractTagsFetcher> tagsFetcher,
- std::string pathPrefix);
+ SongsRepository(ApplicationCommon *application,
+ std::unique_ptr<AbstractTagsFetcher> tagsFetcher,
+ const std::vector<std::string> &pathPrefixes);
void initCache();
void getMusicFilesList(std::uint32_t offset, std::uint32_t limit, const OnGetMusicFilesListCallback &callback);
@@ 88,7 88,7 @@ namespace app::music
std::unique_ptr<AbstractTagsFetcher> tagsFetcher;
- std::string pathPrefix;
+ std::vector<std::string> pathPrefixes;
/// collection of music files displayed in the list view
FilesCache musicFilesViewCache;
M module-db/Interface/MultimediaFilesRecord.cpp => module-db/Interface/MultimediaFilesRecord.cpp +5 -5
@@ 36,8 36,8 @@ namespace db::multimedia_files
if (typeid(*query) == typeid(query::GetLimited)) {
return runQueryImplGetLimited(std::static_pointer_cast<query::GetLimited>(query));
}
- if (typeid(*query) == typeid(query::GetLimitedByPath)) {
- return runQueryImplGetLimited(std::static_pointer_cast<query::GetLimitedByPath>(query));
+ if (typeid(*query) == typeid(query::GetLimitedByPaths)) {
+ return runQueryImplGetLimited(std::static_pointer_cast<query::GetLimitedByPaths>(query));
}
if (typeid(*query) == typeid(query::Remove)) {
return runQueryImplRemove(std::static_pointer_cast<query::Remove>(query));
@@ 252,10 252,10 @@ namespace db::multimedia_files
}
std::unique_ptr<db::multimedia_files::query::GetLimitedResult> MultimediaFilesRecordInterface::
- runQueryImplGetLimited(const std::shared_ptr<db::multimedia_files::query::GetLimitedByPath> &query)
+ runQueryImplGetLimited(const std::shared_ptr<db::multimedia_files::query::GetLimitedByPaths> &query)
{
- const auto records = database->files.getLimitOffsetByPath(query->path, query->offset, query->limit);
- auto response = std::make_unique<query::GetLimitedResult>(records, database->files.count());
+ const auto records = database->files.getLimitOffsetByPaths(query->paths, query->offset, query->limit);
+ auto response = std::make_unique<query::GetLimitedResult>(records, database->files.count(query->paths));
response->setRequestQuery(query);
return response;
M module-db/Interface/MultimediaFilesRecord.hpp => module-db/Interface/MultimediaFilesRecord.hpp +2 -2
@@ 34,7 34,7 @@ namespace db::multimedia_files::query
class GetCountForArtist;
class GetCountResult;
class GetLimited;
- class GetLimitedByPath;
+ class GetLimitedByPaths;
class GetLimitedForAlbum;
class GetLimitedForArtist;
class GetLimitedResult;
@@ 72,7 72,7 @@ namespace db::multimedia_files
std::unique_ptr<db::multimedia_files::query::GetLimitedResult> runQueryImplGetLimited(
const std::shared_ptr<db::multimedia_files::query::GetLimited> &query);
std::unique_ptr<db::multimedia_files::query::GetLimitedResult> runQueryImplGetLimited(
- const std::shared_ptr<db::multimedia_files::query::GetLimitedByPath> &query);
+ const std::shared_ptr<db::multimedia_files::query::GetLimitedByPaths> &query);
std::unique_ptr<db::multimedia_files::query::RemoveResult> runQueryImplRemove(
const std::shared_ptr<db::multimedia_files::query::Remove> &query);
std::unique_ptr<db::multimedia_files::query::RemoveResult> runQueryImplRemoveAll(
M module-db/Tables/MultimediaFilesTable.cpp => module-db/Tables/MultimediaFilesTable.cpp +67 -30
@@ 6,6 6,12 @@
#include <Database/QueryResult.hpp>
#include <Utils.hpp>
#include <magic_enum.hpp>
+#include <inttypes.h>
+
+#define u32_ "%" PRIu32
+#define u32_c "%" PRIu32 ","
+#define str_ "%Q"
+#define str_c "%Q,"
namespace db::multimedia_files
{
@@ 39,6 45,17 @@ namespace db::multimedia_files
return (!fileInfo.path.empty() && Record::isValid());
}
+ auto constructMatchPattern = [](const std::vector<std::string> &paths) -> std::string {
+ std::string ret;
+ for (auto e = paths.begin(); e != paths.end(); e++) {
+ ret += "path LIKE '" + *e + "%%'";
+ if (std::next(e) != paths.end()) {
+ ret += " or ";
+ }
+ }
+ return ret;
+ };
+
MultimediaFilesTable::MultimediaFilesTable(Database *db) : Table(db)
{
createTableRow = CreateTableRow;
@@ 53,7 70,8 @@ namespace db::multimedia_files
{
return db->execute("INSERT INTO files (path, media_type, size, title, artist, album, "
"comment, genre, year, track, song_length, bitrate, sample_rate, channels) "
- "VALUES('%q', '%q', %lu, '%q', '%q', '%q', '%q', '%q', %lu, %lu, %lu, %lu, %lu, %lu) "
+ "VALUES(" str_c str_c u32_c str_c str_c str_c str_c str_c u32_c u32_c u32_c u32_c u32_c u32_
+ ") "
"ON CONFLICT(path) DO UPDATE SET "
"path = excluded.path, "
"media_type = excluded.media_type, "
@@ 98,7 116,7 @@ namespace db::multimedia_files
return false;
}
- return db->execute("DELETE FROM files WHERE %q = '%q';", fieldName.c_str(), str);
+ return db->execute("DELETE FROM files WHERE %q = %Q;", fieldName.c_str(), str);
}
bool MultimediaFilesTable::removeAll()
@@ 108,9 126,10 @@ namespace db::multimedia_files
bool MultimediaFilesTable::update(TableRow entry)
{
- return db->execute("UPDATE files SET path = '%q', media_type = '%q', size = %lu, title = '%q', artist = '%q',"
- "album = '%q', comment = '%q', genre = '%q', year = %lu, track = %lu, song_length = %lu,"
- "bitrate = %lu, sample_rate = %lu, channels = %lu WHERE _id = %lu;",
+ return db->execute("UPDATE files SET path=" str_c "media_type=" str_c "size=" u32_c "title=" str_c
+ "artist=" str_c "album=" str_c "comment=" str_c "genre=" str_c "year=" u32_c "track=" u32_c
+ "song_length=" u32_c "bitrate=" u32_c "sample_rate=" u32_c "channels=" u32_
+ " WHERE _id=" u32_ ";",
entry.fileInfo.path.c_str(),
entry.fileInfo.mediaType.c_str(),
entry.fileInfo.size,
@@ 133,10 152,11 @@ namespace db::multimedia_files
auto path = oldPath.empty() ? entry.fileInfo.path : oldPath;
return db->execute("BEGIN TRANSACTION; "
- "INSERT OR IGNORE INTO files (path) VALUES ('%q'); "
- "UPDATE files SET path = '%q', media_type = '%q', size = %lu, title = '%q', artist = '%q', "
- "album = '%q', comment = '%q', genre = '%q', year = %lu, track = %lu, song_length = %lu, "
- "bitrate = %lu, sample_rate = %lu, channels = %lu WHERE path = '%q'; "
+ "INSERT OR IGNORE INTO files (path) VALUES (" str_ "); "
+ "UPDATE files SET path=" str_c "media_type=" str_c "size=" u32_c "title=" str_c
+ "artist=" str_c "album=" str_c "comment=" str_c "genre=" str_c "year=" u32_c "track=" u32_c
+ "song_length=" u32_c "bitrate=" u32_c "sample_rate=" u32_c "channels=" u32_
+ " WHERE path=" str_ "; "
"COMMIT;",
path.c_str(),
entry.fileInfo.path.c_str(),
@@ 158,7 178,7 @@ namespace db::multimedia_files
TableRow MultimediaFilesTable::getById(uint32_t id)
{
- auto retQuery = db->query("SELECT * FROM files WHERE _id = %lu;", id);
+ auto retQuery = db->query("SELECT * FROM files WHERE _id=" u32_ ";", id);
if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
return TableRow();
@@ 169,7 189,7 @@ namespace db::multimedia_files
TableRow MultimediaFilesTable::getByPath(std::string path)
{
- auto retQuery = db->query("SELECT * FROM files WHERE path = '%q';", path.c_str());
+ auto retQuery = db->query("SELECT * FROM files WHERE path=" str_ ";", path.c_str());
if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
return TableRow();
@@ 180,15 200,16 @@ namespace db::multimedia_files
std::vector<TableRow> MultimediaFilesTable::getLimitOffset(uint32_t offset, uint32_t limit)
{
- auto retQuery = db->query("SELECT * from files ORDER BY title ASC LIMIT %lu OFFSET %lu;", limit, offset);
+ auto retQuery =
+ db->query("SELECT * from files ORDER BY title ASC LIMIT " u32_ " OFFSET " u32_ ";", limit, offset);
return retQueryUnpack(std::move(retQuery));
}
auto MultimediaFilesTable::getArtistsLimitOffset(uint32_t offset, uint32_t limit) -> std::vector<Artist>
{
- auto retQuery =
- db->query("SELECT DISTINCT artist from files ORDER BY artist ASC LIMIT %lu OFFSET %lu;", limit, offset);
+ auto retQuery = db->query(
+ "SELECT DISTINCT artist from files ORDER BY artist ASC LIMIT " u32_ " OFFSET " u32_ ";", limit, offset);
if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
return {};
@@ 214,7 235,7 @@ namespace db::multimedia_files
return {};
}
- retQuery = db->query("SELECT * FROM files WHERE %q = '%q' ORDER BY title ASC LIMIT %lu OFFSET %lu;",
+ retQuery = db->query("SELECT * FROM files WHERE %q=" str_ " ORDER BY title ASC LIMIT " u32_ " OFFSET " u32_ ";",
fieldName.c_str(),
str,
limit,
@@ 245,8 266,10 @@ namespace db::multimedia_files
auto MultimediaFilesTable::getAlbumsLimitOffset(uint32_t offset, uint32_t limit) -> std::vector<Album>
{
- auto retQuery = db->query(
- "SELECT DISTINCT artist,album from files ORDER BY album ASC LIMIT %lu OFFSET %lu;", limit, offset);
+ auto retQuery =
+ db->query("SELECT DISTINCT artist,album from files ORDER BY album ASC LIMIT " u32_ " OFFSET " u32_ ";",
+ limit,
+ offset);
if ((retQuery == nullptr) || (retQuery->getRowCount() < 2)) {
return {};
@@ 277,7 300,7 @@ namespace db::multimedia_files
return 0;
}
- auto queryRet = db->query("SELECT COUNT(*) FROM files WHERE %q=%lu;", field, id);
+ auto queryRet = db->query("SELECT COUNT(*) FROM files WHERE " str_ "=" u32_ ";", field, id);
if ((queryRet == nullptr) || (queryRet->getRowCount() == 0)) {
return 0;
}
@@ 298,7 321,7 @@ namespace db::multimedia_files
auto MultimediaFilesTable::count(const Artist &artist) -> uint32_t
{
- auto queryRet = db->query("SELECT COUNT(*) FROM files WHERE artist='%q';", artist.c_str());
+ auto queryRet = db->query("SELECT COUNT(*) FROM files WHERE artist=" str_ " ;", artist.c_str());
if ((queryRet == nullptr) || (queryRet->getRowCount() == 0)) {
return 0;
}
@@ 309,19 332,19 @@ namespace db::multimedia_files
auto MultimediaFilesTable::getLimitOffset(const Album &album, uint32_t offset, uint32_t limit)
-> std::vector<TableRow>
{
- std::unique_ptr<QueryResult> retQuery = db->query(
- "SELECT * FROM files WHERE artist = '%q' AND album = '%q' ORDER BY title ASC LIMIT %lu OFFSET %lu;",
- album.artist.c_str(),
- album.title.c_str(),
- limit,
- offset);
+ std::unique_ptr<QueryResult> retQuery = db->query("SELECT * FROM files WHERE artist=" str_ " AND album=" str_
+ " ORDER BY title ASC LIMIT " u32_ " OFFSET " u32_ ";",
+ album.artist.c_str(),
+ album.title.c_str(),
+ limit,
+ offset);
return retQueryUnpack(std::move(retQuery));
}
auto MultimediaFilesTable::count(const Album &album) -> uint32_t
{
- auto queryRet = db->query("SELECT COUNT(*) FROM files WHERE artist='%q' AND album = '%q';",
+ auto queryRet = db->query("SELECT COUNT(*) FROM files WHERE artist=" str_ " AND album=" str_ ";",
album.artist.c_str(),
album.title.c_str());
if ((queryRet == nullptr) || (queryRet->getRowCount() == 0)) {
@@ 331,12 354,26 @@ namespace db::multimedia_files
return (*queryRet)[0].getUInt32();
}
- auto MultimediaFilesTable::getLimitOffsetByPath(const std::string &path, uint32_t offset, uint32_t limit)
- -> std::vector<TableRow>
+ auto MultimediaFilesTable::getLimitOffsetByPaths(const std::vector<std::string> &paths,
+ uint32_t offset,
+ uint32_t limit) -> std::vector<TableRow>
{
- std::string query = "SELECT * FROM files WHERE path LIKE '" + path + "%%' ORDER BY title ASC LIMIT " +
- std::to_string(limit) + " OFFSET " + std::to_string(offset) + ";";
+ const std::string query = "SELECT * FROM files WHERE " + constructMatchPattern(paths) +
+ " ORDER BY title ASC LIMIT " + std::to_string(limit) + " OFFSET " +
+ std::to_string(offset) + ";";
std::unique_ptr<QueryResult> retQuery = db->query(query.c_str());
return retQueryUnpack(std::move(retQuery));
}
+
+ auto MultimediaFilesTable::count(const std::vector<std::string> &paths) -> uint32_t
+ {
+ const std::string query = "SELECT COUNT(*) FROM files WHERE " + constructMatchPattern(paths) + ";";
+ const auto retQuery = db->query(query.c_str());
+
+ if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
+ return 0;
+ }
+
+ return (*retQuery)[0].getUInt32();
+ }
} // namespace db::multimedia_files
M module-db/Tables/MultimediaFilesTable.hpp => module-db/Tables/MultimediaFilesTable.hpp +9 -7
@@ 24,16 24,16 @@ namespace db::multimedia_files
Album album{};
std::string comment{};
std::string genre{};
- unsigned year{};
- unsigned track{};
+ std::uint32_t year{};
+ std::uint32_t track{};
};
struct AudioProperties
{
- unsigned songLength{}; /// in seconds
- unsigned bitrate{}; /// in kb/s
- unsigned sampleRate{}; /// in Hz
- unsigned channels{}; /// 1 - mono, 2 - stereo
+ std::uint32_t songLength{}; /// in seconds
+ std::uint32_t bitrate{}; /// in kb/s
+ std::uint32_t sampleRate{}; /// in Hz
+ std::uint32_t channels{}; /// 1 - mono, 2 - stereo
};
struct FileInfo
@@ 101,7 101,9 @@ namespace db::multimedia_files
auto getLimitOffset(const Album &album, uint32_t offset, uint32_t limit) -> std::vector<TableRow>;
auto count(const Album &album) -> uint32_t;
- auto getLimitOffsetByPath(const std::string &path, uint32_t offset, uint32_t limit) -> std::vector<TableRow>;
+ auto getLimitOffsetByPaths(const std::vector<std::string> &paths, uint32_t offset, uint32_t limit)
+ -> std::vector<TableRow>;
+ auto count(const std::vector<std::string> &paths) -> uint32_t;
TableRow getByPath(std::string path);
/// @note entry.ID is skipped
M module-db/queries/multimedia_files/QueryMultimediaFilesGetLimited.cpp => module-db/queries/multimedia_files/QueryMultimediaFilesGetLimited.cpp +4 -4
@@ 106,12 106,12 @@ namespace db::multimedia_files::query
return std::string{"GetAlbumsLimitedResult"};
}
- GetLimitedByPath::GetLimitedByPath(std::string path, uint32_t offset, uint32_t limit)
- : Query(Query::Type::Read), path{path}, offset(offset), limit(limit)
+ GetLimitedByPaths::GetLimitedByPaths(const std::vector<std::string> &paths, uint32_t offset, uint32_t limit)
+ : Query(Query::Type::Read), paths{paths}, offset(offset), limit(limit)
{}
- auto GetLimitedByPath::debugInfo() const -> std::string
+ auto GetLimitedByPaths::debugInfo() const -> std::string
{
- return std::string{"GetLimitedByPath"};
+ return std::string{"GetLimitedByPaths"};
}
} // namespace db::multimedia_files::query
M module-db/queries/multimedia_files/QueryMultimediaFilesGetLimited.hpp => module-db/queries/multimedia_files/QueryMultimediaFilesGetLimited.hpp +3 -3
@@ 101,13 101,13 @@ namespace db::multimedia_files::query
[[nodiscard]] auto debugInfo() const -> std::string override;
};
- class GetLimitedByPath : public Query
+ class GetLimitedByPaths : public Query
{
public:
- GetLimitedByPath(std::string path, uint32_t offset, uint32_t limit);
+ GetLimitedByPaths(const std::vector<std::string> &paths, uint32_t offset, uint32_t limit);
[[nodiscard]] auto debugInfo() const -> std::string override;
- const std::string path;
+ const std::vector<std::string> paths;
const uint32_t offset = 0;
const uint32_t limit = 0;
};
M module-db/tests/MultimediaFilesTable_tests.cpp => module-db/tests/MultimediaFilesTable_tests.cpp +98 -93
@@ 3,6 3,7 @@
#include <catch2/catch.hpp>
+#include "common.hpp"
#include <Databases/MultimediaFilesDB.hpp>
#include <Interface/MultimediaFilesRecord.hpp>
#include <queries/multimedia_files/QueryMultimediaFilesAdd.hpp>
@@ 36,31 37,31 @@ const std::vector<Album> albums = {{.artist = artists[0], .title = {}},
const std::vector<TableRow> records = {
{Record{DB_ID_NONE},
- .fileInfo = {.path = "user/music/file1.mp3", .mediaType = "audio/mp3", .size = 100},
+ .fileInfo = {.path = "user/audio/file1.mp3", .mediaType = "audio/mp3", .size = 100},
.tags = {.title = song1, .album = albums[3], .comment = "", .genre = "", .year = 2011, .track = 1},
.audioProperties = {.songLength = 300, .bitrate = 320, .sampleRate = 44100, .channels = 1}},
{Record{DB_ID_NONE},
- .fileInfo = {.path = "user/music/file2.mp3", .mediaType = "audio/mp3", .size = 100},
+ .fileInfo = {.path = "user/audio/file2.mp3", .mediaType = "audio/mp3", .size = 100},
.tags = {.title = song2, .album = albums[3], .comment = "", .genre = "", .year = 2011, .track = 1},
.audioProperties = {.songLength = 300, .bitrate = 320, .sampleRate = 44100, .channels = 1}},
{Record{DB_ID_NONE},
- .fileInfo = {.path = "user/music/file3.mp3", .mediaType = "audio/mp3", .size = 100},
+ .fileInfo = {.path = "user/audio/file3.mp3", .mediaType = "audio/mp3", .size = 100},
.tags = {.title = song2, .album = albums[4], .comment = "", .genre = "", .year = 2011, .track = 1},
.audioProperties = {.songLength = 300, .bitrate = 320, .sampleRate = 44100, .channels = 1}},
{Record{DB_ID_NONE},
- .fileInfo = {.path = "user/music/file4.mp3", .mediaType = "audio/mp3", .size = 100},
+ .fileInfo = {.path = "user/audio/file4.mp3", .mediaType = "audio/mp3", .size = 100},
.tags = {.title = song2, .album = albums[5], .comment = "", .genre = "", .year = 2011, .track = 1},
.audioProperties = {.songLength = 300, .bitrate = 320, .sampleRate = 44100, .channels = 1}},
{Record{DB_ID_NONE},
- .fileInfo = {.path = "user/music/file5.mp3", .mediaType = "audio/mp3", .size = 100},
+ .fileInfo = {.path = "user/audio/file5.mp3", .mediaType = "audio/mp3", .size = 100},
.tags = {.title = song3, .album = albums[0], .comment = "", .genre = "", .year = 2011, .track = 1},
.audioProperties = {.songLength = 300, .bitrate = 320, .sampleRate = 44100, .channels = 1}},
{Record{DB_ID_NONE},
- .fileInfo = {.path = "user/music/file6.mp3", .mediaType = "audio/mp3", .size = 100},
+ .fileInfo = {.path = "user/audio/file6.mp3", .mediaType = "audio/mp3", .size = 100},
.tags = {.title = song3, .album = albums[7], .comment = "", .genre = "", .year = 2011, .track = 1},
.audioProperties = {.songLength = 300, .bitrate = 320, .sampleRate = 44100, .channels = 1}},
{Record{DB_ID_NONE},
- .fileInfo = {.path = "user/music/file7.mp3", .mediaType = "audio/mp3", .size = 100},
+ .fileInfo = {.path = "user/audio/file7.mp3", .mediaType = "audio/mp3", .size = 100},
.tags = {.title = song3, .album = albums[5], .comment = "", .genre = "", .year = 2011, .track = 1},
.audioProperties = {.songLength = 300, .bitrate = 320, .sampleRate = 44100, .channels = 1}},
{Record{DB_ID_NONE},
@@ 78,17 79,8 @@ const std::vector<TableRow> records = {
TEST_CASE("Multimedia DB tests")
{
- REQUIRE(Database::initialize());
-
- const auto path = (std::filesystem::path{"sys/user"} / "multimedia.db");
- if (std::filesystem::exists(path)) {
- REQUIRE(std::filesystem::remove(path));
- }
-
- MultimediaFilesDB db(path.c_str());
- MultimediaFilesRecordInterface multimediaFilesRecordInterface(&db);
-
- REQUIRE(db.isInitialized());
+ DatabaseUnderTest<MultimediaFilesDB> db{"multimedia.db"};
+ MultimediaFilesRecordInterface multimediaFilesRecordInterface(&db.get());
constexpr auto PageSize = 8;
@@ 100,95 92,95 @@ TEST_CASE("Multimedia DB tests")
REQUIRE(!record.isValid());
record.ID = 1;
- record.fileInfo.path = "music";
+ record.fileInfo.path = "audio";
REQUIRE(record.isValid());
}
SECTION("Empty")
{
- REQUIRE(db.files.count() == 0);
- REQUIRE(db.files.getLimitOffset(0, PageSize).empty());
+ REQUIRE(db.get().files.count() == 0);
+ REQUIRE(db.get().files.getLimitOffset(0, PageSize).empty());
}
SECTION("Add, get and remove")
{
- const auto path = "music/user";
+ const auto path = "audio/user";
TableRow record;
record.fileInfo.path = path;
REQUIRE(!record.isValid());
- REQUIRE(db.files.add(record));
+ REQUIRE(db.get().files.add(record));
- REQUIRE(db.files.count() == 1);
- auto result = db.files.getById(1);
+ REQUIRE(db.get().files.count() == 1);
+ auto result = db.get().files.getById(1);
REQUIRE(result.isValid());
SECTION("Remove by ID")
{
- REQUIRE(db.files.removeById(1));
- REQUIRE(db.files.count() == 0);
- auto result = db.files.getById(1);
+ REQUIRE(db.get().files.removeById(1));
+ REQUIRE(db.get().files.count() == 0);
+ auto result = db.get().files.getById(1);
REQUIRE(!result.isValid());
}
SECTION("Remove by field")
{
- REQUIRE(db.files.removeByField(TableFields::path, path));
- REQUIRE(db.files.count() == 0);
- auto result = db.files.getById(1);
+ REQUIRE(db.get().files.removeByField(TableFields::path, path));
+ REQUIRE(db.get().files.count() == 0);
+ auto result = db.get().files.getById(1);
REQUIRE(!result.isValid());
}
}
for (const auto &record : records) {
- REQUIRE(db.files.add(record));
+ REQUIRE(db.get().files.add(record));
}
SECTION("Remove all")
{
- REQUIRE(db.files.count() == records.size());
- REQUIRE(db.files.removeAll());
- REQUIRE(db.files.count() == 0);
+ REQUIRE(db.get().files.count() == records.size());
+ REQUIRE(db.get().files.removeAll());
+ REQUIRE(db.get().files.count() == 0);
}
SECTION("Add for existing path")
{
- auto resultPre = db.files.getById(2);
+ auto resultPre = db.get().files.getById(2);
resultPre.fileInfo.mediaType = "bla bla";
- REQUIRE(db.files.add(resultPre));
- auto resultPost = db.files.getById(2);
+ REQUIRE(db.get().files.add(resultPre));
+ auto resultPost = db.get().files.getById(2);
REQUIRE((resultPre.ID == resultPost.ID && resultPre.fileInfo.mediaType == resultPost.fileInfo.mediaType));
}
SECTION("Update")
{
- auto resultPre = db.files.getById(2);
+ auto resultPre = db.get().files.getById(2);
resultPre.fileInfo.mediaType = "bla bla";
- REQUIRE(db.files.update(resultPre));
- auto resultPost = db.files.getById(2);
+ REQUIRE(db.get().files.update(resultPre));
+ auto resultPost = db.get().files.getById(2);
REQUIRE((resultPre.ID == resultPost.ID && resultPre.fileInfo.mediaType == resultPost.fileInfo.mediaType));
}
SECTION("Add or Update")
{
- REQUIRE(db.files.removeAll());
- REQUIRE(db.files.count() == 0);
+ REQUIRE(db.get().files.removeAll());
+ REQUIRE(db.get().files.count() == 0);
for (const auto &record : records) {
- REQUIRE(db.files.addOrUpdate(record));
+ REQUIRE(db.get().files.addOrUpdate(record));
}
- REQUIRE(db.files.count() == records.size());
+ REQUIRE(db.get().files.count() == records.size());
auto oldPath = records[1].fileInfo.path;
- auto resultPre = db.files.getByPath(oldPath);
+ auto resultPre = db.get().files.getByPath(oldPath);
const auto referenceID = resultPre.ID;
resultPre.ID = 10;
SECTION("No changes")
{
- REQUIRE(db.files.addOrUpdate(resultPre));
- REQUIRE(db.files.count() == records.size());
- auto resultPost = db.files.getByPath(oldPath);
+ REQUIRE(db.get().files.addOrUpdate(resultPre));
+ REQUIRE(db.get().files.count() == records.size());
+ auto resultPost = db.get().files.getByPath(oldPath);
REQUIRE(resultPost.isValid());
REQUIRE((resultPost.ID == referenceID && resultPre.fileInfo.path == resultPost.fileInfo.path));
}
@@ 196,19 188,19 @@ TEST_CASE("Multimedia DB tests")
{
auto newPath = "user/newPath";
resultPre.fileInfo.path = newPath;
- REQUIRE(db.files.addOrUpdate(resultPre, oldPath));
- REQUIRE(db.files.count() == records.size());
- auto notExistingEntry = db.files.getByPath(oldPath);
+ REQUIRE(db.get().files.addOrUpdate(resultPre, oldPath));
+ REQUIRE(db.get().files.count() == records.size());
+ auto notExistingEntry = db.get().files.getByPath(oldPath);
REQUIRE(!notExistingEntry.isValid());
- auto resultPost = db.files.getByPath(newPath);
+ auto resultPost = db.get().files.getByPath(newPath);
REQUIRE(resultPost.isValid());
REQUIRE((resultPost.ID == referenceID && resultPre.fileInfo.path == resultPost.fileInfo.path));
}
SECTION("change any field")
{
resultPre.fileInfo.mediaType = "bla bla";
- REQUIRE(db.files.addOrUpdate(resultPre));
- auto resultPost = db.files.getByPath(oldPath);
+ REQUIRE(db.get().files.addOrUpdate(resultPre));
+ auto resultPost = db.get().files.getByPath(oldPath);
REQUIRE(resultPost.isValid());
REQUIRE((resultPost.ID == referenceID && resultPre.fileInfo.path == resultPost.fileInfo.path &&
resultPre.fileInfo.mediaType == resultPost.fileInfo.mediaType));
@@ 218,20 210,20 @@ TEST_CASE("Multimedia DB tests")
SECTION("getLimitOffset")
{
auto size = records.size();
- REQUIRE(db.files.getLimitOffset(0, size - 3).size() == size - 3);
- REQUIRE(db.files.getLimitOffset(size - 3, size).size() == 3);
+ REQUIRE(db.get().files.getLimitOffset(0, size - 3).size() == size - 3);
+ REQUIRE(db.get().files.getLimitOffset(size - 3, size).size() == 3);
}
SECTION("getLimitOffsetByField")
{
auto size = records.size();
- REQUIRE(db.files.getLimitOffsetByField(0, size, TableFields::artist, artists[1].c_str()).size() == 4);
+ REQUIRE(db.get().files.getLimitOffsetByField(0, size, TableFields::artist, artists[1].c_str()).size() == 4);
}
SECTION("Artists")
{
- REQUIRE(db.files.countArtists() == artists.size());
- auto artistsList = db.files.getArtistsLimitOffset(0, artists.size());
+ REQUIRE(db.get().files.countArtists() == artists.size());
+ auto artistsList = db.get().files.getArtistsLimitOffset(0, artists.size());
REQUIRE(artistsList.size() == artists.size());
for (size_t i = 0; i < artists.size(); i++) {
REQUIRE(artistsList[i] == artists[i]);
@@ 242,16 234,16 @@ TEST_CASE("Multimedia DB tests")
const auto size = artists.size();
constexpr auto reminder = 2;
const auto pageSize = size - reminder;
- REQUIRE(db.files.getLimitOffset(0, pageSize).size() == pageSize);
- REQUIRE(db.files.getLimitOffset(pageSize, pageSize).size() == reminder);
+ REQUIRE(db.get().files.getLimitOffset(0, pageSize).size() == pageSize);
+ REQUIRE(db.get().files.getLimitOffset(pageSize, pageSize).size() == reminder);
}
}
const auto numberOfAlbums = albums.size();
SECTION("Albums")
{
- REQUIRE(db.files.countAlbums() == numberOfAlbums);
- auto albumsList = db.files.getAlbumsLimitOffset(0, numberOfAlbums);
+ REQUIRE(db.get().files.countAlbums() == numberOfAlbums);
+ auto albumsList = db.get().files.getAlbumsLimitOffset(0, numberOfAlbums);
REQUIRE(albumsList.size() == numberOfAlbums);
for (const auto &album : albumsList) {
auto it = std::find_if(albums.begin(), albums.end(), [album](const Album &albumRef) {
@@ 265,8 257,8 @@ TEST_CASE("Multimedia DB tests")
const auto size = numberOfAlbums;
constexpr auto reminder = 2;
const auto pageSize = size - reminder;
- REQUIRE(db.files.getAlbumsLimitOffset(0, pageSize).size() == pageSize);
- REQUIRE(db.files.getAlbumsLimitOffset(pageSize, pageSize).size() == reminder);
+ REQUIRE(db.get().files.getAlbumsLimitOffset(0, pageSize).size() == pageSize);
+ REQUIRE(db.get().files.getAlbumsLimitOffset(pageSize, pageSize).size() == reminder);
}
}
@@ 276,8 268,8 @@ TEST_CASE("Multimedia DB tests")
size_t size = std::count_if(records.begin(), records.end(), [artist](const TableRow &record) {
return record.tags.album.artist == artist;
});
- REQUIRE(db.files.count(artist) == size);
- auto artistsList = db.files.getLimitOffset(artist, 0, records.size());
+ REQUIRE(db.get().files.count(artist) == size);
+ auto artistsList = db.get().files.getLimitOffset(artist, 0, records.size());
REQUIRE(artistsList.size() == size);
for (size_t i = 0; i < artistsList.size(); i++) {
REQUIRE(artistsList[i].tags.album.artist == artist);
@@ 291,8 283,8 @@ TEST_CASE("Multimedia DB tests")
size_t size = std::count_if(records.begin(), records.end(), [album](const TableRow &record) {
return record.tags.album.artist == album.artist && record.tags.album.title == album.title;
});
- REQUIRE(db.files.count(album) == size);
- auto artistsList = db.files.getLimitOffset(album, 0, records.size());
+ REQUIRE(db.get().files.count(album) == size);
+ auto artistsList = db.get().files.getLimitOffset(album, 0, records.size());
REQUIRE(artistsList.size() == size);
for (size_t i = 0; i < artistsList.size(); i++) {
REQUIRE((artistsList[i].tags.album.artist == album.artist &&
@@ 345,14 337,15 @@ TEST_CASE("Multimedia DB tests")
return record;
};
- auto getLimitedByPathQuery = [&](const std::string &pathPrefix, const uint32_t offset, const uint32_t limit) {
- auto query = std::make_shared<db::multimedia_files::query::GetLimitedByPath>(pathPrefix, offset, limit);
- auto ret = multimediaFilesRecordInterface.runQuery(query);
- auto result = dynamic_cast<db::multimedia_files::query::GetLimitedResult *>(ret.get());
- REQUIRE(result != nullptr);
- auto record = result->getResult();
- return record;
- };
+ auto getLimitedByPathsQuery =
+ [&](const std::vector<std::string> &paths, const uint32_t offset, const uint32_t limit) {
+ auto query = std::make_shared<db::multimedia_files::query::GetLimitedByPaths>(paths, offset, limit);
+ auto ret = multimediaFilesRecordInterface.runQuery(query);
+ auto result = dynamic_cast<db::multimedia_files::query::GetLimitedResult *>(ret.get());
+ REQUIRE(result != nullptr);
+ auto record = result->getResult();
+ return record;
+ };
auto updateQuery = [&](const MultimediaFilesRecord &record) {
const auto query = std::make_shared<db::multimedia_files::query::Edit>(record);
@@ 464,7 457,7 @@ TEST_CASE("Multimedia DB tests")
SECTION("add, get, remove query")
{
- const auto path = "music/user";
+ const auto path = "audio/user";
MultimediaFilesRecord record;
record.fileInfo.path = path;
REQUIRE(!record.isValid());
@@ 573,19 566,31 @@ TEST_CASE("Multimedia DB tests")
REQUIRE(getLimitedQuery(size - 3, size).size() == 3);
}
- SECTION("getLimitOffsetByPath")
+ SECTION("getLimitOffsetByPaths")
{
- auto rootPrefix = "user/";
- auto musicPrefix = "user/music/";
- auto falsePrefix1 = "user/music1/";
- auto flasePrefix2 = "user/music2";
- auto falsePrefix3 = "abc/";
- auto size = records.size();
- REQUIRE(getLimitedByPathQuery(rootPrefix, 0, size).size() == size);
- REQUIRE(getLimitedByPathQuery(musicPrefix, 0, size).size() == (size - 3));
- REQUIRE(getLimitedByPathQuery(falsePrefix1, 0, size).size() == 0);
- REQUIRE(getLimitedByPathQuery(flasePrefix2, 0, size).size() == 0);
- REQUIRE(getLimitedByPathQuery(falsePrefix3, 0, size).size() == 0);
+ MultimediaFilesRecord entry;
+ const auto user_count = records.size();
+ const auto user_audio_count = user_count - 3;
+
+ REQUIRE(getLimitedByPathsQuery({"user/"}, 0, UINT32_MAX).size() == user_count);
+ REQUIRE(getLimitedByPathsQuery({"user/audio/"}, 0, UINT32_MAX).size() == user_audio_count);
+ REQUIRE(getLimitedByPathsQuery({"user/audio1/"}, 0, UINT32_MAX).size() == 0);
+ REQUIRE(getLimitedByPathsQuery({"user/audio2"}, 0, UINT32_MAX).size() == 0);
+ REQUIRE(getLimitedByPathsQuery({"abc/"}, 0, UINT32_MAX).size() == 0);
+
+ entry.fileInfo.path = "assets/audio/file30.mp3";
+ addQuery(entry);
+ entry.fileInfo.path = "assets/audio/file31.mp3";
+ addQuery(entry);
+ REQUIRE(getLimitedByPathsQuery({"user/audio", "assets/audio"}, 0, UINT32_MAX).size() ==
+ user_audio_count + 2);
+ REQUIRE(getLimitedByPathsQuery({"user/audio", "assets/audio", "non/existing/path"}, 0, UINT32_MAX).size() ==
+ user_audio_count + 2);
+
+ entry.fileInfo.path = "assets/audio/app/file32.mp3";
+ addQuery(entry);
+ REQUIRE(getLimitedByPathsQuery({"user/audio", "assets/audio/app"}, 0, UINT32_MAX).size() ==
+ user_audio_count + 1);
}
SECTION("Artists")
@@ 625,8 630,8 @@ TEST_CASE("Multimedia DB tests")
const auto size = numberOfAlbums;
constexpr auto reminder = 2;
const auto pageSize = size - reminder;
- REQUIRE(db.files.getAlbumsLimitOffset(0, pageSize).size() == pageSize);
- REQUIRE(db.files.getAlbumsLimitOffset(pageSize, pageSize).size() == reminder);
+ REQUIRE(db.get().files.getAlbumsLimitOffset(0, pageSize).size() == pageSize);
+ REQUIRE(db.get().files.getAlbumsLimitOffset(pageSize, pageSize).size() == reminder);
}
}
M module-db/tests/common.hpp => module-db/tests/common.hpp +37 -0
@@ 3,6 3,43 @@
#pragma once
+#include "Database/Database.hpp"
+#include <catch2/catch.hpp>
#include <string>
+#include <filesystem>
void RemoveDbFiles(const std::string &dbName);
+
+template <typename Db>
+class DatabaseUnderTest
+{
+ public:
+ explicit DatabaseUnderTest(std::filesystem::path name)
+ {
+ Database::initialize();
+
+ if (std::filesystem::exists(name)) {
+ std::filesystem::remove(name);
+ }
+
+ db = std::make_unique<Db>(name.c_str());
+
+ if (not db->isInitialized()) {
+ throw std::runtime_error("Could not initialize database");
+ }
+ }
+
+ ~DatabaseUnderTest()
+ {
+ Database::deinitialize();
+ }
+
+ Db &get()
+ {
+ return *db;
+ }
+
+ private:
+ std::filesystem::path name;
+ std::unique_ptr<Db> db;
+};
M module-platform/CMakeLists.txt => module-platform/CMakeLists.txt +0 -1
@@ 14,7 14,6 @@ target_sources(
PUBLIC
include/Platform.hpp
- CommonPlatform.cpp
)
target_link_libraries(
D module-platform/CommonPlatform.cpp => module-platform/CommonPlatform.cpp +0 -31
@@ 1,31 0,0 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include <Platform.hpp>
-
-#include <purefs/vfs_subsystem.hpp>
-#include <purefs/filesystem_paths.hpp>
-#include <filesystem>
-
-namespace platform
-{
-
- void Platform::initCommonUserFolders()
- {
- if (!std::filesystem::exists(purefs::dir::getLogsPath())) {
- std::filesystem::create_directories(purefs::dir::getLogsPath());
- }
-
- if (!std::filesystem::exists(purefs::dir::getCrashDumpsPath())) {
- std::filesystem::create_directories(purefs::dir::getCrashDumpsPath());
- }
-
- if (!std::filesystem::exists(purefs::dir::getBackupOSPath())) {
- std::filesystem::create_directories(purefs::dir::getBackupOSPath());
- }
-
- if (!std::filesystem::exists(purefs::dir::getTemporaryPath())) {
- std::filesystem::create_directories(purefs::dir::getTemporaryPath());
- }
- }
-} // namespace platform
M module-platform/include/Platform.hpp => module-platform/include/Platform.hpp +0 -1
@@ 10,7 10,6 @@ namespace platform
public:
virtual ~Platform() = default;
virtual void init() = 0;
- virtual void initCommonUserFolders();
virtual void deinit() = 0;
};
} // namespace platform
M module-platform/linux/src/LinuxPlatform.cpp => module-platform/linux/src/LinuxPlatform.cpp +0 -1
@@ 29,7 29,6 @@ LinuxPlatform::~LinuxPlatform()
void LinuxPlatform::init()
{
initFilesystem();
- ::platform::Platform::initCommonUserFolders();
}
void LinuxPlatform::initFilesystem()
M module-platform/rt1051/src/RT1051Platform.cpp => module-platform/rt1051/src/RT1051Platform.cpp +0 -1
@@ 22,7 22,6 @@ RT1051Platform::RT1051Platform()
void RT1051Platform::init()
{
initFilesystem();
- ::platform::Platform::initCommonUserFolders();
}
void RT1051Platform::initFilesystem()
M module-services/service-desktop/ServiceDesktop.cpp => module-services/service-desktop/ServiceDesktop.cpp +1 -1
@@ 201,7 201,7 @@ auto ServiceDesktop::usbWorkerInit() -> sys::ReturnCodes
*usbSecurityModel,
serialNumber,
caseColour,
- purefs::dir::getUserDiskPath() / "music");
+ purefs::dir::getUserStoragePath());
initialized =
desktopWorker->init({{sdesktop::RECEIVE_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_len},
M module-services/service-fileindexer/StartupIndexer.cpp => module-services/service-fileindexer/StartupIndexer.cpp +60 -50
@@ 12,29 12,66 @@
#include <filesystem>
#include <fstream>
+#include <optional>
namespace service::detail
{
namespace fs = std::filesystem;
- namespace
+ using namespace std::literals;
+ using namespace std::chrono_literals;
+
+ const auto lock_file_name = purefs::dir::getUserDiskPath() / ".directory_is_indexed";
+ constexpr auto indexing_interval = 50ms;
+ constexpr auto start_delay = 10000ms;
+
+ bool isDirectoryFullyTraversed(const std::filesystem::recursive_directory_iterator &directory)
+ {
+ return directory == std::filesystem::recursive_directory_iterator();
+ }
+
+ bool createLockFile()
+ {
+ std::ofstream ofs(lock_file_name);
+ ofs << time(nullptr);
+ return ofs.good();
+ }
+
+ bool hasLockFile()
+ {
+ std::error_code ec;
+ return fs::is_regular_file(lock_file_name, ec);
+ }
+
+ bool removeLockFile()
+ {
+ if (hasLockFile()) {
+ std::error_code ec;
+ if (!remove(lock_file_name, ec)) {
+ LOG_ERROR("Failed to remove lock file, error: %d", ec.value());
+ return false;
+ }
+ }
+ return true;
+ }
+
+ std::optional<std::filesystem::recursive_directory_iterator> scanPath(std::vector<std::string>::const_iterator path)
{
- using namespace std::string_literals;
- // Lock file name
- const auto lock_file_name = purefs::dir::getUserDiskPath() / ".directory_is_indexed";
- // Time for indexing first unit
- constexpr auto timer_indexing_delay = 400;
- // Time for initial delay after start
- constexpr auto timer_run_delay = 10000;
- } // namespace
-
- StartupIndexer::StartupIndexer(const std::vector<std::string> &paths) : start_dirs{paths}
+ std::error_code err;
+ const auto mSubDirIterator = fs::recursive_directory_iterator(*path, err);
+ if (err) {
+ LOG_WARN("Directory '%s' not indexed, it does not exist", path->c_str());
+ return std::nullopt;
+ }
+ return mSubDirIterator;
+ }
+
+ StartupIndexer::StartupIndexer(const std::vector<std::string> &paths) : directoriesToScan{paths}
{}
// Process single entry
auto StartupIndexer::processEntry(std::shared_ptr<sys::Service> svc,
const std::filesystem::recursive_directory_iterator::value_type &entry) -> void
{
- using namespace std::string_view_literals;
if (fs::is_regular_file(entry)) {
auto ext = fs::path(entry).extension();
if (!isExtSupported(ext)) {
@@ 49,24 86,22 @@ namespace service::detail
}
}
- // On timer timeout
auto StartupIndexer::onTimerTimeout(std::shared_ptr<sys::Service> svc) -> void
{
if (mForceStop) {
return;
}
- if (!mStarted) {
- mIdxTimer.restart(std::chrono::milliseconds{timer_indexing_delay});
- mStarted = true;
- }
- if (mSubDirIterator == std::filesystem::recursive_directory_iterator()) {
- if (mTopDirIterator == std::cend(start_dirs)) {
+ if (isDirectoryFullyTraversed(mSubDirIterator)) {
+ if (mTopDirIterator == std::cend(directoriesToScan)) {
createLockFile();
LOG_INFO("Initial startup indexer - Finished ...");
mIdxTimer.stop();
+ return;
}
else {
- mSubDirIterator = fs::recursive_directory_iterator(*mTopDirIterator);
+ if (auto result = scanPath(mTopDirIterator)) {
+ mSubDirIterator = *result;
+ }
mTopDirIterator++;
}
}
@@ 74,15 109,15 @@ namespace service::detail
processEntry(svc, *mSubDirIterator);
mSubDirIterator++;
}
+
+ mIdxTimer.restart(indexing_interval);
}
// Setup timers for notification
auto StartupIndexer::setupTimers(std::shared_ptr<sys::Service> svc, std::string_view svc_name) -> void
{
- mIdxTimer = sys::TimerFactory::createPeriodicTimer(svc.get(),
- "file_indexing",
- std::chrono::milliseconds{timer_run_delay},
- [this, svc](sys::Timer &) { onTimerTimeout(svc); });
+ mIdxTimer = sys::TimerFactory::createSingleShotTimer(
+ svc.get(), svc_name.data(), start_delay, [this, svc](auto &) { onTimerTimeout(svc); });
mIdxTimer.start();
}
@@ 91,7 126,7 @@ namespace service::detail
{
if (!hasLockFile()) {
LOG_INFO("Initial startup indexer - Started...");
- mTopDirIterator = std::begin(start_dirs);
+ mTopDirIterator = std::begin(directoriesToScan);
setupTimers(svc, svc_name);
mForceStop = false;
}
@@ 111,29 146,4 @@ namespace service::detail
stop();
removeLockFile();
}
-
- auto StartupIndexer::createLockFile() -> bool
- {
- std::ofstream ofs(lock_file_name);
- ofs << time(nullptr);
- return ofs.good();
- }
-
- auto StartupIndexer::hasLockFile() -> bool
- {
- std::error_code ec;
- return fs::is_regular_file(lock_file_name, ec);
- }
-
- auto StartupIndexer::removeLockFile() -> bool
- {
- if (hasLockFile()) {
- std::error_code ec;
- if (!remove(lock_file_name, ec)) {
- LOG_ERROR("Failed to remove lock file, error: %d", ec.value());
- return false;
- }
- }
- return true;
- }
} // namespace service::detail
M module-services/service-fileindexer/include/service-fileindexer/StartupIndexer.hpp => module-services/service-fileindexer/include/service-fileindexer/StartupIndexer.hpp +3 -15
@@ 22,28 22,16 @@ namespace service::detail
void stop();
private:
- // Process single entry
- static auto processEntry(std::shared_ptr<sys::Service> svc,
- const std::filesystem::recursive_directory_iterator::value_type &entry) -> void;
- // Setup timers for notification
+ auto processEntry(std::shared_ptr<sys::Service> svc,
+ const std::filesystem::recursive_directory_iterator::value_type &entry) -> void;
auto setupTimers(std::shared_ptr<sys::Service> svc, std::string_view svc_name) -> void;
- // On timer timeout
auto onTimerTimeout(std::shared_ptr<sys::Service> svc) -> void;
- // Create lock file
- static auto createLockFile() -> bool;
- // Check if lock file exists
- static auto hasLockFile() -> bool;
- // remove lock file exists
- static auto removeLockFile() -> bool;
- private:
std::vector<std::string>::const_iterator mTopDirIterator;
std::filesystem::recursive_directory_iterator mSubDirIterator;
sys::TimerHandle mIdxTimer;
- bool mStarted{};
bool mForceStop{};
- // List of initial dirs for scan
- const std::vector<std::string> start_dirs;
+ const std::vector<std::string> directoriesToScan;
};
} // namespace service::detail
M module-vfs/paths/filesystem_paths.cpp => module-vfs/paths/filesystem_paths.cpp +22 -12
@@ 5,19 5,21 @@
namespace
{
- constexpr inline auto PATH_SYS = "/sys";
- constexpr inline auto PATH_CONF = "/mfgconf";
+ constexpr inline auto PATH_SYS = "/sys";
+ constexpr inline auto PATH_CONF = "/mfgconf";
+ constexpr inline auto PATH_USER = "user";
constexpr inline auto PATH_OS = "os";
- constexpr inline auto PATH_USER = "user";
- constexpr inline auto PATH_CURRENT = "current";
- constexpr inline auto PATH_PREVIOUS = "previous";
- constexpr inline auto PATH_UPDATES = "updates";
- constexpr inline auto PATH_TMP = "tmp";
- constexpr inline auto PATH_BACKUP = "backup";
- constexpr inline auto PATH_FACTORY = "factory";
- constexpr inline auto PATH_LOGS = "logs";
- constexpr inline auto PATH_CRASH_DUMPS = "crash_dumps";
- constexpr inline auto eMMC_disk = PATH_SYS;
+ constexpr inline auto PATH_CURRENT = "current";
+ constexpr inline auto PATH_PREVIOUS = "previous";
+ constexpr inline auto PATH_UPDATES = "updates";
+ constexpr inline auto PATH_TMP = "tmp";
+ constexpr inline auto PATH_BACKUP = "backup";
+ constexpr inline auto PATH_FACTORY = "factory";
+ constexpr inline auto PATH_LOGS = "logs";
+ constexpr inline auto PATH_CRASH_DUMPS = "crash_dumps";
+ constexpr inline auto PATH_USER_AUDIO = "audio";
+ constexpr inline auto PATH_USER_STORAGE = "storage";
+ constexpr inline auto eMMC_disk = PATH_SYS;
} // namespace
namespace purefs
@@ 83,5 85,13 @@ namespace purefs
{
return getUserDiskPath() / PATH_CRASH_DUMPS;
}
+ std::filesystem::path getUserAudioPath() noexcept
+ {
+ return getUserDiskPath() / PATH_USER_AUDIO;
+ }
+ std::filesystem::path getUserStoragePath() noexcept
+ {
+ return getUserDiskPath() / PATH_USER_STORAGE;
+ }
} // namespace dir
} // namespace purefs
M module-vfs/paths/include/purefs/filesystem_paths.hpp => module-vfs/paths/include/purefs/filesystem_paths.hpp +2 -0
@@ 22,6 22,8 @@ namespace purefs
std::filesystem::path getFactoryOSPath() noexcept;
std::filesystem::path getLogsPath() noexcept;
std::filesystem::path getCrashDumpsPath() noexcept;
+ std::filesystem::path getUserAudioPath() noexcept;
+ std::filesystem::path getUserStoragePath() noexcept;
} // namespace dir
namespace file
M products/BellHybrid/BellHybridMain.cpp => products/BellHybrid/BellHybridMain.cpp +2 -18
@@ 41,7 41,7 @@
#include <SystemWatchdog/SystemWatchdog.hpp>
#include <thread.hpp>
#include <time/AlarmOperations.hpp>
-#include "alarms/include/AlarmSoundPaths.hpp"
+#include <Paths.hpp>
#include <memory>
#include <vector>
@@ 50,24 50,11 @@
#include <SEGGER/SEGGER_SYSVIEW.h>
#endif
-namespace
-{
- void validate_assets_path()
- {
- if (const auto ret = alarms::paths::validate(); not ret.empty()) {
- for (const auto &e : ret) {
- LOG_FATAL("%s path missing", e.c_str());
- }
- abort();
- }
- }
-} // namespace
-
int main()
{
constexpr auto ApplicationName = "BellHybrid";
- std::vector<std::string> fileIndexerAudioPaths = {alarms::paths::getBackgroundSoundsDir()};
+ std::vector<std::string> fileIndexerAudioPaths = {paths::audio::proprietary(), paths::audio::user()};
#if SYSTEM_VIEW_ENABLED
SEGGER_SYSVIEW_Conf();
@@ 117,9 104,6 @@ int main()
/// otherwise we would end up with an init race and PhonenumberUtil could
/// be initiated in a task with stack not big enough to handle it
i18n::phonenumbers::PhoneNumberUtil::GetInstance();
-
- validate_assets_path();
-
return true;
},
[sysmgr]() {
M products/BellHybrid/CMakeLists.txt => products/BellHybrid/CMakeLists.txt +11 -2
@@ 52,6 52,7 @@ target_link_libraries(BellHybrid
bell::db
bell::audio
bell::evtmgr
+ bell::paths
log
logdump
messagetype
@@ 80,6 81,13 @@ strip_executable(BellHybrid)
include(BinaryAssetsVersions.cmake)
include(AddVersionJson)
+add_directories(
+ TARGET user_directories
+ PREFIX ${CMAKE_BINARY_DIR}/sysroot/sys/user/audio
+ DEPENDS user_directories_common
+ DIRECTORIES relaxation
+)
+
if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
include(AddBootBin)
add_boot_bin(BellHybrid)
@@ 87,7 95,7 @@ if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
PRODUCT BellHybrid
SYSROOT sysroot
LUTS Luts.bin
- DEPENDS assets updater.bin-target ecoboot.bin-target BellHybrid-boot.bin BellHybrid-version.json-target
+ DEPENDS user_directories assets updater.bin-target ecoboot.bin-target BellHybrid-boot.bin BellHybrid-version.json-target
)
add_version_rt1051_json(BellHybrid)
else()
@@ 95,7 103,7 @@ else()
PRODUCT BellHybrid
SYSROOT sysroot
LUTS ""
- DEPENDS assets BellHybrid-version.json-target
+ DEPENDS user_directories assets BellHybrid-version.json-target
)
add_version_linux_json(BellHybrid)
endif()
@@ 144,6 152,7 @@ add_subdirectory(keymap)
add_subdirectory(services)
add_subdirectory(sys)
add_subdirectory(serial-number-reader)
+add_subdirectory(paths)
option(CONFIG_ENABLE_TEMP "Enable displaying temperature" OFF)
option(CONFIG_SHOW_MEMORY_INFO "Enable displaying memory info" OFF)
M products/BellHybrid/alarms/CMakeLists.txt => products/BellHybrid/alarms/CMakeLists.txt +1 -3
@@ 4,7 4,6 @@ add_library(bell::alarms ALIAS alarms)
target_sources(alarms
PRIVATE
BellAlarmHandler.cpp
- src/AlarmSoundPaths.cpp
src/actions/PlayAudioActions.cpp
src/actions/NotifyGUIAction.cpp
src/actions/NotifyGUIBedtimeReminderAction.cpp
@@ 17,7 16,6 @@ target_sources(alarms
src/actions/NotifyGUIAction.hpp
src/actions/NotifyGUIBedtimeReminderAction.hpp
PUBLIC
- include/AlarmSoundPaths.hpp
include/popups/AlarmActivatedPopupRequestParams.hpp
include/popups/AlarmDeactivatedPopupRequestParams.hpp
include/popups/BedtimeReminderPopupRequestParams.hpp
@@ 33,12 31,12 @@ target_include_directories(alarms
target_link_libraries(alarms
PRIVATE
- module-vfs
bell::db
bell::appmgr
bell::app-common
bell::evtmgr
bell::audio
+ bell::paths
apps-common
PUBLIC
module-db
D products/BellHybrid/alarms/include/AlarmSoundPaths.hpp => products/BellHybrid/alarms/include/AlarmSoundPaths.hpp +0 -21
@@ 1,21 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#pragma once
-
-#include <filesystem>
-#include <vector>
-
-namespace alarms::paths
-{
- std::filesystem::path getAlarmDir() noexcept;
- std::filesystem::path getMusicDir() noexcept;
- std::filesystem::path getPreWakeUpChimesDir() noexcept;
- std::filesystem::path getSnoozeChimesDir() noexcept;
- std::filesystem::path getBedtimeReminderChimesDir() noexcept;
- std::filesystem::path getBackgroundSoundsDir() noexcept;
- std::filesystem::path getMeditationSoundsDir() noexcept;
-
- /// Check if system paths exist. In case of error, returns vector of missing entries.
- std::vector<std::filesystem::path> validate() noexcept;
-} // namespace alarms::paths
D products/BellHybrid/alarms/src/AlarmSoundPaths.cpp => products/BellHybrid/alarms/src/AlarmSoundPaths.cpp +0 -71
@@ 1,71 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include "AlarmSoundPaths.hpp"
-
-#include <purefs/filesystem_paths.hpp>
-
-namespace alarms::paths
-{
- std::filesystem::path getAlarmDir() noexcept
- {
- return purefs::dir::getCurrentOSPath() / "assets/audio/alarm";
- }
-
- std::filesystem::path getMusicDir() noexcept
- {
- return purefs::dir::getUserDiskPath() / "music";
- }
-
- std::filesystem::path getPreWakeUpChimesDir() noexcept
- {
- return purefs::dir::getCurrentOSPath() / "assets/audio/prewakeup";
- }
-
- std::filesystem::path getSnoozeChimesDir() noexcept
- {
- return purefs::dir::getCurrentOSPath() / "assets/audio/chimes";
- }
-
- std::filesystem::path getBedtimeReminderChimesDir() noexcept
- {
- return purefs::dir::getCurrentOSPath() / "assets/audio/evening_reminder";
- }
-
- std::filesystem::path getBackgroundSoundsDir() noexcept
- {
- return purefs::dir::getCurrentOSPath() / "assets/audio/bg_sounds";
- }
-
- std::filesystem::path getMeditationSoundsDir() noexcept
- {
- return purefs::dir::getCurrentOSPath() / "assets/audio/meditation";
- }
-
- std::vector<std::filesystem::path> validate() noexcept
- {
- std::vector<std::filesystem::path> ret;
- if (not std::filesystem::exists(getAlarmDir())) {
- ret.push_back(getAlarmDir());
- }
- if (not std::filesystem::exists(getMusicDir())) {
- ret.push_back(getMusicDir());
- }
- if (not std::filesystem::exists(getPreWakeUpChimesDir())) {
- ret.push_back(getPreWakeUpChimesDir());
- }
- if (not std::filesystem::exists(getSnoozeChimesDir())) {
- ret.push_back(getSnoozeChimesDir());
- }
- if (not std::filesystem::exists(getBedtimeReminderChimesDir())) {
- ret.push_back(getBedtimeReminderChimesDir());
- }
- if (not std::filesystem::exists(getBackgroundSoundsDir())) {
- ret.push_back(getBackgroundSoundsDir());
- }
- if (not std::filesystem::exists(getMeditationSoundsDir())) {
- ret.push_back(getMeditationSoundsDir());
- }
- return ret;
- }
-} // namespace alarms::paths
M products/BellHybrid/alarms/src/actions/PlayAudioActions.cpp => products/BellHybrid/alarms/src/actions/PlayAudioActions.cpp +11 -7
@@ 1,9 1,9 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-#include "AlarmSoundPaths.hpp"
#include "PlayAudioActions.hpp"
+#include <Paths.hpp>
#include <audio/AudioMessage.hpp>
#include <db/SystemSettings.hpp>
#include <Timers/TimerFactory.hpp>
@@ 69,26 69,30 @@ namespace alarms
std::unique_ptr<PlayAudioAction> createPreWakeUpChimeAction(sys::Service &service)
{
return std::make_unique<PlayAudioAction>(service,
- paths::getPreWakeUpChimesDir(),
+ paths::audio::proprietary() / paths::audio::preWakeup(),
bell::settings::PrewakeUp::tone,
audio::PlaybackType::PreWakeUp);
}
std::unique_ptr<PlayAudioAction> createSnoozeChimeAction(sys::Service &service)
{
- return std::make_unique<PlayAudioAction>(
- service, paths::getSnoozeChimesDir(), bell::settings::Snooze::tone, audio::PlaybackType::Snooze);
+ return std::make_unique<PlayAudioAction>(service,
+ paths::audio::proprietary() / paths::audio::snooze(),
+ bell::settings::Snooze::tone,
+ audio::PlaybackType::Snooze);
}
std::unique_ptr<PlayAudioAction> createAlarmToneAction(sys::Service &service)
{
/// Alarm duration is controlled from the main application's state machine
- return std::make_unique<PlayAudioAction>(
- service, paths::getAlarmDir(), bell::settings::Alarm::tone, audio::PlaybackType::Alarm);
+ return std::make_unique<PlayAudioAction>(service,
+ paths::audio::proprietary() / paths::audio::alarm(),
+ bell::settings::Alarm::tone,
+ audio::PlaybackType::Alarm);
}
std::unique_ptr<PlayAudioAction> createBedtimeChimeAction(sys::Service &service)
{
return std::make_unique<PlayAudioAction>(service,
- paths::getBedtimeReminderChimesDir(),
+ paths::audio::proprietary() / paths::audio::bedtimeReminder(),
bell::settings::Bedtime::tone,
audio::PlaybackType::Bedtime);
}
A products/BellHybrid/apps/application-bell-background-sounds/ApplicationBellBackgroundSounds.cpp => products/BellHybrid/apps/application-bell-background-sounds/ApplicationBellBackgroundSounds.cpp +0 -0
M products/BellHybrid/apps/application-bell-meditation-timer/CMakeLists.txt => products/BellHybrid/apps/application-bell-meditation-timer/CMakeLists.txt +1 -1
@@ 48,7 48,7 @@ target_link_libraries(application-bell-meditation-timer
bell::audio
bell::app-common
bell::app-main
- bell::alarms
+ bell::paths
service-appmgr
service-time
PUBLIC
M products/BellHybrid/apps/application-bell-meditation-timer/data/MeditationCommon.hpp => products/BellHybrid/apps/application-bell-meditation-timer/data/MeditationCommon.hpp +3 -6
@@ 3,8 3,7 @@
#pragma once
-#include <AlarmSoundPaths.hpp>
-
+#include <Paths.hpp>
#include <filesystem>
#include <string>
@@ 14,15 13,13 @@ namespace app::meditation
{
static constexpr auto meditationCountdown = "MeditationCountdown";
static constexpr auto meditationProgress = "MeditationProgress";
- static constexpr auto sessionEnded = "MeditationSessionEnded";
}; // namespace windows
- constexpr auto meditationDBRecordName = "MeditationTimer";
- constexpr auto meditationCountdownDBRecordName = "start_delay";
+ constexpr auto meditationDBRecordName = "MeditationTimer";
inline std::filesystem::path getMeditationAudioPath()
{
- return alarms::paths::getMeditationSoundsDir() / "Meditation_Gong.mp3";
+ return paths::audio::proprietary() / "Meditation_Gong.mp3";
}
} // namespace app::meditation
M products/BellHybrid/apps/application-bell-powernap/ApplicationBellPowerNap.cpp => products/BellHybrid/apps/application-bell-powernap/ApplicationBellPowerNap.cpp +6 -5
@@ 9,7 9,7 @@
#include "windows/PowerNapProgressWindow.hpp"
#include "windows/PowerNapSessionEndedWindow.hpp"
#include <common/models/TimeModel.hpp>
-#include <AlarmSoundPaths.hpp>
+#include <Paths.hpp>
#include <common/windows/SessionPausedWindow.hpp>
namespace app
@@ 46,10 46,11 @@ namespace app
});
windowsFactory.attach(
gui::window::name::powernapProgress, [this](ApplicationCommon *app, const std::string &name) {
- auto timeModel = std::make_unique<app::TimeModel>();
- auto alarmLightOnOff = std::make_unique<bell_settings::AlarmLightOnOffModel>(this);
- auto soundsRepository = std::make_unique<SoundsRepository>(alarms::paths::getAlarmDir());
- auto presenter = std::make_unique<powernap::PowerNapProgressPresenter>(app,
+ auto timeModel = std::make_unique<app::TimeModel>();
+ auto alarmLightOnOff = std::make_unique<bell_settings::AlarmLightOnOffModel>(this);
+ auto soundsRepository =
+ std::make_unique<SoundsRepository>(paths::audio::proprietary() / paths::audio::alarm());
+ auto presenter = std::make_unique<powernap::PowerNapProgressPresenter>(app,
settings.get(),
std::move(soundsRepository),
*audioModel,
M products/BellHybrid/apps/application-bell-powernap/CMakeLists.txt => products/BellHybrid/apps/application-bell-powernap/CMakeLists.txt +1 -1
@@ 46,7 46,7 @@ target_link_libraries(application-bell-powernap
bell::app-common
bell::app-main
bell::keymap
- bell::alarms
+ bell::paths
bell::db
Microsoft.GSL::GSL
M products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationMainWindowPresenter.cpp => products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationMainWindowPresenter.cpp +3 -1
@@ 2,7 2,9 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "RelaxationMainWindowPresenter.hpp"
-
+#include "data/BGSoundsAudioData.hpp"
+#include "widgets/SoundListItem.hpp"
+#include "ApplicationBellBackgroundSounds.hpp"
#include <apps-common/models/SongsRepository.hpp>
namespace
M products/BellHybrid/apps/application-bell-settings/ApplicationBellSettings.cpp => products/BellHybrid/apps/application-bell-settings/ApplicationBellSettings.cpp +7 -7
@@ 30,9 30,8 @@
#include "windows/BellSettingsWindow.hpp"
#include "widgets/DialogYesNo.hpp"
-#include <AlarmSoundPaths.hpp>
+#include <Paths.hpp>
#include <apps-common/windows/Dialog.hpp>
-#include <common/layouts/BaseHomeScreenLayoutProvider.hpp>
#include <common/BellPowerOffPresenter.hpp>
#include <common/models/BedtimeModel.hpp>
#include <common/models/LayoutModel.hpp>
@@ 125,7 124,7 @@ namespace app
gui::window::name::bellSettingsBedtimeTone, [this](ApplicationCommon *app, const std::string &name) {
auto bedtimeModel = std::make_shared<bell_bedtime::BedtimeModel>(app, *audioModel);
auto soundsRepository =
- std::make_unique<SoundsRepository>(alarms::paths::getBedtimeReminderChimesDir());
+ std::make_unique<SoundsRepository>(paths::audio::proprietary() / paths::audio::bedtimeReminder());
auto provider = std::make_shared<bell_settings::BedtimeSettingsListItemProvider>(
bedtimeModel, soundsRepository->getSongTitles());
auto presenter = std::make_unique<bell_settings::SettingsPresenter>(
@@ 166,7 165,7 @@ namespace app
std::move(prewakeUpChimeVolumeModel),
std::move(prewakeUpLightDurationModel),
std::move(prewakeUpFrontlightModel));
- auto soundsRepository = std::make_unique<SoundsRepository>(alarms::paths::getPreWakeUpChimesDir());
+ auto soundsRepository = std::make_unique<SoundsRepository>(paths::audio::proprietary() / paths::audio::preWakeup());
auto provider = std::make_unique<bell_settings::PrewakeUpListItemProvider>(
*prewakeUpSettingsModel, soundsRepository->getSongTitles());
auto frontlightModel = std::make_unique<bell_settings::FrontlightModel>(app);
@@ 197,8 196,9 @@ namespace app
std::move(snoozeChimeIntervalModel),
std::move(snoozeChimeToneModel),
std::move(snoozeChimeVolumeModel));
- auto soundsRepository = std::make_unique<SoundsRepository>(alarms::paths::getSnoozeChimesDir());
- auto provider = std::make_shared<bell_settings::SnoozeListItemProvider>(
+ auto soundsRepository =
+ std::make_unique<SoundsRepository>(paths::audio::proprietary() / paths::audio::snooze());
+ auto provider = std::make_shared<bell_settings::SnoozeListItemProvider>(
*snoozeSettingsModel, soundsRepository->getSongTitles());
auto presenter = std::make_unique<bell_settings::SnoozePresenter>(
provider, std::move(snoozeSettingsModel), *audioModel, std::move(soundsRepository));
@@ 215,7 215,7 @@ namespace app
std::move(alarmVolumeModel),
std::move(alarmLightOnOffModel),
std::move(alarmFrontlightModel));
- auto soundsRepository = std::make_unique<SoundsRepository>(alarms::paths::getAlarmDir());
+ auto soundsRepository = std::make_unique<SoundsRepository>(paths::audio::proprietary() / paths::audio::alarm());
auto frontlightModel = std::make_unique<bell_settings::FrontlightModel>(app);
auto provider = std::make_unique<bell_settings::AlarmSettingsListItemProvider>(
*alarmSettingsModel, soundsRepository->getSongTitles());
M products/BellHybrid/apps/application-bell-settings/CMakeLists.txt => products/BellHybrid/apps/application-bell-settings/CMakeLists.txt +1 -1
@@ 123,7 123,7 @@ target_link_libraries(application-bell-settings
bell::audio
bellgui
bell::db
- bell::alarms
+ bell::paths
bell::app-main
bell::appmgr
service-appmgr
M products/BellHybrid/apps/common/CMakeLists.txt => products/BellHybrid/apps/common/CMakeLists.txt +1 -0
@@ 20,6 20,7 @@ target_sources(application-bell-common
src/BatteryModel.cpp
src/SoundsRepository.cpp
src/BellListItemProvider.cpp
+ src/SoundsProvider.cpp
src/windows/BellFactoryReset.cpp
src/windows/BellFinishedWindow.cpp
src/windows/BellTurnOffWindow.cpp
A products/BellHybrid/apps/common/include/common/SoundsProvider.hpp => products/BellHybrid/apps/common/include/common/SoundsProvider.hpp +53 -0
@@ 0,0 1,53 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "DatabaseModel.hpp"
+#include "module-gui/gui/widgets/ListItemProvider.hpp"
+#include "module-db/Interface/MultimediaFilesRecord.hpp"
+
+namespace app
+{
+ class ApplicationCommon;
+}
+namespace app::music
+{
+ class AbstractSongsRepository;
+}
+namespace app::bgSounds
+{
+ class SoundsProvider : public app::DatabaseModel<db::multimedia_files::MultimediaFilesRecord>,
+ public gui::ListItemProvider
+ {
+ public:
+ using ItemBuilder = std::function<gui::ListItem *(const db::multimedia_files::MultimediaFilesRecord &)>;
+ using OnSoundItemActivatedCallback =
+ std::function<void(const db::multimedia_files::MultimediaFilesRecord &sound)>;
+
+ SoundsProvider(app::ApplicationCommon *app,
+ ItemBuilder &&itemBuilder,
+ std::unique_ptr<app::music::AbstractSongsRepository> soundsRepository,
+ std::uint32_t itemSize);
+
+ [[nodiscard]] auto requestRecordsCount() -> unsigned int override;
+ [[nodiscard]] auto getMinimalItemSpaceRequired() const -> unsigned int override;
+ auto getItem(gui::Order order) -> gui::ListItem * override;
+ void requestRecords(uint32_t offset, uint32_t limit) override;
+
+ void setOnSoundItemActivatedCallback(OnSoundItemActivatedCallback &&callback);
+
+ private:
+ app::ApplicationCommon *app{nullptr};
+ std::unique_ptr<app::music::AbstractSongsRepository> soundsRepository;
+ ItemBuilder itemBuilder;
+ std::uint32_t itemSize;
+
+ OnSoundItemActivatedCallback onSoundItemActivatedCallback;
+
+ [[nodiscard]] bool updateRecords(std::vector<db::multimedia_files::MultimediaFilesRecord> records) override;
+
+ bool onAudioListRetrieved(const std::vector<db::multimedia_files::MultimediaFilesRecord> &records,
+ std::uint32_t repoRecordsCount);
+ };
+} // namespace app::bgSounds
A products/BellHybrid/apps/common/src/SoundsProvider.cpp => products/BellHybrid/apps/common/src/SoundsProvider.cpp +71 -0
@@ 0,0 1,71 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "products/BellHybrid/apps/common/include/common/SoundsProvider.hpp"
+#include "module-gui/gui/widgets/ListViewEngine.hpp"
+#include "module-apps/apps-common/models/SongsRepository.hpp"
+
+namespace app::bgSounds
+{
+ app::bgSounds::SoundsProvider::SoundsProvider(app::ApplicationCommon *app,
+ ItemBuilder &&itemBuilder,
+ std::unique_ptr<app::music::AbstractSongsRepository> soundsRepository,
+ std::uint32_t itemSize)
+ : DatabaseModel(app),
+ soundsRepository(std::move(soundsRepository)), itemBuilder{std::move(itemBuilder)}, itemSize{itemSize}
+ {}
+
+ auto SoundsProvider::requestRecordsCount() -> unsigned int
+ {
+ return recordsCount;
+ }
+ auto SoundsProvider::getMinimalItemSpaceRequired() const -> unsigned int
+ {
+ return itemSize;
+ }
+ auto SoundsProvider::getItem(gui::Order order) -> gui::ListItem *
+ {
+ auto sound = getRecord(order);
+ if (!sound) {
+ return nullptr;
+ }
+
+ auto item = itemBuilder(*sound);
+ item->activatedCallback = [this, sound](auto &) {
+ if (onSoundItemActivatedCallback) {
+ onSoundItemActivatedCallback(*sound);
+ }
+ return true;
+ };
+
+ return item;
+ }
+ void SoundsProvider::requestRecords(uint32_t offset, uint32_t limit)
+ {
+ soundsRepository->getMusicFilesList(
+ offset,
+ limit,
+ [this](const std::vector<db::multimedia_files::MultimediaFilesRecord> &records,
+ const auto repoRecordsCount) { return onAudioListRetrieved(records, repoRecordsCount); });
+ }
+ bool SoundsProvider::onAudioListRetrieved(const std::vector<db::multimedia_files::MultimediaFilesRecord> &records,
+ const std::uint32_t repoRecordsCount)
+ {
+ if (list != nullptr && recordsCount != repoRecordsCount) {
+ recordsCount = repoRecordsCount;
+ list->reSendLastRebuildRequest();
+ return false;
+ }
+ return updateRecords(records);
+ }
+ bool SoundsProvider::updateRecords(std::vector<db::multimedia_files::MultimediaFilesRecord> records)
+ {
+ DatabaseModel::updateRecords(std::move(records));
+ list->onProviderDataUpdate();
+ return true;
+ }
+ void SoundsProvider::setOnSoundItemActivatedCallback(SoundsProvider::OnSoundItemActivatedCallback &&callback)
+ {
+ onSoundItemActivatedCallback = std::move(callback);
+ }
+} // namespace app::bgSounds
M products/BellHybrid/assets/assets_common.json => products/BellHybrid/assets/assets_common.json +13 -15
@@ 65,18 65,18 @@
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/chimes/Gentle_Chime.mp3", "output": "assets/audio/chimes/Gentle_Chime.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/chimes/Rise_&_Shine.mp3", "output": "assets/audio/chimes/Rise_&_Shine.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/chimes/Twinkle_Chime.mp3", "output": "assets/audio/chimes/Twinkle_Chime.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Ancient_Greek.mp3", "output": "assets/audio/bg_sounds/Ancient_Greek.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Autumnal_Sea.mp3", "output": "assets/audio/bg_sounds/Autumnal_Sea.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Bubbling_Brook.mp3", "output": "assets/audio/bg_sounds/Bubbling_Brook.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Charming_Bells.mp3", "output": "assets/audio/bg_sounds/Charming_Bells.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Forest_Creek.mp3", "output": "assets/audio/bg_sounds/Forest_Creek.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Mountain_Lagoon.mp3", "output": "assets/audio/bg_sounds/Mountain_Lagoon.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Mystic_Nature.mp3", "output": "assets/audio/bg_sounds/Mystic_Nature.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Natures_Harmony.mp3", "output": "assets/audio/bg_sounds/Natures_Harmony.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Rhythmic_Lullaby.mp3", "output": "assets/audio/bg_sounds/Rhythmic_Lullaby.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Seaside_Symphony.mp3", "output": "assets/audio/bg_sounds/Seaside_Symphony.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Under_the_Water.mp3", "output": "assets/audio/bg_sounds/Under_the_Water.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Woodland_Ambiance.mp3", "output": "assets/audio/bg_sounds/Woodland_Ambiance.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Ancient_Greek.mp3", "output": "assets/audio/relaxation/Ancient_Greek.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Autumnal_Sea.mp3", "output": "assets/audio/relaxation/Autumnal_Sea.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Bubbling_Brook.mp3", "output": "assets/audio/relaxation/Bubbling_Brook.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Charming_Bells.mp3", "output": "assets/audio/relaxation/Charming_Bells.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Forest_Creek.mp3", "output": "assets/audio/relaxation/Forest_Creek.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Mountain_Lagoon.mp3", "output": "assets/audio/relaxation/Mountain_Lagoon.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Mystic_Nature.mp3", "output": "assets/audio/relaxation/Mystic_Nature.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Natures_Harmony.mp3", "output": "assets/audio/relaxation/Natures_Harmony.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Rhythmic_Lullaby.mp3", "output": "assets/audio/relaxation/Rhythmic_Lullaby.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Seaside_Symphony.mp3", "output": "assets/audio/relaxation/Seaside_Symphony.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Under_the_Water.mp3", "output": "assets/audio/relaxation/Under_the_Water.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Woodland_Ambiance.mp3", "output": "assets/audio/relaxation/Woodland_Ambiance.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/meditation/Meditation_Gong.mp3", "output": "assets/audio/meditation/Meditation_Gong.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/prewakeup/Joyful_Awakening.mp3", "output": "assets/audio/prewakeup/Joyful_Awakening.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/prewakeup/Morning_Spirit.mp3", "output": "assets/audio/prewakeup/Morning_Spirit.mp3"},
@@ 102,8 102,6 @@
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/evening_reminder/Evening_Horizon.mp3", "output": "assets/audio/evening_reminder/Evening_Horizon.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/evening_reminder/Evolving_Dusk.mp3", "output": "assets/audio/evening_reminder/Evolving_Dusk.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/evening_reminder/Melodic_Mirth.mp3", "output": "assets/audio/evening_reminder/Melodic_Mirth.mp3"},
- {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/evening_reminder/Twilight_Gleam.mp3", "output": "assets/audio/evening_reminder/Twilight_Gleam.mp3"},
-
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/bell/evening_reminder/Twilight_Gleam.mp3", "output": "../user/music/Twilight_Gleam.mp3"}
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/evening_reminder/Twilight_Gleam.mp3", "output": "assets/audio/evening_reminder/Twilight_Gleam.mp3"}
]
}
A products/BellHybrid/paths/CMakeLists.txt => products/BellHybrid/paths/CMakeLists.txt +6 -0
@@ 0,0 1,6 @@
+add_library(paths Paths.cpp)
+add_library(bell::paths ALIAS paths)
+
+target_include_directories(paths PUBLIC .)
+
+target_link_libraries(paths PRIVATE module-vfs)<
\ No newline at end of file
A products/BellHybrid/paths/Paths.cpp => products/BellHybrid/paths/Paths.cpp +38 -0
@@ 0,0 1,38 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "Paths.hpp"
+#include <purefs/filesystem_paths.hpp>
+
+std::filesystem::path paths::audio::user() noexcept
+{
+ return purefs::dir::getUserDiskPath() / "audio";
+}
+std::filesystem::path paths::audio::proprietary() noexcept
+{
+ return purefs::dir::getCurrentOSPath() / "assets/audio";
+}
+std::filesystem::path paths::audio::alarm() noexcept
+{
+ return "alarm";
+}
+std::filesystem::path paths::audio::preWakeup() noexcept
+{
+ return "prewakeup";
+}
+std::filesystem::path paths::audio::snooze() noexcept
+{
+ return "chimes";
+}
+std::filesystem::path paths::audio::bedtimeReminder() noexcept
+{
+ return "evening_reminder";
+}
+std::filesystem::path paths::audio::relaxation() noexcept
+{
+ return "relaxation";
+}
+std::filesystem::path paths::audio::meditation() noexcept
+{
+ return "meditation";
+}
A products/BellHybrid/paths/Paths.hpp => products/BellHybrid/paths/Paths.hpp +22 -0
@@ 0,0 1,22 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <filesystem>
+
+namespace paths
+{
+ namespace audio
+ {
+ std::filesystem::path user() noexcept;
+ std::filesystem::path proprietary() noexcept;
+ std::filesystem::path alarm() noexcept;
+ std::filesystem::path preWakeup() noexcept;
+ std::filesystem::path snooze() noexcept;
+ std::filesystem::path bedtimeReminder() noexcept;
+ std::filesystem::path relaxation() noexcept;
+ std::filesystem::path meditation() noexcept;
+ } // namespace audio
+
+} // namespace paths
M products/BellHybrid/services/db/tests/MeditationStatisticsTable_tests.cpp => products/BellHybrid/services/db/tests/MeditationStatisticsTable_tests.cpp +1 -1
@@ 34,7 34,7 @@ namespace
REQUIRE(std::filesystem::remove(name));
}
- db = std::make_unique<MeditationStatisticsDB>(name.c_str());
+ db = std::make_unique<Db>(name.c_str());
if (not db->isInitialized()) {
throw std::runtime_error("Could not initialize database");
M products/PurePhone/CMakeLists.txt => products/PurePhone/CMakeLists.txt +9 -2
@@ 106,6 106,13 @@ message_serial_status()
include(BinaryAssetsVersions.cmake)
include(AddVersionJson)
+add_directories(
+ TARGET user_directories
+ PREFIX ${CMAKE_BINARY_DIR}/sysroot/sys/user/audio
+ DEPENDS user_directories_common
+ DIRECTORIES music_player
+)
+
if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
include(AddBootBin)
add_boot_bin(PurePhone)
@@ 113,7 120,7 @@ if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
PRODUCT PurePhone
SYSROOT sysroot
LUTS Luts.bin
- DEPENDS assets updater.bin-target ecoboot.bin-target PurePhone-boot.bin PurePhone-version.json-target
+ DEPENDS user_directories assets updater.bin-target ecoboot.bin-target PurePhone-boot.bin PurePhone-version.json-target
)
add_version_rt1051_json(PurePhone)
else()
@@ 121,7 128,7 @@ else()
PRODUCT PurePhone
SYSROOT sysroot
LUTS ""
- DEPENDS assets PurePhone-version.json-target
+ DEPENDS user_directories assets PurePhone-version.json-target
)
add_version_linux_json(PurePhone)
endif()
M products/PurePhone/PurePhoneMain.cpp => products/PurePhone/PurePhoneMain.cpp +1 -1
@@ 133,7 133,7 @@ int main()
{
constexpr auto ApplicationName = "PurePhone";
- const std::vector<std::string> fileIndexerAudioPaths = {{purefs::dir::getUserDiskPath() / "music"}};
+ const std::vector<std::string> fileIndexerAudioPaths = {{purefs::dir::getUserAudioPath()}};
prof::init();
M products/PurePhone/assets/assets_common.json => products/PurePhone/assets/assets_common.json +14 -14
@@ 220,19 220,19 @@
{"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/ringtone/ringtone_drum_2.mp3", "output": "assets/audio/ringtone/ringtone_drum_2.mp3"},
{"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/ringtone/ringtone_drum.mp3", "output": "assets/audio/ringtone/ringtone_drum.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Love_Peace_Harmony.mp3", "output": "../user/music/Nick_Lewis_-_Love_Peace_Harmony.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/lazy_nature_reserve-devel.mp3", "output": "../user/music/lazy_nature_reserve-devel.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Que_Bien_Me_Dijo_Mi_Madre.mp3", "output": "../user/music/Nick_Lewis_-_Que_Bien_Me_Dijo_Mi_Madre.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Mahamrityunjaya_Mantra.mp3", "output": "../user/music/Nick_Lewis_-_Mahamrityunjaya_Mantra.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/autumn_in_jelitkowo-devel.mp3", "output": "../user/music/autumn_in_jelitkowo-devel.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Love_Peace_And_Forgiveness.mp3", "output": "../user/music/Nick_Lewis_-_Love_Peace_And_Forgiveness.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Bring_The_Light.mp3", "output": "../user/music/Nick_Lewis_-_Bring_The_Light.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Kristies_Elephant.mp3", "output": "../user/music/Nick_Lewis_-_Kristies_Elephant.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/secret_river-devel.mp3", "output": "../user/music/secret_river-devel.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/beka_nature_reserve-devel.mp3", "output": "../user/music/beka_nature_reserve-devel.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Always_With_You.mp3", "output": "../user/music/Nick_Lewis_-_Always_With_You.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/baltic_seagulls-devel.mp3", "output": "../user/music/baltic_seagulls-devel.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_You_Are_Holy.mp3", "output": "../user/music/Nick_Lewis_-_You_Are_Holy.mp3"},
- {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Pure_Ocean.mp3", "output": "../user/music/Nick_Lewis_-_Pure_Ocean.mp3"}
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Love_Peace_Harmony.mp3", "output": "../user/audio/music_player/Nick_Lewis_-_Love_Peace_Harmony.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/lazy_nature_reserve-devel.mp3", "output": "../user/audio/music_player/lazy_nature_reserve-devel.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Que_Bien_Me_Dijo_Mi_Madre.mp3", "output": "../user/audio/music_player/Nick_Lewis_-_Que_Bien_Me_Dijo_Mi_Madre.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Mahamrityunjaya_Mantra.mp3", "output": "../user/audio/music_player/Nick_Lewis_-_Mahamrityunjaya_Mantra.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/autumn_in_jelitkowo-devel.mp3", "output": "../user/audio/music_player/autumn_in_jelitkowo-devel.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Love_Peace_And_Forgiveness.mp3", "output": "../user/audio/music_player/Nick_Lewis_-_Love_Peace_And_Forgiveness.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Bring_The_Light.mp3", "output": "../user/audio/music_player/Nick_Lewis_-_Bring_The_Light.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Kristies_Elephant.mp3", "output": "../user/audio/music_player/Nick_Lewis_-_Kristies_Elephant.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/secret_river-devel.mp3", "output": "../user/audio/music_player/secret_river-devel.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/beka_nature_reserve-devel.mp3", "output": "../user/audio/music_player/beka_nature_reserve-devel.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Always_With_You.mp3", "output": "../user/audio/music_player/Nick_Lewis_-_Always_With_You.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/baltic_seagulls-devel.mp3", "output": "../user/audio/music_player/baltic_seagulls-devel.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_You_Are_Holy.mp3", "output": "../user/audio/music_player/Nick_Lewis_-_You_Are_Holy.mp3"},
+ {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/music/Nick_Lewis_-_Pure_Ocean.mp3", "output": "../user/audio/music_player/Nick_Lewis_-_Pure_Ocean.mp3"}
]
}