1 /*
2 * Copyright (C) 2018 Emeric Poupon
3 *
4 * This file is part of LMS.
5 *
6 * LMS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * LMS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with LMS. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "database/ScanSettings.hpp"
21
22 #include <Wt/Dbo/WtSqlTraits.h>
23
24 #include "utils/Path.hpp"
25 #include "utils/Logger.hpp"
26 #include "utils/String.hpp"
27
28 #include "database/Cluster.hpp"
29 #include "database/Session.hpp"
30
31 namespace {
32
33 const std::set<std::string> defaultClusterTypeNames =
34 {
35 "GENRE",
36 "ALBUMGROUPING",
37 "MOOD",
38 "ALBUMMOOD",
39 };
40
41 }
42
43 namespace Database {
44
45 void
init(Session & session)46 ScanSettings::init(Session& session)
47 {
48 session.checkUniqueLocked();
49
50 pointer settings {get(session)};
51 if (settings)
52 return;
53
54 settings = session.getDboSession().add(std::make_unique<ScanSettings>());
55 settings.modify()->setClusterTypes(session, defaultClusterTypeNames );
56 }
57
58 ScanSettings::pointer
get(Session & session)59 ScanSettings::get(Session& session)
60 {
61 session.checkSharedLocked();
62
63 return session.getDboSession().find<ScanSettings>();
64 }
65
66 std::unordered_set<std::filesystem::path>
getAudioFileExtensions() const67 ScanSettings::getAudioFileExtensions() const
68 {
69 auto extensions = StringUtils::splitString(_audioFileExtensions, " ");
70 return std::unordered_set<std::filesystem::path>(std::cbegin(extensions), std::cend(extensions));
71 }
72
73 void
addAudioFileExtension(const std::filesystem::path & ext)74 ScanSettings::addAudioFileExtension(const std::filesystem::path& ext)
75 {
76 _audioFileExtensions += " " + ext.string();
77 }
78
79 std::vector<ClusterType::pointer>
getClusterTypes() const80 ScanSettings::getClusterTypes() const
81 {
82 return std::vector<ClusterType::pointer>(std::cbegin(_clusterTypes), std::cend(_clusterTypes));
83 }
84
85 void
setMediaDirectory(const std::filesystem::path & p)86 ScanSettings::setMediaDirectory(const std::filesystem::path& p)
87 {
88 _mediaDirectory = StringUtils::stringTrimEnd(p.string(), "/\\");
89 }
90
91 template <typename It>
getNames(It begin,It end)92 std::set<std::string> getNames(It begin, It end)
93 {
94 std::set<std::string> names;
95 std::transform(begin, end, std::inserter(names, std::cbegin(names)),
96 [](const ClusterType::pointer& clusterType)
97 {
98 return clusterType->getName();
99 });
100
101 return names;
102 }
103
104 void
setClusterTypes(Session & session,const std::set<std::string> & clusterTypeNames)105 ScanSettings::setClusterTypes(Session& session, const std::set<std::string>& clusterTypeNames)
106 {
107 session.checkUniqueLocked();
108
109 bool needRescan {};
110
111 // Create any missing cluster type
112 for (const std::string& clusterTypeName : clusterTypeNames)
113 {
114 auto clusterType {ClusterType::getByName(session, clusterTypeName)};
115 if (!clusterType)
116 {
117 LMS_LOG(DB, INFO) << "Creating cluster type " << clusterTypeName;
118 clusterType = ClusterType::create(session, clusterTypeName);
119 _clusterTypes.insert(clusterType);
120
121 needRescan = true;
122 }
123 }
124
125 // Delete no longer existing cluster types
126 for (ClusterType::pointer& clusterType : _clusterTypes)
127 {
128 if (std::none_of(clusterTypeNames.begin(), clusterTypeNames.end(),
129 [clusterType](const std::string& name) { return name == clusterType->getName(); }))
130 {
131 LMS_LOG(DB, INFO) << "Deleting cluster type " << clusterType->getName();
132 clusterType.remove();
133 }
134 }
135
136 if (needRescan)
137 _scanVersion += 1;
138 }
139
140 void
incScanVersion()141 ScanSettings::incScanVersion()
142 {
143 _scanVersion += 1;
144 }
145
146 } // namespace Database
147
148