MythTV  0.26-pre
channeldata.cpp
Go to the documentation of this file.
00001 // C++ headers
00002 #include <iostream>
00003 #include <cstdlib>
00004 
00005 // Qt headers
00006 #include <QRegExp>
00007 #include <QDir>
00008 #include <QFile>
00009 
00010 // libmythbase headers
00011 #include "mythdownloadmanager.h"
00012 
00013 // libmyth headers
00014 #include "mythlogging.h"
00015 #include "mythdb.h"
00016 #include "mythmiscutil.h"
00017 
00018 // libmythtv headers
00019 #include "channelutil.h"
00020 #include "frequencytables.h"
00021 #include "cardutil.h"
00022 #include "sourceutil.h"
00023 
00024 // filldata headers
00025 #include "channeldata.h"
00026 #include "fillutil.h"
00027 
00028 static void get_atsc_stuff(QString channum, int sourceid, int freqid,
00029                            int &major, int &minor, long long &freq)
00030 {
00031     major = freqid;
00032     minor = 0;
00033 
00034     int chansep = channum.indexOf(QRegExp("\\D"));
00035     if (chansep < 0)
00036         return;
00037 
00038     major = channum.left(chansep).toInt();
00039     minor = channum.right(channum.length() - (chansep + 1)).toInt();
00040 
00041     freq = get_center_frequency("atsc", "vsb8", "us", freqid);
00042 
00043     // Check if this is connected to an HDTV card.
00044     MSqlQuery query(MSqlQuery::DDCon());
00045     query.prepare(
00046         "SELECT cardtype "
00047         "FROM capturecard, cardinput "
00048         "WHERE cardinput.cardid = capturecard.cardid AND "
00049         "      sourceid         = :SOURCEID");
00050     query.bindValue(":SOURCEID", sourceid);
00051 
00052     if (query.exec() && query.isActive() && query.next() &&
00053         query.value(0).toString() == "HDTV")
00054     {
00055         freq -= 1750000; // convert to visual carrier freq.
00056     }
00057 }
00058 
00059 bool ChannelData::insert_chan(uint sourceid)
00060 {
00061     bool insert_channels = channel_updates;
00062     if (!insert_channels)
00063     {
00064         bool isEncoder, isUnscanable;
00065         bool isCableCard  = SourceUtil::IsCableCardPresent(sourceid);
00066         if (cardtype.isEmpty())
00067         {
00068             isEncoder    = SourceUtil::IsEncoder(sourceid);
00069             isUnscanable = SourceUtil::IsUnscanable(sourceid);
00070         }
00071         else
00072         {
00073             isEncoder    = CardUtil::IsEncoder(cardtype);
00074             isUnscanable = CardUtil::IsUnscanable(cardtype);
00075         }
00076         insert_channels = (isCableCard || isEncoder || isUnscanable) &&
00077                            !remove_new_channels;
00078     }
00079 
00080     return insert_channels;
00081 }
00082 
00083 
00084 unsigned int ChannelData::promptForChannelUpdates(
00085     QList<ChanInfo>::iterator chaninfo, unsigned int chanid)
00086 {
00087     if (chanid == 0)
00088     {
00089         // Default is 0 to allow rapid skipping of many channels,
00090         // in some xmltv outputs there may be over 100 channel, but
00091         // only 10 or so that are available in each area.
00092         chanid = getResponse("Choose a channel ID (positive integer) ", "0")
00093             .toUInt();
00094 
00095         // If we wish to skip this channel, use the default 0 and return.
00096         if (chanid == 0)
00097             return(0);
00098     }
00099 
00100     (*chaninfo).name = getResponse("Choose a channel name (any string, "
00101                                    "long version) ",(*chaninfo).name);
00102     (*chaninfo).callsign = getResponse("Choose a channel callsign (any string, "
00103                                        "short version) ",(*chaninfo).callsign);
00104 
00105     if (channel_preset)
00106     {
00107         (*chaninfo).chanstr = getResponse("Choose a channel preset (0..999) ",
00108                                          (*chaninfo).chanstr);
00109         (*chaninfo).freqid  = getResponse("Choose a frequency id (just like "
00110                                           "xawtv) ",(*chaninfo).freqid);
00111     }
00112     else
00113     {
00114         (*chaninfo).chanstr  = getResponse("Choose a channel number (just like "
00115                                            "xawtv) ",(*chaninfo).chanstr);
00116         (*chaninfo).freqid = (*chaninfo).chanstr;
00117     }
00118 
00119     (*chaninfo).finetune = getResponse("Choose a channel fine tune offset (just"
00120                                        " like xawtv) ",(*chaninfo).finetune);
00121 
00122     (*chaninfo).tvformat = getResponse("Choose a TV format "
00123                                        "(PAL/SECAM/NTSC/ATSC/Default) ",
00124                                        (*chaninfo).tvformat);
00125 
00126     (*chaninfo).iconpath = getResponse("Choose a channel icon image (any path "
00127                                        "name) ",(*chaninfo).iconpath);
00128 
00129     return(chanid);
00130 }
00131 
00132 void ChannelData::handleChannels(int id, QList<ChanInfo> *chanlist)
00133 {
00134     QString fileprefix = SetupIconCacheDirectory();
00135 
00136     QDir::setCurrent(fileprefix);
00137 
00138     fileprefix += "/";
00139 
00140     QList<ChanInfo>::iterator i = chanlist->begin();
00141     for (; i != chanlist->end(); ++i)
00142     {
00143         QString localfile;
00144 
00145         if (!(*i).iconpath.isEmpty())
00146         {
00147             QDir remotefile = QDir((*i).iconpath);
00148             QString filename = remotefile.dirName();
00149 
00150             localfile = fileprefix + filename;
00151             QFile actualfile(localfile);
00152             if (!actualfile.exists() &&
00153                 !GetMythDownloadManager()->download((*i).iconpath, localfile))
00154             {
00155                 LOG(VB_GENERAL, LOG_ERR,
00156                     QString("Failed to fetch icon from '%1'")
00157                         .arg((*i).iconpath));
00158             }
00159         }
00160 
00161         MSqlQuery query(MSqlQuery::InitCon());
00162 
00163         if (!(*i).old_xmltvid.isEmpty())
00164         {
00165             query.prepare(
00166                 "SELECT xmltvid "
00167                 "FROM channel "
00168                 "WHERE xmltvid = :XMLTVID");
00169             query.bindValue(":XMLTVID", (*i).old_xmltvid);
00170 
00171             if (!query.exec())
00172             {
00173                 MythDB::DBError("xmltvid conversion 1", query);
00174             }
00175             else if (query.next())
00176             {
00177                 LOG(VB_GENERAL, LOG_INFO,
00178                     QString("Converting old xmltvid (%1) to new (%2)")
00179                         .arg((*i).old_xmltvid).arg((*i).xmltvid));
00180 
00181                 query.prepare("UPDATE channel "
00182                               "SET xmltvid = :NEWXMLTVID"
00183                               "WHERE xmltvid = :OLDXMLTVID");
00184                 query.bindValue(":NEWXMLTVID", (*i).xmltvid);
00185                 query.bindValue(":OLDXMLTVID", (*i).old_xmltvid);
00186 
00187                 if (!query.exec())
00188                 {
00189                     MythDB::DBError("xmltvid conversion 2", query);
00190                 }
00191             }
00192         }
00193 
00194         query.prepare(
00195             "SELECT chanid,   name, callsign, channum, "
00196             "       finetune, icon, freqid,   tvformat "
00197             "FROM channel "
00198             "WHERE xmltvid  = :XMLTVID AND "
00199             "      sourceid = :SOURCEID");
00200         query.bindValue(":XMLTVID",  (*i).xmltvid);
00201         query.bindValue(":SOURCEID", id);
00202 
00203         if (!query.exec())
00204         {
00205             MythDB::DBError("handleChannels", query);
00206         }
00207         else if (query.next())
00208         {
00209             QString chanid = query.value(0).toString();
00210             if (interactive)
00211             {
00212                 QString name     = query.value(1).toString();
00213                 QString callsign = query.value(2).toString();
00214                 QString chanstr  = query.value(3).toString();
00215                 QString finetune = query.value(4).toString();
00216                 QString icon     = query.value(5).toString();
00217                 QString freqid   = query.value(6).toString();
00218                 QString tvformat = query.value(7).toString();
00219 
00220                 cout << "### " << endl;
00221                 cout << "### Existing channel found" << endl;
00222                 cout << "### " << endl;
00223                 cout << "### xmltvid  = "
00224                      << (*i).xmltvid.toLocal8Bit().constData() << endl;
00225                 cout << "### chanid   = "
00226                      << chanid.toLocal8Bit().constData()       << endl;
00227                 cout << "### name     = "
00228                      << name.toLocal8Bit().constData()         << endl;
00229                 cout << "### callsign = "
00230                      << callsign.toLocal8Bit().constData()     << endl;
00231                 cout << "### channum  = "
00232                      << chanstr.toLocal8Bit().constData()      << endl;
00233                 if (channel_preset)
00234                 {
00235                     cout << "### freqid   = "
00236                          << freqid.toLocal8Bit().constData()   << endl;
00237                 }
00238                 cout << "### finetune = "
00239                      << finetune.toLocal8Bit().constData()     << endl;
00240                 cout << "### tvformat = "
00241                      << tvformat.toLocal8Bit().constData()     << endl;
00242                 cout << "### icon     = "
00243                      << icon.toLocal8Bit().constData()         << endl;
00244                 cout << "### " << endl;
00245 
00246                 (*i).name = name;
00247                 (*i).callsign = callsign;
00248                 (*i).chanstr  = chanstr;
00249                 (*i).finetune = finetune;
00250                 (*i).freqid = freqid;
00251                 (*i).tvformat = tvformat;
00252 
00253                 promptForChannelUpdates(i, chanid.toUInt());
00254 
00255                 if ((*i).callsign.isEmpty())
00256                     (*i).callsign = chanid;
00257 
00258                 if (name     != (*i).name ||
00259                     callsign != (*i).callsign ||
00260                     chanstr  != (*i).chanstr ||
00261                     finetune != (*i).finetune ||
00262                     freqid   != (*i).freqid ||
00263                     icon     != localfile ||
00264                     tvformat != (*i).tvformat)
00265                 {
00266                     MSqlQuery subquery(MSqlQuery::InitCon());
00267                     subquery.prepare("UPDATE channel SET chanid = :CHANID, "
00268                                      "name = :NAME, callsign = :CALLSIGN, "
00269                                      "channum = :CHANNUM, finetune = :FINE, "
00270                                      "icon = :ICON, freqid = :FREQID, "
00271                                      "tvformat = :TVFORMAT "
00272                                      " WHERE xmltvid = :XMLTVID "
00273                                      "AND sourceid = :SOURCEID;");
00274                     subquery.bindValue(":CHANID", chanid);
00275                     subquery.bindValue(":NAME", (*i).name);
00276                     subquery.bindValue(":CALLSIGN", (*i).callsign);
00277                     subquery.bindValue(":CHANNUM", (*i).chanstr);
00278                     subquery.bindValue(":FINE", (*i).finetune.toInt());
00279                     subquery.bindValue(":ICON", localfile);
00280                     subquery.bindValue(":FREQID", (*i).freqid);
00281                     subquery.bindValue(":TVFORMAT", (*i).tvformat);
00282                     subquery.bindValue(":XMLTVID", (*i).xmltvid);
00283                     subquery.bindValue(":SOURCEID", id);
00284 
00285                     if (!subquery.exec())
00286                     {
00287                         MythDB::DBError("update failed", subquery);
00288                     }
00289                     else
00290                     {
00291                         cout << "### " << endl;
00292                         cout << "### Change performed" << endl;
00293                         cout << "### " << endl;
00294                     }
00295                 }
00296                 else
00297                 {
00298                     cout << "### " << endl;
00299                     cout << "### Nothing changed" << endl;
00300                     cout << "### " << endl;
00301                 }
00302             }
00303             else
00304             {
00305                 if (!non_us_updating && !localfile.isEmpty())
00306                 {
00307                     MSqlQuery subquery(MSqlQuery::InitCon());
00308                     subquery.prepare("UPDATE channel SET icon = :ICON WHERE "
00309                                      "chanid = :CHANID;");
00310                     subquery.bindValue(":ICON", localfile);
00311                     subquery.bindValue(":CHANID", chanid);
00312 
00313                     if (!subquery.exec())
00314                         MythDB::DBError("Channel icon change", subquery);
00315                 }
00316             }
00317         }
00318         else if (insert_chan(id)) // Only insert channels for non-scannable sources
00319         {
00320             int major, minor = 0;
00321             long long freq = 0;
00322             get_atsc_stuff((*i).chanstr, id, (*i).freqid.toInt(), major, minor, freq);
00323 
00324             if (interactive && ((minor == 0) || (freq > 0)))
00325             {
00326                 cout << "### " << endl;
00327                 cout << "### New channel found" << endl;
00328                 cout << "### " << endl;
00329                 cout << "### name     = "
00330                      << (*i).name.toLocal8Bit().constData()     << endl;
00331                 cout << "### callsign = "
00332                      << (*i).callsign.toLocal8Bit().constData() << endl;
00333                 cout << "### channum  = "
00334                      << (*i).chanstr.toLocal8Bit().constData()  << endl;
00335                 if (channel_preset)
00336                 {
00337                     cout << "### freqid   = "
00338                          << (*i).freqid.toLocal8Bit().constData() << endl;
00339                 }
00340                 cout << "### finetune = "
00341                      << (*i).finetune.toLocal8Bit().constData() << endl;
00342                 cout << "### tvformat = "
00343                      << (*i).tvformat.toLocal8Bit().constData() << endl;
00344                 cout << "### icon     = "
00345                      << localfile.toLocal8Bit().constData()     << endl;
00346                 cout << "### " << endl;
00347 
00348                 uint chanid = promptForChannelUpdates(i,0);
00349 
00350                 if ((*i).callsign.isEmpty())
00351                     (*i).callsign = QString::number(chanid);
00352 
00353                 int mplexid = 0;
00354                 if ((chanid > 0) && (minor > 0))
00355                     mplexid = ChannelUtil::CreateMultiplex(id,   "atsc",
00356                                                            freq, "8vsb");
00357 
00358                 if (((mplexid > 0) || ((minor == 0) && (chanid > 0))) &&
00359                     ChannelUtil::CreateChannel(
00360                         mplexid,          id,               chanid,
00361                         (*i).callsign,    (*i).name,        (*i).chanstr,
00362                         0 /*service id*/, major,            minor,
00363                         false /*use on air guide*/, false /*hidden*/,
00364                         false /*hidden in guide*/,
00365                         (*i).freqid,      localfile,        (*i).tvformat,
00366                         (*i).xmltvid))
00367                 {
00368                     cout << "### " << endl;
00369                     cout << "### Channel inserted" << endl;
00370                     cout << "### " << endl;
00371                 }
00372                 else
00373                 {
00374                     cout << "### " << endl;
00375                     cout << "### Channel skipped" << endl;
00376                     cout << "### " << endl;
00377                 }
00378             }
00379             else if (!non_us_updating && ((minor == 0) || (freq > 0)))
00380             {
00381                 // We only do this if we are not asked to skip it with the
00382                 // --updating flag.
00383                 int mplexid = 0, chanid = 0;
00384                 if (minor > 0)
00385                 {
00386                     mplexid = ChannelUtil::CreateMultiplex(
00387                         id, "atsc", freq, "8vsb");
00388                 }
00389 
00390                 if ((mplexid > 0) || (minor == 0))
00391                     chanid = ChannelUtil::CreateChanID(id, (*i).chanstr);
00392 
00393                 if ((*i).callsign.isEmpty())
00394                 {
00395                     QStringList words = (*i).name.simplified().toUpper()
00396                         .split(" ");
00397                     QString callsign = "";
00398                     QString w1 = words.size() > 0 ? words[0] : QString();
00399                     QString w2 = words.size() > 1 ? words[1] : QString();
00400                     if (w1.isEmpty())
00401                         callsign = QString::number(chanid);
00402                     else if (w2.isEmpty())
00403                         callsign = words[0].left(5);
00404                     else
00405                     {
00406                         callsign = w1.left(w2.length() == 1 ? 4:3);
00407                         callsign += w2.left(5 - callsign.length());
00408                     }
00409                     (*i).callsign = callsign;
00410                 }
00411 
00412                 if (chanid > 0)
00413                 {
00414                     QString cstr = QString((*i).chanstr);
00415                     if(channel_preset && cstr.isEmpty())
00416                         cstr = QString::number(chanid % 1000);
00417 
00418                     bool retval = ChannelUtil::CreateChannel(
00419                                                      mplexid, id,
00420                                                      chanid,
00421                                                      (*i).callsign,
00422                                                      (*i).name, cstr,
00423                                                      0 /*service id*/,
00424                                                      major, minor,
00425                                                      false /*use on air guide*/,
00426                                                      false /*hidden*/,
00427                                                      false /*hidden in guide*/,
00428                                                      (*i).freqid,
00429                                                      localfile,
00430                                                      (*i).tvformat,
00431                                                      (*i).xmltvid
00432                                                             );
00433                     if (!retval)
00434                         cout << "Channel " << chanid << " creation failed"
00435                              << endl;
00436                 }
00437             }
00438         }
00439     }
00440 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends