[svn r362] Some fixes in the GIOWatcher clean-ups, and changed the API version number.
4 * @file gmyth/gmyth_scheduler.c
6 * @brief <p> The scheduler encapsulates all functions for browsing, scheduling
7 * and modifying the recorded content.
9 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
10 * @author Alexsandro Jose Virginio dos Santos <alexsandro.santos@indt.org.br>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #include <glib/gprintf.h>
37 #include "gmyth_scheduler.h"
38 #include "gmyth_util.h"
39 #include "gmyth_query.h"
40 #include "gmyth_socket.h"
41 #include "gmyth_debug.h"
43 static void gmyth_scheduler_class_init (GMythSchedulerClass *klass);
44 static void gmyth_scheduler_init (GMythScheduler *object);
46 static void gmyth_scheduler_dispose (GObject *object);
47 static void gmyth_scheduler_finalize (GObject *object);
49 static gint get_record_id_from_database (GMythScheduler *scheduler);
50 static void update_backend (GMythScheduler *scheduler, gint record_id);
52 G_DEFINE_TYPE(GMythScheduler, gmyth_scheduler, G_TYPE_OBJECT)
55 gmyth_scheduler_class_init (GMythSchedulerClass *klass)
57 GObjectClass *gobject_class;
59 gobject_class = (GObjectClass *) klass;
61 gobject_class->dispose = gmyth_scheduler_dispose;
62 gobject_class->finalize = gmyth_scheduler_finalize;
66 gmyth_scheduler_init (GMythScheduler *sched)
71 sched->profile = g_string_new("");
75 sched->autoexpire = 0;
76 sched->autotranscode = 0;
77 sched->transcoder = 0;
79 sched->autocommflag = 0;
80 sched->autouserjob1 = 0;
81 sched->autouserjob2 = 0;
82 sched->autouserjob3 = 0;
83 sched->autouserjob4 = 0;
85 sched->startoffset = 0;
87 sched->maxepisodes = 0;
90 sched->recpriority = 0;
97 sched->searchType = g_string_new("");
98 sched->searchForWhat = g_string_new("");
100 sched->msqlquery = gmyth_query_new ();
104 gmyth_scheduler_dispose (GObject *object)
106 GMythScheduler *scheduler = GMYTH_SCHEDULER (object);
108 if (scheduler->backend_info) {
109 g_object_unref (scheduler->backend_info);
110 scheduler->backend_info = NULL;
113 G_OBJECT_CLASS (gmyth_scheduler_parent_class)->dispose (object);
117 gmyth_scheduler_finalize (GObject *object)
119 g_signal_handlers_destroy (object);
121 G_OBJECT_CLASS (gmyth_scheduler_parent_class)->finalize (object);
124 /** Creates a new instance of GMythScheduler.
126 * @return a new instance of GMythScheduler.
129 gmyth_scheduler_new ()
131 GMythScheduler *scheduler =
132 GMYTH_SCHEDULER (g_object_new(GMYTH_SCHEDULER_TYPE, NULL));
138 gmyth_scheduler_connect (GMythScheduler *scheduler, GMythBackendInfo *backend_info)
140 return gmyth_scheduler_connect_with_timeout (scheduler, backend_info, 0);
143 /** Connects to the Mysql database in the backend. The backend address
144 * is loaded from the GMythSettings instance.
146 * @param scheduler the GMythScheduler instance to be connected.
147 * @return true if connection was success, false if failed.
150 gmyth_scheduler_connect_with_timeout (GMythScheduler *scheduler,
151 GMythBackendInfo *backend_info, guint timeout)
154 g_return_val_if_fail (backend_info != NULL, FALSE);
156 g_object_ref (backend_info);
157 scheduler->backend_info = backend_info;
159 if (scheduler->msqlquery == NULL) {
160 g_warning ("[%s] GMythScheduler db initializing", __FUNCTION__);
161 scheduler->msqlquery = gmyth_query_new ();
164 if (!gmyth_query_connect_with_timeout (scheduler->msqlquery,
165 scheduler->backend_info, timeout)) {
166 g_warning ("[%s] Error while connecting to db", __FUNCTION__);
173 /** Disconnects from the Mysql database in the backend.
175 * @param scheduler the GMythScheduler instance to be disconnected
176 * @return true if disconnection was success, false if failed.
179 gmyth_scheduler_disconnect (GMythScheduler *scheduler)
183 if (scheduler->msqlquery != NULL) {
184 gmyth_query_disconnect (scheduler->msqlquery);
185 g_object_unref (scheduler->msqlquery);
191 /** Retrieves from the backend Mysql database the list of recording schedules.
193 * @param scheduler The GMythScheduler instance.
194 * @param schedule_list the GList pointer to be filled with the loaded list of ScheduleInfo items.
195 * @return The amount of schedules retrieved from database, or -1 if error.
198 gmyth_scheduler_get_schedule_list ( GMythScheduler *scheduler, GList **schedule_list)
200 ScheduleInfo *schedule;
202 GString *query_str = g_string_new ("");
203 gchar *date_time = NULL;
207 g_string_printf (query_str,
208 "SELECT recordid,programid,chanid,starttime,startdate,"
209 "endtime,enddate,title,subtitle,description,category FROM record;");
211 if (scheduler->msqlquery == NULL) {
212 g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__);
215 msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str);
217 if (msql_res == NULL) {
218 g_warning ("DB retrieval of schedule list failed");
222 *schedule_list = NULL;
224 while((row = mysql_fetch_row (msql_res)) != NULL) {
225 schedule = g_new0(ScheduleInfo, 1);
227 schedule->record_id = g_ascii_strtoull (row[0], NULL, 10);
228 schedule->program_id = g_ascii_strtoull (row[1], NULL, 10);
229 schedule->channel_id = g_ascii_strtoull (row[2], NULL, 10);
231 /* generate a time_t from a time and a date db field */
232 g_sprintf (date_time, "%sT%s", row[4], row[3]);
234 schedule->start_time = gmyth_util_string_to_time_val (date_time);
236 /* generate a time_t from a time and a date db field */
237 g_sprintf (date_time, "%sT%s", row[6], row[5]);
239 schedule->end_time = gmyth_util_string_to_time_val (date_time);
241 schedule->title = g_string_new (row[7]);
242 schedule->subtitle = g_string_new (row[8]);
243 schedule->description = g_string_new (row[9]);
244 schedule->category = g_string_new (row[10]);
246 (*schedule_list) = g_list_append (*(schedule_list), schedule);
250 mysql_free_result (msql_res);
251 g_string_free(query_str, TRUE);
254 return (*schedule_list == NULL) ? 0 : g_list_length (*schedule_list);
257 /** Retrieves from the backend Mysql database the list of recorded programs.
259 * @param scheduler The GMythScheduler instance.
260 * @param recorded_list the GList pointer to be filled with the loaded RecordInfo items.
261 * @return The amount of recorded retrieved from database, or -1 if error.
264 gmyth_scheduler_get_recorded_list (GMythScheduler *scheduler, GList **recorded_list)
266 RecordedInfo *record;
268 GString *query_str = g_string_new ("");
272 g_string_printf (query_str,
273 "SELECT recordid,programid,chanid,starttime,progstart,"
274 "endtime,progend,title,subtitle,description,category,filesize,basename FROM recorded WHERE recgroup != 'LiveTV'");
276 if (scheduler->msqlquery == NULL) {
277 g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__);
281 msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str);
283 if (msql_res == NULL) {
284 g_warning ("DB retrieval of recording list failed");
288 *recorded_list = NULL;
290 while((row = mysql_fetch_row (msql_res))!=NULL){
291 record = g_new0(RecordedInfo, 1);
293 record->record_id = (guint) g_ascii_strtoull (row[0], NULL, 10);
294 record->program_id = (guint) g_ascii_strtoull (row[1], NULL, 10);
295 record->channel_id = (guint) g_ascii_strtoull (row[2], NULL, 10);
297 record->start_time = gmyth_util_string_to_time_val (row[3]);
298 record->end_time = gmyth_util_string_to_time_val (row[5]);
300 record->title = g_string_new (row[7]);
301 record->subtitle = g_string_new (row[8]);
302 record->description = g_string_new (row[9]);
303 record->category = g_string_new (row[10]);
304 record->filesize = g_ascii_strtoull (row[11], NULL, 10);
305 record->basename = g_string_new (row[12]);
307 *recorded_list = g_list_append (*recorded_list, record);
311 mysql_free_result (msql_res);
312 g_string_free(query_str, TRUE);
314 return (*recorded_list == NULL) ? 0 : g_list_length (*recorded_list);
317 /** Requests the Mysql database in the backend to add a new schedule.
319 * @param scheduler the GMythScheduler instance.
320 * @param schedule_info the ScheduleInfo with recording schedule information
321 * to be added. record_id = -1 to add a new schedule, otherwise this
322 * function will update the schedule in the db
323 * @return gboolean returns FALSE if some error occurs, TRUE otherwise
326 gmyth_scheduler_add_schedule (GMythScheduler *scheduler,
327 ScheduleInfo *schedule_info)
329 //GTimeVal *start_tm;
333 GString *query_str = g_string_new ("");
335 gchar *date_time = NULL;
339 if (scheduler->msqlquery == NULL) {
340 g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__);
344 //TODO: verify if this funtion realy does what it should do!
345 g_string_printf (query_str, "REPLACE INTO record "
346 "(recordid, type, chanid, starttime, "
347 "startdate, endtime, enddate, title,"
348 "profile, recpriority, maxnewest, inactive, "
349 "maxepisodes, autoexpire, startoffset, endoffset, "
350 "recgroup, dupmethod, dupin, station, "
351 "autocommflag, findday, findtime, findid, "
352 "search, autotranscode, transcoder, tsdefault, "
353 "autouserjob1, autouserjob2, autouserjob3, autouserjob4) "
354 " values ( %d, 1, %d, \"%s\"," //recordid, type, chanid, starttime
355 " \"%s\", \"%s\", \"%s\", \"%s\","
356 //startdate, endtime, enddate, title
357 "DEFAULT, 0, 0, 0, " //profile, recpriority, maxnewest, inactive
358 "0, 1, 0, 0, " //maxepisodes, autoexpire, startoffset, endoffset
359 "DEFAULT, 6, 15, %d, " //recgroup, dupmethod, dupin, station
360 "1, %d, \"%s\", %d, " //autocommflag, findday, findtime, findid
361 "5, 0, 29, 1, " //search, autotranscode, transcoder, tsdefault
362 "0, 0, 0, 0 );", //autouserjob1, autouserjob2, autouserjob3, autouserjob4
363 schedule_info->record_id, schedule_info->channel_id,
364 gmyth_util_time_to_string_only_time( schedule_info->start_time ),
365 gmyth_util_time_to_string_only_date( schedule_info->start_time ),
366 gmyth_util_time_to_string_only_time( schedule_info->end_time ),
367 gmyth_util_time_to_string_only_date( schedule_info->end_time ),
368 schedule_info->title->str, //title
369 schedule_info->channel_id,//station
370 (gmyth_util_time_val_to_date( schedule_info->start_time ))->tm_wday, //findday
371 gmyth_util_time_to_string_only_time( schedule_info->start_time ), //findtime
372 (gint)(schedule_info->start_time->tv_sec/60/60/24 + 719528)//findid
375 gmyth_debug ( "Sending query to MySQL = %s.", query_str->str );
377 msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str);
379 /* FIXME: currently no way to detect db error in UPDATE, REPLACES!
380 if (msql_res == NULL) {
381 g_warning ("DB retrieval of recording list failed");
385 /* TODO: verify record_id = -1 semantics */
386 if (schedule_info->record_id <= 0)
387 schedule_info->record_id = get_record_id_from_database(scheduler);
389 /* Notify the backend of changes */
390 update_backend(scheduler, schedule_info->record_id);
392 /* free allocated memory */
393 mysql_free_result (msql_res);
394 g_string_free(query_str, TRUE);
399 /** Requests the Mysql database in the backend to remove an existing schedule.
401 * @param scheduler the GMythScheduler instance.
402 * @param record_id The schedule's record id to be removed
403 * @return gboolean TRUE if success, FALSE if error
406 gmyth_scheduler_delete_schedule (GMythScheduler *scheduler, gint record_id)
410 GString *query_str = g_string_new ("");
414 if (scheduler->msqlquery == NULL) {
415 g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__);
419 //========================================
420 g_string_printf (query_str,
421 "DELETE FROM record WHERE recordid=%d", record_id);
423 msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str);
425 if (msql_res == NULL) {
426 g_warning ("[%s] Error while trying to delete a schedule in the database", __FUNCTION__);
430 update_backend(scheduler, record_id);// Notify the backend of the changes
432 mysql_free_result (msql_res);
433 g_string_free(query_str, TRUE);
438 /** Requests the Mysql database in the backend to remove an existing recorded item.
440 * @param scheduler the GMythScheduler instance.
441 * @param record_id The recorded item id to be removed
442 * @return gboolean TRUE if success, FALSE if error
445 gmyth_scheduler_delete_recorded (GMythScheduler *scheduler, gint record_id)
450 GString *query_str = g_string_new ("");
454 if (scheduler->msqlquery == NULL) {
455 g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__);
459 //========================================
460 g_string_printf (query_str,
461 "DELETE FROM recorded WHERE recordid=%d", record_id);
463 msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str);
465 update_backend(scheduler, record_id);// Notify the backend of the changes
467 mysql_free_result (msql_res);
468 g_string_free(query_str, TRUE);
473 /** Retrieves an existing recorded item information from database. The information
474 * is used to fill the returned GMythProgramInfo.
476 * @param scheduler The GMythScheduler instance.
477 * @param channel The channel associated to the record
478 * @param starttime The record start time
479 * @return A GMythProgramInfo struct with the requested record item
480 * information, or NULL if error.
483 gmyth_scheduler_get_recorded (GMythScheduler *scheduler,
484 GString *channel, GTimeVal* starttime)
487 GMythProgramInfo *proginfo = NULL;
488 GString *query_str = g_string_new("");
489 gchar *time_str = gmyth_util_time_to_string_from_time_val (starttime);
493 if (scheduler->msqlquery == NULL) {
494 g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__);
498 g_string_printf (query_str, "SELECT recorded.chanid,starttime,endtime,title, "
499 "subtitle,description,channel.channum, "
500 "channel.callsign,channel.name,channel.commfree, "
501 "channel.outputfilters,seriesid,programid,filesize, "
502 "lastmodified,stars,previouslyshown,originalairdate, "
503 "hostname,recordid,transcoder,playgroup, "
504 "recorded.recpriority,progstart,progend,basename,recgroup "
507 "ON recorded.chanid = channel.chanid "
508 "WHERE recorded.chanid = \"%s\" "
509 "AND starttime = \"%s\" ;",
510 channel->str, time_str);
512 msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str);
514 if (msql_res /*&& query.size() > 0*/) {
516 MYSQL_ROW msql_row = mysql_fetch_row (msql_res);
519 proginfo = gmyth_program_info_new();
521 proginfo->chanid = g_string_new (msql_row[0]);
522 proginfo->startts = gmyth_util_string_to_time_val (msql_row[23]);
523 proginfo->endts = gmyth_util_string_to_time_val (msql_row[24]);
524 proginfo->recstartts = gmyth_util_string_to_time_val (msql_row[1]);
525 proginfo->recendts = gmyth_util_string_to_time_val (msql_row[2]);
526 proginfo->title = g_string_new (msql_row[3]);
527 proginfo->subtitle = g_string_new (msql_row[4]);
528 proginfo->description = g_string_new (msql_row[5]);
530 proginfo->chanstr = g_string_new (msql_row[6]);
531 proginfo->chansign = g_string_new (msql_row[7]);
532 proginfo->channame = g_string_new (msql_row[0]);
533 proginfo->chancommfree = g_ascii_strtoull (msql_row[9], NULL, 10);
534 proginfo->chanOutputFilters = g_string_new (msql_row[10]);
535 proginfo->seriesid = g_string_new (msql_row[11]);
536 proginfo->programid = g_string_new (msql_row[12]);
537 proginfo->filesize = g_ascii_strtoull (msql_row[13], NULL, 10);
539 proginfo->lastmodified = gmyth_util_string_to_time_val (msql_row[14]);
541 proginfo->stars = g_ascii_strtod (msql_row[15], NULL);
542 proginfo->repeat = g_ascii_strtoull (msql_row[16], NULL, 10);
544 if (msql_row[17] == NULL) {
545 proginfo->originalAirDate = 0;
546 proginfo->hasAirDate = FALSE;
548 proginfo->originalAirDate = gmyth_util_string_to_time_val (msql_row[17]);
549 proginfo->hasAirDate = TRUE;
552 proginfo->hostname = g_string_new (msql_row[18]);
553 proginfo->recordid = g_ascii_strtoull (msql_row[19], NULL, 10);
554 proginfo->transcoder = g_ascii_strtoull (msql_row[20], NULL, 10);
556 //proginfo->spread = -1;
557 //proginfo->programflags = proginfo->getProgramFlags();
559 proginfo->recgroup = g_string_new (msql_row[26]);
560 proginfo->playgroup = g_string_new (msql_row[21]);
561 proginfo->recpriority = g_ascii_strtoull (msql_row[22], NULL, 10);
563 proginfo->pathname = g_string_new (msql_row[25]);
565 gmyth_debug ("One program info loaded from mysql database\n");
569 mysql_free_result (msql_res);
570 g_string_free(query_str, TRUE);
576 /** Retrieves the next record id.
578 * @param scheduler The GMythScheduler instance.
579 * @return gint record_id if success, -1 otherwise
582 get_record_id_from_database (GMythScheduler *scheduler)
588 if (scheduler->msqlquery == NULL) {
589 g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__);
593 record_id = mysql_insert_id (scheduler->msqlquery->conn);
598 /** Notifies the backend of an update in the db.
600 * @param record_id the id of the modified recording.
603 update_backend(GMythScheduler *scheduler, gint record_id)//fixme: put void and discovery record_id inside
606 GMythStringList *strlist = gmyth_string_list_new ();
607 GString *datastr = g_string_new ("RESCHEDULE_RECORDINGS ");
609 g_string_append_printf (datastr, "%d", record_id);
610 gmyth_string_list_append_string (strlist, datastr);
612 socket = gmyth_socket_new ();
613 if (gmyth_socket_connect (socket, scheduler->backend_info->hostname,
614 scheduler->backend_info->port)) {
615 gmyth_socket_sendreceive_stringlist (socket, strlist);
617 g_warning ("[%s] Connection to backend failed!", __FUNCTION__);
620 g_string_free(datastr, TRUE);
621 g_object_unref(strlist);
625 gmyth_scheduler_recorded_info_get_preview (RecordedInfo *info, GByteArray* data)
630 gmyth_scheduler_recorded_info_free (RecordedInfo *info)
632 if (info->title != NULL)
633 g_string_free (info->title, TRUE);
635 if (info->subtitle != NULL)
636 g_string_free (info->subtitle, TRUE);
638 if (info->description != NULL)
639 g_string_free (info->description, TRUE);
641 if (info->category != NULL)
642 g_string_free (info->category, TRUE);
644 if (info->basename != NULL)
645 g_string_free (info->basename, TRUE);
651 gmyth_scheduler_schedule_info_free (ScheduleInfo *info)
653 if (info->title != NULL)
654 g_string_free (info->title, TRUE);
656 if (info->subtitle != NULL)
657 g_string_free (info->subtitle, TRUE);
659 if (info->description != NULL)
660 g_string_free (info->description, TRUE);
662 if (info->category != NULL)
663 g_string_free (info->category, TRUE);