Merge lp:~jamesh/thumbnailer/dbus-service into lp:thumbnailer
- dbus-service
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Jussi Pakkanen |
Approved revision: | 107 |
Merged at revision: | 79 |
Proposed branch: | lp:~jamesh/thumbnailer/dbus-service |
Merge into: | lp:thumbnailer |
Prerequisite: | lp:~jpakkane/thumbnailer/lastfmtest |
Diff against target: |
992 lines (+772/-31) 22 files modified
CMakeLists.txt (+3/-1) debian/changelog (+6/-9) debian/control (+31/-4) debian/qtdeclarative5-ubuntu-thumbnailer0.1.install (+1/-0) debian/thumbnailer-service.install (+2/-0) plugins/Ubuntu/Thumbnailer/CMakeLists.txt (+22/-0) plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp (+90/-0) plugins/Ubuntu/Thumbnailer/albumartgenerator.h (+36/-0) plugins/Ubuntu/Thumbnailer/plugin.cpp (+47/-0) plugins/Ubuntu/Thumbnailer/plugin.h (+34/-0) plugins/Ubuntu/Thumbnailer/qmldir (+2/-0) plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp (+87/-0) plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h (+36/-0) src/CMakeLists.txt (+2/-0) src/service/CMakeLists.txt (+34/-0) src/service/com.canonical.Thumbnailer.service.in (+4/-0) src/service/dbus-interface.xml (+17/-0) src/service/dbusinterface.cpp (+168/-0) src/service/dbusinterface.h (+40/-0) src/service/main.cpp (+44/-0) src/thumbnailer.cpp (+4/-17) tests/qml/tst_image_provider.qml (+62/-0) |
To merge this branch: | bzr merge lp:~jamesh/thumbnailer/dbus-service |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jussi Pakkanen (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+212347@code.launchpad.net |
Commit message
Add a D-Bus service that uses libthumbnailer to download cover art and then provides that art to the client via a read only file descriptor. This allows confined applications to safely access a shared media art cache.
Description of the change
Add a D-Bus service that uses libthumbnailer to download cover art and then provides that art to the client via a read only file descriptor. This allows confined applications to safely access a shared media art cache.
I've put the service in its own binary package marked "Multi-Arch: foreign", since we only need one copy installed on multi-arch systems, and the D-Bus interface should be usable by all architectures on the system.
PS Jenkins bot (ps-jenkins) wrote : | # |
- 98. By James Henstridge
-
Fix up installation of service file.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:98
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Jussi Pakkanen (jpakkane) wrote : | # |
> catch (std::exception &e)
The recommended practice is to catch exceptions by const ref rather than plain ref.
> std::thread t(&getCoverArt,
This may throw, please wrap in try/catch.
> // This should be replaced with actual lookup code.
I think it has been. :)
> /**
> + * A class that sends a broadcast signal that the state of media
> + * files has changed.
> + */
This is still from InvalidationSender and thus not accurate.
Jussi Pakkanen (jpakkane) wrote : | # |
The code talks about album art but the method is called GetCoverArt. We should use one term consistently here, I vote for AlbumArt.
James Henstridge (jamesh) wrote : | # |
Good catch. It looks like I introduced that discrepancy when cleaning up the ubuntu-ui-toolkit branch (looking at the strings in the .so I was testing shows GetCoverArt). I've updated this branch in favour of GetAlbumArt, to match the C++ API name.
- 99. By James Henstridge
-
Update per Jussi's review comments.
James Henstridge (jamesh) wrote : | # |
I've done fresh builds of thumbnailer and ubuntu-ui-toolkit packages, and verified that they talk to each other correctly with these changes.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:99
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Jussi Pakkanen (jpakkane) wrote : | # |
Here's something that bothers me:
static void getAlbumArt(
unique_
This function takes a unique_gobj by value but unique_gobj does not have a copy constructor or operator=. Maybe it invokes the move constructor because it is called with a temporary object?
Anyhow, it works so if no-one can give a feasible case why this would break I'm fine with merging this.
James Henstridge (jamesh) wrote : | # |
The move constructor is the only way this could work, yes.
That said, there isn't much reason the type couldn't have a copy constructor: it's holding a reference counted object after all.
- 100. By James Henstridge
-
Copy over the libthumbnailer QML image providers over from
ubuntu-ui-toolkit. - 101. By James Henstridge
-
Add packaging for thumbnailer QML plugin.
- 102. By James Henstridge
-
Register a bogus type so the QML module can be imported.
James Henstridge (jamesh) wrote : | # |
MP updated with QML plugin code. Note that the bogus qmlRegisterType call is necessary for the plugin to be recognised: plugins that don't register any types are considered broken.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:102
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 103. By James Henstridge
-
Merge from trunk, fixing conflicts.
- 104. By James Henstridge
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:103
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:104
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Jussi Pakkanen (jpakkane) wrote : | # |
The main issue seems to be that the service is called thumbnailer-
That being said, here are a few minor things:
"__ThumbnailerI
#ifndef PLUGIN_H is a bit too generic and may clash, should be THUMBNAILERPLUGIN_H or somesuch.
- 105. By James Henstridge
-
Add a test for the image provider. Not currently hooked up as an
automated test, since it can't run headless.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:105
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 106. By James Henstridge
-
Add a note to the D-Bus interface definition file warning about security
considerations when adding new methods to the service.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:106
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 107. By James Henstridge
-
Other fixes from Jussi's review comments.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:107
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'CMakeLists.txt' | |||
2 | --- CMakeLists.txt 2014-03-28 10:11:10 +0000 | |||
3 | +++ CMakeLists.txt 2014-03-28 10:11:10 +0000 | |||
4 | @@ -29,9 +29,10 @@ | |||
5 | 29 | set(SHARE_PRIV_ABS ${CMAKE_INSTALL_PREFIX}/${SHARE_PRIV_DIR}) | 29 | set(SHARE_PRIV_ABS ${CMAKE_INSTALL_PREFIX}/${SHARE_PRIV_DIR}) |
6 | 30 | 30 | ||
7 | 31 | find_package(Threads REQUIRED) | 31 | find_package(Threads REQUIRED) |
8 | 32 | find_package(Qt5Core REQUIRED) | ||
9 | 32 | include(FindPkgConfig) | 33 | include(FindPkgConfig) |
10 | 33 | pkg_check_modules(GST_DEPS REQUIRED gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-pbutils-1.0 gstreamer-app-1.0) | 34 | pkg_check_modules(GST_DEPS REQUIRED gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-pbutils-1.0 gstreamer-app-1.0) |
12 | 34 | pkg_check_modules(GIO_DEPS REQUIRED gio-2.0) | 35 | pkg_check_modules(GIO_DEPS REQUIRED gio-2.0 gio-unix-2.0) |
13 | 35 | pkg_check_modules(IMG_DEPS REQUIRED gdk-pixbuf-2.0 libexif) | 36 | pkg_check_modules(IMG_DEPS REQUIRED gdk-pixbuf-2.0 libexif) |
14 | 36 | pkg_check_modules(SOUP_DEPS REQUIRED libsoup-2.4) | 37 | pkg_check_modules(SOUP_DEPS REQUIRED libsoup-2.4) |
15 | 37 | pkg_check_modules(XML_DEPS REQUIRED libxml-2.0) | 38 | pkg_check_modules(XML_DEPS REQUIRED libxml-2.0) |
16 | @@ -46,6 +47,7 @@ | |||
17 | 46 | 47 | ||
18 | 47 | enable_testing() | 48 | enable_testing() |
19 | 48 | add_subdirectory(src) | 49 | add_subdirectory(src) |
20 | 50 | add_subdirectory(plugins/Ubuntu/Thumbnailer) | ||
21 | 49 | add_subdirectory(tests) | 51 | add_subdirectory(tests) |
22 | 50 | add_subdirectory(tools) | 52 | add_subdirectory(tools) |
23 | 51 | add_subdirectory(include) | 53 | add_subdirectory(include) |
24 | 52 | 54 | ||
25 | === modified file 'debian/changelog' | |||
26 | --- debian/changelog 2014-03-28 10:11:10 +0000 | |||
27 | +++ debian/changelog 2014-03-28 10:11:10 +0000 | |||
28 | @@ -1,4 +1,9 @@ | |||
30 | 1 | <<<<<<< TREE | 1 | thumbnailer (1.1-0ubuntu1) UNRELEASED; urgency=medium |
31 | 2 | |||
32 | 3 | * New minor release. | ||
33 | 4 | |||
34 | 5 | -- Jussi Pakkanen <jussi.pakkanen@ubuntu.com> Mon, 10 Mar 2014 15:15:28 +0200 | ||
35 | 6 | |||
36 | 2 | thumbnailer (1.0+14.04.20140327-0ubuntu1) trusty; urgency=low | 7 | thumbnailer (1.0+14.04.20140327-0ubuntu1) trusty; urgency=low |
37 | 3 | 8 | ||
38 | 4 | [ Jussi Pakkanen ] | 9 | [ Jussi Pakkanen ] |
39 | @@ -13,14 +18,6 @@ | |||
40 | 13 | 18 | ||
41 | 14 | -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 19 Mar 2014 20:16:40 +0000 | 19 | -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 19 Mar 2014 20:16:40 +0000 |
42 | 15 | 20 | ||
43 | 16 | ======= | ||
44 | 17 | thumbnailer (1.1-0ubuntu1) UNRELEASED; urgency=medium | ||
45 | 18 | |||
46 | 19 | * New minor release. | ||
47 | 20 | |||
48 | 21 | -- Jussi Pakkanen <jussi.pakkanen@ubuntu.com> Mon, 10 Mar 2014 15:15:28 +0200 | ||
49 | 22 | |||
50 | 23 | >>>>>>> MERGE-SOURCE | ||
51 | 24 | thumbnailer (1.0+14.04.20140307-0ubuntu1) trusty; urgency=low | 21 | thumbnailer (1.0+14.04.20140307-0ubuntu1) trusty; urgency=low |
52 | 25 | 22 | ||
53 | 26 | [ Jussi Pakkanen ] | 23 | [ Jussi Pakkanen ] |
54 | 27 | 24 | ||
55 | === modified file 'debian/control' | |||
56 | --- debian/control 2014-03-28 10:11:10 +0000 | |||
57 | +++ debian/control 2014-03-28 10:11:10 +0000 | |||
58 | @@ -6,14 +6,18 @@ | |||
59 | 6 | Build-Depends: cmake, | 6 | Build-Depends: cmake, |
60 | 7 | debhelper (>= 9), | 7 | debhelper (>= 9), |
61 | 8 | gstreamer1.0-plugins-good, | 8 | gstreamer1.0-plugins-good, |
62 | 9 | libexif-dev, | ||
63 | 9 | libgdk-pixbuf2.0-dev, | 10 | libgdk-pixbuf2.0-dev, |
64 | 11 | libgstreamer1.0-dev, | ||
65 | 10 | libgstreamer-plugins-base1.0-dev, | 12 | libgstreamer-plugins-base1.0-dev, |
66 | 11 | libgstreamer1.0-dev, | ||
67 | 12 | shared-mime-info, | ||
68 | 13 | libgtest-dev, | 13 | libgtest-dev, |
69 | 14 | libsoup2.4-dev, | ||
70 | 14 | libxml2-dev, | 15 | libxml2-dev, |
73 | 15 | libsoup2.4-dev, | 16 | qt5-default, |
74 | 16 | libexif-dev, | 17 | qtbase5-dev, |
75 | 18 | qtbase5-dev-tools, | ||
76 | 19 | qtdeclarative5-dev, | ||
77 | 20 | shared-mime-info, | ||
78 | 17 | Homepage: https://launchpad.net/thumbnailer | 21 | Homepage: https://launchpad.net/thumbnailer |
79 | 18 | # if you don't have have commit access to this branch but would like to upload | 22 | # if you don't have have commit access to this branch but would like to upload |
80 | 19 | # directly to Ubuntu, don't worry: your changes will be merged back into the | 23 | # directly to Ubuntu, don't worry: your changes will be merged back into the |
81 | @@ -43,3 +47,26 @@ | |||
82 | 43 | Description: development files for thumbnailer | 47 | Description: development files for thumbnailer |
83 | 44 | This package contains development files | 48 | This package contains development files |
84 | 45 | for the thumbnailer package. | 49 | for the thumbnailer package. |
85 | 50 | |||
86 | 51 | Package: thumbnailer-service | ||
87 | 52 | Architecture: any | ||
88 | 53 | Multi-Arch: foreign | ||
89 | 54 | Pre-Depends: ${misc:Pre-Depends}, | ||
90 | 55 | Depends: ${misc:Depends}, | ||
91 | 56 | ${shlibs:Depends}, | ||
92 | 57 | libthumbnailer0 (= ${binary:Version}), | ||
93 | 58 | Description: D-Bus service for out of process thumbnailing | ||
94 | 59 | This package provides a D-Bus service that can provide thumbnails on | ||
95 | 60 | behalf of another process. | ||
96 | 61 | |||
97 | 62 | Package: qtdeclarative5-ubuntu-thumbnailer0.1 | ||
98 | 63 | Architecture: any | ||
99 | 64 | Multi-Arch: same | ||
100 | 65 | Pre-Depends: ${misc:Pre-Depends}, | ||
101 | 66 | Depends: ${misc:Depends}, | ||
102 | 67 | ${shlibs:Depends}, | ||
103 | 68 | libthumbnailer0 (= ${binary:Version}), | ||
104 | 69 | Recommends: thumbnailer-service (= ${binary:Version}), | ||
105 | 70 | Description: QML interface for the thumbnailer. | ||
106 | 71 | This package provides image providers that allow access to the | ||
107 | 72 | thumbnailer from Qt Quick 2 / QML applications. | ||
108 | 46 | 73 | ||
109 | === added file 'debian/qtdeclarative5-ubuntu-thumbnailer0.1.install' | |||
110 | --- debian/qtdeclarative5-ubuntu-thumbnailer0.1.install 1970-01-01 00:00:00 +0000 | |||
111 | +++ debian/qtdeclarative5-ubuntu-thumbnailer0.1.install 2014-03-28 10:11:10 +0000 | |||
112 | @@ -0,0 +1,1 @@ | |||
113 | 1 | usr/lib/*/qt5/qml/Ubuntu/Thumbnailer.0.1/* | ||
114 | 0 | 2 | ||
115 | === added file 'debian/thumbnailer-service.install' | |||
116 | --- debian/thumbnailer-service.install 1970-01-01 00:00:00 +0000 | |||
117 | +++ debian/thumbnailer-service.install 2014-03-28 10:11:10 +0000 | |||
118 | @@ -0,0 +1,2 @@ | |||
119 | 1 | usr/lib/*/thumbnailer/thumbnailer-service | ||
120 | 2 | usr/share/dbus-1/services/com.canonical.Thumbnailer.service | ||
121 | 0 | 3 | ||
122 | === added directory 'plugins' | |||
123 | === added directory 'plugins/Ubuntu' | |||
124 | === added directory 'plugins/Ubuntu/Thumbnailer' | |||
125 | === added file 'plugins/Ubuntu/Thumbnailer/CMakeLists.txt' | |||
126 | --- plugins/Ubuntu/Thumbnailer/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
127 | +++ plugins/Ubuntu/Thumbnailer/CMakeLists.txt 2014-03-28 10:11:10 +0000 | |||
128 | @@ -0,0 +1,22 @@ | |||
129 | 1 | |||
130 | 2 | set(QML_PLUGIN_DIR "${CMAKE_INSTALL_LIBDIR}/qt5/qml/Ubuntu/Thumbnailer.0.1") | ||
131 | 3 | |||
132 | 4 | add_library(thumbnailer-qml MODULE | ||
133 | 5 | plugin.cpp | ||
134 | 6 | albumartgenerator.cpp | ||
135 | 7 | thumbnailgenerator.cpp | ||
136 | 8 | ) | ||
137 | 9 | |||
138 | 10 | set_target_properties(thumbnailer-qml PROPERTIES AUTOMOC TRUE) | ||
139 | 11 | qt5_use_modules(thumbnailer-qml Qml Quick DBus) | ||
140 | 12 | target_link_libraries(thumbnailer-qml thumbnailer) | ||
141 | 13 | |||
142 | 14 | install( | ||
143 | 15 | TARGETS thumbnailer-qml | ||
144 | 16 | LIBRARY DESTINATION ${QML_PLUGIN_DIR} | ||
145 | 17 | ) | ||
146 | 18 | |||
147 | 19 | install( | ||
148 | 20 | FILES qmldir | ||
149 | 21 | DESTINATION ${QML_PLUGIN_DIR} | ||
150 | 22 | ) | ||
151 | 0 | 23 | ||
152 | === added file 'plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp' | |||
153 | --- plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp 1970-01-01 00:00:00 +0000 | |||
154 | +++ plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp 2014-03-28 10:11:10 +0000 | |||
155 | @@ -0,0 +1,90 @@ | |||
156 | 1 | /* | ||
157 | 2 | * Copyright 2014 Canonical Ltd. | ||
158 | 3 | * | ||
159 | 4 | * This program is free software; you can redistribute it and/or modify | ||
160 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
161 | 6 | * the Free Software Foundation; version 3. | ||
162 | 7 | * | ||
163 | 8 | * This program is distributed in the hope that it will be useful, | ||
164 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
165 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
166 | 11 | * GNU Lesser General Public License for more details. | ||
167 | 12 | * | ||
168 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
169 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
170 | 15 | * | ||
171 | 16 | * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com> | ||
172 | 17 | * James Henstridge <james.henstridge@canonical.com> | ||
173 | 18 | */ | ||
174 | 19 | |||
175 | 20 | #include "albumartgenerator.h" | ||
176 | 21 | #include <stdexcept> | ||
177 | 22 | #include <QDebug> | ||
178 | 23 | #include <QFile> | ||
179 | 24 | #include <QUrlQuery> | ||
180 | 25 | #include <QDBusUnixFileDescriptor> | ||
181 | 26 | #include <QDBusReply> | ||
182 | 27 | |||
183 | 28 | static const char DEFAULT_ALBUM_ART[] = "/usr/share/unity/icons/album_missing.png"; | ||
184 | 29 | |||
185 | 30 | static const char BUS_NAME[] = "com.canonical.Thumbnailer"; | ||
186 | 31 | static const char BUS_PATH[] = "/com/canonical/Thumbnailer"; | ||
187 | 32 | static const char THUMBNAILER_IFACE[] = "com.canonical.Thumbnailer"; | ||
188 | 33 | static const char GET_ALBUM_ART[] = "GetAlbumArt"; | ||
189 | 34 | |||
190 | 35 | AlbumArtGenerator::AlbumArtGenerator() | ||
191 | 36 | : QQuickImageProvider(QQuickImageProvider::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading), | ||
192 | 37 | iface(BUS_NAME, BUS_PATH, THUMBNAILER_IFACE) { | ||
193 | 38 | } | ||
194 | 39 | |||
195 | 40 | static QImage fallbackImage(QSize *realSize) { | ||
196 | 41 | QImage fallback; | ||
197 | 42 | fallback.load(DEFAULT_ALBUM_ART); | ||
198 | 43 | *realSize = fallback.size(); | ||
199 | 44 | return fallback; | ||
200 | 45 | } | ||
201 | 46 | |||
202 | 47 | QImage AlbumArtGenerator::requestImage(const QString &id, QSize *realSize, | ||
203 | 48 | const QSize &requestedSize) { | ||
204 | 49 | QUrlQuery query(id); | ||
205 | 50 | if (!query.hasQueryItem("artist") || !query.hasQueryItem("album")) { | ||
206 | 51 | qWarning() << "Invalid albumart uri:" << id; | ||
207 | 52 | return fallbackImage(realSize); | ||
208 | 53 | } | ||
209 | 54 | |||
210 | 55 | const QString artist = query.queryItemValue("artist", QUrl::FullyDecoded); | ||
211 | 56 | const QString album = query.queryItemValue("album", QUrl::FullyDecoded); | ||
212 | 57 | |||
213 | 58 | QString desiredSize = "original"; | ||
214 | 59 | int size = requestedSize.width() > requestedSize.height() ? requestedSize.width() : requestedSize.height(); | ||
215 | 60 | if (size < 128) { | ||
216 | 61 | desiredSize = "small"; | ||
217 | 62 | } else if (size < 256) { | ||
218 | 63 | desiredSize = "large"; | ||
219 | 64 | } else if (size < 512) { | ||
220 | 65 | desiredSize = "xlarge"; | ||
221 | 66 | } | ||
222 | 67 | |||
223 | 68 | // perform dbus call | ||
224 | 69 | QDBusReply<QDBusUnixFileDescriptor> reply = iface.call( | ||
225 | 70 | GET_ALBUM_ART, artist, album, desiredSize); | ||
226 | 71 | if (!reply.isValid()) { | ||
227 | 72 | qWarning() << "D-Bus error: " << reply.error().message(); | ||
228 | 73 | return fallbackImage(realSize); | ||
229 | 74 | } | ||
230 | 75 | |||
231 | 76 | try { | ||
232 | 77 | QFile file; | ||
233 | 78 | file.open(reply.value().fileDescriptor(), QIODevice::ReadOnly); | ||
234 | 79 | QImage image; | ||
235 | 80 | image.load(&file, NULL); | ||
236 | 81 | *realSize = image.size(); | ||
237 | 82 | return image; | ||
238 | 83 | } catch (const std::exception &e) { | ||
239 | 84 | qDebug() << "Album art loader failed: " << e.what(); | ||
240 | 85 | } catch (...) { | ||
241 | 86 | qDebug() << "Unknown error when generating image."; | ||
242 | 87 | } | ||
243 | 88 | |||
244 | 89 | return fallbackImage(realSize); | ||
245 | 90 | } | ||
246 | 0 | 91 | ||
247 | === added file 'plugins/Ubuntu/Thumbnailer/albumartgenerator.h' | |||
248 | --- plugins/Ubuntu/Thumbnailer/albumartgenerator.h 1970-01-01 00:00:00 +0000 | |||
249 | +++ plugins/Ubuntu/Thumbnailer/albumartgenerator.h 2014-03-28 10:11:10 +0000 | |||
250 | @@ -0,0 +1,36 @@ | |||
251 | 1 | /* | ||
252 | 2 | * Copyright 2014 Canonical Ltd. | ||
253 | 3 | * | ||
254 | 4 | * This program is free software; you can redistribute it and/or modify | ||
255 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
256 | 6 | * the Free Software Foundation; version 3. | ||
257 | 7 | * | ||
258 | 8 | * This program is distributed in the hope that it will be useful, | ||
259 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
260 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
261 | 11 | * GNU Lesser General Public License for more details. | ||
262 | 12 | * | ||
263 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
264 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
265 | 15 | * | ||
266 | 16 | * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com> | ||
267 | 17 | * James Henstridge <james.henstridge@canonical.com> | ||
268 | 18 | */ | ||
269 | 19 | |||
270 | 20 | #ifndef ALBUMART_GENERATOR_H | ||
271 | 21 | #define ALBUMART_GENERATOR_H | ||
272 | 22 | |||
273 | 23 | #include <QDBusInterface> | ||
274 | 24 | #include <QQuickImageProvider> | ||
275 | 25 | |||
276 | 26 | class AlbumArtGenerator: public QQuickImageProvider | ||
277 | 27 | { | ||
278 | 28 | private: | ||
279 | 29 | QDBusInterface iface; | ||
280 | 30 | |||
281 | 31 | public: | ||
282 | 32 | AlbumArtGenerator(); | ||
283 | 33 | QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize); | ||
284 | 34 | }; | ||
285 | 35 | |||
286 | 36 | #endif | ||
287 | 0 | 37 | ||
288 | === added file 'plugins/Ubuntu/Thumbnailer/plugin.cpp' | |||
289 | --- plugins/Ubuntu/Thumbnailer/plugin.cpp 1970-01-01 00:00:00 +0000 | |||
290 | +++ plugins/Ubuntu/Thumbnailer/plugin.cpp 2014-03-28 10:11:10 +0000 | |||
291 | @@ -0,0 +1,47 @@ | |||
292 | 1 | /* | ||
293 | 2 | * Copyright 2014 Canonical Ltd. | ||
294 | 3 | * | ||
295 | 4 | * This program is free software; you can redistribute it and/or modify | ||
296 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
297 | 6 | * the Free Software Foundation; version 3. | ||
298 | 7 | * | ||
299 | 8 | * This program is distributed in the hope that it will be useful, | ||
300 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
301 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
302 | 11 | * GNU Lesser General Public License for more details. | ||
303 | 12 | * | ||
304 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
305 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
306 | 15 | * | ||
307 | 16 | * Authors: James Henstridge <james.henstridge@canonical.com> | ||
308 | 17 | */ | ||
309 | 18 | |||
310 | 19 | #include "plugin.h" | ||
311 | 20 | #include "albumartgenerator.h" | ||
312 | 21 | #include "thumbnailgenerator.h" | ||
313 | 22 | |||
314 | 23 | void ThumbnailerPlugin::registerTypes(const char *uri) { | ||
315 | 24 | qmlRegisterTypeNotAvailable( | ||
316 | 25 | uri, 0, 1, "__ThumbnailerIgnoreMe", | ||
317 | 26 | "Ignore this: QML plugins must contain at least one type"); | ||
318 | 27 | } | ||
319 | 28 | |||
320 | 29 | void ThumbnailerPlugin::initializeEngine(QQmlEngine *engine, const char *uri) { | ||
321 | 30 | QQmlExtensionPlugin::initializeEngine(engine, uri); | ||
322 | 31 | |||
323 | 32 | try { | ||
324 | 33 | engine->addImageProvider("albumart", new AlbumArtGenerator()); | ||
325 | 34 | } catch (const std::exception &e) { | ||
326 | 35 | qWarning() << "Failed to register albumart image provider:" << e.what(); | ||
327 | 36 | } catch (...) { | ||
328 | 37 | qWarning() << "Failed to register albumart image provider."; | ||
329 | 38 | } | ||
330 | 39 | |||
331 | 40 | try { | ||
332 | 41 | engine->addImageProvider("thumbnailer", new ThumbnailGenerator()); | ||
333 | 42 | } catch (const std::exception &e) { | ||
334 | 43 | qWarning() << "Failed to register thumbnailer image provider:" << e.what(); | ||
335 | 44 | } catch (...) { | ||
336 | 45 | qWarning() << "Failed to register thumbnailer image provider."; | ||
337 | 46 | } | ||
338 | 47 | } | ||
339 | 0 | 48 | ||
340 | === added file 'plugins/Ubuntu/Thumbnailer/plugin.h' | |||
341 | --- plugins/Ubuntu/Thumbnailer/plugin.h 1970-01-01 00:00:00 +0000 | |||
342 | +++ plugins/Ubuntu/Thumbnailer/plugin.h 2014-03-28 10:11:10 +0000 | |||
343 | @@ -0,0 +1,34 @@ | |||
344 | 1 | /* | ||
345 | 2 | * Copyright 2014 Canonical Ltd. | ||
346 | 3 | * | ||
347 | 4 | * This program is free software; you can redistribute it and/or modify | ||
348 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
349 | 6 | * the Free Software Foundation; version 3. | ||
350 | 7 | * | ||
351 | 8 | * This program is distributed in the hope that it will be useful, | ||
352 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
353 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
354 | 11 | * GNU Lesser General Public License for more details. | ||
355 | 12 | * | ||
356 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
357 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
358 | 15 | * | ||
359 | 16 | * Authors: James Henstridge <james.henstridge@canonical.com> | ||
360 | 17 | */ | ||
361 | 18 | |||
362 | 19 | #ifndef THUMBNAILER_PLUGIN_H | ||
363 | 20 | #define THUMBNAILER_PLUGIN_H | ||
364 | 21 | |||
365 | 22 | #include <QtQml> | ||
366 | 23 | |||
367 | 24 | class ThumbnailerPlugin : public QQmlExtensionPlugin | ||
368 | 25 | { | ||
369 | 26 | Q_OBJECT | ||
370 | 27 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") | ||
371 | 28 | |||
372 | 29 | public: | ||
373 | 30 | virtual void registerTypes(const char *uri) override; | ||
374 | 31 | virtual void initializeEngine(QQmlEngine *engine, const char *uri) override; | ||
375 | 32 | }; | ||
376 | 33 | |||
377 | 34 | #endif | ||
378 | 0 | 35 | ||
379 | === added file 'plugins/Ubuntu/Thumbnailer/qmldir' | |||
380 | --- plugins/Ubuntu/Thumbnailer/qmldir 1970-01-01 00:00:00 +0000 | |||
381 | +++ plugins/Ubuntu/Thumbnailer/qmldir 2014-03-28 10:11:10 +0000 | |||
382 | @@ -0,0 +1,2 @@ | |||
383 | 1 | module Ubuntu.Thumbnailer | ||
384 | 2 | plugin thumbnailer-qml | ||
385 | 0 | 3 | ||
386 | === added file 'plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp' | |||
387 | --- plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp 1970-01-01 00:00:00 +0000 | |||
388 | +++ plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp 2014-03-28 10:11:10 +0000 | |||
389 | @@ -0,0 +1,87 @@ | |||
390 | 1 | /* | ||
391 | 2 | * Copyright 2013 Canonical Ltd. | ||
392 | 3 | * | ||
393 | 4 | * This program is free software; you can redistribute it and/or modify | ||
394 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
395 | 6 | * the Free Software Foundation; version 3. | ||
396 | 7 | * | ||
397 | 8 | * This program is distributed in the hope that it will be useful, | ||
398 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
399 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
400 | 11 | * GNU Lesser General Public License for more details. | ||
401 | 12 | * | ||
402 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
403 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
404 | 15 | * | ||
405 | 16 | * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com> | ||
406 | 17 | */ | ||
407 | 18 | |||
408 | 19 | #include "thumbnailgenerator.h" | ||
409 | 20 | #include <stdexcept> | ||
410 | 21 | #include <QDebug> | ||
411 | 22 | #include <QMimeDatabase> | ||
412 | 23 | #include <QUrl> | ||
413 | 24 | |||
414 | 25 | static const char *DEFAULT_VIDEO_ART = "/usr/share/unity/icons/video_missing.png"; | ||
415 | 26 | static const char *DEFAULT_ALBUM_ART = "/usr/share/unity/icons/album_missing.png"; | ||
416 | 27 | |||
417 | 28 | ThumbnailGenerator::ThumbnailGenerator() : QQuickImageProvider(QQuickImageProvider::Image, | ||
418 | 29 | QQmlImageProviderBase::ForceAsynchronousImageLoading) { | ||
419 | 30 | |||
420 | 31 | } | ||
421 | 32 | |||
422 | 33 | QImage ThumbnailGenerator::requestImage(const QString &id, QSize *realSize, | ||
423 | 34 | const QSize &requestedSize) { | ||
424 | 35 | /* Allow appending a query string (e.g. ?something=timestamp) | ||
425 | 36 | * to the id and then ignore it. | ||
426 | 37 | * This is workaround to force reloading a thumbnail when it has | ||
427 | 38 | * the same file name on disk but we know the content has changed. | ||
428 | 39 | * It is necessary because in such a situation the QML image cache | ||
429 | 40 | * will kick in and this ImageProvider will never get called. | ||
430 | 41 | * The only "solution" is setting Image.cache = false, but in some | ||
431 | 42 | * cases we don't want to do that for performance reasons, so this | ||
432 | 43 | * is the only way around the issue for now. */ | ||
433 | 44 | std::string src_path(QUrl(id).path().toUtf8().data()); | ||
434 | 45 | std::string tgt_path; | ||
435 | 46 | try { | ||
436 | 47 | ThumbnailSize desiredSize; | ||
437 | 48 | const int xlarge_cutoff = 512; | ||
438 | 49 | const int large_cutoff = 256; | ||
439 | 50 | const int small_cutoff = 128; | ||
440 | 51 | if(requestedSize.width() > xlarge_cutoff || requestedSize.height() > xlarge_cutoff) { | ||
441 | 52 | desiredSize = TN_SIZE_ORIGINAL; | ||
442 | 53 | } if(requestedSize.width() > large_cutoff || requestedSize.height() > large_cutoff) { | ||
443 | 54 | desiredSize = TN_SIZE_XLARGE; | ||
444 | 55 | } else if(requestedSize.width() > small_cutoff || requestedSize.height() > small_cutoff) { | ||
445 | 56 | desiredSize = TN_SIZE_LARGE; | ||
446 | 57 | } else { | ||
447 | 58 | desiredSize = TN_SIZE_SMALL; | ||
448 | 59 | } | ||
449 | 60 | tgt_path = tn.get_thumbnail(src_path, desiredSize); | ||
450 | 61 | if(!tgt_path.empty()) { | ||
451 | 62 | QString tgt(tgt_path.c_str()); | ||
452 | 63 | QImage image; | ||
453 | 64 | image.load(tgt); | ||
454 | 65 | *realSize = image.size(); | ||
455 | 66 | return image; | ||
456 | 67 | } | ||
457 | 68 | } catch(std::runtime_error &e) { | ||
458 | 69 | qDebug() << "Thumbnail generator failed: " << e.what(); | ||
459 | 70 | } | ||
460 | 71 | return getFallbackImage(id, realSize, requestedSize); | ||
461 | 72 | } | ||
462 | 73 | |||
463 | 74 | QImage ThumbnailGenerator::getFallbackImage(const QString &id, QSize *size, | ||
464 | 75 | const QSize &requestedSize) { | ||
465 | 76 | Q_UNUSED(requestedSize); | ||
466 | 77 | QMimeDatabase db; | ||
467 | 78 | QMimeType mime = db.mimeTypeForFile(id); | ||
468 | 79 | QImage result; | ||
469 | 80 | if(mime.name().contains("audio")) { | ||
470 | 81 | result.load(DEFAULT_ALBUM_ART); | ||
471 | 82 | } else if(mime.name().contains("video")) { | ||
472 | 83 | result.load(DEFAULT_VIDEO_ART); | ||
473 | 84 | } | ||
474 | 85 | *size = result.size(); | ||
475 | 86 | return result; | ||
476 | 87 | } | ||
477 | 0 | 88 | ||
478 | === added file 'plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h' | |||
479 | --- plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h 1970-01-01 00:00:00 +0000 | |||
480 | +++ plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h 2014-03-28 10:11:10 +0000 | |||
481 | @@ -0,0 +1,36 @@ | |||
482 | 1 | /* | ||
483 | 2 | * Copyright 2013 Canonical Ltd. | ||
484 | 3 | * | ||
485 | 4 | * This program is free software; you can redistribute it and/or modify | ||
486 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
487 | 6 | * the Free Software Foundation; version 3. | ||
488 | 7 | * | ||
489 | 8 | * This program is distributed in the hope that it will be useful, | ||
490 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
491 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
492 | 11 | * GNU Lesser General Public License for more details. | ||
493 | 12 | * | ||
494 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
495 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
496 | 15 | * | ||
497 | 16 | * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com> | ||
498 | 17 | */ | ||
499 | 18 | |||
500 | 19 | #ifndef THUMBNAIL_GENERATOR_H | ||
501 | 20 | #define THUMBNAIL_GENERATOR_H | ||
502 | 21 | |||
503 | 22 | #include <QQuickImageProvider> | ||
504 | 23 | #include <thumbnailer.h> | ||
505 | 24 | |||
506 | 25 | class ThumbnailGenerator: public QQuickImageProvider | ||
507 | 26 | { | ||
508 | 27 | private: | ||
509 | 28 | Thumbnailer tn; | ||
510 | 29 | |||
511 | 30 | public: | ||
512 | 31 | ThumbnailGenerator(); | ||
513 | 32 | QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize); | ||
514 | 33 | QImage getFallbackImage(const QString &id, QSize *size, const QSize &requestedSize); | ||
515 | 34 | }; | ||
516 | 35 | |||
517 | 36 | #endif | ||
518 | 0 | 37 | ||
519 | === modified file 'src/CMakeLists.txt' | |||
520 | --- src/CMakeLists.txt 2014-03-28 10:11:10 +0000 | |||
521 | +++ src/CMakeLists.txt 2014-03-28 10:11:10 +0000 | |||
522 | @@ -37,3 +37,5 @@ | |||
523 | 37 | RUNTIME DESTINATION ${SHARE_PRIV_DIR} | 37 | RUNTIME DESTINATION ${SHARE_PRIV_DIR} |
524 | 38 | LIBRARY DESTINATION ${SHARE_PRIV_DIR} | 38 | LIBRARY DESTINATION ${SHARE_PRIV_DIR} |
525 | 39 | ) | 39 | ) |
526 | 40 | |||
527 | 41 | add_subdirectory(service) | ||
528 | 40 | 42 | ||
529 | === added directory 'src/service' | |||
530 | === added file 'src/service/CMakeLists.txt' | |||
531 | --- src/service/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
532 | +++ src/service/CMakeLists.txt 2014-03-28 10:11:10 +0000 | |||
533 | @@ -0,0 +1,34 @@ | |||
534 | 1 | add_definitions(${THUMBNAILER_CFLAGS}) | ||
535 | 2 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) | ||
536 | 3 | |||
537 | 4 | add_executable(thumbnailer-service | ||
538 | 5 | main.cpp | ||
539 | 6 | dbusinterface.cpp | ||
540 | 7 | dbus-generated.c | ||
541 | 8 | ) | ||
542 | 9 | |||
543 | 10 | target_link_libraries(thumbnailer-service thumbnailer) | ||
544 | 11 | |||
545 | 12 | install( | ||
546 | 13 | TARGETS thumbnailer-service | ||
547 | 14 | RUNTIME DESTINATION ${SHARE_PRIV_DIR} | ||
548 | 15 | ) | ||
549 | 16 | |||
550 | 17 | find_program(gdbus_codegen gdbus-codegen) | ||
551 | 18 | if(NOT gdbus_codegen) | ||
552 | 19 | msg(FATAL_ERROR "Could not locate gdbus-codegen") | ||
553 | 20 | endif() | ||
554 | 21 | |||
555 | 22 | add_custom_command( | ||
556 | 23 | OUTPUT dbus-generated.c dbus-generated.h | ||
557 | 24 | COMMAND ${gdbus_codegen} --interface-prefix=com.canonical. --generate-c-code dbus-generated --c-namespace TN ${CMAKE_CURRENT_SOURCE_DIR}/dbus-interface.xml | ||
558 | 25 | MAIN_DEPENDENCY dbus-interface.xml | ||
559 | 26 | ) | ||
560 | 27 | |||
561 | 28 | # Install the service file. | ||
562 | 29 | configure_file(com.canonical.Thumbnailer.service.in com.canonical.Thumbnailer.service) | ||
563 | 30 | |||
564 | 31 | install( | ||
565 | 32 | FILES ${CMAKE_CURRENT_BINARY_DIR}/com.canonical.Thumbnailer.service | ||
566 | 33 | DESTINATION ${CMAKE_INSTALL_DATADIR}/dbus-1/services | ||
567 | 34 | ) | ||
568 | 0 | 35 | ||
569 | === added file 'src/service/com.canonical.Thumbnailer.service.in' | |||
570 | --- src/service/com.canonical.Thumbnailer.service.in 1970-01-01 00:00:00 +0000 | |||
571 | +++ src/service/com.canonical.Thumbnailer.service.in 2014-03-28 10:11:10 +0000 | |||
572 | @@ -0,0 +1,4 @@ | |||
573 | 1 | [D-BUS Service] | ||
574 | 2 | Name=com.canonical.Thumbnailer | ||
575 | 3 | Exec=@SHARE_PRIV_ABS@/thumbnailer-service | ||
576 | 4 | |||
577 | 0 | 5 | ||
578 | === added file 'src/service/dbus-interface.xml' | |||
579 | --- src/service/dbus-interface.xml 1970-01-01 00:00:00 +0000 | |||
580 | +++ src/service/dbus-interface.xml 2014-03-28 10:11:10 +0000 | |||
581 | @@ -0,0 +1,17 @@ | |||
582 | 1 | <node> | ||
583 | 2 | <interface name="com.canonical.Thumbnailer"> | ||
584 | 3 | <method name="GetAlbumArt"> | ||
585 | 4 | <arg direction="in" type="s" name="artist" /> | ||
586 | 5 | <arg direction="in" type="s" name="album" /> | ||
587 | 6 | <!-- possible values are "small", "large", "xlarge" and "original" --> | ||
588 | 7 | <arg direction="in" type="s" name="desiredSize" /> | ||
589 | 8 | <arg direction="out" type="h" name="fd" /> | ||
590 | 9 | <annotation name="org.gtk.GDBus.C.UnixFD" value="true" /> | ||
591 | 10 | </method> | ||
592 | 11 | |||
593 | 12 | <!-- Note: if adding additional thumbnailing methods that take a | ||
594 | 13 | file name as input, ensure that the calling process has | ||
595 | 14 | permission to read said file. Otherwise we will leak | ||
596 | 15 | information to confined applications. --> | ||
597 | 16 | </interface> | ||
598 | 17 | </node> | ||
599 | 0 | 18 | ||
600 | === added file 'src/service/dbusinterface.cpp' | |||
601 | --- src/service/dbusinterface.cpp 1970-01-01 00:00:00 +0000 | |||
602 | +++ src/service/dbusinterface.cpp 2014-03-28 10:11:10 +0000 | |||
603 | @@ -0,0 +1,168 @@ | |||
604 | 1 | /* | ||
605 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
606 | 3 | * | ||
607 | 4 | * Authors: | ||
608 | 5 | * James Henstridge <james.henstridge@canonical.com> | ||
609 | 6 | * | ||
610 | 7 | * This library is free software; you can redistribute it and/or modify it under | ||
611 | 8 | * the terms of version 3 of the GNU General Public License as published | ||
612 | 9 | * by the Free Software Foundation. | ||
613 | 10 | * | ||
614 | 11 | * This library is distributed in the hope that it will be useful, but WITHOUT | ||
615 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
616 | 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
617 | 14 | * details. | ||
618 | 15 | * | ||
619 | 16 | * You should have received a copy of the GNU General Public License | ||
620 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
621 | 18 | */ | ||
622 | 19 | |||
623 | 20 | #include "dbusinterface.h" | ||
624 | 21 | |||
625 | 22 | #include <cstdio> | ||
626 | 23 | #include <cstring> | ||
627 | 24 | #include <memory> | ||
628 | 25 | #include <stdexcept> | ||
629 | 26 | #include <string> | ||
630 | 27 | #include <thread> | ||
631 | 28 | #include <fcntl.h> | ||
632 | 29 | #include <unistd.h> | ||
633 | 30 | |||
634 | 31 | #include <glib.h> | ||
635 | 32 | #include <glib-object.h> | ||
636 | 33 | #include <gio/gio.h> | ||
637 | 34 | #include <gio/gunixfdlist.h> | ||
638 | 35 | #include <thumbnailer.h> | ||
639 | 36 | |||
640 | 37 | #include <internal/gobj_memory.h> | ||
641 | 38 | #include "dbus-generated.h" | ||
642 | 39 | |||
643 | 40 | using namespace std; | ||
644 | 41 | |||
645 | 42 | static const char BUS_NAME[] = "com.canonical.MediaScanner2"; | ||
646 | 43 | static const char ART_ERROR[] = "com.canonical.MediaScanner2.Error.Failed"; | ||
647 | 44 | |||
648 | 45 | static const char MISSING_ALBUM_ART[] = "/usr/share/unity/icons/album_missing.png"; | ||
649 | 46 | |||
650 | 47 | struct DBusInterfacePrivate { | ||
651 | 48 | const std::string bus_path; | ||
652 | 49 | unique_gobj<GDBusConnection> bus; | ||
653 | 50 | unique_gobj<TNThumbnailer> iface; | ||
654 | 51 | unsigned int handler_id; | ||
655 | 52 | std::shared_ptr<Thumbnailer> thumbnailer; | ||
656 | 53 | |||
657 | 54 | DBusInterfacePrivate(GDBusConnection *g_bus, const std::string& bus_path) | ||
658 | 55 | : bus_path(bus_path), | ||
659 | 56 | bus(static_cast<GDBusConnection*>(g_object_ref(g_bus))), | ||
660 | 57 | iface(tn_thumbnailer_skeleton_new()), | ||
661 | 58 | handler_id(0), | ||
662 | 59 | thumbnailer(std::make_shared<Thumbnailer>()) { | ||
663 | 60 | handler_id = g_signal_connect( | ||
664 | 61 | iface.get(), "handle-get-album-art", | ||
665 | 62 | G_CALLBACK(&DBusInterfacePrivate::handleGetAlbumArt), this); | ||
666 | 63 | |||
667 | 64 | GError *error = nullptr; | ||
668 | 65 | if (!g_dbus_interface_skeleton_export( | ||
669 | 66 | G_DBUS_INTERFACE_SKELETON(iface.get()), bus.get(), | ||
670 | 67 | bus_path.c_str(), &error)) { | ||
671 | 68 | string errortxt(error->message); | ||
672 | 69 | g_error_free(error); | ||
673 | 70 | |||
674 | 71 | string msg = "Failed to export interface: "; | ||
675 | 72 | msg += errortxt; | ||
676 | 73 | throw runtime_error(msg); | ||
677 | 74 | } | ||
678 | 75 | } | ||
679 | 76 | |||
680 | 77 | ~DBusInterfacePrivate() { | ||
681 | 78 | g_dbus_interface_skeleton_unexport( | ||
682 | 79 | G_DBUS_INTERFACE_SKELETON(iface.get())); | ||
683 | 80 | g_signal_handler_disconnect(iface.get(), handler_id); | ||
684 | 81 | } | ||
685 | 82 | |||
686 | 83 | static gboolean handleGetAlbumArt(TNThumbnailer *iface, GDBusMethodInvocation *invocation, GUnixFDList *, const char *artist, const char *album, const char *size, void *user_data) { | ||
687 | 84 | auto p = static_cast<DBusInterfacePrivate*>(user_data); | ||
688 | 85 | fprintf(stderr, "Look up cover art for %s/%s at size %s\n", artist, album, size); | ||
689 | 86 | |||
690 | 87 | ThumbnailSize desiredSize; | ||
691 | 88 | if (!strcmp(size, "small")) { | ||
692 | 89 | desiredSize = TN_SIZE_SMALL; | ||
693 | 90 | } else if (!strcmp(size, "large")) { | ||
694 | 91 | desiredSize = TN_SIZE_LARGE; | ||
695 | 92 | } else if (!strcmp(size, "xlarge")) { | ||
696 | 93 | desiredSize = TN_SIZE_XLARGE; | ||
697 | 94 | } else if (!strcmp(size, "original")) { | ||
698 | 95 | desiredSize = TN_SIZE_ORIGINAL; | ||
699 | 96 | } else { | ||
700 | 97 | std::string error("Unknown size: "); | ||
701 | 98 | error += size; | ||
702 | 99 | g_dbus_method_invocation_return_dbus_error( | ||
703 | 100 | invocation, ART_ERROR, error.c_str()); | ||
704 | 101 | return TRUE; | ||
705 | 102 | } | ||
706 | 103 | |||
707 | 104 | try { | ||
708 | 105 | std::thread t(&getAlbumArt, | ||
709 | 106 | unique_gobj<TNThumbnailer>(static_cast<TNThumbnailer*>(g_object_ref(iface))), | ||
710 | 107 | unique_gobj<GDBusMethodInvocation>(static_cast<GDBusMethodInvocation*>(g_object_ref(invocation))), | ||
711 | 108 | p->thumbnailer, | ||
712 | 109 | std::string(artist), std::string(album), desiredSize); | ||
713 | 110 | t.detach(); | ||
714 | 111 | } catch (const std::exception &e) { | ||
715 | 112 | g_dbus_method_invocation_return_dbus_error( | ||
716 | 113 | invocation, ART_ERROR, e.what()); | ||
717 | 114 | } | ||
718 | 115 | return TRUE; | ||
719 | 116 | } | ||
720 | 117 | |||
721 | 118 | static void getAlbumArt(unique_gobj<TNThumbnailer> iface, | ||
722 | 119 | unique_gobj<GDBusMethodInvocation> invocation, | ||
723 | 120 | std::shared_ptr<Thumbnailer> thumbnailer, | ||
724 | 121 | const std::string artist, const std::string album, | ||
725 | 122 | ThumbnailSize desiredSize) { | ||
726 | 123 | std::string art; | ||
727 | 124 | try { | ||
728 | 125 | art = thumbnailer->get_album_art( | ||
729 | 126 | artist, album, desiredSize, TN_REMOTE); | ||
730 | 127 | } catch (const std::exception &e) { | ||
731 | 128 | g_dbus_method_invocation_return_dbus_error( | ||
732 | 129 | invocation.get(), ART_ERROR, e.what()); | ||
733 | 130 | return; | ||
734 | 131 | } | ||
735 | 132 | |||
736 | 133 | if (art.empty()) { | ||
737 | 134 | g_dbus_method_invocation_return_dbus_error( | ||
738 | 135 | invocation.get(), ART_ERROR, "Could not get thumbnail"); | ||
739 | 136 | return; | ||
740 | 137 | } | ||
741 | 138 | int fd = open(art.c_str(), O_RDONLY); | ||
742 | 139 | if (fd < 0) { | ||
743 | 140 | g_dbus_method_invocation_return_dbus_error( | ||
744 | 141 | invocation.get(), ART_ERROR, strerror(errno)); | ||
745 | 142 | return; | ||
746 | 143 | } | ||
747 | 144 | |||
748 | 145 | unique_gobj<GUnixFDList> fd_list(g_unix_fd_list_new()); | ||
749 | 146 | GError *error = nullptr; | ||
750 | 147 | g_unix_fd_list_append(fd_list.get(), fd, &error); | ||
751 | 148 | close(fd); | ||
752 | 149 | if (error != nullptr) { | ||
753 | 150 | g_dbus_method_invocation_return_dbus_error( | ||
754 | 151 | invocation.get(), ART_ERROR, error->message); | ||
755 | 152 | g_error_free(error); | ||
756 | 153 | return; | ||
757 | 154 | } | ||
758 | 155 | |||
759 | 156 | tn_thumbnailer_complete_get_album_art( | ||
760 | 157 | iface.get(), invocation.get(), fd_list.get(), g_variant_new_handle(0)); | ||
761 | 158 | } | ||
762 | 159 | |||
763 | 160 | }; | ||
764 | 161 | |||
765 | 162 | DBusInterface::DBusInterface(GDBusConnection *bus, const std::string& bus_path) | ||
766 | 163 | : p(new DBusInterfacePrivate(bus, bus_path)) { | ||
767 | 164 | } | ||
768 | 165 | |||
769 | 166 | DBusInterface::~DBusInterface() { | ||
770 | 167 | delete p; | ||
771 | 168 | } | ||
772 | 0 | 169 | ||
773 | === added file 'src/service/dbusinterface.h' | |||
774 | --- src/service/dbusinterface.h 1970-01-01 00:00:00 +0000 | |||
775 | +++ src/service/dbusinterface.h 2014-03-28 10:11:10 +0000 | |||
776 | @@ -0,0 +1,40 @@ | |||
777 | 1 | /* | ||
778 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
779 | 3 | * | ||
780 | 4 | * Authors: | ||
781 | 5 | * James Henstridge <james.henstridge@canonical.com> | ||
782 | 6 | * | ||
783 | 7 | * This library is free software; you can redistribute it and/or modify it under | ||
784 | 8 | * the terms of version 3 of the GNU General Public License as published | ||
785 | 9 | * by the Free Software Foundation. | ||
786 | 10 | * | ||
787 | 11 | * This library is distributed in the hope that it will be useful, but WITHOUT | ||
788 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
789 | 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
790 | 14 | * details. | ||
791 | 15 | * | ||
792 | 16 | * You should have received a copy of the GNU General Public License | ||
793 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
794 | 18 | */ | ||
795 | 19 | |||
796 | 20 | #ifndef DBUSINTERFACE_H | ||
797 | 21 | #define DBUSINTERFACE_H | ||
798 | 22 | |||
799 | 23 | #include <string> | ||
800 | 24 | |||
801 | 25 | struct DBusInterfacePrivate; | ||
802 | 26 | typedef struct _GDBusConnection GDBusConnection; | ||
803 | 27 | |||
804 | 28 | class DBusInterface final { | ||
805 | 29 | public: | ||
806 | 30 | DBusInterface(GDBusConnection *bus, const std::string& bus_path); | ||
807 | 31 | ~DBusInterface(); | ||
808 | 32 | |||
809 | 33 | DBusInterface(const DBusInterface&) = delete; | ||
810 | 34 | DBusInterface& operator=(DBusInterface&) = delete; | ||
811 | 35 | |||
812 | 36 | private: | ||
813 | 37 | DBusInterfacePrivate *p; | ||
814 | 38 | }; | ||
815 | 39 | |||
816 | 40 | #endif | ||
817 | 0 | 41 | ||
818 | === added file 'src/service/main.cpp' | |||
819 | --- src/service/main.cpp 1970-01-01 00:00:00 +0000 | |||
820 | +++ src/service/main.cpp 2014-03-28 10:11:10 +0000 | |||
821 | @@ -0,0 +1,44 @@ | |||
822 | 1 | #include <cstdio> | ||
823 | 2 | #include <memory> | ||
824 | 3 | #include <stdexcept> | ||
825 | 4 | #include <glib.h> | ||
826 | 5 | #include <gio/gio.h> | ||
827 | 6 | |||
828 | 7 | #include "dbusinterface.h" | ||
829 | 8 | |||
830 | 9 | static const char BUS_NAME[] = "com.canonical.Thumbnailer"; | ||
831 | 10 | static const char BUS_PATH[] = "/com/canonical/Thumbnailer"; | ||
832 | 11 | |||
833 | 12 | static std::unique_ptr<GMainLoop,void(*)(GMainLoop*)> main_loop( | ||
834 | 13 | g_main_loop_new(nullptr, FALSE), g_main_loop_unref); | ||
835 | 14 | |||
836 | 15 | static void nameLost(GDBusConnection *, const char *, void *) { | ||
837 | 16 | fprintf(stderr, "Could no acquire D-Bus name %s. Quitting.\n", BUS_NAME); | ||
838 | 17 | g_main_loop_quit(main_loop.get()); | ||
839 | 18 | } | ||
840 | 19 | |||
841 | 20 | int main(int argc, char **argv) { | ||
842 | 21 | GError *error = nullptr; | ||
843 | 22 | std::unique_ptr<GDBusConnection, void(*)(void*)> bus( | ||
844 | 23 | g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, &error), | ||
845 | 24 | g_object_unref); | ||
846 | 25 | if (error != nullptr) { | ||
847 | 26 | fprintf(stderr, "Failed to connect to session bus: %s\n", error->message); | ||
848 | 27 | g_error_free(error); | ||
849 | 28 | return 1; | ||
850 | 29 | } | ||
851 | 30 | |||
852 | 31 | DBusInterface dbus(bus.get(), BUS_PATH); | ||
853 | 32 | |||
854 | 33 | unsigned int name_id = g_bus_own_name_on_connection( | ||
855 | 34 | bus.get(), BUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, | ||
856 | 35 | nullptr, &nameLost, nullptr, nullptr); | ||
857 | 36 | |||
858 | 37 | g_main_loop_run(main_loop.get()); | ||
859 | 38 | |||
860 | 39 | if (name_id != 0) { | ||
861 | 40 | g_bus_unown_name(name_id); | ||
862 | 41 | } | ||
863 | 42 | |||
864 | 43 | return 0; | ||
865 | 44 | } | ||
866 | 0 | 45 | ||
867 | === modified file 'src/thumbnailer.cpp' | |||
868 | --- src/thumbnailer.cpp 2014-03-28 10:11:10 +0000 | |||
869 | +++ src/thumbnailer.cpp 2014-03-28 10:11:10 +0000 | |||
870 | @@ -53,16 +53,12 @@ | |||
871 | 53 | 53 | ||
872 | 54 | ThumbnailerPrivate() {}; | 54 | ThumbnailerPrivate() {}; |
873 | 55 | 55 | ||
876 | 56 | <<<<<<< TREE | 56 | string create_thumbnail(const string &abspath, ThumbnailSize desired_size, |
877 | 57 | string create_thumbnail(const string &abspath, ThumbnailSize desired_size); | 57 | ThumbnailPolicy policy); |
878 | 58 | string create_random_filename(); | 58 | string create_random_filename(); |
879 | 59 | ======= | ||
880 | 60 | string create_thumbnail(const string &abspath, ThumbnailSize desired_size, | ||
881 | 61 | ThumbnailPolicy policy); | ||
882 | 62 | >>>>>>> MERGE-SOURCE | ||
883 | 63 | }; | 59 | }; |
884 | 64 | 60 | ||
886 | 65 | <<<<<<< TREE | 61 | |
887 | 66 | string ThumbnailerPrivate::create_random_filename() { | 62 | string ThumbnailerPrivate::create_random_filename() { |
888 | 67 | string fname; | 63 | string fname; |
889 | 68 | char *dirbase = getenv("TMPDIR"); // Set when in a confined application. | 64 | char *dirbase = getenv("TMPDIR"); // Set when in a confined application. |
890 | @@ -77,8 +73,6 @@ | |||
891 | 77 | return fname; | 73 | return fname; |
892 | 78 | } | 74 | } |
893 | 79 | 75 | ||
894 | 80 | string ThumbnailerPrivate::create_thumbnail(const string &abspath, ThumbnailSize desired_size) { | ||
895 | 81 | ======= | ||
896 | 82 | string ThumbnailerPrivate::create_audio_thumbnail(const string &/*abspath*/, | 76 | string ThumbnailerPrivate::create_audio_thumbnail(const string &/*abspath*/, |
897 | 83 | ThumbnailSize /*desired_size*/, ThumbnailPolicy /*policy*/) { | 77 | ThumbnailSize /*desired_size*/, ThumbnailPolicy /*policy*/) { |
898 | 84 | // There was a symbol clash between 1.0 and 0.10 versions of | 78 | // There was a symbol clash between 1.0 and 0.10 versions of |
899 | @@ -101,14 +95,8 @@ | |||
900 | 101 | return ""; | 95 | return ""; |
901 | 102 | } | 96 | } |
902 | 103 | string ThumbnailerPrivate::create_generic_thumbnail(const string &abspath, ThumbnailSize desired_size) { | 97 | string ThumbnailerPrivate::create_generic_thumbnail(const string &abspath, ThumbnailSize desired_size) { |
903 | 104 | >>>>>>> MERGE-SOURCE | ||
904 | 105 | int tmpw, tmph; | 98 | int tmpw, tmph; |
905 | 106 | string tnfile = cache.get_cache_file_name(abspath, desired_size); | 99 | string tnfile = cache.get_cache_file_name(abspath, desired_size); |
906 | 107 | <<<<<<< TREE | ||
907 | 108 | string tmpname = create_random_filename(); | ||
908 | 109 | |||
909 | 110 | ======= | ||
910 | 111 | >>>>>>> MERGE-SOURCE | ||
911 | 112 | // Special case: full size image files are their own preview. | 100 | // Special case: full size image files are their own preview. |
912 | 113 | if(desired_size == TN_SIZE_ORIGINAL && | 101 | if(desired_size == TN_SIZE_ORIGINAL && |
913 | 114 | gdk_pixbuf_get_file_info(abspath.c_str(), &tmpw, &tmph)) { | 102 | gdk_pixbuf_get_file_info(abspath.c_str(), &tmpw, &tmph)) { |
914 | @@ -123,9 +111,8 @@ | |||
915 | 123 | } | 111 | } |
916 | 124 | 112 | ||
917 | 125 | string ThumbnailerPrivate::create_video_thumbnail(const string &abspath, ThumbnailSize desired_size) { | 113 | string ThumbnailerPrivate::create_video_thumbnail(const string &abspath, ThumbnailSize desired_size) { |
918 | 126 | char filebuf[] = "/tmp/some/long/text/here/so/path/will/fit"; | ||
919 | 127 | string tnfile = cache.get_cache_file_name(abspath, desired_size); | 114 | string tnfile = cache.get_cache_file_name(abspath, desired_size); |
921 | 128 | string tmpname = tmpnam(filebuf); | 115 | string tmpname = create_random_filename(); |
922 | 129 | if(video.extract(abspath, tmpname)) { | 116 | if(video.extract(abspath, tmpname)) { |
923 | 130 | scaler.scale(tmpname, tnfile, desired_size, abspath); | 117 | scaler.scale(tmpname, tnfile, desired_size, abspath); |
924 | 131 | unlink(tmpname.c_str()); | 118 | unlink(tmpname.c_str()); |
925 | 132 | 119 | ||
926 | === added directory 'tests/qml' | |||
927 | === added file 'tests/qml/tst_image_provider.qml' | |||
928 | --- tests/qml/tst_image_provider.qml 1970-01-01 00:00:00 +0000 | |||
929 | +++ tests/qml/tst_image_provider.qml 2014-03-28 10:11:10 +0000 | |||
930 | @@ -0,0 +1,62 @@ | |||
931 | 1 | import QtQuick 2.0 | ||
932 | 2 | import QtTest 1.0 | ||
933 | 3 | import Ubuntu.Thumbnailer 0.1 | ||
934 | 4 | |||
935 | 5 | Item { | ||
936 | 6 | Image { | ||
937 | 7 | id: image | ||
938 | 8 | width: 200 | ||
939 | 9 | height: 200 | ||
940 | 10 | |||
941 | 11 | SignalSpy { | ||
942 | 12 | id: spy | ||
943 | 13 | target: image | ||
944 | 14 | signalName: "statusChanged" | ||
945 | 15 | } | ||
946 | 16 | } | ||
947 | 17 | |||
948 | 18 | Canvas { | ||
949 | 19 | id: canvas | ||
950 | 20 | width: 200 | ||
951 | 21 | height: 200 | ||
952 | 22 | renderStrategy: Canvas.Immediate | ||
953 | 23 | renderTarget: Canvas.Image | ||
954 | 24 | } | ||
955 | 25 | |||
956 | 26 | TestCase { | ||
957 | 27 | name: "ThumbnailerProviderTests" | ||
958 | 28 | when: windowShown | ||
959 | 29 | |||
960 | 30 | function test_albumart() { | ||
961 | 31 | var ctx = loadImage( | ||
962 | 32 | "image://albumart/artist=Gotye&album=Making%20Mirrors"); | ||
963 | 33 | comparePixel(ctx, 0, 0, 242, 228, 209, 255); | ||
964 | 34 | } | ||
965 | 35 | |||
966 | 36 | function loadImage(uri) { | ||
967 | 37 | image.source = uri | ||
968 | 38 | while (image.status == Image.Loading) { | ||
969 | 39 | spy.wait(); | ||
970 | 40 | } | ||
971 | 41 | compare(image.status, Image.Ready); | ||
972 | 42 | |||
973 | 43 | var ctx = canvas.getContext("2d"); | ||
974 | 44 | ctx.drawImage(image, 0, 0); | ||
975 | 45 | return ctx; | ||
976 | 46 | } | ||
977 | 47 | |||
978 | 48 | function comparePixel(ctx,x,y,r,g,b,a, d) { | ||
979 | 49 | var c = ctx.getImageData(x,y,1,1).data; | ||
980 | 50 | if (d === undefined) | ||
981 | 51 | d = 0; | ||
982 | 52 | r = Math.round(r); | ||
983 | 53 | g = Math.round(g); | ||
984 | 54 | b = Math.round(b); | ||
985 | 55 | a = Math.round(a); | ||
986 | 56 | var notSame = Math.abs(c[0]-r)>d || Math.abs(c[1]-g)>d || Math.abs(c[2]-b)>d || Math.abs(c[3]-a)>d; | ||
987 | 57 | if (notSame) | ||
988 | 58 | qtest_fail('Pixel compare fail:\nactual :[' + c[0]+','+c[1]+','+c[2]+','+c[3] + ']\nexpected:['+r+','+g+','+b+','+a+'] +/- '+d, 1); | ||
989 | 59 | |||
990 | 60 | } | ||
991 | 61 | } | ||
992 | 62 | } |
FAILED: Continuous integration, rev:97 jenkins. qa.ubuntu. com/job/ thumbnailer- ci/47/ jenkins. qa.ubuntu. com/job/ thumbnailer- trusty- amd64-ci/ 35/console jenkins. qa.ubuntu. com/job/ thumbnailer- trusty- armhf-ci/ 35/console jenkins. qa.ubuntu. com/job/ thumbnailer- trusty- i386-ci/ 35/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/thumbnailer -ci/47/ rebuild
http://