7e4d89e1256fe0bf53970c3a4349ffbfad2881ca
[cinaest] / src / backends / google / google-backend.vala
1 using Gee;
2
3 public Gee.HashMap <string, MovieSearch> searches;
4 public DBus.Connection conn;
5
6 [DBus (name = "org.maemo.cinaest.MovieSearch", signals="movies_found")]
7 public class MovieSearch : Object {
8         public int id;
9         bool aborted;
10         string title;
11         GoogleParser parser;
12         GLib.List<GoogleMovie> results;
13         GoogleMovieService service;
14
15         public string path;
16         public string sender;
17
18         // D-Bus API
19
20         public void abort () {
21                 print ("aborting\n");
22                 aborted = true;
23         }
24
25         public void start (string query) {
26                 parser = new GoogleParser ();
27                 title = query;
28
29                 query_async.begin ();
30         }
31
32         public signal void movies_found (string[] movies, bool finished);
33
34         // Internal methods
35
36         internal MovieSearch (GoogleMovieService _service, string _sender, string _path) {
37                 service = _service;
38                 sender = _sender;
39                 path = _path;
40         }
41
42         private async void query_async () {
43                 var gc = GConf.Client.get_default ();
44
45                 results = new GLib.List<GoogleMovie> ();
46
47                 string location = null;
48                 try {
49                         location = gc.get_string ("/apps/cinaest/location");
50                 } catch (Error e) {
51                         stdout.printf ("Error getting GConf option: %s\n", e.message);
52                 }
53                 if (location == null)
54                         location = "";
55
56                 int n = yield parser.query (title, location, receive_movie);
57
58                 try {
59                         var locations = ((SList<string>) gc.get_list ("/apps/cinaest/locations", GConf.ValueType.STRING)).copy ();
60                         if (insert_location_sorted (parser.location, ref locations)) {
61                                 gc.set_list ("/apps/cinaest/locations", GConf.ValueType.STRING, locations);
62                         }
63                         if (location != parser.location) {
64                                 location = parser.location;
65                                 gc.set_string ("/apps/cinaest/location", location);
66                         }
67                 } catch (Error e2) {
68                         stdout.printf ("GConf error: %s\n", e2.message);
69                 }
70
71                 print ("got %d movies\n", n);
72
73                 var m = new string[results.length ()];
74                 int i = 0;
75                 for (unowned GLib.List<GoogleMovie> node = results.first (); node != null; node = node.next) {
76                         m[i++] = "{\"title\":\"%s\",\"rating\":%f,\"runtime\":%d,\"showtimes\":\"%s\",\"cinema_name\":\"%s\",\"cinema_phone\":\"%s\"}".printf (node.data.title, node.data.rating, node.data.runtime, node.data.showtimes, node.data.cinema.name, node.data.cinema.phone);
77                 }
78                 movies_found (m, true);
79                 service.timeout_quit ();
80         }
81
82         private bool insert_location_sorted (string? location, ref SList<string> locations) {
83                 if (location == null)
84                         return false;
85                 if (locations != null) {
86                         for (unowned SList<string> l = locations; l != null; l = l.next) {
87                                 if (l.data == location) {
88                                         return false;
89                                 }
90                                 if (l.data > location) {
91                                         l.insert (location, 0);
92                                         return true;
93                                 }
94                         }
95                 }
96                 locations.append (location);
97                 return true;
98         }
99
100         private void receive_movie (GoogleMovie movie) {
101         //      print ("received %s\n", movie.title);
102                 results.append (movie);
103         }
104 }
105
106 [DBus (name = "org.maemo.cinaest.MovieService")]
107 public class GoogleMovieService : Object {
108         private MainLoop loop;
109         private uint source_id;
110         int id = 0;
111
112         // D-Bus API
113
114         public string new_search (DBus.BusName sender) {
115                 var path = "/org/maemo/cinaest/moviepilot/search%d".printf (id);
116                 var search = new MovieSearch (this, sender, path);
117                 search.id = id++;
118                 conn.register_object (path, search);
119
120                 print ("creating new search %s for %s\n", path, sender);
121                 searches.set (path, search);
122
123                 return path;
124         }
125
126         public void unregister (string path) {
127                 print ("unregistering search %s\n", path);
128
129                 searches.remove (path);
130                 print ("%d\n", searches.size);
131         }
132
133         // Internal methods
134
135         internal GoogleMovieService () {
136                 loop = new MainLoop (null);
137         }
138
139         internal void timeout_quit () {
140                 // With every change we reset the timer to 3min
141                 if (source_id != 0) {
142                         Source.remove (source_id);
143                 }
144                 source_id = Timeout.add_seconds (180, quit);
145         }
146
147         private bool quit () {
148                 loop.quit ();
149
150                 // One-shot only
151                 return false;
152         }
153
154         internal void run () {
155                 loop.run ();
156         }
157 }
158
159 void on_client_lost (DBus.Object sender, string name, string prev, string newp) {
160         if (newp == "") {
161                 var remove_list = new SList<string> ();
162                 // We lost a client
163                 print ("lost a client: %s\n", prev);
164                 foreach (MovieSearch search in searches.values) {
165                         if (search.sender == prev) {
166                                 print ("removing %s\n", search.path);
167                                 remove_list.append (search.path);
168                         }
169                 }
170                 foreach (string path in remove_list)
171                         searches.remove (path);
172         }
173 }
174
175 void main () {
176         try {
177                 conn = DBus.Bus.get (DBus.BusType. SESSION);
178
179                 searches = new Gee.HashMap <string, MovieSearch> ();
180
181                 dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus",
182                                                            "/org/freedesktop/DBus",
183                                                            "org.freedesktop.DBus");
184
185                 uint res = bus.request_name ("org.maemo.cinaest.GoogleShowtimes", (uint) 0);
186
187                 if (res == DBus.RequestNameReply.PRIMARY_OWNER) {
188                         var server = new GoogleMovieService ();
189
190                         conn.register_object ("/org/maemo/cinaest/googleshowtimes", server);
191
192                         bus.NameOwnerChanged.connect (on_client_lost);
193
194                         server.timeout_quit ();
195                         server.run ();
196                 }
197         } catch (Error e) {
198                 stderr.printf ("Oops: %s\n", e.message);
199         }
200 }