gmyth/gmyth/gmyth_epg.c
author renatofilho
Mon Feb 25 17:51:43 2008 +0000 (2008-02-25)
branchtrunk
changeset 925 4a8d56080089
parent 895 gmyth/src/gmyth_epg.c@4bdd0f922b68
child 942 c93bfa74c71f
permissions -rw-r--r--
[svn r934] renamed src dir to gmyth
     1 /**
     2  * GMyth Library
     3  *
     4  * @file gmyth/gmyth_epg.c
     5  * 
     6  * @brief <p> GMythEPG class provides access to the program and channel data
     7  * from the Electronic Program Guide (EPG) of the Mythtv backend.
     8  *
     9  * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
    10  * @author Leonardo Sobral Cunha <leonardo.cunha@indt.org.br>
    11  * 
    12  * This program is free software; you can redistribute it and/or modify
    13  * it under the terms of the GNU Lesser General Public License as published by
    14  * the Free Software Foundation; either version 2 of the License, or
    15  * (at your option) any later version.
    16  *
    17  * This program is distributed in the hope that it will be useful,
    18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    20  * GNU General Public License for more details.
    21  *
    22  * You should have received a copy of the GNU Lesser General Public License
    23  * along with this program; if not, write to the Free Software
    24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    25  */
    26 
    27 #ifdef HAVE_CONFIG_H
    28 #include "config.h"
    29 #endif
    30 
    31 #include <mysql/mysql.h>
    32 #include <stdlib.h>
    33 #include <string.h>
    34 #include <assert.h>
    35 
    36 #include "gmyth_epg.h"
    37 #include "gmyth_programinfo.h"
    38 #include "gmyth_util.h"
    39 #include "gmyth_file_transfer.h"
    40 #include "gmyth_debug.h"
    41 
    42 #define CONNECT_TIMEOUT 6
    43 
    44 static void     gmyth_epg_class_init(GMythEPGClass * klass);
    45 static void     gmyth_epg_init(GMythEPG * object);
    46 
    47 static void     gmyth_epg_dispose(GObject * object);
    48 static void     gmyth_epg_finalize(GObject * object);
    49 
    50 G_DEFINE_TYPE(GMythEPG, gmyth_epg, G_TYPE_OBJECT)
    51     static void     gmyth_epg_class_init(GMythEPGClass * klass)
    52 {
    53     GObjectClass   *gobject_class = G_OBJECT_CLASS(klass);
    54 
    55     gobject_class->dispose = gmyth_epg_dispose;
    56     gobject_class->finalize = gmyth_epg_finalize;
    57 }
    58 
    59 static void
    60 gmyth_epg_init(GMythEPG * gmyth_epg)
    61 {
    62 
    63 }
    64 
    65 static void
    66 gmyth_epg_dispose(GObject * object)
    67 {
    68     GMythEPG       *gmyth_epg = GMYTH_EPG(object);
    69 
    70     if (gmyth_epg->sqlquery != NULL) {
    71         g_object_unref(gmyth_epg->sqlquery);
    72         gmyth_epg->sqlquery = NULL;
    73     }
    74 
    75     G_OBJECT_CLASS(gmyth_epg_parent_class)->dispose(object);
    76 }
    77 
    78 static void
    79 gmyth_epg_finalize(GObject * object)
    80 {
    81     g_signal_handlers_destroy(object);
    82 
    83     G_OBJECT_CLASS(gmyth_epg_parent_class)->finalize(object);
    84 }
    85 
    86 /**
    87  * Creates a new instance of GMythEPG.
    88  * 
    89  * @return a new instance of GMythEPG.
    90  */
    91 GMythEPG       *
    92 gmyth_epg_new(void)
    93 {
    94     GMythEPG       *epg = GMYTH_EPG(g_object_new(GMYTH_EPG_TYPE, NULL));
    95 
    96     return epg;
    97 }
    98 
    99 /** Connects to the Mysql database in the backend. The backend address
   100  * is loaded from the GMythSettings instance.
   101  *
   102  * @param gmyth_epg the GMythEPG instance to be connected.
   103  * @return true if connection was success, false if failed.
   104  */
   105 gboolean
   106 gmyth_epg_connect(GMythEPG * gmyth_epg, GMythBackendInfo * backend_info)
   107 {
   108     g_return_val_if_fail(gmyth_epg != NULL, FALSE);
   109 
   110     if (gmyth_epg->sqlquery == NULL) {
   111         gmyth_debug("[%s] Creating gmyth_query", __FUNCTION__);
   112         gmyth_epg->sqlquery = gmyth_query_new();
   113     }
   114 
   115     if (!gmyth_query_connect_with_timeout(gmyth_epg->sqlquery,
   116                                           backend_info, CONNECT_TIMEOUT)) {
   117         gmyth_debug("[%s] Error while connecting to db", __FUNCTION__);
   118         return FALSE;
   119     }
   120 
   121     gmyth_epg->backend_info = backend_info;
   122     g_object_ref(backend_info);
   123 
   124     return TRUE;
   125 }
   126 
   127 /** Disconnects from the Mysql database in the backend.
   128  *
   129  * @param gmyth_epg the GMythEPG instance to be disconnected
   130  * @return true if disconnection was success, false if failed.
   131  */
   132 gboolean
   133 gmyth_epg_disconnect(GMythEPG * gmyth_epg)
   134 {
   135     g_return_val_if_fail(gmyth_epg != NULL, FALSE);
   136 
   137     if (gmyth_epg->sqlquery != NULL) {
   138         gmyth_query_disconnect(gmyth_epg->sqlquery);
   139         g_object_unref(gmyth_epg->sqlquery);
   140         gmyth_epg->sqlquery = NULL;
   141     }
   142 
   143     if (gmyth_epg->backend_info != NULL) {
   144         g_object_unref(gmyth_epg->backend_info);
   145         gmyth_epg->backend_info = NULL;
   146     }
   147 
   148     return TRUE;
   149 }
   150 
   151 /** Retrieves the available list of channels from the backend Mysql database.
   152  * 
   153  * @param gmyth_epg the GMythEPG instance.
   154  * @param glist_ptr the GSList pointer to be filled with the loaded list address.
   155  * @return The amount of channels retrieved from database,  or -1 if error.
   156  */
   157 gint
   158 gmyth_epg_get_channel_list(GMythEPG * gmyth_epg, GList ** glist_ptr)
   159 {
   160     MYSQL_RES      *msql_res;
   161 
   162     g_return_val_if_fail(gmyth_epg != NULL, -1);
   163 
   164     msql_res = gmyth_query_process_statement(gmyth_epg->sqlquery,
   165                                              "SELECT chanid, channum, name, icon FROM channel;");
   166 
   167     (*glist_ptr) = NULL;
   168 
   169     if (msql_res == NULL) {
   170         gmyth_debug("[%s] msql query returned NULL MYSQL_RES",
   171                     __FUNCTION__);
   172         return -1;
   173     } else {
   174         MYSQL_ROW       row;
   175         GMythChannelInfo *channel_info;
   176 
   177         while ((row = mysql_fetch_row(msql_res)) != NULL) {
   178 
   179             channel_info = g_new0(GMythChannelInfo, 1);
   180             channel_info->channel_ID =
   181                 (gint) g_ascii_strtoull(row[0], NULL, 10);
   182             channel_info->channel_num = g_string_new(row[1]);
   183             channel_info->channel_name = g_string_new(row[2]);
   184             channel_info->channel_icon = g_string_new(row[3]);
   185 #ifdef GMYTH_USE_DEBUG
   186             gmyth_channel_info_print(channel_info);
   187 #endif
   188             (*glist_ptr) = g_list_append((*glist_ptr), channel_info);
   189         }
   190     }
   191     mysql_free_result(msql_res);
   192 
   193     return (!(*glist_ptr)) ? 0 : g_list_length(*glist_ptr);
   194 }
   195 
   196 GMythChannelInfo *
   197 gmyth_epg_get_channel_info(GMythEPG * gmyth_epg, gint channel_id)
   198 {
   199     GMythChannelInfo *channel_info = NULL;
   200     MYSQL_RES      *msql_res;
   201     gchar          *query_str;
   202 
   203     g_return_val_if_fail(gmyth_epg != NULL, NULL);
   204 
   205     query_str =
   206         g_strdup_printf
   207         ("SELECT channum, name, icon FROM channel WHERE chanid=%d;",
   208          channel_id);
   209     msql_res =
   210         gmyth_query_process_statement(gmyth_epg->sqlquery, query_str);
   211 
   212     if (msql_res == NULL) {
   213         gmyth_debug("[%s] msql query returned NULL MYSQL_RES",
   214                     __FUNCTION__);
   215         return NULL;
   216     } else {
   217         MYSQL_ROW       row;
   218 
   219         if ((row = mysql_fetch_row(msql_res)) != NULL) {
   220 
   221             channel_info = g_new0(GMythChannelInfo, 1);
   222             channel_info->channel_ID = channel_id;
   223             channel_info->channel_num = g_string_new(row[0]);
   224             channel_info->channel_name = g_string_new(row[1]);
   225             channel_info->channel_icon = g_string_new(row[2]);
   226 #ifdef GMYTH_USE_DEBUG
   227             gmyth_channel_info_print(channel_info);
   228 #endif
   229         }
   230     }
   231     mysql_free_result(msql_res);
   232 
   233     return channel_info;
   234 }
   235 
   236 /** 
   237  * Retrieves the available list of channels from the backend Mysql database.
   238  * 
   239  * @param gmyth_epg the GMythEPG instance.
   240  * @param proglist the GSList pointer to be filled with the loaded list.
   241  * @param chan_num the channel num on which to search for program.
   242  * @param starttime the start time to search for programs.
   243  * @param endtime the end time to search for programs.
   244  * @return The amount of channels retrieved from database, or -1 if error.
   245  */
   246 gint
   247 gmyth_epg_get_program_list(GMythEPG * gmyth_epg, GList ** proglist,
   248                            const gint chan_num, GTimeVal * starttime,
   249                            GTimeVal * endtime)
   250 {
   251 
   252     gchar          *startts =
   253         gmyth_util_time_to_string_from_time_val(starttime);
   254     gchar          *endts =
   255         gmyth_util_time_to_string_from_time_val(endtime);
   256     MYSQL_ROW       row;
   257     GString        *querystr;
   258 
   259     assert(gmyth_epg);
   260 
   261     querystr =
   262         g_string_new
   263         ("SELECT DISTINCT program.chanid, program.starttime, program.endtime, "
   264          "    program.title, program.subtitle, program.description, "
   265          "    program.category, channel.channum, channel.callsign, "
   266          "    channel.name, program.previouslyshown, channel.commfree, "
   267          "    channel.outputfilters, program.seriesid, program.programid, "
   268          "    program.airdate, program.stars, program.originalairdate, "
   269          "    program.category_type, record.recordid, "
   270          "    oldrecstatus.rectype, oldrecstatus.recstatus, "
   271          "    oldrecstatus.findid "
   272          "FROM program "
   273          "LEFT JOIN channel ON program.chanid = channel.chanid "
   274          "LEFT JOIN record ON "
   275          "    program.chanid = record.chanid AND "
   276          "    DATE (program.starttime) = record.startdate AND "
   277          "    TIME (program.starttime) = record.starttime AND "
   278          "    DATE (program.endtime) = record.enddate AND "
   279          "    TIME (program.endtime) = record.endtime "
   280          "LEFT JOIN oldrecorded AS oldrecstatus ON "
   281          "    program.title = oldrecstatus.title AND "
   282          "    channel.callsign = oldrecstatus.station AND "
   283          "    program.starttime = oldrecstatus.starttime ");
   284 
   285     g_string_append_printf(querystr,
   286                            "WHERE program.chanid = %d "
   287                            "  AND program.endtime >= '%s' "
   288                            "  AND program.starttime <= '%s' "
   289                            "  AND program.manualid = 0 ", chan_num,
   290                            startts, endts);
   291 
   292     if (!g_strrstr(querystr->str, " GROUP BY "))
   293         querystr = g_string_append(querystr,
   294                                    " GROUP BY program.starttime, channel.channum, "
   295                                    "  channel.callsign, program.title ");
   296 
   297     if (!g_strrstr(querystr->str, " LIMIT "))
   298         querystr = g_string_append(querystr, " LIMIT 1000 ");
   299 
   300     MYSQL_RES      *res_set =
   301         gmyth_query_process_statement(gmyth_epg->sqlquery, querystr->str);
   302 
   303     if (res_set == NULL) {
   304         gmyth_debug("[%s] msql query returned NULL MYSQL_RES",
   305                     __FUNCTION__);
   306         return -1;
   307     }
   308 
   309     *proglist = NULL;
   310     while ((row = mysql_fetch_row(res_set)) != NULL) {
   311 
   312         GMythProgramInfo *p = gmyth_program_info_new();
   313 
   314         p->channel_id = (int) g_ascii_strtoull (row[0], NULL, 10);
   315 
   316         p->startts = gmyth_util_string_to_time_val(row[1]);
   317         p->endts = gmyth_util_string_to_time_val(row[2]);
   318 
   319         p->recstartts = g_new0(GTimeVal, 1);
   320         p->recstartts->tv_sec = p->startts->tv_sec;
   321         p->recstartts->tv_usec = p->startts->tv_usec;
   322 
   323         p->recendts = g_new0(GTimeVal, 1);
   324         p->recendts->tv_sec = p->endts->tv_sec;
   325         p->recendts->tv_usec = p->endts->tv_usec;
   326 
   327         p->lastmodified = g_new0(GTimeVal, 1);
   328         p->lastmodified->tv_sec = p->startts->tv_sec;
   329         p->lastmodified->tv_usec = p->startts->tv_usec;
   330 
   331 
   332         p->title = g_string_new(row[3]);
   333         p->subtitle = g_string_new(row[4]);
   334         p->description = g_string_new(row[5]);
   335         p->category = g_string_new(row[6]);
   336         p->chanstr = g_string_new(row[7]);
   337         p->chansign = g_string_new(row[8]);
   338         p->channame = g_string_new(row[9]);
   339         p->repeat = g_ascii_strtoull(row[10], NULL, 10);
   340         p->chancommfree = g_ascii_strtoull(row[11], NULL, 10);
   341         p->chanOutputFilters = g_string_new(row[12]);
   342         p->seriesid = g_string_new(row[13]);
   343         p->program_id = g_string_new(row[14]);
   344         p->year = g_string_new(row[15]);
   345         p->stars = g_ascii_strtod(row[16], NULL);
   346 
   347         if (!row[17] || !strcmp(row[17], "")) {
   348             p->originalAirDate = 0;
   349             p->hasAirDate = FALSE;
   350         } else {
   351             p->originalAirDate = gmyth_util_string_to_time_val(row[17]);
   352             p->hasAirDate = TRUE;
   353         }
   354 
   355         p->catType = g_string_new(row[18]);
   356         if (row[19] != NULL)
   357             p->recordid =  g_ascii_strtoull(row[19], NULL, 10);
   358 
   359         *proglist = g_list_append(*proglist, p);
   360 
   361 #ifdef GMYTH_USE_DEBUG
   362         gmyth_program_info_print(p);
   363 #endif
   364     }
   365 
   366     /*
   367      * deallocate 
   368      */
   369     mysql_free_result(res_set);
   370     g_string_free(querystr, TRUE);
   371 
   372     return g_list_length (*proglist);
   373 }
   374 
   375 gboolean
   376 gmyth_epg_channel_has_icon(GMythEPG * gmyth_epg,
   377                            GMythChannelInfo * channel_info)
   378 {
   379     gboolean        res = FALSE;
   380 
   381     g_return_val_if_fail(gmyth_epg != NULL, FALSE);
   382     g_return_val_if_fail(channel_info != NULL, FALSE);
   383 
   384     if (channel_info->channel_icon != NULL) {
   385         res = gmyth_util_file_exists(gmyth_epg->backend_info,
   386                                      channel_info->channel_icon->str);
   387     }
   388 
   389     return res;
   390 
   391 }
   392 
   393 /**
   394  * 
   395  * @param data the data pointer to be filled with icon binary data. It must be freed by the calling function.
   396  * @return TRUE if success, FALSE if any error happens.
   397  */
   398 gboolean
   399 gmyth_epg_channel_get_icon(GMythEPG * gmyth_epg,
   400                            GMythChannelInfo * channel_info, guint8 ** data,
   401                            guint * length)
   402 {
   403     gboolean res = FALSE;
   404 
   405     g_return_val_if_fail(gmyth_epg != NULL, FALSE);
   406     g_return_val_if_fail(channel_info != NULL, FALSE);
   407 
   408     if (gmyth_epg_channel_has_icon(gmyth_epg, channel_info)) {
   409         GMythFileTransfer *transfer =
   410             gmyth_file_transfer_new(gmyth_epg->backend_info);
   411 
   412         GMythFileReadResult gmyth_res;
   413         GByteArray *icon_data;
   414         guint64 icon_length = 0;
   415 
   416         res = gmyth_file_transfer_open(transfer,
   417                                        channel_info->channel_icon->str);
   418         if (!res) {
   419             gmyth_debug("Channel icon could not be opened");
   420             return FALSE;
   421         }
   422 
   423         icon_length = gmyth_file_transfer_get_filesize(transfer);
   424         if (icon_length <= 0) {
   425             gmyth_debug("Channel icon file size is zero or negative");
   426             return FALSE;
   427         }
   428 
   429         icon_data = g_byte_array_new();
   430         gmyth_res = gmyth_file_transfer_read(transfer,
   431                                              icon_data,
   432                                              icon_length, FALSE);
   433         if (gmyth_res == GMYTH_FILE_READ_EOF) {
   434             *length = icon_length;
   435             *data = icon_data->data;
   436             g_byte_array_free(icon_data, FALSE);
   437             res = TRUE;
   438         } else {
   439             *length = 0;
   440             *data = NULL;
   441             g_byte_array_free(icon_data, TRUE);
   442         }
   443     }
   444 
   445     return res;
   446 }