gsoc

Sign in or create your account | Project List | Help

gsoc Commit Details

Date:2009-07-27 21:27:18 (1 year 1 day ago)
Author:Adrien Bustany
Commit:cc8f9e7819949e199c17ef05a81cf37d57b5b6ed
Message:Flickr bridge : autotoolize

Files: bridges/flickr/AUTHORS (1 diff)
bridges/flickr/COPYING (0 diffs)
bridges/flickr/ChangeLog (0 diffs)
bridges/flickr/INSTALL (0 diffs)
bridges/flickr/Makefile (1 diff)
bridges/flickr/Makefile.am (1 diff)
bridges/flickr/NEWS (0 diffs)
bridges/flickr/README (0 diffs)
bridges/flickr/autogen.sh (1 diff)
bridges/flickr/config.h (1 diff)
bridges/flickr/configure.ac (1 diff)
bridges/flickr/data/Makefile.am (1 diff)
bridges/flickr/data/flickr.desktop (1 diff)
bridges/flickr/flickr.desktop (1 diff)
bridges/flickr/flickr.vala (1 diff)
bridges/flickr/po/LINGUAS (0 diffs)
bridges/flickr/po/POTFILES.in (1 diff)
bridges/flickr/po/POTFILES.skip (1 diff)
bridges/flickr/src/Makefile.am (1 diff)
bridges/flickr/src/flickr.vala (1 diff)

Change Details

