00001
00002 #include <iostream>
00003 #include <cstdlib>
00004
00005
00006 #include <QRegExp>
00007 #include <QDir>
00008 #include <QFile>
00009
00010
00011 #include "mythdownloadmanager.h"
00012
00013
00014 #include "mythlogging.h"
00015 #include "mythdb.h"
00016 #include "mythmiscutil.h"
00017
00018
00019 #include "channelutil.h"
00020 #include "frequencytables.h"
00021 #include "cardutil.h"
00022 #include "sourceutil.h"
00023
00024
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
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;
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
00090
00091
00092 chanid = getResponse("Choose a channel ID (positive integer) ", "0")
00093 .toUInt();
00094
00095
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))
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 , major, minor,
00363 false , false ,
00364 false ,
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
00382
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 ,
00424 major, minor,
00425 false ,
00426 false ,
00427 false ,
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 }