gmyth/src/gmyth_epg.c
author renatofilho
Thu Oct 25 15:28:35 2007 +0100 (2007-10-25)
branchtrunk
changeset 868 d6e8c7ec5fd8
parent 767 372e7c8135b9
child 886 781db4177ba2
permissions -rw-r--r--
[svn r874] fixed retur of funcion programlist
     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, oldrecstatus.recordid, "
   270          "    oldrecstatus.rectype, oldrecstatus.recstatus, "
   271          "    oldrecstatus.findid " "FROM program "
   272          "LEFT JOIN channel ON program.chanid = channel.chanid "
   273          "LEFT JOIN oldrecorded AS oldrecstatus ON "
   274          "    program.title = oldrecstatus.title AND "
   275          "    channel.callsign = oldrecstatus.station AND "
   276          "    program.starttime = oldrecstatus.starttime ");
   277 
   278     g_string_append_printf(querystr,
   279                            "WHERE program.chanid = %d "
   280                            "  AND program.endtime >= '%s' "
   281                            "  AND program.starttime <= '%s' "
   282                            "  AND program.manualid = 0 ", chan_num,
   283                            startts, endts);
   284 
   285     if (!g_strrstr(querystr->str, " GROUP BY "))
   286         querystr = g_string_append(querystr,
   287                                    " GROUP BY program.starttime, channel.channum, "
   288                                    "  channel.callsign, program.title ");
   289 
   290     if (!g_strrstr(querystr->str, " LIMIT "))
   291         querystr = g_string_append(querystr, " LIMIT 1000 ");
   292 
   293     MYSQL_RES      *res_set =
   294         gmyth_query_process_statement(gmyth_epg->sqlquery, querystr->str);
   295 
   296     if (res_set == NULL) {
   297         gmyth_debug("[%s] msql query returned NULL MYSQL_RES",
   298                     __FUNCTION__);
   299         return -1;
   300     }
   301 
   302     *proglist = NULL;
   303     while ((row = mysql_fetch_row(res_set)) != NULL) {
   304 
   305         GMythProgramInfo *p = gmyth_program_info_new();
   306 
   307         p->chanid = g_string_new(row[0]);
   308 
   309         p->startts = gmyth_util_string_to_time_val(row[1]);
   310         p->endts = gmyth_util_string_to_time_val(row[2]);
   311 
   312         p->recstartts = g_new0(GTimeVal, 1);
   313         p->recstartts->tv_sec = p->startts->tv_sec;
   314         p->recstartts->tv_usec = p->startts->tv_usec;
   315 
   316         p->recendts = g_new0(GTimeVal, 1);
   317         p->recendts->tv_sec = p->endts->tv_sec;
   318         p->recendts->tv_usec = p->endts->tv_usec;
   319 
   320         p->lastmodified = g_new0(GTimeVal, 1);
   321         p->lastmodified->tv_sec = p->startts->tv_sec;
   322         p->lastmodified->tv_usec = p->startts->tv_usec;
   323 
   324         p->title = g_string_new(row[3]);
   325         p->subtitle = g_string_new(row[4]);
   326         p->description = g_string_new(row[5]);
   327         p->category = g_string_new(row[6]);
   328         p->chanstr = g_string_new(row[7]);
   329         p->chansign = g_string_new(row[8]);
   330         p->channame = g_string_new(row[9]);
   331         p->repeat = g_ascii_strtoull(row[10], NULL, 10);
   332         p->chancommfree = g_ascii_strtoull(row[11], NULL, 10);
   333         p->chanOutputFilters = g_string_new(row[12]);
   334         p->seriesid = g_string_new(row[13]);
   335         p->programid = g_string_new(row[14]);
   336         p->year = g_string_new(row[15]);
   337         p->stars = g_ascii_strtod(row[16], NULL);
   338 
   339         if (!row[17] || !strcmp(row[17], "")) {
   340             p->originalAirDate = 0;
   341             p->hasAirDate = FALSE;
   342         } else {
   343             p->originalAirDate = gmyth_util_string_to_time_val(row[17]);
   344             p->hasAirDate = TRUE;
   345         }
   346 
   347         p->catType = g_string_new(row[18]);
   348 
   349         *proglist = g_list_append(*proglist, p);
   350 
   351 #ifdef GMYTH_USE_DEBUG
   352         gmyth_program_info_print(p);
   353 #endif
   354     }
   355 
   356     /*
   357      * deallocate 
   358      */
   359     mysql_free_result(res_set);
   360     g_string_free(querystr, TRUE);
   361 
   362     return g_list_length (*proglist);
   363 }
   364 
   365 gboolean
   366 gmyth_epg_channel_has_icon(GMythEPG * gmyth_epg,
   367                            GMythChannelInfo * channel_info)
   368 {
   369     gboolean        res = FALSE;
   370 
   371     g_return_val_if_fail(gmyth_epg != NULL, FALSE);
   372     g_return_val_if_fail(channel_info != NULL, FALSE);
   373 
   374     if (channel_info->channel_icon != NULL) {
   375         res = gmyth_util_file_exists(gmyth_epg->backend_info,
   376                                      channel_info->channel_icon->str);
   377     }
   378 
   379     return res;
   380 
   381 }
   382 
   383 /**
   384  * 
   385  * @param data the data pointer to be filled with icon binary data. It must be freed by the calling function.
   386  * @return TRUE if success, FALSE if any error happens.
   387  */
   388 gboolean
   389 gmyth_epg_channel_get_icon(GMythEPG * gmyth_epg,
   390                            GMythChannelInfo * channel_info, guint8 ** data,
   391                            guint * length)
   392 {
   393     gboolean res = FALSE;
   394 
   395     g_return_val_if_fail(gmyth_epg != NULL, FALSE);
   396     g_return_val_if_fail(channel_info != NULL, FALSE);
   397 
   398     if (gmyth_epg_channel_has_icon(gmyth_epg, channel_info)) {
   399         GMythFileTransfer *transfer =
   400             gmyth_file_transfer_new(gmyth_epg->backend_info);
   401 
   402         GMythFileReadResult gmyth_res;
   403         GByteArray *icon_data;
   404         guint64 icon_length = 0;
   405 
   406         res = gmyth_file_transfer_open(transfer,
   407                                        channel_info->channel_icon->str);
   408         if (!res) {
   409             gmyth_debug("Channel icon could not be opened");
   410             return FALSE;
   411         }
   412 
   413         icon_length = gmyth_file_transfer_get_filesize(transfer);
   414         if (icon_length <= 0) {
   415             gmyth_debug("Channel icon file size is zero or negative");
   416             return FALSE;
   417         }
   418 
   419         icon_data = g_byte_array_new();
   420         gmyth_res = gmyth_file_transfer_read(transfer,
   421                                              icon_data,
   422                                              icon_length, FALSE);
   423         if (gmyth_res == GMYTH_FILE_READ_EOF) {
   424             *length = icon_length;
   425             *data = icon_data->data;
   426             g_byte_array_free(icon_data, FALSE);
   427             res = TRUE;
   428         } else {
   429             *length = 0;
   430             *data = NULL;
   431             g_byte_array_free(icon_data, TRUE);
   432         }
   433     }
   434 
   435     return res;
   436 }