using GLib; class IMDbDownloadServer : Object, IMDbDownloader { MainLoop loop; Cancellable cancellable; bool running; uint source_id; unowned IMDbSqlite sqlite; string[] mirrors = { "ftp.fu-berlin.de/pub/misc/movies/database/", "ftp.funet.fi/pub/mirrors/ftp.imdb.com/pub/", "ftp.sunet.se/pub/tv+movies/imdb/" }; string url; int flags; int percent_finished; delegate void ParseLineFunction (string line); construct { loop = new MainLoop (null, false); cancellable = new Cancellable (); } // IMDbDownloader implementation public void download (string mirror, int _flags) throws DBus.Error { if (running) { stdout.printf ("Download in progress. Abort.\n"); return; } running = true; if (source_id != 0) { Source.remove (source_id); } stdout.printf ("Download started (%x).", flags); progress (0); url = "ftp://anonymous@" + mirror; flags = _flags; try { Thread.create(download_thread, false); } catch (ThreadError e) { critical ("Failed to create download thread\n"); return; } } public void cancel () throws DBus.Error { cancellable.cancel (); } public string[] get_mirrors () throws DBus.Error { return mirrors; } // Private methods private void* download_thread () { description_changed ("Connecting to FTP ..."); progress (0); percent_finished = 0; var cache_dir = Path.build_filename (Environment.get_user_cache_dir (), "cinaest"); DirUtils.create_with_parents (cache_dir, 0770); var _sqlite = new IMDbSqlite (Path.build_filename (cache_dir, "imdb.db")); sqlite = _sqlite; _sqlite.clear (); try { var movie_parser = new MovieLineParser (sqlite); var genre_parser = new GenreLineParser (sqlite); var rating_parser = new RatingLineParser (sqlite); var aka_parser = new AkaLineParser (sqlite); var plot_parser = new PlotLineParser (sqlite); var person_parser = new PersonParser (sqlite); var downloader = new FtpDownloader (cancellable); downloader.progress.connect (on_progress); var parser = new IMDbGzipParser (cancellable); parser.progress.connect (on_progress); if (MOVIES in flags) { description_changed ("Downloading movie list ..."); downloader.download (url + "movies.list.gz", Path.build_filename (cache_dir, "movies.list.gz")); } percent_finished = 10; if (GENRES in flags) { description_changed ("Downloading genre data ..."); downloader.download (url + "genres.list.gz", Path.build_filename (cache_dir, "genres.list.gz")); } percent_finished = 20; if (RATINGS in flags) { description_changed ("Downloading rating data ..."); downloader.download (url + "ratings.list.gz", Path.build_filename (cache_dir, "ratings.list.gz")); } percent_finished = 30; if (AKAS in flags) { description_changed ("Downloading alternative titles ..."); downloader.download (url + "aka-titles.list.gz", Path.build_filename (cache_dir, "aka-titles.list.gz")); } percent_finished = 40; if (PLOTS in flags) { description_changed ("Downloading plots ..."); downloader.download (url + "plot.list.gz", Path.build_filename (cache_dir, "plot.list.gz")); } if (ACTORS in flags) { description_changed ("Downloading actors ..."); downloader.download (url + "actors.list.gz", Path.build_filename (cache_dir, "actors.list.gz")); description_changed ("Downloading actresses ..."); downloader.download (url + "actresses.list.gz", Path.build_filename (cache_dir, "actresses.list.gz")); } // composers // costume-designers if (DIRECTORS in flags) { description_changed ("Downloading directors ..."); downloader.download (url + "directors.list.gz", Path.build_filename (cache_dir, "directors.list.gz")); } // editors // producers // production-designers if (WRITERS in flags) { description_changed ("Downloading writers ..."); downloader.download (url + "writers.list.gz", Path.build_filename (cache_dir, "writers.list.gz")); } percent_finished = 50; if (MOVIES in flags) { description_changed ("Parsing movie list ..."); parser.parse (Path.build_filename (cache_dir, "movies.list.gz"), movie_parser); } percent_finished = 60; if (GENRES in flags) { description_changed ("Parsing genre data ..."); parser.parse (Path.build_filename (cache_dir, "genres.list.gz"), genre_parser); } percent_finished = 70; if (RATINGS in flags) { description_changed ("Parsing rating data ..."); parser.parse (Path.build_filename (cache_dir, "ratings.list.gz"), rating_parser); } percent_finished = 80; if (AKAS in flags) { description_changed ("Parsing alternative titles ..."); parser.parse (Path.build_filename (cache_dir, "aka-titles.list.gz"), aka_parser); } percent_finished = 90; if (PLOTS in flags) { description_changed ("Parsing plots ..."); parser.parse (Path.build_filename (cache_dir, "plot.list.gz"), plot_parser); } if (ACTORS in flags) { description_changed ("Parsing actors ..."); parser.parse (Path.build_filename (cache_dir, "actors.list.gz"), person_parser); person_parser.reset (); description_changed ("Parsing actresses ..."); parser.parse (Path.build_filename (cache_dir, "actresses.list.gz"), person_parser); } } catch (Error e2) { if (e2 is IOError.CANCELLED) stdout.printf ("Download cancelled.\n"); else warning ("Failed to open/read stream: %s\n", e2.message); } description_changed ("Creating indices ..."); if (AKAS in flags) sqlite.create_aka_index (); if (MOVIES in flags) sqlite.create_votes_index (); if (!cancellable.is_cancelled ()) { stdout.printf ("Download complete.\n"); progress (100); } sqlite = null; running = false; timeout_quit (); return null; } private void on_progress (int dltotal, int dlnow) { stdout.printf ("%d / %d\r", dlnow, dltotal); if (dltotal > 0) { int p = percent_finished + 10*dlnow/dltotal; if (p < 100) progress (p); } } private void timeout_quit () { source_id = Timeout.add (3000, quit); } private bool quit () { loop.quit (); // One-shot only return false; } public void run () { loop.run (); } public static void main () { Curl.global_init (Curl.GLOBAL_DEFAULT); try { var conn = DBus.Bus.get (DBus.BusType.SESSION); dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus"); // Try to register service in session bus uint request_name_result = bus.request_name (DBUS_SERVICE, (uint) 0); if (request_name_result == DBus.RequestNameReply.PRIMARY_OWNER) { // Start server var server = new IMDbDownloadServer (); conn.register_object (DBUS_OBJECT, server); server.run (); } else { critical ("Service \"org.maemo.cinaest.IMDb\" already registered. Abort.\n"); } } catch (Error e) { critical ("Oops: %s\n", e.message); } Curl.global_cleanup (); } }