|
MythTV
0.26-pre
|
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 }
1.7.6.1