[svn r951] gmyth now is 0.8.1. Added methods epg_is_connected() and scheduler_is_connected()
4 * @file gmyth/gmyth_epg.c
6 * @brief <p> GMythEPG class provides access to the program and channel data
7 * from the Electronic Program Guide (EPG) of the Mythtv backend.
9 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
10 * @author Leonardo Sobral Cunha <leonardo.cunha@indt.org.br>
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.
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.
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
31 #include <mysql/mysql.h>
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"
42 #define CONNECT_TIMEOUT 6
44 static void gmyth_epg_class_init(GMythEPGClass * klass);
45 static void gmyth_epg_init(GMythEPG * object);
47 static void gmyth_epg_dispose(GObject * object);
48 static void gmyth_epg_finalize(GObject * object);
50 G_DEFINE_TYPE(GMythEPG, gmyth_epg, G_TYPE_OBJECT)
51 static void gmyth_epg_class_init(GMythEPGClass * klass)
53 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
55 gobject_class->dispose = gmyth_epg_dispose;
56 gobject_class->finalize = gmyth_epg_finalize;
60 gmyth_epg_init(GMythEPG * gmyth_epg)
66 gmyth_epg_dispose(GObject * object)
68 GMythEPG *gmyth_epg = GMYTH_EPG(object);
70 if (gmyth_epg->sqlquery != NULL) {
71 g_object_unref(gmyth_epg->sqlquery);
72 gmyth_epg->sqlquery = NULL;
75 G_OBJECT_CLASS(gmyth_epg_parent_class)->dispose(object);
79 gmyth_epg_finalize(GObject * object)
81 g_signal_handlers_destroy(object);
83 G_OBJECT_CLASS(gmyth_epg_parent_class)->finalize(object);
87 * Creates a new instance of GMythEPG.
89 * @return a new instance of GMythEPG.
94 GMythEPG *epg = GMYTH_EPG(g_object_new(GMYTH_EPG_TYPE, NULL));
99 /** Connects to the Mysql database in the backend. The backend address
100 * is loaded from the GMythSettings instance.
102 * @param gmyth_epg the GMythEPG instance to be connected.
103 * @return true if connection was success, false if failed.
106 gmyth_epg_connect(GMythEPG * gmyth_epg, GMythBackendInfo * backend_info)
108 g_return_val_if_fail(gmyth_epg != NULL, FALSE);
110 if (gmyth_epg->sqlquery == NULL) {
111 gmyth_debug("[%s] Creating gmyth_query", __FUNCTION__);
112 gmyth_epg->sqlquery = gmyth_query_new();
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__);
121 gmyth_epg->backend_info = backend_info;
122 g_object_ref(backend_info);
128 gmyth_epg_is_connected (GMythEPG *gmyth_epg)
130 g_return_val_if_fail (gmyth_epg != NULL, FALSE);
132 return gmyth_query_is_alive (gmyth_epg->sqlquery);
135 /** Disconnects from the Mysql database in the backend.
137 * @param gmyth_epg the GMythEPG instance to be disconnected
138 * @return true if disconnection was success, false if failed.
141 gmyth_epg_disconnect(GMythEPG * gmyth_epg)
143 g_return_val_if_fail(gmyth_epg != NULL, FALSE);
145 if (gmyth_epg->sqlquery != NULL) {
146 gmyth_query_disconnect(gmyth_epg->sqlquery);
147 g_object_unref(gmyth_epg->sqlquery);
148 gmyth_epg->sqlquery = NULL;
151 if (gmyth_epg->backend_info != NULL) {
152 g_object_unref(gmyth_epg->backend_info);
153 gmyth_epg->backend_info = NULL;
159 /** Retrieves the available list of channels from the backend Mysql database.
161 * @param gmyth_epg the GMythEPG instance.
162 * @param glist_ptr the GSList pointer to be filled with the loaded list address.
163 * @return The amount of channels retrieved from database, or -1 if error.
166 gmyth_epg_get_channel_list(GMythEPG * gmyth_epg, GList ** glist_ptr)
170 g_return_val_if_fail(gmyth_epg != NULL, -1);
172 msql_res = gmyth_query_process_statement(gmyth_epg->sqlquery,
173 "SELECT chanid, channum, name, icon FROM channel;");
177 if (msql_res == NULL) {
178 gmyth_debug("[%s] msql query returned NULL MYSQL_RES",
183 GMythChannelInfo *channel_info;
185 while ((row = mysql_fetch_row(msql_res)) != NULL) {
187 channel_info = g_new0(GMythChannelInfo, 1);
188 channel_info->channel_ID =
189 (gint) g_ascii_strtoull(row[0], NULL, 10);
190 channel_info->channel_num = g_string_new(row[1]);
191 channel_info->channel_name = g_string_new(row[2]);
192 channel_info->channel_icon = g_string_new(row[3]);
193 #ifdef GMYTH_USE_DEBUG
194 gmyth_channel_info_print(channel_info);
196 (*glist_ptr) = g_list_append((*glist_ptr), channel_info);
199 mysql_free_result(msql_res);
201 return (!(*glist_ptr)) ? 0 : g_list_length(*glist_ptr);
205 gmyth_epg_get_channel_info(GMythEPG * gmyth_epg, gint channel_id)
207 GMythChannelInfo *channel_info = NULL;
211 g_return_val_if_fail(gmyth_epg != NULL, NULL);
215 ("SELECT channum, name, icon FROM channel WHERE chanid=%d;",
218 gmyth_query_process_statement(gmyth_epg->sqlquery, query_str);
220 if (msql_res == NULL) {
221 gmyth_debug("[%s] msql query returned NULL MYSQL_RES",
227 if ((row = mysql_fetch_row(msql_res)) != NULL) {
229 channel_info = g_new0(GMythChannelInfo, 1);
230 channel_info->channel_ID = channel_id;
231 channel_info->channel_num = g_string_new(row[0]);
232 channel_info->channel_name = g_string_new(row[1]);
233 channel_info->channel_icon = g_string_new(row[2]);
234 #ifdef GMYTH_USE_DEBUG
235 gmyth_channel_info_print(channel_info);
239 mysql_free_result(msql_res);
245 * Retrieves the available list of channels from the backend Mysql database.
247 * @param gmyth_epg the GMythEPG instance.
248 * @param proglist the GSList pointer to be filled with the loaded list.
249 * @param chan_num the channel num on which to search for program.
250 * @param starttime the start time to search for programs.
251 * @param endtime the end time to search for programs.
252 * @return The amount of channels retrieved from database, or -1 if error.
255 gmyth_epg_get_program_list(GMythEPG * gmyth_epg, GList ** proglist,
256 const gint chan_num, GTimeVal * starttime,
261 gmyth_util_time_to_string_from_time_val(starttime);
263 gmyth_util_time_to_string_from_time_val(endtime);
271 ("SELECT DISTINCT program.chanid, program.starttime, program.endtime, "
272 " program.title, program.subtitle, program.description, "
273 " program.category, channel.channum, channel.callsign, "
274 " channel.name, program.previouslyshown, channel.commfree, "
275 " channel.outputfilters, program.seriesid, program.programid, "
276 " program.airdate, program.stars, program.originalairdate, "
277 " program.category_type, record.recordid, "
278 " oldrecstatus.rectype, oldrecstatus.recstatus, "
279 " oldrecstatus.findid "
281 "LEFT JOIN channel ON program.chanid = channel.chanid "
282 "LEFT JOIN record ON "
283 " program.chanid = record.chanid AND "
284 " DATE (program.starttime) = record.startdate AND "
285 " TIME (program.starttime) = record.starttime AND "
286 " DATE (program.endtime) = record.enddate AND "
287 " TIME (program.endtime) = record.endtime "
288 "LEFT JOIN oldrecorded AS oldrecstatus ON "
289 " program.title = oldrecstatus.title AND "
290 " channel.callsign = oldrecstatus.station AND "
291 " program.starttime = oldrecstatus.starttime ");
293 g_string_append_printf(querystr,
294 "WHERE program.chanid = %d "
295 " AND program.endtime >= '%s' "
296 " AND program.starttime <= '%s' "
297 " AND program.manualid = 0 ", chan_num,
300 if (!g_strrstr(querystr->str, " GROUP BY "))
301 querystr = g_string_append(querystr,
302 " GROUP BY program.starttime, channel.channum, "
303 " channel.callsign, program.title ");
305 if (!g_strrstr(querystr->str, " LIMIT "))
306 querystr = g_string_append(querystr, " LIMIT 1000 ");
309 gmyth_query_process_statement(gmyth_epg->sqlquery, querystr->str);
311 if (res_set == NULL) {
312 gmyth_debug("[%s] msql query returned NULL MYSQL_RES",
318 while ((row = mysql_fetch_row(res_set)) != NULL) {
320 GMythProgramInfo *p = gmyth_program_info_new();
322 p->channel_id = (int) g_ascii_strtoull (row[0], NULL, 10);
324 p->startts = gmyth_util_string_to_time_val(row[1]);
325 p->endts = gmyth_util_string_to_time_val(row[2]);
327 p->recstartts = g_new0(GTimeVal, 1);
328 p->recstartts->tv_sec = p->startts->tv_sec;
329 p->recstartts->tv_usec = p->startts->tv_usec;
331 p->recendts = g_new0(GTimeVal, 1);
332 p->recendts->tv_sec = p->endts->tv_sec;
333 p->recendts->tv_usec = p->endts->tv_usec;
335 p->lastmodified = g_new0(GTimeVal, 1);
336 p->lastmodified->tv_sec = p->startts->tv_sec;
337 p->lastmodified->tv_usec = p->startts->tv_usec;
340 p->title = g_string_new(row[3]);
341 p->subtitle = g_string_new(row[4]);
342 p->description = g_string_new(row[5]);
343 p->category = g_string_new(row[6]);
344 p->chanstr = g_string_new(row[7]);
345 p->chansign = g_string_new(row[8]);
346 p->channame = g_string_new(row[9]);
347 p->repeat = g_ascii_strtoull(row[10], NULL, 10);
348 p->chancommfree = g_ascii_strtoull(row[11], NULL, 10);
349 p->chanOutputFilters = g_string_new(row[12]);
350 p->seriesid = g_string_new(row[13]);
351 p->program_id = g_string_new(row[14]);
352 p->year = g_string_new(row[15]);
353 p->stars = g_ascii_strtod(row[16], NULL);
355 if (!row[17] || !strcmp(row[17], "")) {
356 p->originalAirDate = 0;
357 p->hasAirDate = FALSE;
359 p->originalAirDate = gmyth_util_string_to_time_val(row[17]);
360 p->hasAirDate = TRUE;
363 p->catType = g_string_new(row[18]);
365 p->recordid = g_ascii_strtoull(row[19], NULL, 10);
367 *proglist = g_list_append(*proglist, p);
369 #ifdef GMYTH_USE_DEBUG
370 gmyth_program_info_print(p);
377 mysql_free_result(res_set);
378 g_string_free(querystr, TRUE);
380 return g_list_length (*proglist);
384 gmyth_epg_channel_has_icon(GMythEPG * gmyth_epg,
385 GMythChannelInfo * channel_info)
387 gboolean res = FALSE;
389 g_return_val_if_fail(gmyth_epg != NULL, FALSE);
390 g_return_val_if_fail(channel_info != NULL, FALSE);
392 if (channel_info->channel_icon != NULL) {
393 res = gmyth_util_file_exists(gmyth_epg->backend_info,
394 channel_info->channel_icon->str);
403 * @param data the data pointer to be filled with icon binary data. It must be freed by the calling function.
404 * @return TRUE if success, FALSE if any error happens.
407 gmyth_epg_channel_get_icon(GMythEPG * gmyth_epg,
408 GMythChannelInfo * channel_info, guint8 ** data,
411 gboolean res = FALSE;
413 g_return_val_if_fail(gmyth_epg != NULL, FALSE);
414 g_return_val_if_fail(channel_info != NULL, FALSE);
416 if (gmyth_epg_channel_has_icon(gmyth_epg, channel_info)) {
417 GMythFileTransfer *transfer =
418 gmyth_file_transfer_new(gmyth_epg->backend_info);
420 GMythFileReadResult gmyth_res;
421 GByteArray *icon_data;
422 guint64 icon_length = 0;
424 res = gmyth_file_transfer_open(transfer,
425 channel_info->channel_icon->str);
427 gmyth_debug("Channel icon could not be opened");
431 icon_length = gmyth_file_transfer_get_filesize(transfer);
432 if (icon_length <= 0) {
433 gmyth_debug("Channel icon file size is zero or negative");
437 icon_data = g_byte_array_new();
438 gmyth_res = gmyth_file_transfer_read(transfer,
441 if (gmyth_res == GMYTH_FILE_READ_EOF) {
442 *length = icon_length;
443 *data = icon_data->data;
444 g_byte_array_free(icon_data, FALSE);
449 g_byte_array_free(icon_data, TRUE);