Merge lp:~jamesh/mediascanner2/folder-coverart into lp:mediascanner2
- folder-coverart
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Michi Henning |
Approved revision: | 325 |
Merged at revision: | 315 |
Proposed branch: | lp:~jamesh/mediascanner2/folder-coverart |
Merge into: | lp:mediascanner2 |
Diff against target: |
730 lines (+453/-36) 16 files modified
CMakeLists.txt (+1/-1) debian/changelog (+9/-0) debian/libmediascanner-2.0-3.symbols (+2/-0) debian/libmediascanner-2.0-4.shlibs (+1/-1) src/mediascanner/Album.cc (+25/-8) src/mediascanner/Album.hh (+4/-0) src/mediascanner/CMakeLists.txt (+1/-0) src/mediascanner/FolderArtCache.cc (+169/-0) src/mediascanner/MediaFile.cc (+10/-4) src/mediascanner/MediaStore.cc (+1/-1) src/mediascanner/internal/FolderArtCache.hh (+55/-0) src/ms-dbus/dbus-codec.cc (+4/-2) src/ms-dbus/dbus-codec.hh (+1/-1) test/test_dbus.cc (+3/-2) test/test_mfbuilder.cc (+164/-16) test/test_util.cc (+3/-0) |
To merge this branch: | bzr merge lp:~jamesh/mediascanner2/folder-coverart |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michi Henning (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+278099@code.launchpad.net |
Commit message
If a folder contains an image file named {cover,
Description of the change
Add folder based cover art detection to the MediaFile:
PS Jenkins bot (ps-jenkins) wrote : | # |
- 321. By James Henstridge
-
Remove unneeded #define.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:321
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 322. By James Henstridge
-
Add new constructor for album, explicitly passing the has_thumbnail boolean.
- 323. By James Henstridge
-
Add Album::
getHasThumbnail () for use by dbus code, and make MediaStore
pass in has_thumbnail to Album. - 324. By James Henstridge
-
Add folder artwork support to Album class.
- 325. By James Henstridge
-
Bump version number to account for API additions.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:325
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michi Henning (michihenning) wrote : | # |
Looks good! I tested on the phone and, after dropping a folder.jpg file into a dir with songs without artwork, the image was used by the music app.
Preview Diff
1 | === modified file 'CMakeLists.txt' | |||
2 | --- CMakeLists.txt 2015-11-07 09:13:53 +0000 | |||
3 | +++ CMakeLists.txt 2015-11-23 03:14:55 +0000 | |||
4 | @@ -1,7 +1,7 @@ | |||
5 | 1 | project(mediascanner2 CXX C) | 1 | project(mediascanner2 CXX C) |
6 | 2 | cmake_minimum_required(VERSION 2.8.9) | 2 | cmake_minimum_required(VERSION 2.8.9) |
7 | 3 | 3 | ||
9 | 4 | set(MEDIASCANNER_VERSION "0.108") | 4 | set(MEDIASCANNER_VERSION "0.109") |
10 | 5 | 5 | ||
11 | 6 | execute_process( | 6 | execute_process( |
12 | 7 | COMMAND /bin/sh ${CMAKE_CURRENT_SOURCE_DIR}/get-soversion.sh | 7 | COMMAND /bin/sh ${CMAKE_CURRENT_SOURCE_DIR}/get-soversion.sh |
13 | 8 | 8 | ||
14 | === modified file 'debian/changelog' | |||
15 | --- debian/changelog 2015-11-09 01:56:39 +0000 | |||
16 | +++ debian/changelog 2015-11-23 03:14:55 +0000 | |||
17 | @@ -1,3 +1,12 @@ | |||
18 | 1 | mediascanner2 (0.109-0ubuntu1) UNRELEASED; urgency=medium | ||
19 | 2 | |||
20 | 3 | * If a folder contains an image file named | ||
21 | 4 | {cover,album,albumart,.folder,folder}.{jpeg,jpg,png} use it as album | ||
22 | 5 | art for songs in preference to online art if the songs do not have | ||
23 | 6 | embedded art. (LP: #1372000) | ||
24 | 7 | |||
25 | 8 | -- James Henstridge <james.henstridge@canonical.com> Mon, 23 Nov 2015 11:12:59 +0800 | ||
26 | 9 | |||
27 | 1 | mediascanner2 (0.108+16.04.20151109-0ubuntu1) xenial; urgency=medium | 10 | mediascanner2 (0.108+16.04.20151109-0ubuntu1) xenial; urgency=medium |
28 | 2 | 11 | ||
29 | 3 | * Move the metadata extractor to a separate process to isolate bugs in | 12 | * Move the metadata extractor to a separate process to isolate bugs in |
30 | 4 | 13 | ||
31 | === modified file 'debian/libmediascanner-2.0-3.symbols' | |||
32 | --- debian/libmediascanner-2.0-3.symbols 2015-09-21 10:56:50 +0000 | |||
33 | +++ debian/libmediascanner-2.0-3.symbols 2015-11-23 03:14:55 +0000 | |||
34 | @@ -5,11 +5,13 @@ | |||
35 | 5 | (c++)"mediascanner::Album::Album(mediascanner::Album const&)@Base" 0.105+14.10.20140903 | 5 | (c++)"mediascanner::Album::Album(mediascanner::Album const&)@Base" 0.105+14.10.20140903 |
36 | 6 | (c++)"mediascanner::Album::Album(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.105+14.10.20140903 | 6 | (c++)"mediascanner::Album::Album(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.105+14.10.20140903 |
37 | 7 | (c++)"mediascanner::Album::Album(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.105+14.10.20140903 | 7 | (c++)"mediascanner::Album::Album(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.105+14.10.20140903 |
38 | 8 | (c++)"mediascanner::Album::Album(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)@Base" 0replaceme | ||
39 | 8 | (c++)"mediascanner::Album::getArtFile() const@Base" 0.105+14.10.20140903 | 9 | (c++)"mediascanner::Album::getArtFile() const@Base" 0.105+14.10.20140903 |
40 | 9 | (c++)"mediascanner::Album::getArtist() const@Base" 0.105+14.10.20140903 | 10 | (c++)"mediascanner::Album::getArtist() const@Base" 0.105+14.10.20140903 |
41 | 10 | (c++)"mediascanner::Album::getArtUri() const@Base" 0.105+14.10.20140903 | 11 | (c++)"mediascanner::Album::getArtUri() const@Base" 0.105+14.10.20140903 |
42 | 11 | (c++)"mediascanner::Album::getDate() const@Base" 0.105+14.10.20140903 | 12 | (c++)"mediascanner::Album::getDate() const@Base" 0.105+14.10.20140903 |
43 | 12 | (c++)"mediascanner::Album::getGenre() const@Base" 0.105+14.10.20140903 | 13 | (c++)"mediascanner::Album::getGenre() const@Base" 0.105+14.10.20140903 |
44 | 14 | (c++)"mediascanner::Album::getHasThumbnail() const@Base" 0replaceme | ||
45 | 13 | (c++)"mediascanner::Album::getTitle() const@Base" 0.101+14.10.20140613 | 15 | (c++)"mediascanner::Album::getTitle() const@Base" 0.101+14.10.20140613 |
46 | 14 | (c++)"mediascanner::Album::operator=(mediascanner::Album&&)@Base" 0.105+14.10.20140903 | 16 | (c++)"mediascanner::Album::operator=(mediascanner::Album&&)@Base" 0.105+14.10.20140903 |
47 | 15 | (c++)"mediascanner::Album::operator=(mediascanner::Album const&)@Base" 0.105+14.10.20140903 | 17 | (c++)"mediascanner::Album::operator=(mediascanner::Album const&)@Base" 0.105+14.10.20140903 |
48 | 16 | 18 | ||
49 | === modified file 'debian/libmediascanner-2.0-4.shlibs' | |||
50 | --- debian/libmediascanner-2.0-4.shlibs 2015-09-21 10:20:38 +0000 | |||
51 | +++ debian/libmediascanner-2.0-4.shlibs 2015-11-23 03:14:55 +0000 | |||
52 | @@ -1,1 +1,1 @@ | |||
54 | 1 | libmediascanner-2.0 4 libmediascanner-2.0-4 (>= 0.107) | 1 | libmediascanner-2.0 4 libmediascanner-2.0-4 (>= 0.109) |
55 | 2 | 2 | ||
56 | === modified file 'src/mediascanner/Album.cc' | |||
57 | --- src/mediascanner/Album.cc 2014-09-03 07:00:02 +0000 | |||
58 | +++ src/mediascanner/Album.cc 2015-11-23 03:14:55 +0000 | |||
59 | @@ -18,6 +18,7 @@ | |||
60 | 18 | */ | 18 | */ |
61 | 19 | 19 | ||
62 | 20 | #include "Album.hh" | 20 | #include "Album.hh" |
63 | 21 | #include "internal/FolderArtCache.hh" | ||
64 | 21 | #include "internal/utils.hh" | 22 | #include "internal/utils.hh" |
65 | 22 | 23 | ||
66 | 23 | using namespace std; | 24 | using namespace std; |
67 | @@ -30,13 +31,14 @@ | |||
68 | 30 | string date; | 31 | string date; |
69 | 31 | string genre; | 32 | string genre; |
70 | 32 | string filename; | 33 | string filename; |
71 | 34 | bool has_thumbnail; | ||
72 | 33 | 35 | ||
73 | 34 | Private() {} | 36 | Private() {} |
74 | 35 | Private(const string &title, const string &artist, | 37 | Private(const string &title, const string &artist, |
75 | 36 | const string &date, const string &genre, | 38 | const string &date, const string &genre, |
77 | 37 | const string &filename) | 39 | const string &filename, bool has_thumbnail) |
78 | 38 | : title(title), artist(artist), date(date), genre(genre), | 40 | : title(title), artist(artist), date(date), genre(genre), |
80 | 39 | filename(filename) {} | 41 | filename(filename), has_thumbnail(has_thumbnail) {} |
81 | 40 | Private(const Private &other) { | 42 | Private(const Private &other) { |
82 | 41 | *this = other; | 43 | *this = other; |
83 | 42 | } | 44 | } |
84 | @@ -46,13 +48,19 @@ | |||
85 | 46 | } | 48 | } |
86 | 47 | 49 | ||
87 | 48 | Album::Album(const std::string &title, const std::string &artist) | 50 | Album::Album(const std::string &title, const std::string &artist) |
89 | 49 | : Album(title, artist, "", "", "") { | 51 | : Album(title, artist, "", "", "", false) { |
90 | 50 | } | 52 | } |
91 | 51 | 53 | ||
92 | 52 | Album::Album(const std::string &title, const std::string &artist, | 54 | Album::Album(const std::string &title, const std::string &artist, |
93 | 53 | const std::string &date, const std::string &genre, | 55 | const std::string &date, const std::string &genre, |
94 | 54 | const std::string &filename) | 56 | const std::string &filename) |
96 | 55 | : p(new Private(title, artist, date, genre, filename)) { | 57 | : Album(title, artist, date, genre, filename, !filename.empty()) { |
97 | 58 | } | ||
98 | 59 | |||
99 | 60 | Album::Album(const std::string &title, const std::string &artist, | ||
100 | 61 | const std::string &date, const std::string &genre, | ||
101 | 62 | const std::string &filename, bool has_thumbnail) | ||
102 | 63 | : p(new Private(title, artist, date, genre, filename, has_thumbnail)) { | ||
103 | 56 | } | 64 | } |
104 | 57 | 65 | ||
105 | 58 | Album::Album(const Album &other) : p(new Private(*other.p)) { | 66 | Album::Album(const Album &other) : p(new Private(*other.p)) { |
106 | @@ -100,11 +108,19 @@ | |||
107 | 100 | return p->filename; | 108 | return p->filename; |
108 | 101 | } | 109 | } |
109 | 102 | 110 | ||
110 | 111 | bool Album::getHasThumbnail() const noexcept { | ||
111 | 112 | return p->has_thumbnail; | ||
112 | 113 | } | ||
113 | 114 | |||
114 | 103 | std::string Album::getArtUri() const { | 115 | std::string Album::getArtUri() const { |
116 | 104 | if (p->filename.empty()) { | 116 | if (p->has_thumbnail) { |
117 | 117 | return make_thumbnail_uri(getUri(p->filename)); | ||
118 | 118 | } else { | ||
119 | 119 | auto standalone = FolderArtCache::get().get_art_for_file(p->filename); | ||
120 | 120 | if (!standalone.empty()) { | ||
121 | 121 | return make_thumbnail_uri(getUri(standalone)); | ||
122 | 122 | } | ||
123 | 105 | return make_album_art_uri(p->artist, p->title); | 123 | return make_album_art_uri(p->artist, p->title); |
124 | 106 | } else { | ||
125 | 107 | return make_thumbnail_uri(getUri(p->filename)); | ||
126 | 108 | } | 124 | } |
127 | 109 | } | 125 | } |
128 | 110 | 126 | ||
129 | @@ -113,7 +129,8 @@ | |||
130 | 113 | p->artist == other.p->artist && | 129 | p->artist == other.p->artist && |
131 | 114 | p->date == other.p->date && | 130 | p->date == other.p->date && |
132 | 115 | p->genre == other.p->genre && | 131 | p->genre == other.p->genre && |
134 | 116 | p->filename == other.p->filename; | 132 | p->filename == other.p->filename && |
135 | 133 | p->has_thumbnail == other.p->has_thumbnail; | ||
136 | 117 | } | 134 | } |
137 | 118 | 135 | ||
138 | 119 | bool Album::operator!=(const Album &other) const { | 136 | bool Album::operator!=(const Album &other) const { |
139 | 120 | 137 | ||
140 | === modified file 'src/mediascanner/Album.hh' | |||
141 | --- src/mediascanner/Album.hh 2014-09-03 07:00:02 +0000 | |||
142 | +++ src/mediascanner/Album.hh 2015-11-23 03:14:55 +0000 | |||
143 | @@ -32,6 +32,9 @@ | |||
144 | 32 | Album(const std::string &title, const std::string &artist, | 32 | Album(const std::string &title, const std::string &artist, |
145 | 33 | const std::string &date, const std::string &genre, | 33 | const std::string &date, const std::string &genre, |
146 | 34 | const std::string &filename); | 34 | const std::string &filename); |
147 | 35 | Album(const std::string &title, const std::string &artist, | ||
148 | 36 | const std::string &date, const std::string &genre, | ||
149 | 37 | const std::string &filename, bool has_thumbnail); | ||
150 | 35 | Album(const Album &other); | 38 | Album(const Album &other); |
151 | 36 | Album(Album &&other); | 39 | Album(Album &&other); |
152 | 37 | ~Album(); | 40 | ~Album(); |
153 | @@ -44,6 +47,7 @@ | |||
154 | 44 | const std::string& getDate() const noexcept; | 47 | const std::string& getDate() const noexcept; |
155 | 45 | const std::string& getGenre() const noexcept; | 48 | const std::string& getGenre() const noexcept; |
156 | 46 | const std::string& getArtFile() const noexcept; | 49 | const std::string& getArtFile() const noexcept; |
157 | 50 | bool getHasThumbnail() const noexcept; | ||
158 | 47 | std::string getArtUri() const; | 51 | std::string getArtUri() const; |
159 | 48 | bool operator==(const Album &other) const; | 52 | bool operator==(const Album &other) const; |
160 | 49 | bool operator!=(const Album &other) const; | 53 | bool operator!=(const Album &other) const; |
161 | 50 | 54 | ||
162 | === modified file 'src/mediascanner/CMakeLists.txt' | |||
163 | --- src/mediascanner/CMakeLists.txt 2015-07-14 08:59:01 +0000 | |||
164 | +++ src/mediascanner/CMakeLists.txt 2015-11-23 03:14:55 +0000 | |||
165 | @@ -6,6 +6,7 @@ | |||
166 | 6 | Album.cc | 6 | Album.cc |
167 | 7 | MediaStore.cc | 7 | MediaStore.cc |
168 | 8 | MediaStoreBase.cc | 8 | MediaStoreBase.cc |
169 | 9 | FolderArtCache.cc | ||
170 | 9 | utils.cc | 10 | utils.cc |
171 | 10 | mozilla/fts3_porter.c | 11 | mozilla/fts3_porter.c |
172 | 11 | mozilla/Normalize.c | 12 | mozilla/Normalize.c |
173 | 12 | 13 | ||
174 | === added file 'src/mediascanner/FolderArtCache.cc' | |||
175 | --- src/mediascanner/FolderArtCache.cc 1970-01-01 00:00:00 +0000 | |||
176 | +++ src/mediascanner/FolderArtCache.cc 2015-11-23 03:14:55 +0000 | |||
177 | @@ -0,0 +1,169 @@ | |||
178 | 1 | /* | ||
179 | 2 | * Copyright (C) 2015 Canonical, Ltd. | ||
180 | 3 | * | ||
181 | 4 | * Authors: | ||
182 | 5 | * James Henstridge <james.henstridge@canonical.com> | ||
183 | 6 | * | ||
184 | 7 | * This program is free software: you can redistribute it and/or modify | ||
185 | 8 | * it under the terms of the GNU Lesser General Public License version 3 as | ||
186 | 9 | * published by the Free Software Foundation. | ||
187 | 10 | * | ||
188 | 11 | * This program is distributed in the hope that it will be useful, | ||
189 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
190 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
191 | 14 | * GNU Lesser General Public License for more details. | ||
192 | 15 | * | ||
193 | 16 | * You should have received a copy of the GNU Lesser General Public License | ||
194 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
195 | 18 | */ | ||
196 | 19 | |||
197 | 20 | #include "internal/FolderArtCache.hh" | ||
198 | 21 | |||
199 | 22 | #include <algorithm> | ||
200 | 23 | #include <array> | ||
201 | 24 | #include <cctype> | ||
202 | 25 | #include <cerrno> | ||
203 | 26 | #include <cstdlib> | ||
204 | 27 | #include <cstring> | ||
205 | 28 | #include <dirent.h> | ||
206 | 29 | #include <memory> | ||
207 | 30 | #include <stdexcept> | ||
208 | 31 | #include <sys/types.h> | ||
209 | 32 | #include <sys/stat.h> | ||
210 | 33 | #include <unistd.h> | ||
211 | 34 | |||
212 | 35 | using namespace std; | ||
213 | 36 | |||
214 | 37 | namespace { | ||
215 | 38 | |||
216 | 39 | const int CACHE_SIZE = 50; | ||
217 | 40 | |||
218 | 41 | string detect_albumart(string directory) { | ||
219 | 42 | static const array<const char*, 5> art_basenames = { | ||
220 | 43 | "cover", | ||
221 | 44 | "album", | ||
222 | 45 | "albumart", | ||
223 | 46 | ".folder", | ||
224 | 47 | "folder", | ||
225 | 48 | }; | ||
226 | 49 | static const array<const char*, 3> art_extensions = { | ||
227 | 50 | "jpeg", | ||
228 | 51 | "jpg", | ||
229 | 52 | "png", | ||
230 | 53 | }; | ||
231 | 54 | if (!directory.empty() && directory[directory.size()-1] != '/') { | ||
232 | 55 | directory += "/"; | ||
233 | 56 | } | ||
234 | 57 | unique_ptr<DIR, decltype(&closedir)> dir( | ||
235 | 58 | opendir(directory.c_str()), &closedir); | ||
236 | 59 | if (!dir) { | ||
237 | 60 | return ""; | ||
238 | 61 | } | ||
239 | 62 | |||
240 | 63 | const int dirent_size = sizeof(dirent) + fpathconf(dirfd(dir.get()), _PC_NAME_MAX) + 1; | ||
241 | 64 | unique_ptr<struct dirent, decltype(&free)> entry( | ||
242 | 65 | reinterpret_cast<struct dirent*>(malloc(dirent_size)), &free); | ||
243 | 66 | |||
244 | 67 | string detected; | ||
245 | 68 | int best_score = 0; | ||
246 | 69 | struct dirent *de = nullptr; | ||
247 | 70 | while (readdir_r(dir.get(), entry.get(), &de) == 0 && de) { | ||
248 | 71 | const string filename(de->d_name); | ||
249 | 72 | auto dot = filename.rfind('.'); | ||
250 | 73 | // Ignore files with no extension | ||
251 | 74 | if (dot == string::npos) { | ||
252 | 75 | continue; | ||
253 | 76 | } | ||
254 | 77 | auto basename = filename.substr(0, dot); | ||
255 | 78 | auto extension = filename.substr(dot+1); | ||
256 | 79 | |||
257 | 80 | // Does the file name match one of the required names when | ||
258 | 81 | // converted to lower case? | ||
259 | 82 | transform(basename.begin(), basename.end(), | ||
260 | 83 | basename.begin(), ::tolower); | ||
261 | 84 | transform(extension.begin(), extension.end(), | ||
262 | 85 | extension.begin(), ::tolower); | ||
263 | 86 | auto base_pos = find(art_basenames.begin(), art_basenames.end(), basename); | ||
264 | 87 | if (base_pos == art_basenames.end()) { | ||
265 | 88 | continue; | ||
266 | 89 | } | ||
267 | 90 | auto ext_pos = find(art_extensions.begin(), art_extensions.end(), extension); | ||
268 | 91 | if (ext_pos == art_extensions.end()) { | ||
269 | 92 | continue; | ||
270 | 93 | } | ||
271 | 94 | |||
272 | 95 | int score = (base_pos - art_basenames.begin()) * art_basenames.size() + | ||
273 | 96 | (ext_pos - art_extensions.begin()); | ||
274 | 97 | if (detected.empty() || score < best_score) { | ||
275 | 98 | detected = filename; | ||
276 | 99 | best_score = score; | ||
277 | 100 | } | ||
278 | 101 | } | ||
279 | 102 | if (detected.empty()) { | ||
280 | 103 | return detected; | ||
281 | 104 | } | ||
282 | 105 | return directory + detected; | ||
283 | 106 | } | ||
284 | 107 | |||
285 | 108 | } | ||
286 | 109 | |||
287 | 110 | namespace mediascanner { | ||
288 | 111 | |||
289 | 112 | FolderArtCache::FolderArtCache() = default; | ||
290 | 113 | FolderArtCache::~FolderArtCache() = default; | ||
291 | 114 | |||
292 | 115 | // Get a singleton instance of the cache | ||
293 | 116 | FolderArtCache& FolderArtCache::get() { | ||
294 | 117 | static FolderArtCache cache; | ||
295 | 118 | return cache; | ||
296 | 119 | } | ||
297 | 120 | |||
298 | 121 | string FolderArtCache::get_art_for_directory(const string &directory) { | ||
299 | 122 | struct stat s; | ||
300 | 123 | if (lstat(directory.c_str(), &s) < 0) { | ||
301 | 124 | return ""; | ||
302 | 125 | } | ||
303 | 126 | if (!S_ISDIR(s.st_mode)) { | ||
304 | 127 | return ""; | ||
305 | 128 | } | ||
306 | 129 | FolderArtInfo info; | ||
307 | 130 | bool update = false; | ||
308 | 131 | try { | ||
309 | 132 | info = cache_.at(directory); | ||
310 | 133 | } catch (const out_of_range &) { | ||
311 | 134 | // Fall back to checking the previous iteration of the cache | ||
312 | 135 | try { | ||
313 | 136 | info = old_cache_.at(directory); | ||
314 | 137 | update = true; | ||
315 | 138 | } catch (const out_of_range &) { | ||
316 | 139 | } | ||
317 | 140 | } | ||
318 | 141 | |||
319 | 142 | if (info.dir_mtime.tv_sec != s.st_mtim.tv_sec || | ||
320 | 143 | info.dir_mtime.tv_nsec != s.st_mtim.tv_nsec) { | ||
321 | 144 | info.art = detect_albumart(directory); | ||
322 | 145 | info.dir_mtime = s.st_mtim; | ||
323 | 146 | update = true; | ||
324 | 147 | } | ||
325 | 148 | |||
326 | 149 | if (update) { | ||
327 | 150 | cache_[directory] = info; | ||
328 | 151 | // Start new cache generation if we've exceeded the size. | ||
329 | 152 | if (cache_.size() > CACHE_SIZE) { | ||
330 | 153 | old_cache_ = move(cache_); | ||
331 | 154 | cache_.clear(); | ||
332 | 155 | } | ||
333 | 156 | } | ||
334 | 157 | return info.art; | ||
335 | 158 | } | ||
336 | 159 | |||
337 | 160 | string FolderArtCache::get_art_for_file(const string &filename) { | ||
338 | 161 | auto slash = filename.rfind('/'); | ||
339 | 162 | if (slash == string::npos) { | ||
340 | 163 | return ""; | ||
341 | 164 | } | ||
342 | 165 | auto directory = filename.substr(0, slash + 1); | ||
343 | 166 | return get_art_for_directory(directory); | ||
344 | 167 | } | ||
345 | 168 | |||
346 | 169 | } | ||
347 | 0 | 170 | ||
348 | === modified file 'src/mediascanner/MediaFile.cc' | |||
349 | --- src/mediascanner/MediaFile.cc 2015-07-07 04:36:02 +0000 | |||
350 | +++ src/mediascanner/MediaFile.cc 2015-11-23 03:14:55 +0000 | |||
351 | @@ -20,6 +20,7 @@ | |||
352 | 20 | #include "MediaFile.hh" | 20 | #include "MediaFile.hh" |
353 | 21 | #include "MediaFileBuilder.hh" | 21 | #include "MediaFileBuilder.hh" |
354 | 22 | #include "internal/MediaFilePrivate.hh" | 22 | #include "internal/MediaFilePrivate.hh" |
355 | 23 | #include "internal/FolderArtCache.hh" | ||
356 | 23 | #include "internal/utils.hh" | 24 | #include "internal/utils.hh" |
357 | 24 | #include <stdexcept> | 25 | #include <stdexcept> |
358 | 25 | 26 | ||
359 | @@ -155,12 +156,17 @@ | |||
360 | 155 | 156 | ||
361 | 156 | std::string MediaFile::getArtUri() const { | 157 | std::string MediaFile::getArtUri() const { |
362 | 157 | switch (p->type) { | 158 | switch (p->type) { |
364 | 158 | case AudioMedia: | 159 | case AudioMedia: { |
365 | 159 | if (p->has_thumbnail) { | 160 | if (p->has_thumbnail) { |
366 | 160 | return make_thumbnail_uri(getUri()); | 161 | return make_thumbnail_uri(getUri()); |
370 | 161 | } else { | 162 | } |
371 | 162 | return make_album_art_uri(getAuthor(), getAlbum()); | 163 | auto standalone = FolderArtCache::get().get_art_for_file(p->filename); |
372 | 163 | } | 164 | if(!standalone.empty()) { |
373 | 165 | return make_thumbnail_uri(mediascanner::getUri(standalone)); | ||
374 | 166 | } | ||
375 | 167 | return make_album_art_uri(getAuthor(), getAlbum()); | ||
376 | 168 | } | ||
377 | 169 | |||
378 | 164 | default: | 170 | default: |
379 | 165 | return make_thumbnail_uri(getUri()); | 171 | return make_thumbnail_uri(getUri()); |
380 | 166 | } | 172 | } |
381 | 167 | 173 | ||
382 | === modified file 'src/mediascanner/MediaStore.cc' | |||
383 | --- src/mediascanner/MediaStore.cc 2015-10-07 06:49:12 +0000 | |||
384 | +++ src/mediascanner/MediaStore.cc 2015-11-23 03:14:55 +0000 | |||
385 | @@ -604,7 +604,7 @@ | |||
386 | 604 | const string genre = query.getText(3); | 604 | const string genre = query.getText(3); |
387 | 605 | const string filename = query.getText(4); | 605 | const string filename = query.getText(4); |
388 | 606 | const bool has_thumbnail = query.getInt(5); | 606 | const bool has_thumbnail = query.getInt(5); |
390 | 607 | return Album(album, album_artist, date, genre, has_thumbnail ? filename : ""); | 607 | return Album(album, album_artist, date, genre, filename, has_thumbnail); |
391 | 608 | } | 608 | } |
392 | 609 | 609 | ||
393 | 610 | static vector<Album> collect_albums(Statement &query) { | 610 | static vector<Album> collect_albums(Statement &query) { |
394 | 611 | 611 | ||
395 | === added file 'src/mediascanner/internal/FolderArtCache.hh' | |||
396 | --- src/mediascanner/internal/FolderArtCache.hh 1970-01-01 00:00:00 +0000 | |||
397 | +++ src/mediascanner/internal/FolderArtCache.hh 2015-11-23 03:14:55 +0000 | |||
398 | @@ -0,0 +1,55 @@ | |||
399 | 1 | /* | ||
400 | 2 | * Copyright (C) 2015 Canonical, Ltd. | ||
401 | 3 | * | ||
402 | 4 | * Authors: | ||
403 | 5 | * James Henstridge <james.henstridge@canonical.com> | ||
404 | 6 | * | ||
405 | 7 | * This program is free software: you can redistribute it and/or modify | ||
406 | 8 | * it under the terms of the GNU Lesser General Public License version 3 as | ||
407 | 9 | * published by the Free Software Foundation. | ||
408 | 10 | * | ||
409 | 11 | * This program is distributed in the hope that it will be useful, | ||
410 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
411 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
412 | 14 | * GNU Lesser General Public License for more details. | ||
413 | 15 | * | ||
414 | 16 | * You should have received a copy of the GNU Lesser General Public License | ||
415 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
416 | 18 | */ | ||
417 | 19 | |||
418 | 20 | #ifndef FOLDERARTCACHE_HH | ||
419 | 21 | #define FOLDERARTCACHE_HH | ||
420 | 22 | |||
421 | 23 | #include <cstdint> | ||
422 | 24 | #include <ctime> | ||
423 | 25 | #include <map> | ||
424 | 26 | #include <string> | ||
425 | 27 | |||
426 | 28 | namespace mediascanner { | ||
427 | 29 | |||
428 | 30 | struct FolderArtInfo { | ||
429 | 31 | std::string art; | ||
430 | 32 | struct timespec dir_mtime {0, 0}; | ||
431 | 33 | }; | ||
432 | 34 | |||
433 | 35 | class FolderArtCache final { | ||
434 | 36 | public: | ||
435 | 37 | FolderArtCache(); | ||
436 | 38 | ~FolderArtCache(); | ||
437 | 39 | |||
438 | 40 | FolderArtCache(const FolderArtCache &other) = delete; | ||
439 | 41 | FolderArtCache& operator=(const FolderArtCache &other) = delete; | ||
440 | 42 | |||
441 | 43 | // Get a singleton instance of the cache | ||
442 | 44 | static FolderArtCache& get(); | ||
443 | 45 | |||
444 | 46 | std::string get_art_for_directory(const std::string &directory); | ||
445 | 47 | std::string get_art_for_file(const std::string &filename); | ||
446 | 48 | private: | ||
447 | 49 | std::map<std::string, FolderArtInfo> cache_; | ||
448 | 50 | std::map<std::string, FolderArtInfo> old_cache_; | ||
449 | 51 | }; | ||
450 | 52 | |||
451 | 53 | } | ||
452 | 54 | |||
453 | 55 | #endif | ||
454 | 0 | 56 | ||
455 | === modified file 'src/ms-dbus/dbus-codec.cc' | |||
456 | --- src/ms-dbus/dbus-codec.cc 2015-07-07 05:00:16 +0000 | |||
457 | +++ src/ms-dbus/dbus-codec.cc 2015-11-23 03:14:55 +0000 | |||
458 | @@ -104,14 +104,16 @@ | |||
459 | 104 | core::dbus::encode_argument(w, album.getDate()); | 104 | core::dbus::encode_argument(w, album.getDate()); |
460 | 105 | core::dbus::encode_argument(w, album.getGenre()); | 105 | core::dbus::encode_argument(w, album.getGenre()); |
461 | 106 | core::dbus::encode_argument(w, album.getArtFile()); | 106 | core::dbus::encode_argument(w, album.getArtFile()); |
462 | 107 | core::dbus::encode_argument(w, album.getHasThumbnail()); | ||
463 | 107 | out.close_structure(std::move(w)); | 108 | out.close_structure(std::move(w)); |
464 | 108 | } | 109 | } |
465 | 109 | 110 | ||
466 | 110 | void Codec<Album>::decode_argument(Message::Reader &in, Album &album) { | 111 | void Codec<Album>::decode_argument(Message::Reader &in, Album &album) { |
467 | 111 | auto r = in.pop_structure(); | 112 | auto r = in.pop_structure(); |
468 | 112 | string title, artist, date, genre, art_file; | 113 | string title, artist, date, genre, art_file; |
471 | 113 | r >> title >> artist >> date >> genre >> art_file; | 114 | bool has_thumbnail; |
472 | 114 | album = Album(title, artist, date, genre, art_file); | 115 | r >> title >> artist >> date >> genre >> art_file >> has_thumbnail; |
473 | 116 | album = Album(title, artist, date, genre, art_file, has_thumbnail); | ||
474 | 115 | } | 117 | } |
475 | 116 | 118 | ||
476 | 117 | void Codec<Filter>::encode_argument(Message::Writer &out, const Filter &filter) { | 119 | void Codec<Filter>::encode_argument(Message::Writer &out, const Filter &filter) { |
477 | 118 | 120 | ||
478 | === modified file 'src/ms-dbus/dbus-codec.hh' | |||
479 | --- src/ms-dbus/dbus-codec.hh 2015-07-07 05:00:16 +0000 | |||
480 | +++ src/ms-dbus/dbus-codec.hh 2015-11-23 03:14:55 +0000 | |||
481 | @@ -82,7 +82,7 @@ | |||
482 | 82 | return true; | 82 | return true; |
483 | 83 | } | 83 | } |
484 | 84 | static const std::string &signature() { | 84 | static const std::string &signature() { |
486 | 85 | static const std::string s = "(sssss)"; | 85 | static const std::string s = "(sssssb)"; |
487 | 86 | return s; | 86 | return s; |
488 | 87 | } | 87 | } |
489 | 88 | }; | 88 | }; |
490 | 89 | 89 | ||
491 | === modified file 'test/test_dbus.cc' | |||
492 | --- test/test_dbus.cc 2015-07-07 05:00:16 +0000 | |||
493 | +++ test/test_dbus.cc 2015-11-23 03:14:55 +0000 | |||
494 | @@ -53,10 +53,10 @@ | |||
495 | 53 | } | 53 | } |
496 | 54 | 54 | ||
497 | 55 | TEST_F(MediaStoreDBusTests, album_codec) { | 55 | TEST_F(MediaStoreDBusTests, album_codec) { |
499 | 56 | mediascanner::Album album("title", "artist", "date", "genre", "art_file"); | 56 | mediascanner::Album album("title", "artist", "date", "genre", "art_file", true); |
500 | 57 | message->writer() << album; | 57 | message->writer() << album; |
501 | 58 | 58 | ||
503 | 59 | EXPECT_EQ("(sssss)", message->signature()); | 59 | EXPECT_EQ("(sssssb)", message->signature()); |
504 | 60 | EXPECT_EQ(core::dbus::helper::TypeMapper<mediascanner::Album>::signature(), message->signature()); | 60 | EXPECT_EQ(core::dbus::helper::TypeMapper<mediascanner::Album>::signature(), message->signature()); |
505 | 61 | 61 | ||
506 | 62 | mediascanner::Album album2; | 62 | mediascanner::Album album2; |
507 | @@ -66,6 +66,7 @@ | |||
508 | 66 | EXPECT_EQ("date", album2.getDate()); | 66 | EXPECT_EQ("date", album2.getDate()); |
509 | 67 | EXPECT_EQ("genre", album2.getGenre()); | 67 | EXPECT_EQ("genre", album2.getGenre()); |
510 | 68 | EXPECT_EQ("art_file", album2.getArtFile()); | 68 | EXPECT_EQ("art_file", album2.getArtFile()); |
511 | 69 | EXPECT_EQ(true, album2.getHasThumbnail()); | ||
512 | 69 | EXPECT_EQ(album, album2); | 70 | EXPECT_EQ(album, album2); |
513 | 70 | } | 71 | } |
514 | 71 | 72 | ||
515 | 72 | 73 | ||
516 | === modified file 'test/test_mfbuilder.cc' | |||
517 | --- test/test_mfbuilder.cc 2015-07-07 08:21:29 +0000 | |||
518 | +++ test/test_mfbuilder.cc 2015-11-23 03:14:55 +0000 | |||
519 | @@ -17,26 +17,60 @@ | |||
520 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
521 | 18 | */ | 18 | */ |
522 | 19 | 19 | ||
527 | 20 | #include<gtest/gtest.h> | 20 | #include "test_config.h" |
528 | 21 | #include"mediascanner/MediaFile.hh" | 21 | #include "mediascanner/Album.hh" |
529 | 22 | #include"mediascanner/MediaFileBuilder.hh" | 22 | #include "mediascanner/MediaFile.hh" |
530 | 23 | #include<stdexcept> | 23 | #include "mediascanner/MediaFileBuilder.hh" |
531 | 24 | |||
532 | 25 | #include <gtest/gtest.h> | ||
533 | 26 | |||
534 | 27 | #include <chrono> | ||
535 | 28 | #include <cstdlib> | ||
536 | 29 | #include <fcntl.h> | ||
537 | 30 | #include <sys/stat.h> | ||
538 | 31 | #include <sys/types.h> | ||
539 | 32 | #include <stdexcept> | ||
540 | 33 | #include <thread> | ||
541 | 34 | #include <vector> | ||
542 | 24 | 35 | ||
543 | 25 | using namespace mediascanner; | 36 | using namespace mediascanner; |
544 | 26 | 37 | ||
545 | 27 | class MFBTest : public ::testing::Test { | 38 | class MFBTest : public ::testing::Test { |
558 | 28 | protected: | 39 | protected: |
559 | 29 | MFBTest() { | 40 | MFBTest() = default; |
560 | 30 | } | 41 | virtual ~MFBTest() = default; |
561 | 31 | 42 | ||
562 | 32 | virtual ~MFBTest() { | 43 | virtual void SetUp() override { |
563 | 33 | } | 44 | tmpdir = TEST_DIR "/mfbuilder-test.XXXXXX"; |
564 | 34 | 45 | ASSERT_NE(nullptr, mkdtemp(&tmpdir[0])); | |
565 | 35 | virtual void SetUp() { | 46 | } |
566 | 36 | } | 47 | |
567 | 37 | 48 | virtual void TearDown() override { | |
568 | 38 | virtual void TearDown() { | 49 | if (!tmpdir.empty()) { |
569 | 39 | } | 50 | std::string cmd = "rm -rf " + tmpdir; |
570 | 51 | ASSERT_EQ(0, system(cmd.c_str())); | ||
571 | 52 | } | ||
572 | 53 | } | ||
573 | 54 | |||
574 | 55 | void touch(const std::string &fname, bool sleep=false) { | ||
575 | 56 | if (sleep) { | ||
576 | 57 | // Ensure time stamps change | ||
577 | 58 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); | ||
578 | 59 | } | ||
579 | 60 | int fd = open(fname.c_str(), O_CREAT, 0600); | ||
580 | 61 | ASSERT_GT(fd, 0); | ||
581 | 62 | ASSERT_EQ(0, close(fd)); | ||
582 | 63 | } | ||
583 | 64 | |||
584 | 65 | void remove(const std::string &fname, bool sleep=false) { | ||
585 | 66 | if (sleep) { | ||
586 | 67 | // Ensure time stamps change | ||
587 | 68 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); | ||
588 | 69 | } | ||
589 | 70 | ASSERT_EQ(0, unlink(fname.c_str())); | ||
590 | 71 | } | ||
591 | 72 | |||
592 | 73 | std::string tmpdir; | ||
593 | 40 | }; | 74 | }; |
594 | 41 | 75 | ||
595 | 42 | TEST_F(MFBTest, basic) { | 76 | TEST_F(MFBTest, basic) { |
596 | @@ -209,6 +243,120 @@ | |||
597 | 209 | EXPECT_EQ("image://thumbnailer/file:///foo/bar/baz.mp4", mf.getArtUri()); | 243 | EXPECT_EQ("image://thumbnailer/file:///foo/bar/baz.mp4", mf.getArtUri()); |
598 | 210 | } | 244 | } |
599 | 211 | 245 | ||
600 | 246 | TEST_F(MFBTest, folder_art) { | ||
601 | 247 | std::string fname = tmpdir + "/dummy.mp3"; | ||
602 | 248 | MediaFile media = MediaFileBuilder(fname) | ||
603 | 249 | .setType(AudioMedia) | ||
604 | 250 | .setTitle("Title") | ||
605 | 251 | .setAuthor("Artist") | ||
606 | 252 | .setAlbum("Album"); | ||
607 | 253 | |||
608 | 254 | EXPECT_EQ("image://albumart/artist=Artist&album=Album", media.getArtUri()); | ||
609 | 255 | touch(tmpdir + "/folder.jpg", true); | ||
610 | 256 | EXPECT_NE(std::string::npos, media.getArtUri().find("/folder.jpg")) << media.getArtUri(); | ||
611 | 257 | remove(tmpdir + "/folder.jpg", true); | ||
612 | 258 | EXPECT_EQ("image://albumart/artist=Artist&album=Album", media.getArtUri()); | ||
613 | 259 | } | ||
614 | 260 | |||
615 | 261 | TEST_F(MFBTest, folder_art_case_insensitive) { | ||
616 | 262 | std::string fname = tmpdir + "/dummy.mp3"; | ||
617 | 263 | MediaFile media = MediaFileBuilder(fname) | ||
618 | 264 | .setType(AudioMedia) | ||
619 | 265 | .setTitle("Title") | ||
620 | 266 | .setAuthor("Artist") | ||
621 | 267 | .setAlbum("Album"); | ||
622 | 268 | |||
623 | 269 | touch(tmpdir + "/FOLDER.JPG"); | ||
624 | 270 | EXPECT_NE(std::string::npos, media.getArtUri().find("/FOLDER.JPG")) << media.getArtUri(); | ||
625 | 271 | } | ||
626 | 272 | |||
627 | 273 | TEST_F(MFBTest, folder_art_precedence) { | ||
628 | 274 | std::string fname = tmpdir + "/dummy.mp3"; | ||
629 | 275 | MediaFile media = MediaFileBuilder(fname) | ||
630 | 276 | .setType(AudioMedia) | ||
631 | 277 | .setTitle("Title") | ||
632 | 278 | .setAuthor("Artist") | ||
633 | 279 | .setAlbum("Album"); | ||
634 | 280 | |||
635 | 281 | touch(tmpdir + "/cover.jpg"); | ||
636 | 282 | touch(tmpdir + "/album.jpg"); | ||
637 | 283 | touch(tmpdir + "/albumart.jpg"); | ||
638 | 284 | touch(tmpdir + "/.folder.jpg"); | ||
639 | 285 | touch(tmpdir + "/folder.jpeg"); | ||
640 | 286 | touch(tmpdir + "/folder.jpg"); | ||
641 | 287 | touch(tmpdir + "/folder.png"); | ||
642 | 288 | |||
643 | 289 | EXPECT_NE(std::string::npos, media.getArtUri().find("/cover.jpg")) << media.getArtUri(); | ||
644 | 290 | remove(tmpdir + "/cover.jpg", true); | ||
645 | 291 | |||
646 | 292 | EXPECT_NE(std::string::npos, media.getArtUri().find("/album.jpg")) << media.getArtUri(); | ||
647 | 293 | remove(tmpdir + "/album.jpg", true); | ||
648 | 294 | |||
649 | 295 | EXPECT_NE(std::string::npos, media.getArtUri().find("/albumart.jpg")) << media.getArtUri(); | ||
650 | 296 | remove(tmpdir + "/albumart.jpg", true); | ||
651 | 297 | |||
652 | 298 | EXPECT_NE(std::string::npos, media.getArtUri().find("/.folder.jpg")) << media.getArtUri(); | ||
653 | 299 | remove(tmpdir + "/.folder.jpg", true); | ||
654 | 300 | |||
655 | 301 | EXPECT_NE(std::string::npos, media.getArtUri().find("/folder.jpeg")) << media.getArtUri(); | ||
656 | 302 | remove(tmpdir + "/folder.jpeg", true); | ||
657 | 303 | |||
658 | 304 | EXPECT_NE(std::string::npos, media.getArtUri().find("/folder.jpg")) << media.getArtUri(); | ||
659 | 305 | remove(tmpdir + "/folder.jpg", true); | ||
660 | 306 | |||
661 | 307 | EXPECT_NE(std::string::npos, media.getArtUri().find("/folder.png")) << media.getArtUri(); | ||
662 | 308 | } | ||
663 | 309 | |||
664 | 310 | TEST_F(MFBTest, folder_art_cache_coverage) { | ||
665 | 311 | std::vector<MediaFile> files; | ||
666 | 312 | for (int i = 0; i < 100; i++) { | ||
667 | 313 | std::string directory = tmpdir + "/" + std::to_string(i); | ||
668 | 314 | ASSERT_EQ(0, mkdir(directory.c_str(), 0700)); | ||
669 | 315 | touch(directory + "/folder.jpg"); | ||
670 | 316 | |||
671 | 317 | std::string fname = directory + "/dummy.mp3"; | ||
672 | 318 | files.emplace_back(MediaFileBuilder(fname) | ||
673 | 319 | .setType(AudioMedia) | ||
674 | 320 | .setTitle("Title") | ||
675 | 321 | .setAuthor("Artist") | ||
676 | 322 | .setAlbum("Album")); | ||
677 | 323 | } | ||
678 | 324 | |||
679 | 325 | // Check art for a number of files smaller than the cache size twice | ||
680 | 326 | for (int i = 0; i < 10; i++) { | ||
681 | 327 | const auto &media = files[i]; | ||
682 | 328 | EXPECT_NE(std::string::npos, media.getArtUri().find("/folder.jpg")) << media.getArtUri(); | ||
683 | 329 | } | ||
684 | 330 | for (int i = 0; i < 10; i++) { | ||
685 | 331 | const auto &media = files[i]; | ||
686 | 332 | EXPECT_NE(std::string::npos, media.getArtUri().find("/folder.jpg")) << media.getArtUri(); | ||
687 | 333 | } | ||
688 | 334 | |||
689 | 335 | // Now check a larger number of files twice | ||
690 | 336 | for (const auto &media : files) { | ||
691 | 337 | EXPECT_NE(std::string::npos, media.getArtUri().find("/folder.jpg")) << media.getArtUri(); | ||
692 | 338 | } | ||
693 | 339 | for (const auto &media : files) { | ||
694 | 340 | EXPECT_NE(std::string::npos, media.getArtUri().find("/folder.jpg")) << media.getArtUri(); | ||
695 | 341 | } | ||
696 | 342 | } | ||
697 | 343 | |||
698 | 344 | TEST_F(MFBTest, album_art) { | ||
699 | 345 | std::string fname = tmpdir + "/dummy.mp3"; | ||
700 | 346 | |||
701 | 347 | // File with embedded art | ||
702 | 348 | Album album("Album", "Artist", "2015-11-23", "Rock", fname, true); | ||
703 | 349 | EXPECT_NE(std::string::npos, album.getArtUri().find("/dummy.mp3")) << album.getArtUri(); | ||
704 | 350 | |||
705 | 351 | // No embedded art | ||
706 | 352 | album = Album("Album", "Artist", "2015-11-23", "Rock", fname, false); | ||
707 | 353 | EXPECT_EQ("image://albumart/artist=Artist&album=Album", album.getArtUri()); | ||
708 | 354 | |||
709 | 355 | // No embedded art, but folder art available | ||
710 | 356 | touch(tmpdir + "/folder.jpg", true); | ||
711 | 357 | EXPECT_NE(std::string::npos, album.getArtUri().find("/folder.jpg")) << album.getArtUri(); | ||
712 | 358 | } | ||
713 | 359 | |||
714 | 212 | int main(int argc, char **argv) { | 360 | int main(int argc, char **argv) { |
715 | 213 | ::testing::InitGoogleTest(&argc, argv); | 361 | ::testing::InitGoogleTest(&argc, argv); |
716 | 214 | return RUN_ALL_TESTS(); | 362 | return RUN_ALL_TESTS(); |
717 | 215 | 363 | ||
718 | === modified file 'test/test_util.cc' | |||
719 | --- test/test_util.cc 2014-05-09 14:04:48 +0000 | |||
720 | +++ test/test_util.cc 2015-11-23 03:14:55 +0000 | |||
721 | @@ -19,6 +19,9 @@ | |||
722 | 19 | 19 | ||
723 | 20 | #include <gtest/gtest.h> | 20 | #include <gtest/gtest.h> |
724 | 21 | #include"../src/mediascanner/internal/utils.hh" | 21 | #include"../src/mediascanner/internal/utils.hh" |
725 | 22 | #include"../src/mediascanner/MediaFile.hh" | ||
726 | 23 | #include"../src/mediascanner/MediaFileBuilder.hh" | ||
727 | 24 | |||
728 | 22 | #include "test_config.h" | 25 | #include "test_config.h" |
729 | 23 | 26 | ||
730 | 24 | using namespace mediascanner; | 27 | using namespace mediascanner; |
FAILED: Continuous integration, rev:320 /code.launchpad .net/~jamesh/ mediascanner2/ folder- coverart/ +merge/ 278099/ +edit-commit- message
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http:// jenkins. qa.ubuntu. com/job/ mediascanner2- ci/199/ jenkins. qa.ubuntu. com/job/ mediascanner2- vivid-amd64- ci/36 jenkins. qa.ubuntu. com/job/ mediascanner2- vivid-armhf- ci/36 jenkins. qa.ubuntu. com/job/ mediascanner2- vivid-armhf- ci/36/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mediascanner2- vivid-i386- ci/36 jenkins. qa.ubuntu. com/job/ mediascanner2- wily-amd64- ci/11 jenkins. qa.ubuntu. com/job/ mediascanner2- wily-armhf- ci/11 jenkins. qa.ubuntu. com/job/ mediascanner2- wily-armhf- ci/11/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mediascanner2- wily-i386- ci/11
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mediascanne r2-ci/199/ rebuild
http://