Merge lp:~jamesh/mediascanner2/query-artists into lp:mediascanner2

Proposed by James Henstridge
Status: Merged
Approved by: Jussi Pakkanen
Approved revision: 258
Merged at revision: 256
Proposed branch: lp:~jamesh/mediascanner2/query-artists
Merge into: lp:mediascanner2
Prerequisite: lp:~jamesh/mediascanner2/streaming-model
Diff against target: 348 lines (+203/-1)
10 files modified
debian/libmediascanner-2.0-0.symbols (+3/-1)
src/mediascanner/CMakeLists.txt (+1/-0)
src/mediascanner/MediaStore.cc (+40/-0)
src/mediascanner/MediaStore.hh (+1/-0)
src/mediascanner/MediaStoreBase.hh (+1/-0)
src/ms-dbus/dbus-interface.hh (+13/-0)
src/ms-dbus/service-skeleton.cc (+25/-0)
src/ms-dbus/service-stub.cc (+7/-0)
src/ms-dbus/service-stub.hh (+1/-0)
test/test_mediastore.cc (+111/-0)
To merge this branch: bzr merge lp:~jamesh/mediascanner2/query-artists
Reviewer Review Type Date Requested Status
Jussi Pakkanen (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+228248@code.launchpad.net

Commit message

Add MediaStore::queryArtists() method, needed for the new scope design.

Description of the change

Add MediaStore::queryArtists() method, needed for the new scope design.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

Looking really nice.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/libmediascanner-2.0-0.symbols'
2--- debian/libmediascanner-2.0-0.symbols 2014-07-25 07:35:08 +0000
3+++ debian/libmediascanner-2.0-0.symbols 2014-07-25 07:35:08 +0000
4@@ -66,6 +66,7 @@
5 (c++)"mediascanner::MediaStore::listGenres(mediascanner::Filter const&) const@Base" 0replaceme
6 (c++)"mediascanner::MediaStore::listArtists(mediascanner::Filter const&) const@Base" 0replaceme
7 (c++)"mediascanner::MediaStore::queryAlbums(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int) const@Base" 0.101+14.10.20140613
8+ (c++)"mediascanner::MediaStore::queryArtists(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int) const@Base" 0replaceme
9 (c++)"mediascanner::MediaStore::getAlbumSongs(mediascanner::Album const&) const@Base" 0.101+14.10.20140613
10 (c++)"mediascanner::MediaStore::listAlbumArtists(mediascanner::Filter const&) const@Base" 0replaceme
11 (c++)"mediascanner::MediaStore::size() const@Base" 0.101+14.10.20140613
12@@ -119,14 +120,15 @@
13 (c++)"VTT for mediascanner::MediaStore@Base" 0.101+14.10.20140625
14 (c++)"vtable for mediascanner::MediaStore@Base" 0.101+14.10.20140625
15 (c++)"vtable for mediascanner::MediaStoreBase@Base" 0.101+14.10.20140625
16+ (c++)"virtual thunk to mediascanner::MediaStore::listAlbumArtists(mediascanner::Filter const&) const@Base" 0replaceme
17 (c++)"virtual thunk to mediascanner::MediaStore::listGenres(mediascanner::Filter const&) const@Base" 0replaceme
18 (c++)"virtual thunk to mediascanner::MediaStore::~MediaStore()@Base" 0.101+14.10.20140625
19 (c++)"virtual thunk to mediascanner::MediaStore::lookup(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const@Base" 0.101+14.10.20140625
20 (c++)"virtual thunk to mediascanner::MediaStore::query(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, mediascanner::MediaType, int) const@Base" 0.101+14.10.20140625
21 (c++)"virtual thunk to mediascanner::MediaStore::queryAlbums(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int) const@Base" 0.101+14.10.20140625
22+ (c++)"virtual thunk to mediascanner::MediaStore::queryArtists(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int) const@Base" 0replaceme
23 (c++)"virtual thunk to mediascanner::MediaStore::getAlbumSongs(mediascanner::Album const&) const@Base" 0.101+14.10.20140625
24 (c++)"virtual thunk to mediascanner::MediaStore::getETag(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const@Base" 0.101+14.10.20140625
25 (c++)"virtual thunk to mediascanner::MediaStore::listSongs(mediascanner::Filter const&) const@Base" 0replaceme
26 (c++)"virtual thunk to mediascanner::MediaStore::listAlbums(mediascanner::Filter const&) const@Base" 0replaceme
27 (c++)"virtual thunk to mediascanner::MediaStore::listArtists(mediascanner::Filter const&) const@Base" 0replaceme
28- (c++)"virtual thunk to mediascanner::MediaStore::listAlbumArtists(mediascanner::Filter const&) const@Base" 0replaceme
29
30=== modified file 'src/mediascanner/CMakeLists.txt'
31--- src/mediascanner/CMakeLists.txt 2014-06-24 10:33:29 +0000
32+++ src/mediascanner/CMakeLists.txt 2014-07-25 07:35:08 +0000
33@@ -32,6 +32,7 @@
34
35 install(FILES
36 Album.hh
37+ Filter.hh
38 MediaFile.hh
39 MediaFileBuilder.hh
40 MediaStore.hh
41
42=== modified file 'src/mediascanner/MediaStore.cc'
43--- src/mediascanner/MediaStore.cc 2014-07-25 07:35:08 +0000
44+++ src/mediascanner/MediaStore.cc 2014-07-25 07:35:08 +0000
45@@ -58,6 +58,7 @@
46 MediaFile lookup(const std::string &filename) const;
47 std::vector<MediaFile> query(const std::string &q, MediaType type, int limit=-1) const;
48 std::vector<Album> queryAlbums(const std::string &core_term, int limit=-1) const;
49+ std::vector<string> queryArtists(const std::string &q, int limit=-1) const;
50 std::vector<MediaFile> getAlbumSongs(const Album& album) const;
51 std::string getETag(const std::string &filename) const;
52
53@@ -471,6 +472,40 @@
54 }
55 }
56
57+vector<string> MediaStorePrivate::queryArtists(const string &q, int limit) const {
58+ if (q.empty()) {
59+ Statement query(db, R"(
60+SELECT artist FROM media
61+WHERE type = ? AND artist <> ''
62+GROUP BY artist
63+LIMIT ?
64+)");
65+ query.bind(1, (int)AudioMedia);
66+ query.bind(2, limit);
67+ vector<string> result;
68+ while (query.step()) {
69+ result.push_back(query.getText(0));
70+ }
71+ return result;
72+ } else {
73+ Statement query(db, R"(
74+SELECT artist FROM media
75+WHERE rowid IN (SELECT docid FROM media_fts WHERE media_fts MATCH ?)
76+AND type == ? AND artist <> ''
77+GROUP BY artist
78+LIMIT ?
79+)");
80+ query.bind(1, q + "*");
81+ query.bind(2, (int)AudioMedia);
82+ query.bind(3, limit);
83+ vector<string> result;
84+ while (query.step()) {
85+ result.push_back(query.getText(0));
86+ }
87+ return result;
88+ }
89+}
90+
91 vector<MediaFile> MediaStorePrivate::getAlbumSongs(const Album& album) const {
92 Statement query(db, R"(
93 SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, width, height, latitude, longitude, type FROM media
94@@ -731,6 +766,11 @@
95 return p->queryAlbums(core_term, limit);
96 }
97
98+std::vector<string> MediaStore::queryArtists(const std::string &q, int limit) const {
99+ std::lock_guard<std::mutex> lock(p->dbMutex);
100+ return p->queryArtists(q, limit);
101+}
102+
103 std::vector<MediaFile> MediaStore::getAlbumSongs(const Album& album) const {
104 std::lock_guard<std::mutex> lock(p->dbMutex);
105 return p->getAlbumSongs(album);
106
107=== modified file 'src/mediascanner/MediaStore.hh'
108--- src/mediascanner/MediaStore.hh 2014-07-25 07:35:08 +0000
109+++ src/mediascanner/MediaStore.hh 2014-07-25 07:35:08 +0000
110@@ -47,6 +47,7 @@
111 virtual MediaFile lookup(const std::string &filename) const override;
112 virtual std::vector<MediaFile> query(const std::string &q, MediaType type, int limit=-1) const override;
113 virtual std::vector<Album> queryAlbums(const std::string &core_term, int limit=-1) const override;
114+ virtual std::vector<std::string> queryArtists(const std::string &q, int limit=-1) const override;
115 virtual std::vector<MediaFile> getAlbumSongs(const Album& album) const override;
116 virtual std::string getETag(const std::string &filename) const override;
117 virtual std::vector<MediaFile> listSongs(const Filter &filter) const override;
118
119=== modified file 'src/mediascanner/MediaStoreBase.hh'
120--- src/mediascanner/MediaStoreBase.hh 2014-07-25 07:35:08 +0000
121+++ src/mediascanner/MediaStoreBase.hh 2014-07-25 07:35:08 +0000
122@@ -42,6 +42,7 @@
123 virtual MediaFile lookup(const std::string &filename) const = 0;
124 virtual std::vector<MediaFile> query(const std::string &q, MediaType type, int limit=-1) const = 0;
125 virtual std::vector<Album> queryAlbums(const std::string &core_term, int limit=-1) const = 0;
126+ virtual std::vector<std::string> queryArtists(const std::string &q, int limit=-1) const = 0;
127 virtual std::vector<MediaFile> getAlbumSongs(const Album& album) const = 0;
128 virtual std::string getETag(const std::string &filename) const = 0;
129 virtual std::vector<MediaFile> listSongs(const Filter &filter) const = 0;
130
131=== modified file 'src/ms-dbus/dbus-interface.hh'
132--- src/ms-dbus/dbus-interface.hh 2014-06-10 04:58:51 +0000
133+++ src/ms-dbus/dbus-interface.hh 2014-07-25 07:35:08 +0000
134@@ -93,6 +93,19 @@
135 }
136 };
137
138+ struct QueryArtists {
139+ typedef MediaStoreInterface Interface;
140+
141+ inline static const std::string& name() {
142+ static std::string s = "QueryArtists";
143+ return s;
144+ }
145+
146+ inline static const std::chrono::milliseconds default_timeout() {
147+ return std::chrono::seconds{1};
148+ }
149+ };
150+
151 struct GetAlbumSongs {
152 typedef MediaStoreInterface Interface;
153
154
155=== modified file 'src/ms-dbus/service-skeleton.cc'
156--- src/ms-dbus/service-skeleton.cc 2014-07-25 07:35:08 +0000
157+++ src/ms-dbus/service-skeleton.cc 2014-07-25 07:35:08 +0000
158@@ -64,6 +64,11 @@
159 &Private::handle_query_albums,
160 this,
161 std::placeholders::_1));
162+ object->install_method_handler<MediaStoreInterface::QueryArtists>(
163+ std::bind(
164+ &Private::handle_query_artists,
165+ this,
166+ std::placeholders::_1));
167 object->install_method_handler<MediaStoreInterface::GetAlbumSongs>(
168 std::bind(
169 &Private::handle_get_album_songs,
170@@ -221,6 +226,26 @@
171 impl->access_bus()->send(reply);
172 }
173
174+ void handle_query_artists(const Message::Ptr &message) {
175+ if (!check_access(message, AudioMedia))
176+ return;
177+
178+ std::string query;
179+ int32_t limit;
180+ message->reader() >> query >> limit;
181+ Message::Ptr reply;
182+ try {
183+ auto artists = store->queryArtists(query, limit);
184+ reply = Message::make_method_return(message);
185+ reply->writer() << artists;
186+ } catch (const std::exception &e) {
187+ reply = Message::make_error(
188+ message, MediaStoreInterface::Errors::Error::name(),
189+ e.what());
190+ }
191+ impl->access_bus()->send(reply);
192+ }
193+
194 void handle_get_album_songs(const Message::Ptr &message) {
195 if (!check_access(message, AudioMedia))
196 return;
197
198=== modified file 'src/ms-dbus/service-stub.cc'
199--- src/ms-dbus/service-stub.cc 2014-07-25 07:35:08 +0000
200+++ src/ms-dbus/service-stub.cc 2014-07-25 07:35:08 +0000
201@@ -66,6 +66,13 @@
202 return result.value();
203 }
204
205+std::vector<string> ServiceStub::queryArtists(const string &q, int limit) const {
206+ auto result = p->object->invoke_method_synchronously<MediaStoreInterface::QueryArtists, std::vector<string>>(q, (int32_t)limit);
207+ if (result.is_error())
208+ throw std::runtime_error(result.error().print());
209+ return result.value();
210+}
211+
212 std::vector<MediaFile> ServiceStub::getAlbumSongs(const Album& album) const {
213 auto result = p->object->invoke_method_synchronously<MediaStoreInterface::GetAlbumSongs, std::vector<MediaFile>>(album);
214 if (result.is_error())
215
216=== modified file 'src/ms-dbus/service-stub.hh'
217--- src/ms-dbus/service-stub.hh 2014-07-25 07:35:08 +0000
218+++ src/ms-dbus/service-stub.hh 2014-07-25 07:35:08 +0000
219@@ -45,6 +45,7 @@
220 virtual MediaFile lookup(const std::string &filename) const override;
221 virtual std::vector<MediaFile> query(const std::string &q, MediaType type, int limit=-1) const override;
222 virtual std::vector<Album> queryAlbums(const std::string &core_term, int limit=-1) const override;
223+ virtual std::vector<std::string> queryArtists(const std::string &q, int limit=-1) const override;
224 virtual std::vector<MediaFile> getAlbumSongs(const Album& album) const override;
225 virtual std::string getETag(const std::string &filename) const override;
226 virtual std::vector<MediaFile> listSongs(const Filter &filter) const override;
227
228=== modified file 'test/test_mediastore.cc'
229--- test/test_mediastore.cc 2014-07-25 07:35:08 +0000
230+++ test/test_mediastore.cc 2014-07-25 07:35:08 +0000
231@@ -552,6 +552,117 @@
232 EXPECT_EQ(1, albums.size());
233 }
234
235+TEST_F(MediaStoreTest, queryArtists) {
236+ MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
237+ .setType(AudioMedia)
238+ .setTitle("TitleOne")
239+ .setAuthor("ArtistOne")
240+ .setAlbum("AlbumOne")
241+ .setAlbumArtist("Various Artists")
242+ .setDiscNumber(1)
243+ .setTrackNumber(1);
244+ MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
245+ .setType(AudioMedia)
246+ .setTitle("TitleTwo")
247+ .setAuthor("ArtistTwo")
248+ .setAlbum("AlbumOne")
249+ .setAlbumArtist("Various Artists")
250+ .setDiscNumber(1)
251+ .setTrackNumber(2);
252+ MediaFile audio3 = MediaFileBuilder("/home/username/Music/track3.ogg")
253+ .setType(AudioMedia)
254+ .setTitle("TitleThree")
255+ .setAuthor("ArtistThree")
256+ .setAlbum("AlbumOne")
257+ .setAlbumArtist("Various Artists")
258+ .setDiscNumber(2)
259+ .setTrackNumber(1);
260+ MediaFile audio4 = MediaFileBuilder("/home/username/Music/fname.ogg")
261+ .setType(AudioMedia)
262+ .setTitle("TitleFour")
263+ .setAuthor("ArtistFour")
264+ .setAlbum("AlbumTwo")
265+ .setAlbumArtist("ArtistFour")
266+ .setTrackNumber(1);
267+
268+ MediaStore store(":memory:", MS_READ_WRITE);
269+ store.insert(audio1);
270+ store.insert(audio2);
271+ store.insert(audio3);
272+ store.insert(audio4);
273+
274+ // Query a track title
275+ vector<string> artists = store.queryArtists("TitleOne");
276+ ASSERT_EQ(artists.size(), 1);
277+ EXPECT_EQ(artists[0], "ArtistOne");
278+
279+ // Query an album name
280+ artists = store.queryArtists("AlbumTwo");
281+ ASSERT_EQ(artists.size(), 1);
282+ EXPECT_EQ(artists[0], "ArtistFour");
283+
284+ // Query an artist name
285+ artists = store.queryArtists("ArtistTwo");
286+ ASSERT_EQ(artists.size(), 1);
287+ EXPECT_EQ(artists[0], "ArtistTwo");
288+}
289+
290+TEST_F(MediaStoreTest, queryArtists_limit) {
291+ MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
292+ .setType(AudioMedia)
293+ .setTitle("TitleOne")
294+ .setAuthor("ArtistOne")
295+ .setAlbum("AlbumOne")
296+ .setAlbumArtist("Various Artists")
297+ .setDiscNumber(1)
298+ .setTrackNumber(1);
299+ MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
300+ .setType(AudioMedia)
301+ .setTitle("TitleTwo")
302+ .setAuthor("ArtistTwo")
303+ .setAlbum("AlbumOne")
304+ .setAlbumArtist("Various Artists")
305+ .setDiscNumber(1)
306+ .setTrackNumber(2);
307+
308+ MediaStore store(":memory:", MS_READ_WRITE);
309+ store.insert(audio1);
310+ store.insert(audio2);
311+
312+ vector<string> artists = store.queryArtists("Artist");
313+ EXPECT_EQ(2, artists.size());
314+ artists = store.queryArtists("Artist", 1);
315+ EXPECT_EQ(1, artists.size());
316+}
317+
318+TEST_F(MediaStoreTest, queryArtists_empty) {
319+ MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
320+ .setType(AudioMedia)
321+ .setTitle("TitleOne")
322+ .setAuthor("ArtistOne")
323+ .setAlbum("AlbumOne")
324+ .setAlbumArtist("Various Artists")
325+ .setDiscNumber(1)
326+ .setTrackNumber(1);
327+ MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
328+ .setType(AudioMedia)
329+ .setTitle("TitleTwo")
330+ .setAuthor("ArtistTwo")
331+ .setAlbum("AlbumOne")
332+ .setAlbumArtist("Various Artists")
333+ .setDiscNumber(1)
334+ .setTrackNumber(2);
335+
336+ MediaStore store(":memory:", MS_READ_WRITE);
337+ store.insert(audio1);
338+ store.insert(audio2);
339+
340+ vector<string> artists = store.queryArtists("");
341+ EXPECT_EQ(2, artists.size());
342+ artists = store.queryArtists("", 1);
343+ EXPECT_EQ(1, artists.size());
344+}
345+
346 TEST_F(MediaStoreTest, getAlbumSongs) {
347 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
348 .setType(AudioMedia)

Subscribers

People subscribed via source and target branches