bridges/flickr/AUTHORS
1Adrien Bustany <madcat@mymadcat.com>
bridges/flickr/COPYING
bridges/flickr/ChangeLog
bridges/flickr/INSTALL
bridges/flickr/Makefile
1VALAC=valac
2
3VALAFLAGS=-v -g --thread --vapidir=. --vapidir=.. --pkg dbus-glib-1 --pkg rest --pkg gnome-keyring-1 --pkg tracker-bridge --pkg uuid -X --include=config.h -D DEBUG -X -I.. -X -L.. -X -ltracker-bridge
4
5.SUFFIXES:.vala
6
7SOURCES=flickr.vala
8TARGET=flickr_bridge
9
10$(TARGET) : $(SOURCES) Makefile
11    $(VALAC) $(VALAFLAGS) -o $(TARGET) $(SOURCES)
12
13C : $(SOURCES)
14    $(VALAC) $(VALAFLAGS) -C $(SOURCES)
bridges/flickr/Makefile.am
1SUBDIRS=src po data
2
3EXTRA_DIST= \
4    intltool-extract.in \
5    intltool-merge.in \
6    intltool-update.in
7
8DISTCLEANFILES= \
9    intltool-extract \
10    intltool-merge \
11    intltool-update
12
bridges/flickr/NEWS
bridges/flickr/README
bridges/flickr/autogen.sh
1#!/bin/sh
2# Run this to generate all the initial makefiles, etc.
3
4srcdir=`dirname $0`
5test -z "$srcdir" && srcdir=.
6
7PKG_NAME="tracker-bridge-flickr"
8
9. gnome-autogen.sh
bridges/flickr/config.h
1#define GETTEXT_PACKAGE "FlickrBridge"
2
3// Baaaaah this is an ugly hack because I don't know the right VAPI syntax
4void flickcurl_search_params_destroy (void* s) {}
5void flickcurl_photos_list_params_destroy (void* s) {}
bridges/flickr/configure.ac
1AC_INIT([tracker-bridge-flickr], [0.1.0], [http://bugzilla.gnome.org/enter_bug.cgi?product=tracker], [tracker-bridge-flickr])
2AC_CONFIG_SRCDIR([src/flickr.vala])
3AC_CONFIG_HEADERS(config.h)
4AM_INIT_AUTOMAKE([dist-bzip2])
5
6AC_SUBST(PACKAGE_URL, [http://www.tracker-project.org])
7
8AC_PROG_CC
9AM_PROG_CC_C_O
10AC_DISABLE_STATIC
11AC_PROG_LIBTOOL
12
13AC_PATH_PROG(VALAC, valac, valac)
14AC_SUBST(VALAC)
15
16AH_TEMPLATE([GETTEXT_PACKAGE], [Package name for gettext])
17GETTEXT_PACKAGE=tracker-bridge-flickr
18AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE")
19AC_SUBST(GETTEXT_PACKAGE)
20AM_GLIB_GNU_GETTEXT
21IT_PROG_INTLTOOL([0.35.0])
22AM_MAINTAINER_MODE
23
24AC_SUBST(CFLAGS)
25AC_SUBST(CPPFLAGS)
26AC_SUBST(LDFLAGS)
27
28GLIB_REQUIRED=2.12.0
29DBUS_REQUIRED=0.60
30TRACKERBRIDGE_REQUIRED=0.1
31GNOMEKEYRING_REQUIRED=2.26
32REST_REQUIRED=0.4
33UUID_REQUIRED=1.41
34
35PKG_CHECK_MODULES(GLIB2, glib-2.0 >= $GLIB_REQUIRED)
36AC_SUBST(GLIB2_CFLAGS)
37AC_SUBST(GLIB2_LIBS)
38
39PKG_CHECK_MODULES(GOBJECT, gobject-2.0 >= $GLIB_REQUIRED)
40AC_SUBST(GOBJECT_CFLAGS)
41AC_SUBST(GOBJECT_LIBS)
42
43PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= $GLIB_REQUIRED)
44AC_SUBST(GOBJECT_CFLAGS)
45AC_SUBST(GOBJECT_LIBS)
46
47PKG_CHECK_MODULES(DBUS, [dbus-1 >= $DBUS_REQUIRED dbus-glib-1 >= $DBUS_REQUIRED])
48AC_SUBST(DBUS_CFLAGS)
49AC_SUBST(DBUS_LIBS)
50
51PKG_CHECK_MODULES(TRACKERBRIDGE, tracker-bridge-0.1 >= $TRACKERBRIDGE_REQUIRED)
52AC_SUBST(TRACKERBRIDGE_CFLAGS)
53AC_SUBST(TRACKERBRIDGE_LIBS)
54
55PKG_CHECK_MODULES(GNOMEKEYRING, gnome-keyring-1 >= $GNOMEKEYRING_REQUIRED)
56AC_SUBST(GNOMEKEYRING_CFLAGS)
57AC_SUBST(GNOMEKEYRING_LIBS)
58
59PKG_CHECK_MODULES(REST, rest >= $REST_REQUIRED)
60AC_SUBST(REST_CFLAGS)
61AC_SUBST(REST_LIBS)
62
63PKG_CHECK_MODULES(UUID, uuid >= $UUID_REQUIRED)
64AC_SUBST(UUID_CFLAGS)
65AC_SUBST(UUID_LIBS)
66
67AC_CONFIG_FILES([Makefile
68    src/Makefile
69    data/Makefile
70    po/Makefile.in])
71
72AC_OUTPUT
bridges/flickr/data/Makefile.am
1desktopdir=$(datadir)/tracker/bridges
2desktop_DATA= \
3    flickr.desktop
bridges/flickr/data/flickr.desktop
1[Desktop Entry]
2Encoding=UTF-8
3Type=Service
4Name=Flickr
5Comment=Index your pictures on Flickr
6Icon=/usr/share/hplip/data/images/48x48/prog.png
7X-DBus-Name=org.freedesktop.Tracker.FlickrBridge
8X-DBus-Path=/org/freedesktop/Tracker/Bridge
9X-Tracker-Bridge-AuthScheme=Token
bridges/flickr/flickr.desktop
1[Desktop Entry]
2Encoding=UTF-8
3Type=Service
4Name=Flickr
5Comment=Index your pictures on Flickr
6Icon=/usr/share/hplip/data/images/48x48/prog.png
7X-DBus-Name=org.freedesktop.Tracker.FlickrBridge
8X-DBus-Path=/org/freedesktop/Tracker/Bridge
9X-Tracker-Bridge-AuthScheme=Token
bridges/flickr/flickr.vala
1using Tracker;
2using Rest;
3
4public class FlickrBridge : Object, Tracker.Bridge {
5    private const string SERVICE_NAME = "Flickr";
6    private const string API_KEY = "7983269709fa3158c752e3e4d6b3b9e5";
7    private const string SHARED_SECRET = "c0316d1cb4b15e2d";
8    private const string TRACKER_NAME = "org.freedesktop.Tracker";
9    private const string TRACKER_RESOURCES_PATH = "/org/freedesktop/Tracker/Resources";
10    private const string TRACKER_RESOURCES_INTERFACE = "org.freedesktop.Tracker.Resources";
11    private const string FLICKR_REST = "http://api.flickr.com/services/rest/";
12
13    private DBus.Connection conn;
14    dynamic DBus.Object tracker;
15    private Proxy rest;
16    private string auth_token = null;
17
18    private string frob;
19    private string username;
20
21    private uint bridge_status;
22
23    public FlickrBridge ()
24    {
25        set_bridge_status (Status.NotAuthenticated);
26
27        try {
28            conn = DBus.Bus.get (DBus.BusType.SESSION);
29        } catch (Error e) {
30            critical ("Cannot connect to session bus : %s\n", e.message);
31        }
32
33        tracker = conn.get_object (TRACKER_NAME, TRACKER_RESOURCES_PATH, TRACKER_RESOURCES_INTERFACE);
34
35        rest = new Proxy (FLICKR_REST, false);
36    }
37
38    // DBus signals callbacks
39    public HashTable<string, string> GetAssociationData ()
40    {
41        var ret = new HashTable<string, string> (str_hash, str_equal);
42        var c = rest.new_call ();
43        c.add_param ("method", "flickr.auth.getFrob");
44        var node = runCall (c);
45
46        if (node == null) {
47            critical ("Call to getFrob failed");
48            return ret;
49        }
50
51        frob = node.find ("frob").content;
52
53        string url = "http://flickr.com/services/auth/?api_key=" + API_KEY + "&perms=read&frob=" + frob + "&api_sig=";
54
55        string api_sig = SHARED_SECRET + "api_key" + API_KEY + "frob" + frob + "permsread";
56        api_sig = Checksum.compute_for_string (ChecksumType.MD5, api_sig);
57        url += api_sig;
58
59        ret.insert ("url", url);
60        return ret;
61    }
62
63    // This supposes we have a valid frob. Else, well, it'll just fail...
64    public void FinishAssociation (HashTable<string, string> data)
65    {
66        var c = rest.new_call ();
67        c.add_params ("method", "flickr.auth.getToken",
68                      "frob", frob,
69                      null);
70        var node = runCall (c);
71
72        string token = node.find ("token").content;
73
74        if (token == null) {
75            set_bridge_status (Status.NotAuthenticated);
76            Error (DBusErrorCode.AuthenticationError, _("Couldn't get an authentication token from the remote site"));
77#if DEBUG
78            critical ("Couldn't get token");
79#endif
80            return;
81        }
82
83        username = node.find ("user").get_attr ("fullname");
84        if (username == "") username = node.find ("user").get_attr ("username");
85
86        if (username == null) {
87            set_bridge_status (Status.WrongToken);
88            Error (DBusErrorCode.AuthenticationError, _("Couldn't get the login associated to the authenticated account"));
89#if DEBUG
90            critical ("Couldn't get account username");
91#endif
92            return;
93        }
94
95        try {
96            Tracker.passwordProvider.save (username, SERVICE_NAME, token, "Authentication token for Flickr");
97        } catch (Error e) {
98            critical ("Cannot store token : %s", e.message);
99        }
100
101        set_bridge_status (Status.Authenticated, username);
102    }
103
104    public void Authenticate ()
105    {
106        string username = null;
107        string token;
108
109        HashTable<string, string> pwdData = null;
110        try {
111            pwdData = Tracker.passwordProvider.search (null, SERVICE_NAME);
112        } catch (Error e) {
113            critical ("Cannot retrieve stored token : %s", e.message);
114        }
115
116        if (pwdData != null) {
117            token = pwdData.lookup ("secret");
118            auth_token = token;
119
120            var c = rest.new_call ();
121            c.add_param ("method", "flickr.test.login");
122
123
124            var node = runCall (c);
125            username = node.find ("username").content;
126
127            if (username == null) {
128                set_bridge_status (Status.WrongToken);
129                Error (DBusErrorCode.AuthenticationError, _("Couldn't login on the remote website"));
130#if DEBUG
131                critical ("Couldn't get account username");
132#endif
133                return;
134            }
135            set_bridge_status (Status.Authenticated, username);
136        } else {
137            set_bridge_status (Status.NotAuthenticated);
138            return;
139        }
140    }
141
142    public uint GetStatus ()
143    {
144        return bridge_status;
145    }
146
147    public void Pull ()
148    {
149
150        set_bridge_status (Status.Working);
151
152        int maxpage = 1;
153        for (int i = 1 ; i <= maxpage ; i++) {
154            var c = rest.new_call ();
155            c.add_param ("method", "flickr.photos.search");
156            c.add_param ("user_id", "me");
157            c.add_param ("extras", "original_format");
158            c.add_param ("per_page", "500");
159            c.add_param ("page", "%d".printf (i));
160            var node = runCall (c);
161            //maxpage = node.find ("photos").get_attr ("pages").to_int ();
162
163            var photo = node.find ("photo");
164
165            while (photo != null) {
166                insertIntoTracker (photo);
167                photo = photo.next;
168            }
169        }
170    }
171
172    public void Shutdown ()
173    {
174#if DEBUG
175        message ("Shutting down...\n");
176#endif
177        loop.quit ();
178    }
179
180    // Private functions
181    private void set_bridge_status (Tracker.Bridge.Status s, string message = "")
182    {
183#if DEBUG
184        debug ("Changing status to %u", s);
185#endif
186        bridge_status = s;
187        StatusChanged ((uint)s, message);
188    }
189
190    private void insertIntoTracker (XmlNode p)
191    {
192        string urn = "urn:uuid:%s".printf (uuid_generate_string ());
193        string uri = "http://farm%s.static.flickr.com/%s/%s_%s.jpg".printf (p.get_attr ("farm"), p.get_attr ("server"), p.get_attr ("id"), p.get_attr ("secret"));
194        try {
195            tracker.SparqlUpdate ("insert {<%s> a nmm:Photo}".printf (urn));
196            tracker.SparqlUpdate ("insert {<%s> nie:isStoredAs <%s>}".printf (urn, uri));
197            tracker.SparqlUpdate ("insert {<%s> a nfo:RemoteDataObject}".printf (uri));
198            tracker.SparqlUpdate ("insert {<%s> rdfs:label '%s'}".printf (uri, p.get_attr ("title").escape ("")));
199
200            insertExifIntoTracker (p, urn);
201            insertTagsIntoTracker (p, urn);
202        } catch (Error e) {
203            critical ("Error while entering metadata into Tracker : %s", e.message);
204        }
205    }
206
207    private void insertExifIntoTracker (XmlNode p, string uri) throws GLib.Error
208    {
209        var exif_call = rest.new_call ();
210        exif_call.add_param ("method", "flickr.photos.getExif");
211        exif_call.add_param ("photo_id", p.get_attr ("id"));
212
213        var node = runCall (exif_call).find ("exif");
214
215        while (node != null) {
216            switch (node.get_attr ("tag").to_int ()) {
217                case 271:
218                    tracker.SparqlUpdate ("insert {<%s> nmm:camera '%s'}".printf (uri, node.find ("raw").content));
219                    break;
220// case 33434:
221// tracker.SparqlUpdate ("insert {<%s> nmm:exposureTime %s}".printf (uri, e.raw_value));
222// break;
223                case 37385:
224                    tracker.SparqlUpdate ("insert {<%s> nmm:flash %s}".printf (uri, (node.find ("raw").content.to_int ()%2 == 1 ? "nmm:flash-on" : "flash-off") ));
225                    break;
226                case 33437:
227                    tracker.SparqlUpdate ("insert {<%s> nmm:fnumber %f}".printf (uri, fracToDouble (node.find ("raw").content)));
228                    break;
229                case 37386:
230                    tracker.SparqlUpdate ("insert {<%s> nmm:focalLength %f}".printf (uri, fracToDouble (node.find ("raw").content)));
231                    break;
232                case 2:
233                    tracker.SparqlUpdate ("insert {<%s> nmm:isoSpeed %s}".printf (uri, node.find ("raw").content));
234                    break;
235                case 37383:
236                    string meteringMode = "";
237                    switch (node.find ("raw").content.to_int ()) {
238                        case 1:
239                            meteringMode = "nmm:meteringMode-average";
240                            break;
241                        case 2:
242                            meteringMode = "nmm:meteringMode-center-weighted-average";
243                            break;
244                        case 3:
245                            meteringMode = "nmm:meteringMode-spot";
246                            break;
247                        case 4:
248                            meteringMode = "nmm:meteringMode-multispot";
249                            break;
250                        case 5:
251                            meteringMode = "nmm:meteringMode-pattern";
252                            break;
253                        case 6:
254                            meteringMode = "nmm:meteringMode-partial";
255                            break;
256                        case 255:
257                            meteringMode = "nmm:meteringMode-partial";
258                            break;
259                        default: // Should match 0 = unknown + other values
260                            break;
261                    }
262                    if (meteringMode == "")
263                        break;
264
265                    tracker.SparqlUpdate ("insert {<%s> nmm:meteringMode %s}".printf (uri, meteringMode));
266                    break;
267                case 5:
268                    string whiteBalance = "";
269                    switch (node.find ("raw").content.to_int ()) {
270                        case 0:
271                            whiteBalance = "nmm:whiteBalance-auto";
272                            break;
273                        case 1:
274                            whiteBalance = "nmm:whiteBalance-manual";
275                            break;
276                        default:
277                            break;
278                    }
279                    if (whiteBalance == "")
280                        break;
281
282                    tracker.SparqlUpdate ("insert {<%s> nmm:whiteBalance %s}".printf (uri, whiteBalance));
283                    break;
284                default:
285                    break;
286            }
287
288            node = node.next;
289        }
290    }
291
292    private void insertTagsIntoTracker (XmlNode p, string uri) throws GLib.Error
293    {
294        var tag_call = rest.new_call ();
295        tag_call.add_param ("method", "flickr.tags.getListPhoto");
296        tag_call.add_param ("photo_id", p.get_attr ("id"));
297
298        var node = runCall (tag_call).find ("tag");
299
300        while (node != null) {
301            string tagUri = getTagUri (node.content);
302            tracker.SparqlUpdate ("insert {<%s> a nao:Tag}".printf (tagUri));
303            tracker.SparqlUpdate ("insert {<%s> rdfs:label \"%s\"}".printf (tagUri, node.get_attr ("raw").escape ("")));
304            tracker.SparqlUpdate ("insert {<%s> nao:hasTag <%s>}".printf (uri, tagUri));
305            node = node.next;
306        }
307    }
308
309    private double fracToDouble (string s)
310    {
311        string[] tokens = s.split ("/");
312        if (tokens[1].to_int () == 0) {
313            critical ("fracToDouble : divide by zero while parsing %s\n", s);
314            return 0;
315        }
316        return (tokens[0].to_int () * 1.0) / (tokens[1].to_int ());
317    }
318
319    private XmlNode? runCall (ProxyCall c)
320    {
321        signCall (c);
322
323        try {
324            c.run (null);
325        } catch (Error e) {
326            critical ("Error in REST call : %s\n", e.message);
327            return null;
328        }
329
330        var parser = new XmlParser ();
331        var node = parser.parse_from_data (c.get_payload (), c.get_payload_length ());
332        if (node == null || node.name != "rsp") {
333            critical ("Invalid response : %s\n", c.get_payload ());
334            return null;
335        }
336        return node;
337    }
338
339    // Add version, api_key, call_id and sig
340    private void signCall (ProxyCall c)
341    {
342        c.add_param ("api_key", API_KEY);
343        if (auth_token != null)
344            c.add_param ("auth_token", auth_token);
345
346        string sig = SHARED_SECRET;
347        var par = c.get_params ();
348        List<weak string> keys = par.get_keys ().copy ();
349        keys.sort ((CompareFunc)strcmp);
350
351        for (int i = 0 ; i < keys.length () ; ++i) {
352            sig += keys.nth_data (i) + par.lookup (keys.nth_data (i));
353        }
354
355        sig = Checksum.compute_for_string (ChecksumType.MD5, sig);
356
357        c.add_param ("api_sig", sig);
358    }
359}
360
361MainLoop loop;
362
363void main ()
364{
365    loop = new MainLoop (null, false);
366
367    Environment.set_application_name ("FlickrBrige");
368
369    try {
370        var conn = DBus.Bus.get (DBus.BusType.SESSION);
371        dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus");
372
373        uint request_name_result = bus.request_name ("org.freedesktop.Tracker.FlickrBridge", (uint)0);
374        if (request_name_result != DBus.RequestNameReply.PRIMARY_OWNER) {
375            critical ("Somebody already got our name on the bus !");
376            return;
377        }
378
379#if DEBUG
380        message ("Creating the bridge...\n");
381#endif
382
383        var bridge = new FlickrBridge ();
384        conn.register_object ("/org/freedesktop/Tracker/Bridge", bridge);
385
386
387        loop.run ();
388    } catch (Error e) {
389        critical ("Cannot start the bridge : %s", e.message);
390    }
391}
bridges/flickr/po/LINGUAS
bridges/flickr/po/POTFILES.in
1src/flickr.vala
bridges/flickr/po/POTFILES.skip
1src/flickr.c
bridges/flickr/src/Makefile.am
1AM_CPPFLAGS = \
2    -include $(CONFIG_HEADER)
3
4VALAINCLUDES= \
5    --pkg dbus-glib-1 \
6    --pkg tracker-bridge \
7    --pkg rest \
8    --pkg uuid \
9    --thread
10
11libexec_PROGRAMS=tracker-bridge-flickr
12
13tracker_bridge_flickr_VALASOURCES= \
14    flickr.vala
15
16tracker_bridge_flickr_SOURCES= \
17    $(tracker_bridge_flickr_VALASOURCES:.vala=.c)
18
19tracker-bridge-flickr.vala.stamp: $(tracker_bridge_flickr_VALASOURCES)
20    $(VALAC) -C $(VALAINCLUDES) $(VALAFLAGS) $^
21    touch $@
22
23tracker_bridge_flickr_CFLAGS= \
24    -DSHAREDIR=\""$(datadir)"\" \
25    -DLOCALEDIR=\""$(localedir)"\" \
26    -I$(top_srcdir)/src \
27    $(WARN_CFLAGS) \
28    $(GLIB2_CFLAGS) \
29    $(GOBJECT_CFLAGS) \
30    $(GTHREAD_CFLAGS) \
31    $(DBUS_CFLAGS) \
32    $(TRACKERBRIDGE_CFLAGS) \
33    $(REST_CFLAGS) \
34    $(UUID_CFLAGS)
35
36tracker_bridge_flickr_LDADD= \
37    $(GLIB2_LIBS) \
38    $(GOBJECT_LIBS) \
39    $(GTHREAD_LIBS) \
40    $(DBUS_LIBS) \
41    $(TRACKERBRIDGE_LIBS) \
42    $(REST_LIBS) \
43    $(UUID_LIBS)
44
45BUILT_SOURCES= \
46    tracker-bridge-flickr.vala.stamp
47
48CLEANFILES= $(BUILT_SOURCES)
49
50EXTRA_DIST= \
51    tracker-bridge-flickr.vala.stamp \
52    $(tracker_bridge_flickr_SOURCES) \
53    $(tracker_bridge_flickr_VALASOURCES)
54
55MAINTAINERCLEANFILES= \
56    $(tracker_bridge_flickr_SOURCES) \
57    tracker-bridge-flickr.vala.stamp
bridges/flickr/src/flickr.vala
1using Tracker;
2using Rest;
3
4public class FlickrBridge : Object, Tracker.Bridge {
5    private const string SERVICE_NAME = "Flickr";
6    private const string API_KEY = "7983269709fa3158c752e3e4d6b3b9e5";
7    private const string SHARED_SECRET = "c0316d1cb4b15e2d";
8    private const string TRACKER_NAME = "org.freedesktop.Tracker";
9    private const string TRACKER_RESOURCES_PATH = "/org/freedesktop/Tracker/Resources";
10    private const string TRACKER_RESOURCES_INTERFACE = "org.freedesktop.Tracker.Resources";
11    private const string FLICKR_REST = "http://api.flickr.com/services/rest/";
12
13    private DBus.Connection conn;
14    dynamic DBus.Object tracker;
15    private Proxy rest;
16    private string auth_token = null;
17
18    private string frob;
19    private string username;
20
21    private uint bridge_status;
22
23    public FlickrBridge ()
24    {
25        set_bridge_status (Status.NotAuthenticated);
26
27        try {
28            conn = DBus.Bus.get (DBus.BusType.SESSION);
29        } catch (Error e) {
30            critical ("Cannot connect to session bus : %s\n", e.message);
31        }
32
33        tracker = conn.get_object (TRACKER_NAME, TRACKER_RESOURCES_PATH, TRACKER_RESOURCES_INTERFACE);
34
35        rest = new Proxy (FLICKR_REST, false);
36    }
37
38    // DBus signals callbacks
39    public HashTable<string, string> GetAssociationData ()
40    {
41        var ret = new HashTable<string, string> (str_hash, str_equal);
42        var c = rest.new_call ();
43        c.add_param ("method", "flickr.auth.getFrob");
44        var node = runCall (c);
45
46        if (node == null) {
47            critical ("Call to getFrob failed");
48            return ret;
49        }
50
51        frob = node.find ("frob").content;
52
53        string url = "http://flickr.com/services/auth/?api_key=" + API_KEY + "&perms=read&frob=" + frob + "&api_sig=";
54
55        string api_sig = SHARED_SECRET + "api_key" + API_KEY + "frob" + frob + "permsread";
56        api_sig = Checksum.compute_for_string (ChecksumType.MD5, api_sig);
57        url += api_sig;
58
59        ret.insert ("url", url);
60        return ret;
61    }
62
63    // This supposes we have a valid frob. Else, well, it'll just fail...
64    public void FinishAssociation (HashTable<string, string> data)
65    {
66        var c = rest.new_call ();
67        c.add_params ("method", "flickr.auth.getToken",
68                      "frob", frob,
69                      null);
70        var node = runCall (c);
71
72        string token = node.find ("token").content;
73
74        if (token == null) {
75            set_bridge_status (Status.NotAuthenticated);
76            Error (DBusErrorCode.AuthenticationError, _("Couldn't get an authentication token from the remote site"));
77#if DEBUG
78            critical ("Couldn't get token");
79#endif
80            return;
81        }
82
83        username = node.find ("user").get_attr ("fullname");
84        if (username == "") username = node.find ("user").get_attr ("username");
85
86        if (username == null) {
87            set_bridge_status (Status.WrongToken);
88            Error (DBusErrorCode.AuthenticationError, _("Couldn't get the login associated to the authenticated account"));
89#if DEBUG
90            critical ("Couldn't get account username");
91#endif
92            return;
93        }
94
95        try {
96            Tracker.passwordProvider.save (username, SERVICE_NAME, token, "Authentication token for Flickr");
97        } catch (Error e) {
98            critical ("Cannot store token : %s", e.message);
99        }
100
101        set_bridge_status (Status.Authenticated, username);
102    }
103
104    public void Authenticate ()
105    {
106        string username = null;
107        string token;
108
109        HashTable<string, string> pwdData = null;
110        try {
111            pwdData = Tracker.passwordProvider.search (null, SERVICE_NAME);
112        } catch (Error e) {
113            critical ("Cannot retrieve stored token : %s", e.message);
114        }
115
116        if (pwdData != null) {
117            token = pwdData.lookup ("secret");
118            auth_token = token;
119
120            var c = rest.new_call ();
121            c.add_param ("method", "flickr.test.login");
122
123
124            var node = runCall (c);
125            username = node.find ("username").content;
126
127            if (username == null) {
128                set_bridge_status (Status.WrongToken);
129                Error (DBusErrorCode.AuthenticationError, _("Couldn't login on the remote website"));
130#if DEBUG
131                critical ("Couldn't get account username");
132#endif
133                return;
134            }
135            set_bridge_status (Status.Authenticated, username);
136        } else {
137            set_bridge_status (Status.NotAuthenticated);
138            return;
139        }
140    }
141
142    public uint GetStatus ()
143    {
144        return bridge_status;
145    }
146
147    public void Pull ()
148    {
149
150        set_bridge_status (Status.Working);
151
152        int maxpage = 1;
153        for (int i = 1 ; i <= maxpage ; i++) {
154            var c = rest.new_call ();
155            c.add_param ("method", "flickr.photos.search");
156            c.add_param ("user_id", "me");
157            c.add_param ("extras", "original_format");
158            c.add_param ("per_page", "500");
159            c.add_param ("page", "%d".printf (i));
160            var node = runCall (c);
161            //maxpage = node.find ("photos").get_attr ("pages").to_int ();
162
163            var photo = node.find ("photo");
164
165            while (photo != null) {
166                insertIntoTracker (photo);
167                photo = photo.next;
168            }
169        }
170    }
171
172    public void Shutdown ()
173    {
174#if DEBUG
175        message ("Shutting down...\n");
176#endif
177        loop.quit ();
178    }
179
180    // Private functions
181    private void set_bridge_status (Tracker.Bridge.Status s, string message = "")
182    {
183#if DEBUG
184        debug ("Changing status to %u", s);
185#endif
186        bridge_status = s;
187        StatusChanged ((uint)s, message);
188    }
189
190    private void insertIntoTracker (XmlNode p)
191    {
192        string urn = "urn:uuid:%s".printf (uuid_generate_string ());
193        string uri = "http://farm%s.static.flickr.com/%s/%s_%s.jpg".printf (p.get_attr ("farm"), p.get_attr ("server"), p.get_attr ("id"), p.get_attr ("secret"));
194        try {
195            tracker.SparqlUpdate ("insert {<%s> a nmm:Photo}".printf (urn));
196            tracker.SparqlUpdate ("insert {<%s> nie:isStoredAs <%s>}".printf (urn, uri));
197            tracker.SparqlUpdate ("insert {<%s> a nfo:RemoteDataObject}".printf (uri));
198            tracker.SparqlUpdate ("insert {<%s> rdfs:label '%s'}".printf (uri, p.get_attr ("title").escape ("")));
199
200            insertExifIntoTracker (p, urn);
201            insertTagsIntoTracker (p, urn);
202        } catch (Error e) {
203            critical ("Error while entering metadata into Tracker : %s", e.message);
204        }
205    }
206
207    private void insertExifIntoTracker (XmlNode p, string uri) throws GLib.Error
208    {
209        var exif_call = rest.new_call ();
210        exif_call.add_param ("method", "flickr.photos.getExif");
211        exif_call.add_param ("photo_id", p.get_attr ("id"));
212
213        var node = runCall (exif_call).find ("exif");
214
215        while (node != null) {
216            switch (node.get_attr ("tag").to_int ()) {
217                case 271:
218                    tracker.SparqlUpdate ("insert {<%s> nmm:camera '%s'}".printf (uri, node.find ("raw").content));
219                    break;
220// case 33434:
221// tracker.SparqlUpdate ("insert {<%s> nmm:exposureTime %s}".printf (uri, e.raw_value));
222// break;
223                case 37385:
224                    tracker.SparqlUpdate ("insert {<%s> nmm:flash %s}".printf (uri, (node.find ("raw").content.to_int ()%2 == 1 ? "nmm:flash-on" : "flash-off") ));
225                    break;
226                case 33437:
227                    tracker.SparqlUpdate ("insert {<%s> nmm:fnumber %f}".printf (uri, fracToDouble (node.find ("raw").content)));
228                    break;
229                case 37386:
230                    tracker.SparqlUpdate ("insert {<%s> nmm:focalLength %f}".printf (uri, fracToDouble (node.find ("raw").content)));
231                    break;
232                case 2:
233                    tracker.SparqlUpdate ("insert {<%s> nmm:isoSpeed %s}".printf (uri, node.find ("raw").content));
234                    break;
235                case 37383:
236                    string meteringMode = "";
237                    switch (node.find ("raw").content.to_int ()) {
238                        case 1:
239                            meteringMode = "nmm:meteringMode-average";
240                            break;
241                        case 2:
242                            meteringMode = "nmm:meteringMode-center-weighted-average";
243                            break;
244                        case 3:
245                            meteringMode = "nmm:meteringMode-spot";
246                            break;
247                        case 4:
248                            meteringMode = "nmm:meteringMode-multispot";
249                            break;
250                        case 5:
251                            meteringMode = "nmm:meteringMode-pattern";
252                            break;
253                        case 6:
254                            meteringMode = "nmm:meteringMode-partial";
255                            break;
256                        case 255:
257                            meteringMode = "nmm:meteringMode-partial";
258                            break;
259                        default: // Should match 0 = unknown + other values
260                            break;
261                    }
262                    if (meteringMode == "")
263                        break;
264
265                    tracker.SparqlUpdate ("insert {<%s> nmm:meteringMode %s}".printf (uri, meteringMode));
266                    break;
267                case 5:
268                    string whiteBalance = "";
269                    switch (node.find ("raw").content.to_int ()) {
270                        case 0:
271                            whiteBalance = "nmm:whiteBalance-auto";
272                            break;
273                        case 1:
274                            whiteBalance = "nmm:whiteBalance-manual";
275                            break;
276                        default:
277                            break;
278                    }
279                    if (whiteBalance == "")
280                        break;
281
282                    tracker.SparqlUpdate ("insert {<%s> nmm:whiteBalance %s}".printf (uri, whiteBalance));
283                    break;
284                default:
285                    break;
286            }
287
288            node = node.next;
289        }
290    }
291
292    private void insertTagsIntoTracker (XmlNode p, string uri) throws GLib.Error
293    {
294        var tag_call = rest.new_call ();
295        tag_call.add_param ("method", "flickr.tags.getListPhoto");
296        tag_call.add_param ("photo_id", p.get_attr ("id"));
297
298        var node = runCall (tag_call).find ("tag");
299
300        while (node != null) {
301            string tagUri = getTagUri (node.content);
302            tracker.SparqlUpdate ("insert {<%s> a nao:Tag}".printf (tagUri));
303            tracker.SparqlUpdate ("insert {<%s> rdfs:label \"%s\"}".printf (tagUri, node.get_attr ("raw").escape ("")));
304            tracker.SparqlUpdate ("insert {<%s> nao:hasTag <%s>}".printf (uri, tagUri));
305            node = node.next;
306        }
307    }
308
309    private double fracToDouble (string s)
310    {
311        string[] tokens = s.split ("/");
312        if (tokens[1].to_int () == 0) {
313            critical ("fracToDouble : divide by zero while parsing %s\n", s);
314            return 0;
315        }
316        return (tokens[0].to_int () * 1.0) / (tokens[1].to_int ());
317    }
318
319    private XmlNode? runCall (ProxyCall c)
320    {
321        signCall (c);
322
323        try {
324            c.run (null);
325        } catch (Error e) {
326            critical ("Error in REST call : %s\n", e.message);
327            return null;
328        }
329
330        var parser = new XmlParser ();
331        var node = parser.parse_from_data (c.get_payload (), c.get_payload_length ());
332        if (node == null || node.name != "rsp") {
333            critical ("Invalid response : %s\n", c.get_payload ());
334            return null;
335        }
336        return node;
337    }
338
339    // Add version, api_key, call_id and sig
340    private void signCall (ProxyCall c)
341    {
342        c.add_param ("api_key", API_KEY);
343        if (auth_token != null)
344            c.add_param ("auth_token", auth_token);
345
346        string sig = SHARED_SECRET;
347        var par = c.get_params ();
348        List<weak string> keys = par.get_keys ().copy ();
349        keys.sort ((CompareFunc)strcmp);
350
351        for (int i = 0 ; i < keys.length () ; ++i) {
352            sig += keys.nth_data (i) + par.lookup (keys.nth_data (i));
353        }
354
355        sig = Checksum.compute_for_string (ChecksumType.MD5, sig);
356
357        c.add_param ("api_sig", sig);
358    }
359}
360
361MainLoop loop;
362
363void main ()
364{
365    loop = new MainLoop (null, false);
366
367    Environment.set_application_name ("FlickrBrige");
368
369    try {
370        var conn = DBus.Bus.get (DBus.BusType.SESSION);
371        dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus");
372
373        uint request_name_result = bus.request_name ("org.freedesktop.Tracker.FlickrBridge", (uint)0);
374        if (request_name_result != DBus.RequestNameReply.PRIMARY_OWNER) {
375            critical ("Somebody already got our name on the bus !");
376            return;
377        }
378
379#if DEBUG
380        message ("Creating the bridge...\n");
381#endif
382
383        var bridge = new FlickrBridge ();
384        conn.register_object ("/org/freedesktop/Tracker/Bridge", bridge);
385
386
387        loop.run ();
388    } catch (Error e) {
389        critical ("Cannot start the bridge : %s", e.message);
390    }
391}

Archive Download the corresponding diff file

Branches:
master