Exemple #1
0
 Source* Station::getSourceByName()
 {
     std::string path(Core::AbstractConfig::prefix);
     path += Core::AbstractConfig::sourcesPath;
     SourceList *sourcelist = new Core::SourceList(path);
     for (int i=0; i<(int)sourcelist->size(); i++){
         if (_sourceName->compare(sourcelist->at(i)->name()) == 0){
             Source* source = new Core::Source(*sourcelist->at(i));
             delete sourcelist;
             return source; 
         }
     }
     return 0;
 }
void build_sources_and_dests(const size_t num_sources_x, const size_t num_sources_y,
	const size_t num_dests_x, const size_t num_dests_y,
	const size_t ts_size, const shyft::timeseries::utctimespan dt,
	const point_timeaxis& time_axis, bool insert_nans, SourceList& sources, DestinationList& dests,bool randomize=false) {
	const double x_min = 0.0; // [m]
	const double x_max = 100000.0; // [m]
	const double y_min = 0.0; // [m]
	const double y_max = 1000000.0; // [m]

	sources.reserve(num_sources_x*num_sources_y);
	dests.reserve(num_dests_x*num_dests_y);
	geo_point pt;
	double lower_bound = 0.0;
	double upper_bound = 10.0;
	std::uniform_real_distribution<double> unif(lower_bound, upper_bound);
	std::default_random_engine re;
    vector<utctime> times;times.reserve(ts_size);
    for (size_t l = 0; l < ts_size; ++l)
        times.emplace_back(l*dt);
    times.emplace_back(shyft::core::max_utctime);
    point_timeaxis dta(times);
    geo_point p0(x_min,y_min,0.0);
    const double max_distance=geo_point::xy_distance(p0,geo_point(x_max,y_max,0.0));
    auto base_temp=[&unif,&re,randomize,&p0,max_distance](geo_point p1)->double {
        if(randomize)
            return unif(re);
        return 10+ 2.0*geo_point::xy_distance(p0,p1)/max_distance;
    };
	for (size_t i = 0; i < num_sources_x; ++i) {
		pt.x = x_min + i*(x_max - x_min) / (num_sources_x - 1);
		for (size_t j = 0; j < num_sources_y; ++j) {
			pt.y = y_min + j*(y_max - y_min) / (num_sources_y - 1);
			pt.z = 500 * std::sin(pt.x / x_max) + std::sin(pt.y / y_max) / 2;
			vector<double> pts; pts.reserve(ts_size);
			double b_t = base_temp(pt);
			for (size_t l = 0; l < ts_size; ++l)
				pts.emplace_back( b_t + pt.z*(0.6 / 100));
			sources.emplace_back(pt, xpts_t(dta,pts));
		}
	}
	for (size_t i = 0; i < num_dests_x; ++i) {
		pt.x = x_min + i*(x_max - x_min) / (num_dests_x - 1);
		for (size_t j = 0; j < num_dests_y; ++j) {
			pt.y = y_min + j*(y_max - y_min) / (num_dests_y - 1);
			pt.z = 500 * (std::sin(pt.x / x_max) + std::sin(pt.y / y_max)) / 2;
			dests.emplace_back(pt, time_axis);
		}
	}
}
Exemple #3
0
// Clear all sources from the monitored sources list
void
XmlRpcDispatch::clear()
{
  if (_inWork)
  {
    _doClear = true;  // Finish reporting current events before clearing
  }
  else
  {
    SourceList sourcesToClose;
    _sources.swap(sourcesToClose);
    for (SourceList::iterator it=sourcesToClose.begin(); it!=sourcesToClose.end(); ++it)
      it->getSource()->close();
  }
}
void build_sources_and_dests(const size_t num_sources_x, const size_t num_sources_y,
	const size_t num_dests_x, const size_t num_dests_y,
	const size_t ts_size, const shyft::timeseries::utctimespan dt,
	const point_timeaxis& time_axis, bool insert_nans, SourceList& sources, DestinationList& dests) {
	const double x_min = 0.0; // [m]
	const double x_max = 100000.0; // [m]
	const double y_min = 0.0; // [m]
	const double y_max = 1000000.0; // [m]

	sources.reserve(num_sources_x*num_sources_y);
	dests.reserve(num_dests_x*num_dests_y);
	geo_point pt;
	double lower_bound = 0.0;
	double upper_bound = 10.0;
	std::uniform_real_distribution<double> unif(lower_bound, upper_bound);
	std::default_random_engine re;
    vector<utctime> times;times.reserve(ts_size);
    for (size_t l = 0; l < ts_size; ++l)
        times.emplace_back(l*dt);
    times.emplace_back(shyft::core::max_utctime);
    point_timeaxis dta(times);
	for (size_t i = 0; i < num_sources_x; ++i) {
		pt.x = x_min + i*(x_max - x_min) / (num_sources_x - 1);
		for (size_t j = 0; j < num_sources_y; ++j) {
			pt.y = y_min + j*(y_max - y_min) / (num_sources_y - 1);
			pt.z = 500 * std::sin(pt.x / x_max) + std::sin(pt.y / y_max) / 2;
			vector<double> pts; pts.reserve(ts_size);
			double b_t = unif(re);
			//std::cout << "Base temp at pos (i,j) = " << i << ", " << j << ") = " << b_t << std::endl;
			for (size_t l = 0; l < ts_size; ++l)
				pts.emplace_back( b_t + pt.z*(0.6 / 100));
			sources.emplace_back(pt, xpts_t(dta,pts));
		}
	}
	for (size_t i = 0; i < num_dests_x; ++i) {
		pt.x = x_min + i*(x_max - x_min) / (num_dests_x - 1);
		for (size_t j = 0; j < num_dests_y; ++j) {
			pt.y = y_min + j*(y_max - y_min) / (num_dests_y - 1);
			pt.z = 500 * (std::sin(pt.x / x_max) + std::sin(pt.y / y_max)) / 2;
			dests.emplace_back(pt, time_axis);
		}
	}
}
Exemple #5
0
/** \fn FillData::Run(SourceList &sourcelist)
 *  \brief Goes through the sourcelist and updates its channels with
 *         program info grabbed with the associated grabber.
 *  \return true if there were no failures
 */
bool FillData::Run(SourceList &sourcelist)
{
    SourceList::iterator it;
    SourceList::iterator it2;

    QString status, querystr;
    MSqlQuery query(MSqlQuery::InitCon());
    QDateTime GuideDataBefore, GuideDataAfter;
    int failures = 0;
    int externally_handled = 0;
    int total_sources = sourcelist.size();
    int source_channels = 0;

    QString sidStr = QString("Updating source #%1 (%2) with grabber %3");

    need_post_grab_proc = false;
    int nonewdata = 0;
    bool has_dd_source = false;

    // find all DataDirect duplicates, so we only data download once.
    for (it = sourcelist.begin(); it != sourcelist.end(); ++it)
    {
        if (!is_grabber_datadirect((*it).xmltvgrabber))
            continue;

        has_dd_source = true;
        for (it2 = sourcelist.begin(); it2 != sourcelist.end(); ++it2)
        {
            if (((*it).id           != (*it2).id)           &&
                ((*it).xmltvgrabber == (*it2).xmltvgrabber) &&
                ((*it).userid       == (*it2).userid)       &&
                ((*it).password     == (*it2).password))
            {
                (*it).dd_dups.push_back((*it2).id);
            }
        }
    }
    if (has_dd_source)
        ddprocessor.CreateTempDirectory();

    for (it = sourcelist.begin(); it != sourcelist.end(); ++it)
    {
        if (!fatalErrors.empty())
            break;

        query.prepare("SELECT MAX(endtime) FROM program p LEFT JOIN channel c "
                      "ON p.chanid=c.chanid WHERE c.sourceid= :SRCID "
                      "AND manualid = 0;");
        query.bindValue(":SRCID", (*it).id);

        if (query.exec() && query.size() > 0)
        {
            query.next();

            if (!query.isNull(0))
                GuideDataBefore = 
                    QDateTime::fromString(query.value(0).toString(),
                                          Qt::ISODate);
        }

        channel_update_run = false;
        endofdata = false;

        QString xmltv_grabber = (*it).xmltvgrabber;

        if (xmltv_grabber == "eitonly")
        {
            LOG(VB_GENERAL, LOG_INFO,
                QString("Source %1 configured to use only the "
                        "broadcasted guide data. Skipping.") .arg((*it).id));

            externally_handled++;
            updateLastRunStart(query);
            updateLastRunEnd(query);
            continue;
        }
        else if (xmltv_grabber.trimmed().isEmpty() ||
                 xmltv_grabber == "/bin/true" ||
                 xmltv_grabber == "none")
        {
            LOG(VB_GENERAL, LOG_INFO, 
                QString("Source %1 configured with no grabber. Nothing to do.")
                    .arg((*it).id));

            externally_handled++;
            updateLastRunStart(query);
            updateLastRunEnd(query);
            continue;
        }

        LOG(VB_GENERAL, LOG_INFO, sidStr.arg((*it).id)
                                  .arg((*it).name)
                                  .arg(xmltv_grabber));

        query.prepare(
            "SELECT COUNT(chanid) FROM channel WHERE sourceid = "
             ":SRCID AND xmltvid != ''");
        query.bindValue(":SRCID", (*it).id);

        if (query.exec() && query.size() > 0)
        {
            query.next();
            source_channels = query.value(0).toInt();
            if (source_channels > 0)
            {
                LOG(VB_GENERAL, LOG_INFO,
                    QString("Found %1 channels for source %2 which use grabber")
                        .arg(source_channels).arg((*it).id));
            }
            else
            {
                LOG(VB_GENERAL, LOG_INFO,
                    QString("No channels are configured to use grabber."));
            }
        }
        else
        {
            source_channels = 0;
            LOG(VB_GENERAL, LOG_INFO,
                QString("Can't get a channel count for source id %1")
                    .arg((*it).id));
        }

        bool hasprefmethod = false;

        if (is_grabber_external(xmltv_grabber))
        {
            uint flags = kMSRunShell | kMSStdOut | kMSBuffered;
            MythSystem grabber_capabilities_proc(xmltv_grabber,
                                                 QStringList("--capabilities"),
                                                 flags);
            grabber_capabilities_proc.Run(25);
            if (grabber_capabilities_proc.Wait() != GENERIC_EXIT_OK)
                LOG(VB_GENERAL, LOG_ERR,
                    QString("%1  --capabilities failed or we timed out waiting."                            " You may need to upgrade your xmltv grabber")
                        .arg(xmltv_grabber));
            else
            {
                QByteArray result = grabber_capabilities_proc.ReadAll();
                QTextStream ostream(result);
                QString capabilities;
                while (!ostream.atEnd())
                {
                    QString capability
                        = ostream.readLine().simplified();

                    if (capability.isEmpty())
                        continue;

                    capabilities += capability + ' ';

                    if (capability == "baseline")
                        (*it).xmltvgrabber_baseline = true;

                    if (capability == "manualconfig")
                        (*it).xmltvgrabber_manualconfig = true;

                    if (capability == "cache")
                        (*it).xmltvgrabber_cache = true;

                    if (capability == "preferredmethod")
                        hasprefmethod = true;
                }
                LOG(VB_GENERAL, LOG_INFO,
                    QString("Grabber has capabilities: %1") .arg(capabilities));
            }
        }

        if (hasprefmethod)
        {
            uint flags = kMSRunShell | kMSStdOut | kMSBuffered;
            MythSystem grabber_method_proc(xmltv_grabber,
                                           QStringList("--preferredmethod"),
                                           flags);
            grabber_method_proc.Run(15);
            if (grabber_method_proc.Wait() != GENERIC_EXIT_OK)
                LOG(VB_GENERAL, LOG_ERR,
                    QString("%1 --preferredmethod failed or we timed out "
                            "waiting. You may need to upgrade your xmltv "
                            "grabber").arg(xmltv_grabber));
            else
            {
                QTextStream ostream(grabber_method_proc.ReadAll());
                (*it).xmltvgrabber_prefmethod =
                                ostream.readLine().simplified();

                LOG(VB_GENERAL, LOG_INFO, QString("Grabber prefers method: %1")
                                    .arg((*it).xmltvgrabber_prefmethod));
            }
        }

        need_post_grab_proc |= !is_grabber_datadirect(xmltv_grabber);

        if (is_grabber_datadirect(xmltv_grabber) && dd_grab_all)
        {
            if (only_update_channels)
                DataDirectUpdateChannels(*it);
            else
            {
                QDate qCurrentDate = QDate::currentDate();
                if (!GrabData(*it, 0, &qCurrentDate))
                    ++failures;
            }
        }
        else if ((*it).xmltvgrabber_prefmethod == "allatonce")
        {
            if (!GrabData(*it, 0))
                ++failures;
        }
        else if ((*it).xmltvgrabber_baseline ||
                 is_grabber_datadirect(xmltv_grabber))
        {

            QDate qCurrentDate = QDate::currentDate();

            // We'll keep grabbing until it returns nothing
            // Max days currently supported is 21
            int grabdays = (is_grabber_datadirect(xmltv_grabber)) ?
                14 : REFRESH_MAX;

            grabdays = (maxDays > 0)          ? maxDays : grabdays;
            grabdays = (only_update_channels) ? 1       : grabdays;

            vector<bool> refresh_request;
            refresh_request.resize(grabdays, refresh_all);
            for (int i = 0; i < refresh_day.size(); i++)
                refresh_request[i] = refresh_day[i];

            if (is_grabber_datadirect(xmltv_grabber) && only_update_channels)
            {
                DataDirectUpdateChannels(*it);
                grabdays = 0;
            }

            for (int i = 0; i < grabdays; i++)
            {
                if (!fatalErrors.empty())
                    break;

                // We need to check and see if the current date has changed
                // since we started in this loop.  If it has, we need to adjust
                // the value of 'i' to compensate for this.
                if (QDate::currentDate() != qCurrentDate)
                {
                    QDate newDate = QDate::currentDate();
                    i += (newDate.daysTo(qCurrentDate));
                    if (i < 0)
                        i = 0;
                    qCurrentDate = newDate;
                }

                QString prevDate(qCurrentDate.addDays(i-1).toString());
                QString currDate(qCurrentDate.addDays(i).toString());

                LOG(VB_GENERAL, LOG_INFO, ""); // add a space between days
                LOG(VB_GENERAL, LOG_INFO, "Checking day @ " +
                    QString("offset %1, date: %2").arg(i).arg(currDate));

                bool download_needed = false;

                if (refresh_request[i])
                {
                    if ( i == 1 )
                    {
                        LOG(VB_GENERAL, LOG_INFO,
                            "Data Refresh always needed for tomorrow");
                    }
                    else
                    {
                        LOG(VB_GENERAL, LOG_INFO,
                            "Data Refresh needed because of user request");
                    }
                    download_needed = true;
                }
                else
                {
                    // Check to see if we already downloaded data for this date.

                    querystr = "SELECT c.chanid, COUNT(p.starttime) "
                               "FROM channel c "
                               "LEFT JOIN program p ON c.chanid = p.chanid "
                               "  AND starttime >= "
                                   "DATE_ADD(DATE_ADD(CURRENT_DATE(), "
                                   "INTERVAL '%1' DAY), INTERVAL '20' HOUR) "
                               "  AND starttime < DATE_ADD(CURRENT_DATE(), "
                                   "INTERVAL '%2' DAY) "
                               "WHERE c.sourceid = %3 AND c.xmltvid != '' "
                               "GROUP BY c.chanid;";

                    if (query.exec(querystr.arg(i-1).arg(i).arg((*it).id)) &&
                        query.isActive())
                    {
                        int prevChanCount = 0;
                        int currentChanCount = 0;
                        int previousDayCount = 0;
                        int currentDayCount = 0;

                        LOG(VB_CHANNEL, LOG_INFO,
                            QString("Checking program counts for day %1")
                                .arg(i-1));

                        while (query.next())
                        {
                            if (query.value(1).toInt() > 0)
                                prevChanCount++;
                            previousDayCount += query.value(1).toInt();

                            LOG(VB_CHANNEL, LOG_INFO,
                                QString("    chanid %1 -> %2 programs")
                                    .arg(query.value(0).toString())
                                    .arg(query.value(1).toInt()));
                        }

                        if (query.exec(querystr.arg(i).arg(i+1).arg((*it).id))
                                && query.isActive())
                        {
                            LOG(VB_CHANNEL, LOG_INFO,
                                QString("Checking program counts for day %1")
                                    .arg(i));
                            while (query.next())
                            {
                                if (query.value(1).toInt() > 0)
                                    currentChanCount++;
                                currentDayCount += query.value(1).toInt();

                                LOG(VB_CHANNEL, LOG_INFO,
                                    QString("    chanid %1 -> %2 programs")
                                                .arg(query.value(0).toString())
                                                .arg(query.value(1).toInt()));
                            }
                        }
                        else
                        {
                            LOG(VB_GENERAL, LOG_INFO,
                                QString("Data Refresh because we are unable to "
                                        "query the data for day %1 to "
                                        "determine if we have enough").arg(i));
                            download_needed = true;
                        }

                        if (currentChanCount < (prevChanCount * 0.90))
                        {
                            LOG(VB_GENERAL, LOG_INFO,
                                QString("Data refresh needed because only %1 "
                                        "out of %2 channels have at least one "
                                        "program listed for day @ offset %3 "
                                        "from 8PM - midnight.  Previous day "
                                        "had %4 channels with data in that "
                                        "time period.")
                                    .arg(currentChanCount).arg(source_channels)
                                    .arg(i).arg(prevChanCount));
                            download_needed = true;
                        }
                        else if (currentDayCount == 0)
                        {
                            LOG(VB_GENERAL, LOG_INFO,
                                QString("Data refresh needed because no data "
                                        "exists for day @ offset %1 from 8PM - "
                                        "midnight.").arg(i));
                            download_needed = true;
                        }
                        else if (previousDayCount == 0)
                        {
                            LOG(VB_GENERAL, LOG_INFO,
                                QString("Data refresh needed because no data "
                                        "exists for day @ offset %1 from 8PM - "
                                        "midnight.  Unable to calculate how "
                                        "much we should have for the current "
                                        "day so a refresh is being forced.")
                                    .arg(i-1));
                            download_needed = true;
                        }
                        else if (currentDayCount < (currentChanCount * 3))
                        {
                            LOG(VB_GENERAL, LOG_INFO,
                                QString("Data Refresh needed because offset "
                                        "day %1 has less than 3 programs "
                                        "per channel for the 8PM - midnight "
                                        "time window for channels that "
                                        "normally have data. "
                                        "We want at least %2 programs, but "
                                        "only found %3")
                                    .arg(i).arg(currentChanCount * 3)
                                    .arg(currentDayCount));
                            download_needed = true;
                        }
                        else if (currentDayCount < (previousDayCount / 2))
                        {
                            LOG(VB_GENERAL, LOG_INFO,
                                QString("Data Refresh needed because offset "
                                        "day %1 has less than half the number "
                                        "of programs as the previous day for "
                                        "the 8PM - midnight time window. "
                                        "We want at least %2 programs, but "
                                        "only found %3").arg(i)
                                    .arg(previousDayCount / 2)
                                    .arg(currentDayCount));
                            download_needed = true;
                        }
                    }
                    else
                    {
                        LOG(VB_GENERAL, LOG_INFO,
                            QString("Data Refresh needed because we are unable "
                                    "to query the data for day @ offset %1 to "
                                    "determine how much we should have for "
                                    "offset day %2.").arg(i-1).arg(i));
                        download_needed = true;
                    }
                }

                if (download_needed)
                {
                    LOG(VB_GENERAL, LOG_NOTICE,
                        QString("Refreshing data for ") + currDate);
                    if (!GrabData(*it, i, &qCurrentDate))
                    {
                        ++failures;
                        if (!fatalErrors.empty() || interrupted)
                        {
                            break;
                        }
                    }

                    if (endofdata)
                    {
                        LOG(VB_GENERAL, LOG_INFO,
                            "Grabber is no longer returning program data, "
                            "finishing");
                        break;
                    }
                }
                else
                {
                    LOG(VB_GENERAL, LOG_NOTICE,
                        QString("Data is already present for ") + currDate +
                        ", skipping");
                }
            }
            if (!fatalErrors.empty())
                break;
        }
        else
        {
            LOG(VB_GENERAL, LOG_ERR,
                QString("Grabbing XMLTV data using ") + xmltv_grabber +
                " is not supported. You may need to upgrade to"
                " the latest version of XMLTV.");
        }

        if (interrupted)
        {
            break;
        }

        query.prepare("SELECT MAX(endtime) FROM program p LEFT JOIN channel c "
                      "ON p.chanid=c.chanid WHERE c.sourceid= :SRCID "
                      "AND manualid = 0;");
        query.bindValue(":SRCID", (*it).id);

        if (query.exec() && query.size() > 0)
        {
            query.next();

            if (!query.isNull(0))
                GuideDataAfter = QDateTime::fromString(
                                     query.value(0).toString(), Qt::ISODate);
        }

        if (GuideDataAfter == GuideDataBefore)
        {
            nonewdata++;
        }
    }

    if (!fatalErrors.empty())
    {
        for (int i = 0; i < fatalErrors.size(); i++)
        {
            LOG(VB_GENERAL, LOG_CRIT, LOC + "Encountered Fatal Error: " +
                    fatalErrors[i]);
        }
        return false;
    }

    if (only_update_channels && !need_post_grab_proc)
        return true;

    if (failures == 0)
    {
        if (nonewdata > 0 &&
            (total_sources != externally_handled))
            status = QString(QObject::tr(
                     "mythfilldatabase ran, but did not insert "
                     "any new data into the Guide for %1 of %2 sources. "
                     "This can indicate a potential grabber failure."))
                     .arg(nonewdata)
                     .arg(total_sources);
        else
            status = QObject::tr("Successful.");

        updateLastRunStatus(query, status);
    }

    return (failures == 0);
}
Exemple #6
0
// Watch current set of sources and process events
void XmlRpcDispatch::work(double timeout_ms, XmlRpcClient *chunkWait)
{
	// Compute end time
	_endTime = (timeout_ms < 0.0) ? -1.0 : (getTime() + timeout_ms/1000.0);
	_doClear = false;
	_inWork = true;

	if (chunkWait)
	{
		setSourceEvents(chunkWait, ReadableEvent | WritableEvent | Exception);
	}

	// Only work while there is something to monitor
	while (_sources.size() > 0)
	{

		// Construct the sets of descriptors we are interested in
		struct pollfd fds[MAX_POLLS];
		nfds_t nfds = 0;

		addToFds (fds, nfds);
		fds[nfds].fd = -1;

		// Check for events
		int nEvents;
		if (timeout_ms < 0.0)
			nEvents = poll(fds, nfds, 0);
		else
		{
			struct timespec tv;
			tv.tv_sec = (int) floor (timeout_ms / 1000.0);
			tv.tv_nsec = (int) (fmod (timeout_ms, 1000.0) * 1000000.0);
			nEvents = ppoll(fds, nfds, &tv, NULL);
		}

		if (nEvents < 0)
		{
			XmlRpcUtil::error("Error in XmlRpcDispatch::work: error in select (%d).", nEvents);
			_inWork = false;
			return;
		}

		checkFds (fds, nfds, chunkWait);

		// Check whether to clear all sources
		if (_doClear)
		{
			SourceList closeList = _sources;
			_sources.clear();
			for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it)
			{
				XmlRpcSource *src = it->getSource();
				src->close();
			}

			_doClear = false;
		}

		// Check whether end time has passed
		if (0 <= _endTime && getTime() > _endTime)
			break;

		// if chunkWait and the connection received chunk..
		if (chunkWait && chunkWait->gotChunk ())
			break;
	}

	_inWork = false;
}
// Watch current set of sources and process events
void
XmlRpcDispatch::work(double timeout)
{
  // Compute end time
  _endTime = (timeout < 0.0) ? -1.0 : (getTime() + timeout);
  _doClear = false;
  _inWork = true;

  // Only work while there is something to monitor
  while (_sources.size() > 0) {

    // Construct the sets of descriptors we are interested in
    fd_set inFd, outFd, excFd;
	  FD_ZERO(&inFd);
	  FD_ZERO(&outFd);
	  FD_ZERO(&excFd);

    int maxFd = -1;     // Not used on windows
    SourceList::iterator it;
    for (it=_sources.begin(); it!=_sources.end(); ++it) {
      int fd = it->getSource()->getfd();
      if (it->getMask() & ReadableEvent) FD_SET(fd, &inFd);
      if (it->getMask() & WritableEvent) FD_SET(fd, &outFd);
      if (it->getMask() & Exception)     FD_SET(fd, &excFd);
      if (it->getMask() && fd > maxFd)   maxFd = fd;
    }

    // Check for events
    int nEvents;
    if (timeout < 0.0)
      nEvents = select(maxFd+1, &inFd, &outFd, &excFd, NULL);
    else 
    {
      struct timeval tv;
      tv.tv_sec = (int)floor(timeout);
      tv.tv_usec = ((int)floor(1000000.0 * (timeout-floor(timeout)))) % 1000000;
      nEvents = select(maxFd+1, &inFd, &outFd, &excFd, &tv);
    }

    if (nEvents < 0)
    {
      XmlRpcUtil::error("Error in XmlRpcDispatch::work: error in select (%d).", nEvents);
      _inWork = false;
      return;
    }

    // Process events
    for (it=_sources.begin(); it != _sources.end(); )
    {
      SourceList::iterator thisIt = it++;
      XmlRpcSource* src = thisIt->getSource();
      int fd = src->getfd();
      unsigned newMask = (unsigned) -1;
      if (fd <= maxFd) {
        // If you select on multiple event types this could be ambiguous
        if (FD_ISSET(fd, &inFd))
          newMask &= src->handleEvent(ReadableEvent);
        if (FD_ISSET(fd, &outFd))
          newMask &= src->handleEvent(WritableEvent);
        if (FD_ISSET(fd, &excFd))
          newMask &= src->handleEvent(Exception);

        if ( ! newMask) {
          _sources.erase(thisIt);  // Stop monitoring this one
          if ( ! src->getKeepOpen())
            src->close();
        } else if (newMask != (unsigned) -1) {
          thisIt->getMask() = newMask;
        }
      }
    }

    // Check whether to clear all sources
    if (_doClear)
    {
      SourceList closeList = _sources;
      _sources.clear();
      for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it) {
	XmlRpcSource *src = it->getSource();
        src->close();
      }

      _doClear = false;
    }

    // Check whether end time has passed
    if (0 <= _endTime && getTime() > _endTime)
      break;
  }

  _inWork = false;
}
Exemple #8
0
int main(int argc, char *argv[])
{
    FillData fill_data;
    int fromfile_id = 1;
    int fromfile_offset = 0;
    QString fromfile_name;
    bool from_file = false;
    bool mark_repeats = true;

    bool usingDataDirect = false;

    bool from_dd_file = false;
    int sourceid = -1;
    QString fromddfile_lineupid;

    MythFillDatabaseCommandLineParser cmdline;
    if (!cmdline.Parse(argc, argv))
    {
        cmdline.PrintHelp();
        return GENERIC_EXIT_INVALID_CMDLINE;
    }

    if (cmdline.toBool("showhelp"))
    {
        cmdline.PrintHelp();
        return GENERIC_EXIT_OK;
    }

    if (cmdline.toBool("showversion"))
    {
        cmdline.PrintVersion();
        return GENERIC_EXIT_OK;
    }

    QCoreApplication a(argc, argv);
    QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHFILLDATABASE);

    myth_nice(19);

    int retval;
    if ((retval = cmdline.ConfigureLogging()) != GENERIC_EXIT_OK)
        return retval;

    if (cmdline.toBool("manual"))
    {
        cout << "###\n";
        cout << "### Running in manual channel configuration mode.\n";
        cout << "### This will ask you questions about every channel.\n";
        cout << "###\n";
        fill_data.chan_data.m_interactive = true;
    }

    if (cmdline.toBool("onlyguide") || cmdline.toBool("update"))
    {
        LOG(VB_GENERAL, LOG_NOTICE,
            "Only updating guide data, channel and icon updates will be ignored");
        fill_data.chan_data.m_guideDataOnly = true;
    }

    if (cmdline.toBool("preset"))
    {
        cout << "###\n";
        cout << "### Running in preset channel configuration mode.\n";
        cout << "### This will assign channel ";
        cout << "preset numbers to every channel.\n";
        cout << "###\n";
        fill_data.chan_data.m_channelPreset = true;
    }

    if (cmdline.toBool("file"))
    {
        // manual file mode
        if (!cmdline.toBool("sourceid") ||
            !cmdline.toBool("xmlfile"))
        {
            cerr << "The --file option must be used in combination" << endl
                 << "with both --sourceid and --xmlfile." << endl;
            return GENERIC_EXIT_INVALID_CMDLINE;
        }

        fromfile_id = cmdline.toInt("sourceid");
        fromfile_name = cmdline.toString("xmlfile");

        LOG(VB_GENERAL, LOG_INFO,
            "Bypassing grabbers, reading directly from file");
        from_file = true;
    }

    if (cmdline.toBool("ddfile"))
    {
        // datadirect file mode
        if (!cmdline.toBool("sourceid") || 
            !cmdline.toBool("offset") ||
            !cmdline.toBool("lineupid") ||
            !cmdline.toBool("xmlfile"))
        {
            cerr << "The --dd-file option must be used in combination" << endl
                 << "with each of --sourceid, --offset, --lineupid," << endl
                 << "and --xmlfile." << endl;
            return GENERIC_EXIT_INVALID_CMDLINE;
        }

        fromfile_id         = cmdline.toInt("sourceid");
        fromfile_offset     = cmdline.toInt("offset");
        fromddfile_lineupid = cmdline.toString("lineupid");
        fromfile_name       = cmdline.toString("xmlfile");

        LOG(VB_GENERAL, LOG_INFO,
            "Bypassing grabbers, reading directly from file");
        from_dd_file = true;
    }

    if (cmdline.toBool("dochannelupdates"))
        fill_data.chan_data.m_channelUpdates = true;
    if (cmdline.toBool("removechannels"))
        fill_data.chan_data.m_removeNewChannels = true;
    if (cmdline.toBool("nofilterchannels"))
        fill_data.chan_data.m_filterNewChannels = false;
    if (!cmdline.GetPassthrough().isEmpty())
        fill_data.graboptions = " " + cmdline.GetPassthrough();
    if (cmdline.toBool("sourceid"))
        sourceid = cmdline.toInt("sourceid");
    if (cmdline.toBool("cardtype"))
    {
        if (!cmdline.toBool("sourceid"))
        {
            cerr << "The --cardtype option must be used in combination" << endl
                 << "with a --sourceid option." << endl;
            return GENERIC_EXIT_INVALID_CMDLINE;
        }

        fill_data.chan_data.m_cardType = cmdline.toString("cardtype")
                                                .trimmed().toUpper();
    }
    if (cmdline.toBool("maxdays") && cmdline.toInt("maxdays") > 0)
    {
        fill_data.maxDays = cmdline.toInt("maxdays");
        if (fill_data.maxDays == 1)
            fill_data.SetRefresh(0, true);
    }

    if (cmdline.toBool("refreshtoday"))
        cmdline.SetValue("refresh",
                cmdline.toStringList("refresh") << "today");
    if (cmdline.toBool("dontrefreshtomorrow"))
        cmdline.SetValue("refresh", 
                cmdline.toStringList("refresh") << "nottomorrow");
    if (cmdline.toBool("refreshsecond"))
        cmdline.SetValue("refresh", 
                cmdline.toStringList("refresh") << "second");
    if (cmdline.toBool("refreshall"))
        cmdline.SetValue("refresh", 
                cmdline.toStringList("refresh") << "all");
    if (cmdline.toBool("refreshday"))
        cmdline.SetValue("refresh",
                cmdline.toStringList("refresh") << 
                                        cmdline.toStringList("refreshday"));

    QStringList sl = cmdline.toStringList("refresh");
    if (!sl.isEmpty())
    {
        QStringList::const_iterator i = sl.constBegin();
        for (; i != sl.constEnd(); ++i)
        {
            QString warn = QString("Invalid entry in --refresh list: %1")
                                .arg(*i);

            bool enable = (*i).contains("not") ? false : true;

            if ((*i).contains("today"))
                fill_data.SetRefresh(0, enable);
            else if ((*i).contains("tomorrow"))
                fill_data.SetRefresh(1, enable);
            else if ((*i).contains("second"))
                fill_data.SetRefresh(2, enable);
            else if ((*i).contains("all"))
                fill_data.SetRefresh(FillData::kRefreshAll, enable);
            else if ((*i).contains("-"))
            {
                bool ok;
                QStringList r = (*i).split("-");

                uint lower = r[0].toUInt(&ok);
                if (!ok)
                {
                    cerr << warn.toLocal8Bit().constData() << endl;
                    return false;
                }

                uint upper = r[1].toUInt(&ok);
                if (!ok)
                {
                    cerr << warn.toLocal8Bit().constData() << endl;
                    return false;
                }

                if (lower > upper)
                {
                    cerr << warn.toLocal8Bit().constData() << endl;
                    return false;
                }

                for (uint j = lower; j <= upper; ++j)
                    fill_data.SetRefresh(j, true);
            }
            else
            {
                bool ok;
                uint day = (*i).toUInt(&ok);
                if (!ok)
                {
                    cerr << warn.toLocal8Bit().constData() << endl;
                    return false;
                }

                fill_data.SetRefresh(day, true);
            }
        }
    }

    if (cmdline.toBool("dontrefreshtba"))
        fill_data.refresh_tba = false;
    if (cmdline.toBool("ddgraball"))
    {
        fill_data.SetRefresh(FillData::kRefreshClear, false);
        fill_data.dd_grab_all = true;
    }
    if (cmdline.toBool("onlychannels"))
        fill_data.only_update_channels = true;

    mark_repeats = cmdline.toBool("markrepeats");

    CleanupGuard callCleanup(cleanup);

#ifndef _WIN32
    QList<int> signallist;
    signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
               << SIGILL;
#if ! CONFIG_DARWIN
    signallist << SIGRTMIN;
#endif
    SignalHandler::Init(signallist);
    signal(SIGHUP, SIG_IGN);
#endif

    gContext = new MythContext(MYTH_BINARY_VERSION);
    if (!gContext->Init(false))
    {
        LOG(VB_GENERAL, LOG_ERR, "Failed to init MythContext, exiting.");
        return GENERIC_EXIT_NO_MYTHCONTEXT;
    }

    setHttpProxy();

    MythTranslation::load("mythfrontend");

    if (!UpgradeTVDatabaseSchema(false))
    {
        LOG(VB_GENERAL, LOG_ERR, "Incorrect database schema");
        return GENERIC_EXIT_DB_OUTOFDATE;
    }

    if (gCoreContext->SafeConnectToMasterServer(true, false))
        LOG(VB_GENERAL, LOG_INFO,
            "Opening blocking connection to master backend");
    else
        LOG(VB_GENERAL, LOG_WARNING,
            "Failed to connect to master backend. MythFillDatabase will "
            "continue running but will be unable to prevent backend from "
            "shutting down, or triggering a reschedule when complete.");

    if (from_file)
    {
        QString status = QObject::tr("currently running.");
        QDateTime GuideDataBefore, GuideDataAfter;

        updateLastRunStart();
        updateLastRunStatus(status);

        MSqlQuery query(MSqlQuery::InitCon());
        query.prepare("SELECT MAX(endtime) FROM program p LEFT JOIN channel c "
                      "ON p.chanid=c.chanid WHERE c.sourceid= :SRCID "
                      "AND manualid = 0 AND c.xmltvid != '';");
        query.bindValue(":SRCID", fromfile_id);

        if (query.exec() && query.next())
        {
            if (!query.isNull(0))
                GuideDataBefore =
                    MythDate::fromString(query.value(0).toString());
        }

        if (!fill_data.GrabDataFromFile(fromfile_id, fromfile_name))
        {
            return GENERIC_EXIT_NOT_OK;
        }

        updateLastRunEnd();

        query.prepare("SELECT MAX(endtime) FROM program p LEFT JOIN channel c "
                      "ON p.chanid=c.chanid WHERE c.sourceid= :SRCID "
                      "AND manualid = 0 AND c.xmltvid != '';");
        query.bindValue(":SRCID", fromfile_id);

        if (query.exec() && query.next())
        {
            if (!query.isNull(0))
                GuideDataAfter =
                    MythDate::fromString(query.value(0).toString());
        }

        if (GuideDataAfter == GuideDataBefore)
            status = QObject::tr("mythfilldatabase ran, but did not insert "
                    "any new data into the Guide.  This can indicate a "
                    "potential problem with the XML file used for the update.");
        else
            status = QObject::tr("Successful.");

        updateLastRunStatus(status);
    }
    else if (from_dd_file)
    {
        fill_data.GrabDataFromDDFile(
            fromfile_id, fromfile_offset, fromfile_name, fromddfile_lineupid);
    }
    else
    {
        SourceList sourcelist;

        MSqlQuery sourcequery(MSqlQuery::InitCon());
        QString where;

        if (sourceid != -1)
        {
            LOG(VB_GENERAL, LOG_INFO,
                QString("Running for sourceid %1 ONLY because --sourceid "
                        "was given on command-line").arg(sourceid));
            where = QString("WHERE sourceid = %1").arg(sourceid);
        }

        QString querystr = QString("SELECT sourceid,name,xmltvgrabber,userid,"
                                   "password,lineupid "
                                   "FROM videosource ") + where +
                                   QString(" ORDER BY sourceid;");

        if (sourcequery.exec(querystr))
        {
             if (sourcequery.size() > 0)
             {
                  while (sourcequery.next())
                  {
                       Source newsource;

                       newsource.id = sourcequery.value(0).toInt();
                       newsource.name = sourcequery.value(1).toString();
                       newsource.xmltvgrabber = sourcequery.value(2).toString();
                       newsource.userid = sourcequery.value(3).toString();
                       newsource.password = sourcequery.value(4).toString();
                       newsource.lineupid = sourcequery.value(5).toString();

                       newsource.xmltvgrabber_baseline = false;
                       newsource.xmltvgrabber_manualconfig = false;
                       newsource.xmltvgrabber_cache = false;
                       newsource.xmltvgrabber_prefmethod = "";

                       sourcelist.push_back(newsource);
                       usingDataDirect |=
                           is_grabber_datadirect(newsource.xmltvgrabber);
                  }
             }
             else
             {
                  LOG(VB_GENERAL, LOG_ERR,
                      "There are no channel sources defined, did you run "
                      "the setup program?");
                  return GENERIC_EXIT_SETUP_ERROR;
             }
        }
        else
        {
             MythDB::DBError("loading channel sources", sourcequery);
             return GENERIC_EXIT_DB_ERROR;
        }

        if (!fill_data.Run(sourcelist))
            LOG(VB_GENERAL, LOG_ERR, "Failed to fetch some program info");
        else
            LOG(VB_GENERAL, LOG_NOTICE, "Data fetching complete.");
    }

    if (fill_data.only_update_channels && !fill_data.need_post_grab_proc)
    {
        return GENERIC_EXIT_OK;
    }

    LOG(VB_GENERAL, LOG_INFO, "Adjusting program database end times.");
    int update_count = ProgramData::fix_end_times();
    if (update_count == -1)
        LOG(VB_GENERAL, LOG_ERR, "fix_end_times failed!");
    else
        LOG(VB_GENERAL, LOG_INFO,
            QString("    %1 replacements made").arg(update_count));

    LOG(VB_GENERAL, LOG_INFO, "Marking generic episodes.");

    MSqlQuery query(MSqlQuery::InitCon());
    query.prepare("UPDATE program SET generic = 1 WHERE "
        "((programid = '' AND subtitle = '' AND description = '') OR "
        " (programid <> '' AND category_type = 'series' AND "
        "  program.programid LIKE '%0000'));");

    if (!query.exec())
        MythDB::DBError("mark generic", query);
    else
        LOG(VB_GENERAL, LOG_INFO,
            QString("    Found %1").arg(query.numRowsAffected()));

    LOG(VB_GENERAL, LOG_INFO, "Extending non-unique programids "
                                "with multiple parts.");

    int found = 0;
    MSqlQuery sel(MSqlQuery::InitCon());
    sel.prepare("SELECT DISTINCT programid, partnumber, parttotal "
                "FROM program WHERE partnumber > 0 AND parttotal > 0 AND "
                "programid LIKE '%0000'");
    if (sel.exec())
    {
        MSqlQuery repl(MSqlQuery::InitCon());
        repl.prepare("UPDATE program SET programid = :NEWID "
                        "WHERE programid = :OLDID AND "
                        "partnumber = :PARTNUM AND "
                        "parttotal = :PARTTOTAL");

        while (sel.next())
        {
            QString orig_programid = sel.value(0).toString();
            QString new_programid = orig_programid.left(10);
            int     partnum, parttotal;
            QString part;

            partnum   = sel.value(1).toInt();
            parttotal = sel.value(2).toInt();

            part.setNum(parttotal);
            new_programid.append(part.rightJustified(2, '0'));
            part.setNum(partnum);
            new_programid.append(part.rightJustified(2, '0'));

            LOG(VB_GENERAL, LOG_INFO,
                QString("    %1 -> %2 (part %3 of %4)")
                    .arg(orig_programid).arg(new_programid)
                    .arg(partnum).arg(parttotal));

            repl.bindValue(":NEWID", new_programid);
            repl.bindValue(":OLDID", orig_programid);
            repl.bindValue(":PARTNUM",   partnum);
            repl.bindValue(":PARTTOTAL", parttotal);
            if (!repl.exec())
            {
                LOG(VB_GENERAL, LOG_INFO,
                    QString("Fudging programid from '%1' to '%2'")
                        .arg(orig_programid)
                        .arg(new_programid));
            }
            else
                found += repl.numRowsAffected();
        }
    }

    LOG(VB_GENERAL, LOG_INFO, QString("    Found %1").arg(found));

    LOG(VB_GENERAL, LOG_INFO, "Fixing missing original airdates.");
    query.prepare("UPDATE program p "
                    "JOIN ( "
                    "  SELECT programid, MAX(originalairdate) maxoad "
                    "  FROM program "
                    "  WHERE programid <> '' AND "
                    "        originalairdate IS NOT NULL "
                    "  GROUP BY programid ) oad "
                    "  ON p.programid = oad.programid "
                    "SET p.originalairdate = oad.maxoad "
                    "WHERE p.originalairdate IS NULL");

    if (query.exec())
        LOG(VB_GENERAL, LOG_INFO,
            QString("    Found %1 with programids")
            .arg(query.numRowsAffected()));

    query.prepare("UPDATE program p "
                    "JOIN ( "
                    "  SELECT title, subtitle, description, "
                    "         MAX(originalairdate) maxoad "
                    "  FROM program "
                    "  WHERE programid = '' AND "
                    "        originalairdate IS NOT NULL "
                    "  GROUP BY title, subtitle, description ) oad "
                    "  ON p.programid = '' AND "
                    "     p.title = oad.title AND "
                    "     p.subtitle = oad.subtitle AND "
                    "     p.description = oad.description "
                    "SET p.originalairdate = oad.maxoad "
                    "WHERE p.originalairdate IS NULL");

    if (query.exec())
        LOG(VB_GENERAL, LOG_INFO,
            QString("    Found %1 without programids")
            .arg(query.numRowsAffected()));

    if (mark_repeats)
    {
        LOG(VB_GENERAL, LOG_INFO, "Marking repeats.");

        int newEpiWindow = gCoreContext->GetNumSetting( "NewEpisodeWindow", 14);

        MSqlQuery query(MSqlQuery::InitCon());
        query.prepare("UPDATE program SET previouslyshown = 1 "
                      "WHERE previouslyshown = 0 "
                      "AND originalairdate is not null "
                      "AND (to_days(starttime) - to_days(originalairdate)) "
                      "    > :NEWWINDOW;");
        query.bindValue(":NEWWINDOW", newEpiWindow);

        if (query.exec())
            LOG(VB_GENERAL, LOG_INFO,
                QString("    Found %1").arg(query.numRowsAffected()));

        LOG(VB_GENERAL, LOG_INFO, "Unmarking new episode rebroadcast repeats.");
        query.prepare("UPDATE program SET previouslyshown = 0 "
                      "WHERE previouslyshown = 1 "
                      "AND originalairdate is not null "
                      "AND (to_days(starttime) - to_days(originalairdate)) "
                      "    <= :NEWWINDOW;");
        query.bindValue(":NEWWINDOW", newEpiWindow);

        if (query.exec())
            LOG(VB_GENERAL, LOG_INFO,
                QString("    Found %1").arg(query.numRowsAffected()));
    }

    // Mark first and last showings
    MSqlQuery updt(MSqlQuery::InitCon());
    updt.prepare("UPDATE program SET first = 0, last = 0;");
    if (!updt.exec())
        MythDB::DBError("Clearing first and last showings", updt);

    LOG(VB_GENERAL, LOG_INFO, "Marking episode first showings.");
    updt.prepare("UPDATE program "
                    "JOIN (SELECT MIN(p.starttime) AS starttime, p.programid "
                    "      FROM program p, channel c "
                    "      WHERE p.programid <> '' "
                    "            AND p.chanid = c.chanid "
                    "            AND c.visible = 1 "
                    "      GROUP BY p.programid "
                    "     ) AS firsts "
                    "ON program.programid = firsts.programid "
                    "  AND program.starttime = firsts.starttime "
                    "SET program.first=1;");
    if (!updt.exec())
        MythDB::DBError("Marking first showings by id", updt);
    found = updt.numRowsAffected();

    updt.prepare("UPDATE program "
                    "JOIN (SELECT MIN(p.starttime) AS starttime, p.title, p.subtitle, "
                    "           LEFT(p.description, 1024) AS partdesc "
                    "      FROM program p, channel c "
                    "      WHERE p.programid = '' "
                    "            AND p.chanid = c.chanid "
                    "            AND c.visible = 1 "
                    "      GROUP BY p.title, p.subtitle, partdesc "
                    "     ) AS firsts "
                    "ON program.starttime = firsts.starttime "
                    "  AND program.title = firsts.title "
                    "  AND program.subtitle = firsts.subtitle "
                    "  AND LEFT(program.description, 1024) = firsts.partdesc "
                    "SET program.first = 1 "
                    "WHERE program.programid = '';");
    if (!updt.exec())
        MythDB::DBError("Marking first showings", updt);
    found += updt.numRowsAffected();
    LOG(VB_GENERAL, LOG_INFO, QString("    Found %1").arg(found));

    LOG(VB_GENERAL, LOG_INFO, "Marking episode last showings.");
    updt.prepare("UPDATE program "
                    "JOIN (SELECT MAX(p.starttime) AS starttime, p.programid "
                    "      FROM program p, channel c "
                    "      WHERE p.programid <> '' "
                    "            AND p.chanid = c.chanid "
                    "            AND c.visible = 1 "
                    "      GROUP BY p.programid "
                    "     ) AS lasts "
                    "ON program.programid = lasts.programid "
                    "  AND program.starttime = lasts.starttime "
                    "SET program.last=1;");
    if (!updt.exec())
        MythDB::DBError("Marking last showings by id", updt);
    found = updt.numRowsAffected();

    updt.prepare("UPDATE program "
                    "JOIN (SELECT MAX(p.starttime) AS starttime, p.title, p.subtitle, "
                    "           LEFT(p.description, 1024) AS partdesc "
                    "      FROM program p, channel c "
                    "      WHERE p.programid = '' "
                    "            AND p.chanid = c.chanid "
                    "            AND c.visible = 1 "
                    "      GROUP BY p.title, p.subtitle, partdesc "
                    "     ) AS lasts "
                    "ON program.starttime = lasts.starttime "
                    "  AND program.title = lasts.title "
                    "  AND program.subtitle = lasts.subtitle "
                    "  AND LEFT(program.description, 1024) = lasts.partdesc "
                    "SET program.last = 1 "
                    "WHERE program.programid = '';");
    if (!updt.exec())
        MythDB::DBError("Marking last showings", updt);
    found += updt.numRowsAffected();
    LOG(VB_GENERAL, LOG_INFO, QString("    Found %1").arg(found));

    if (1) // limit MSqlQuery's lifetime
    {
        MSqlQuery query(MSqlQuery::InitCon());
        query.prepare("SELECT count(previouslyshown) "
                      "FROM program WHERE previouslyshown = 1;");
        if (query.exec() && query.next())
        {
            if (query.value(0).toInt() != 0)
                gCoreContext->SaveSettingOnHost("HaveRepeats", "1", NULL);
            else
                gCoreContext->SaveSettingOnHost("HaveRepeats", "0", NULL);
        }
    }

    if ((usingDataDirect) &&
        (gCoreContext->GetNumSetting("MythFillGrabberSuggestsTime", 1)))
    {
        fill_data.ddprocessor.GrabNextSuggestedTime();
    }

    LOG(VB_GENERAL, LOG_INFO, "\n"
            "===============================================================\n"
            "| Attempting to contact the master backend for rescheduling.  |\n"
            "| If the master is not running, rescheduling will happen when |\n"
            "| the master backend is restarted.                            |\n"
            "===============================================================");

    if (mark_repeats)
        ScheduledRecording::RescheduleMatch(0, 0, 0, QDateTime(),
                                            "MythFillDatabase");

    gCoreContext->SendMessage("CLEAR_SETTINGS_CACHE");

    gCoreContext->SendSystemEvent("MYTHFILLDATABASE_RAN");

    LOG(VB_GENERAL, LOG_NOTICE, "mythfilldatabase run complete.");

    return GENERIC_EXIT_OK;
}
void NITFWriteControl::save(
        SourceList& imageData,
        nitf::IOInterface& outputFile,
        const std::vector<std::string>& schemaPaths)
{

    mWriter.prepareIO(outputFile, mRecord);
    bool doByteSwap;

    int byteSwapping =
        (int) mOptions.getParameter(OPT_BYTE_SWAP,
                                    Parameter((int) ByteSwapping::SWAP_AUTO));

    if (byteSwapping == ByteSwapping::SWAP_AUTO)
    {
        // Have to if its not a BE machine
        doByteSwap = !sys::isBigEndianSystem();
    }
    else
    {
        // Do what they say.  You really shouldnt do this
        // unless you know what you're doing anyway!
        doByteSwap = byteSwapping ? true : false;
    }

    if (mInfos.size() != imageData.size())
    {
        std::ostringstream ostr;
        ostr << "Require " << mInfos.size() << " images, received "
             << imageData.size();
        throw except::Exception(Ctxt(ostr.str()));
    }

    size_t numImages = mInfos.size();

    //! TODO: This section of code (unlike the memory section below)
    //        does not account for blocked writing or J2K compression.
    //        CODA ticket #443 will update support for this.
    for (size_t i = 0; i < numImages; ++i)
    {
        NITFImageInfo* info = mInfos[i];
        std::vector < NITFSegmentInfo > imageSegments
                = info->getImageSegments();
        size_t numIS = imageSegments.size();
        size_t pixelSize = info->getData()->getNumBytesPerPixel();
        size_t numCols = info->getData()->getNumCols();
        size_t numChannels = info->getData()->getNumChannels();

        for (size_t j = 0; j < numIS; ++j)
        {
            NITFSegmentInfo segmentInfo = imageSegments[j];

            mem::SharedPtr< ::nitf::WriteHandler> writeHandler( 
                new StreamWriteHandler (segmentInfo, imageData[i], numCols,
                                        numChannels, pixelSize, doByteSwap));

            mWriter.setImageWriteHandler(info->getStartIndex() + j,
                                         writeHandler);
        }
    }

    addDataAndWrite(schemaPaths);

}
Exemple #10
0
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    FillData fill_data;
    int argpos = 1;
    int fromfile_id = 1;
    int fromfile_offset = 0;
    QString fromfile_name;
    bool from_xawfile = false;
    int fromxawfile_id = 1;
    QString fromxawfile_name;
    bool from_file = false;
    bool mark_repeats = true;

    bool usingDataDirect = false;
    bool grab_data = true;

    bool export_iconmap = false;
    bool import_iconmap = false;
    bool reset_iconmap = false;
    bool reset_iconmap_icons = false;
    QString import_icon_data_filename("iconmap.xml");
    QString export_icon_data_filename("iconmap.xml");

    bool update_icon_data = false;

    bool from_dd_file = false;
    int sourceid = -1;
    QString fromddfile_lineupid;

    QFileInfo finfo(a.argv()[0]);
    QString binname = finfo.baseName();

    myth_nice(19);

    while (argpos < a.argc())
    {
        // The manual and update flags should be mutually exclusive.
        if (!strcmp(a.argv()[argpos], "--manual"))
        {
            cout << "###\n";
            cout << "### Running in manual channel configuration mode.\n";
            cout << "### This will ask you questions about every channel.\n";
            cout << "###\n";
            fill_data.chan_data.interactive = true;
        }
        else if (!strcmp(a.argv()[argpos], "--preset"))
        {
            // For using channel preset values instead of channel numbers.
            cout << "###\n";
            cout << "### Running in preset channel configuration mode.\n";
            cout << "### This will assign channel ";
            cout << "preset numbers to every channel.\n";
            cout << "###\n";
            fill_data.chan_data.channel_preset = true;
        }
        else if (!strcmp(a.argv()[argpos], "--update"))
        {
            // For running non-destructive updates on the database for
            // users in xmltv zones that do not provide channel data.
            fill_data.chan_data.non_us_updating = true;
        }
        else if (!strcmp(a.argv()[argpos], "--file"))
        {
            if (((argpos + 2) >= a.argc()) ||
                !strncmp(a.argv()[argpos + 1], "--", 2) ||
                !strncmp(a.argv()[argpos + 2], "--", 2))
            {
                printf("missing or invalid parameters for --file option\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            if (!fromfile_name.isEmpty())
            {
                printf("only one --file option allowed\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            fromfile_id = atoi(a.argv()[++argpos]);
            fromfile_name = a.argv()[++argpos];

            VERBOSE(VB_GENERAL, "Bypassing grabbers, reading directly from file");
            from_file = true;
        }
        else if (!strcmp(a.argv()[argpos], "--dd-file"))
        {
            if (((argpos + 4) >= a.argc()) ||
                !strncmp(a.argv()[argpos + 1], "--", 2) ||
                !strncmp(a.argv()[argpos + 2], "--", 2) ||
                !strncmp(a.argv()[argpos + 3], "--", 2) ||
                !strncmp(a.argv()[argpos + 4], "--", 2))
            {
                printf("missing or invalid parameters for --dd-file option\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            if (!fromfile_name.isEmpty())
            {
                printf("only one --dd-file option allowed\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            fromfile_id = atoi(a.argv()[++argpos]);
            fromfile_offset = atoi(a.argv()[++argpos]);
            fromddfile_lineupid = a.argv()[++argpos];
            fromfile_name = a.argv()[++argpos];

            VERBOSE(VB_GENERAL, "Bypassing grabbers, reading directly from file");
            from_dd_file = true;
        }
        else if (!strcmp(a.argv()[argpos], "--xawchannels"))
        {
            if (((argpos + 2) >= a.argc()) ||
                !strncmp(a.argv()[argpos + 1], "--", 2) ||
                !strncmp(a.argv()[argpos + 2], "--", 2))
            {
                printf("missing or invalid parameters for --xawchannels option\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            if (!fromxawfile_name.isEmpty())
            {
                printf("only one --xawchannels option allowed\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            fromxawfile_id = atoi(a.argv()[++argpos]);
            fromxawfile_name = a.argv()[++argpos];

            VERBOSE(VB_GENERAL, "Reading channels from xawtv configfile");
            from_xawfile = true;
        }
        else if (!strcmp(a.argv()[argpos], "--do-channel-updates"))
        {
            fill_data.chan_data.channel_updates = true;
        }
        else if (!strcmp(a.argv()[argpos], "--remove-new-channels"))
        {
            fill_data.chan_data.remove_new_channels = true;
        }
        else if (!strcmp(a.argv()[argpos], "--do-not-filter-new-channels"))
        {
            fill_data.chan_data.filter_new_channels = false;
        }
        else if (!strcmp(a.argv()[argpos], "--graboptions"))
        {
            if (((argpos + 1) >= a.argc()))
            {
                printf("missing parameter for --graboptions option\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            fill_data.graboptions = QString(" ") + QString(a.argv()[++argpos]);
        }
        else if (!strcmp(a.argv()[argpos], "--sourceid"))
        {
            if (((argpos + 1) >= a.argc()))
            {
                printf("missing parameter for --sourceid option\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            sourceid = QString(a.argv()[++argpos]).toInt();
        }
        else if (!strcmp(a.argv()[argpos], "--cardtype"))
        {
            if (!sourceid)
            {
                printf("--cardtype option must follow a --sourceid option\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            if (((argpos + 1) >= a.argc()))
            {
                printf("missing parameter for --cardtype option\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            fill_data.chan_data.cardtype =
                QString(a.argv()[++argpos]).trimmed().toUpper();
        }
        else if (!strcmp(a.argv()[argpos], "--max-days"))
        {
            if (((argpos + 1) >= a.argc()))
            {
                printf("missing parameter for --max-days option\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            fill_data.maxDays = QString(a.argv()[++argpos]).toUInt();

            if (fill_data.maxDays < 1)
            {
                printf("ignoring invalid parameter for --max-days\n");
                fill_data.maxDays = 0;
            }
            else if (fill_data.maxDays == 1)
            {
                fill_data.SetRefresh(0, true);
            }
        }
        else if (!strcmp(a.argv()[argpos], "--refresh-today"))
        {
            fill_data.SetRefresh(0, true);
        }
        else if (!strcmp(a.argv()[argpos], "--dont-refresh-tomorrow"))
        {
            fill_data.SetRefresh(1, false);
        }
        else if (!strcmp(a.argv()[argpos], "--refresh-second"))
        {
            fill_data.SetRefresh(2, true);
        }
        else if (!strcmp(a.argv()[argpos], "--refresh-all"))
        {
            fill_data.SetRefresh(FillData::kRefreshAll, true);
        }
        else if (!strcmp(a.argv()[argpos], "--refresh-day"))
        {
            if (((argpos + 1) >= a.argc()))
            {
                printf("missing parameter for --refresh-day option\n");
                return FILLDB_EXIT_INVALID_CMDLINE;
            }

            bool ok = true;
            uint day = QString(a.argv()[++argpos]).toUInt(&ok);

            if (!ok)
            {
                printf("ignoring invalid parameter for --refresh-day\n");
            }
            else
            {
                fill_data.SetRefresh(day, true);
            }
        }
        else if (!strcmp(a.argv()[argpos], "--dont-refresh-tba"))
        {
            fill_data.refresh_tba = false;
        }
        else if (!strcmp(a.argv()[argpos], "--only-update-channels"))
        {
            fill_data.only_update_channels = true;
        }
        else if (!strcmp(a.argv()[argpos],"-v") ||
                 !strcmp(a.argv()[argpos],"--verbose"))
        {
            if (a.argc()-1 > argpos)
            {
                if (parse_verbose_arg(a.argv()[argpos+1]) ==
                        GENERIC_EXIT_INVALID_CMDLINE)
                    return GENERIC_EXIT_INVALID_CMDLINE;

                ++argpos;
            }
            else
            {
                cerr << "Missing argument to -v/--verbose option\n";
                return GENERIC_EXIT_INVALID_CMDLINE;
            }
        }
        else if (!strcmp(a.argv()[argpos], "--dd-grab-all"))
        {
            fill_data.SetRefresh(FillData::kRefreshClear, false);
            fill_data.dd_grab_all = true;
        }
        else if (!strcmp(a.argv()[argpos], "--quiet"))
        {
            print_verbose_messages = VB_NONE;
        }
        else if (!strcmp(a.argv()[argpos], "--mark-repeats"))
        {
             mark_repeats = true;
        }
        else if (!strcmp(a.argv()[argpos], "--nomark-repeats"))
        {
            mark_repeats = false;
        }
        else if (!strcmp(a.argv()[argpos], "--export-icon-map"))
        {
            export_iconmap = true;
            grab_data = false;

            if ((argpos + 1) >= a.argc() ||
                    !strncmp(a.argv()[argpos + 1], "--", 2))
            {
                if (!isatty(fileno(stdout)))
                {
                    export_icon_data_filename = '-';
                }
            }
            else
            {
                export_icon_data_filename = a.argv()[++argpos];
            }
        }
        else if (!strcmp(a.argv()[argpos], "--import-icon-map"))
        {
            import_iconmap = true;
            grab_data = false;

            if ((argpos + 1) >= a.argc() ||
                    !strncmp(a.argv()[argpos + 1], "--", 2))
            {
                if (!isatty(fileno(stdin)))
                {
                    import_icon_data_filename = '-';
                }
            }
            else
            {
                import_icon_data_filename = a.argv()[++argpos];
            }
        }
        else if (!strcmp(a.argv()[argpos], "--update-icon-map"))
        {
            update_icon_data = true;
            grab_data = false;
        }
        else if (!strcmp(a.argv()[argpos], "--reset-icon-map"))
        {
            reset_iconmap = true;
            grab_data = false;

            if ((argpos + 1) < a.argc() &&
                    strncmp(a.argv()[argpos + 1], "--", 2))
            {
                ++argpos;
                if (QString(a.argv()[argpos]) == "all")
                {
                    reset_iconmap_icons = true;
                }
                else
                {
                    cerr << "Unknown icon group '" << a.argv()[argpos]
                            << "' for --reset-icon-map option" << endl;
                    return FILLDB_EXIT_UNKNOWN_ICON_GROUP;
                }
            }
        }
        else if (!strcmp(a.argv()[argpos], "-h") ||
                 !strcmp(a.argv()[argpos], "--help"))
        {
            cout << "usage:\n";
            cout << "--manual\n";
            cout << "   Run in manual channel configuration mode\n";
            cout << "   This will ask you questions about every channel\n";
            cout << "\n";
            cout << "--update\n";
            cout << "   For running non-destructive updates on the database for\n";
            cout << "   users in xmltv zones that do not provide channel data\n";
            cout << "   Stops the addition of new channels and the changing of channel icons.\n";
            cout << "\n";
            cout << "--preset\n";
            cout << "   Use it in case that you want to assign a preset number for\n";
            cout << "   each channel, useful for non US countries where people\n";
            cout << "   are used to assigning a sequenced number for each channel, i.e.:\n";
            cout << "   1->TVE1(S41), 2->La 2(SE18), 3->TV3(21), 4->Canal 33(60)...\n";
            cout << "\n";
            cout << "--file <sourceid> <xmlfile>\n";
            cout << "   Bypass the grabbers and read data directly from a file\n";
            cout << "   <sourceid> = number of the video source to use with this file\n";
            cout << "   <xmlfile>  = file to read\n";
            cout << "\n";
            cout << "--dd-file <sourceid> <offset> <lineupid> <xmlfile>\n";
            cout << "   <sourceid> = number of the video source to use with this file\n";
            cout << "   <offset>   = days from today that xmlfile defines\n";
            cout << "                (-1 means to replace all data, up to 10 days)\n";
            cout << "   <lineupid> = the lineup id\n";
            cout << "   <xmlfile>  = file to read\n";
            cout << "\n";
            cout << "--xawchannels <sourceid> <xawtvrcfile>\n";
            cout << "   (--manual flag works in combination with this)\n";
            cout << "   Read channels as defined in xawtvrc file given\n";
            cout << "   <sourceid>    = cardinput\n";
            cout << "   <xawtvrcfile> = file to read\n";
            cout << "\n";
            cout << "--do-channel-updates\n";
            cout << "   When using DataDirect, ask mythfilldatabase to\n";
            cout << "   overwrite channel names, frequencies, etc. with the\n";
            cout << "   values available from the data source. This will \n";
            cout << "   override custom channel names, which is why it is\n";
            cout << "   off by default.\n";
            cout << "\n";
            cout << "--remove-new-channels\n";
            cout << "   When using DataDirect, ask mythfilldatabase to\n";
            cout << "   remove new channels (those not in the database)\n";
            cout << "   from the DataDirect lineup.  These channels are\n";
            cout << "   removed from the lineup as if you had done so\n";
            cout << "   via the DataDirect website's Lineup Wizard, but\n";
            cout << "   may be re-added manually and incorporated into\n";
            cout << "   MythTV by running mythfilldatabase without this\n";
            cout << "   option.  New channels are automatically removed\n";
            cout << "   for DVB and HDTV sources that use DataDirect.\n";
            cout << "\n";
            cout << "--do-not-filter-new-channels\n";
            cout << "   Normally MythTV tries to avoid adding ATSC channels\n";
            cout << "   to NTSC channel lineups. This option restores the\n";
            cout << "   behaviour of adding every channel in the downloaded\n";
            cout << "   channel lineup to MythTV's lineup, in case MythTV's\n";
            cout << "   smarts fail you.\n";
            cout << "\n";
            cout << "--graboptions <\"options\">\n";
            cout << "   Pass options to grabber. Do NOT use unless you know\n";
            cout << "   what you are doing. Mythfilldatabase will\n";
            cout << "   automatically use the correct options for xmltv\n";
            cout << "   compliant grabbers.\n";
            cout << "\n";
            cout << "--sourceid <number>\n";
            cout << "   Only refresh data for sourceid given\n";
            cout << "\n";
            cout << "--max-days <number>\n";
            cout << "   Force the maximum number of days, counting today,\n";
            cout << "   for the grabber to check for future listings\n";
            cout << "--only-update-channels\n";
            cout << "   Get as little listings data as possible to update channels\n";
            cout << "--refresh-today\n";
            cout << "--refresh-second\n";
            cout << "--refresh-all\n";
            cout << "--refresh-day <number>";
            cout << "   (Only valid for selected grabbers: e.g. DataDirect)\n";
            cout << "   Force a refresh today, two days, every day, or a specific day from now,\n";
            cout << "   to catch the latest changes.  --refresh-all will update every day except\n";
            cout << "   the current day. To refresh today and all following days, XMLTV users\n";
            cout << "   should combine --refresh-today and --refresh-all.  Schedules Direct/\n";
            cout << "   DataDirect users should use --dd-grab-all.\n";
            cout << "--dont-refresh-tomorrow\n";
            cout << "   Tomorrow will always be refreshed unless this argument is used\n";
            cout << "--dont-refresh-tba\n";
            cout << "   \"To be announced\" programs will always be refreshed \n";
            cout << "   unless this argument is used\n";
            cout << "\n";
            cout << "--dd-grab-all\n";
            cout << "   The DataDirect grabber will grab all available data\n";
            cout << "   in a single pull. This will ensure you always have\n";
            cout << "   the most up-to-date data, but requires significantly\n";
            cout << "   more CPU and RAM. It is not expected to work on all\n";
            cout << "   backend systems and with all lineups, and may\n";
            cout << "   interfere with recording due to resource starvation.\n";
            cout << "\n";
            cout << "--export-icon-map [<filename>]\n";
            cout << "   Exports your current icon map to <filename> (default: "
                 << export_icon_data_filename.toLocal8Bit().constData()
                 << ")\n";
            cout << "--import-icon-map [<filename>]\n";
            cout << "   Imports an icon map from <filename> (default: "
                 << import_icon_data_filename.toLocal8Bit().constData()
                 << ")\n";
            cout << "--update-icon-map\n";
            cout << "   Updates icon map icons only\n";
            cout << "--reset-icon-map [all]\n";
            cout << "   Resets your icon map (pass all to reset channel icons as well)\n";
            cout << "\n";
            cout << "--mark-repeats\n";
            cout << "   Marks any programs with a OriginalAirDate earlier\n";
            cout << "   than their start date as a repeat\n";
            cout << "\n";
            cout << "-v or --verbose debug-level\n";
            cout << "   Use '-v help' for level info\n";
            cout << "\n";

            cout << "--help\n";
            cout << "   This text\n";
            cout << "\n";
            cout << "\n";
            cout << "  --manual and --update cannot be used together.\n";
            cout << "\n";
            return FILLDB_EXIT_INVALID_CMDLINE;
        }
        else if (!strcmp(a.argv()[argpos], "--no-delete"))
        {
            cerr << "Deprecated option '" << a.argv()[argpos] << "'" << endl;
        }
#ifdef Q_WS_MACX
        else if (!strncmp(argv[argpos],"-psn_",5))
        {
            cerr << "Ignoring Process Serial Number from command line\n";
        }
#endif
        else
        {
            fprintf(stderr, "illegal option: '%s' (use --help)\n",
                    a.argv()[argpos]);
            return FILLDB_EXIT_INVALID_CMDLINE;
        }

        ++argpos;
    }

    CleanupGuard callCleanup(cleanup);

    gContext = new MythContext(MYTH_BINARY_VERSION);
    if (!gContext->Init(false))
    {
        VERBOSE(VB_IMPORTANT, "Failed to init MythContext, exiting.");
        return FILLDB_EXIT_NO_MYTHCONTEXT;
    }

    gCoreContext->SetAppName(binname);

    MythTranslation::load("mythfrontend");

    if (!UpgradeTVDatabaseSchema(false))
    {
        VERBOSE(VB_IMPORTANT, "Incorrect database schema");
        return GENERIC_EXIT_DB_OUTOFDATE;
    }

    gCoreContext->LogEntry("mythfilldatabase", LP_INFO,
                       "Listings Download Started", "");

    if (!grab_data)
    {
    }
    else if (from_xawfile)
    {
        fill_data.readXawtvChannels(fromxawfile_id, fromxawfile_name);
    }
    else if (from_file)
    {
        QString status = QObject::tr("currently running.");
        QDateTime GuideDataBefore, GuideDataAfter;

        MSqlQuery query(MSqlQuery::InitCon());
        updateLastRunStart(query);
        updateLastRunStatus(query, status);

        query.prepare("SELECT MAX(endtime) FROM program p LEFT JOIN channel c "
                      "ON p.chanid=c.chanid WHERE c.sourceid= :SRCID "
                      "AND manualid = 0;");
        query.bindValue(":SRCID", fromfile_id);

        if (query.exec() && query.next())
        {
            if (!query.isNull(0))
                GuideDataBefore = QDateTime::fromString(query.value(0).toString(),
                                                    Qt::ISODate);
        }

        if (!fill_data.GrabDataFromFile(fromfile_id, fromfile_name))
        {
            return FILLDB_EXIT_GRAB_DATA_FAILED;
        }

        updateLastRunEnd(query);

        query.prepare("SELECT MAX(endtime) FROM program p LEFT JOIN channel c "
                      "ON p.chanid=c.chanid WHERE c.sourceid= :SRCID "
                      "AND manualid = 0;");
        query.bindValue(":SRCID", fromfile_id);

        if (query.exec() && query.next())
        {
            if (!query.isNull(0))
                GuideDataAfter = QDateTime::fromString(query.value(0).toString(),
                                                   Qt::ISODate);
        }

        if (GuideDataAfter == GuideDataBefore)
            status = QObject::tr("mythfilldatabase ran, but did not insert "
                     "any new data into the Guide.  This can indicate a "
                     "potential problem with the XML file used for the update.");
        else
            status = QObject::tr("Successful.");

        updateLastRunStatus(query, status);
    }
    else if (from_dd_file)
    {
        fill_data.GrabDataFromDDFile(
            fromfile_id, fromfile_offset, fromfile_name, fromddfile_lineupid);
    }
    else
    {
        SourceList sourcelist;

        MSqlQuery sourcequery(MSqlQuery::InitCon());
        QString where = "";

        if (sourceid != -1)
        {
            VERBOSE(VB_GENERAL,
                    QString("Running for sourceid %1 ONLY because --sourceid "
                            "was given on command-line").arg(sourceid));
            where = QString("WHERE sourceid = %1").arg(sourceid);
        }

        QString querystr = QString("SELECT sourceid,name,xmltvgrabber,userid,"
                                   "password,lineupid "
                                   "FROM videosource ") + where +
                                   QString(" ORDER BY sourceid;");

        if (sourcequery.exec(querystr))
        {
             if (sourcequery.size() > 0)
             {
                  while (sourcequery.next())
                  {
                       Source newsource;

                       newsource.id = sourcequery.value(0).toInt();
                       newsource.name = sourcequery.value(1).toString();
                       newsource.xmltvgrabber = sourcequery.value(2).toString();
                       newsource.userid = sourcequery.value(3).toString();
                       newsource.password = sourcequery.value(4).toString();
                       newsource.lineupid = sourcequery.value(5).toString();

                       newsource.xmltvgrabber_baseline = false;
                       newsource.xmltvgrabber_manualconfig = false;
                       newsource.xmltvgrabber_cache = false;
                       newsource.xmltvgrabber_prefmethod = "";

                       sourcelist.push_back(newsource);
                       usingDataDirect |=
                           is_grabber_datadirect(newsource.xmltvgrabber);
                  }
             }
             else
             {
                  VERBOSE(VB_IMPORTANT,
                          "There are no channel sources defined, did you run "
                          "the setup program?");
                  gCoreContext->LogEntry("mythfilldatabase", LP_CRITICAL,
                                     "No channel sources defined",
                                     "Could not find any defined channel "
                                     "sources - did you run the setup "
                                     "program?");
                  return FILLDB_EXIT_NO_CHAN_SRC;
             }
        }
        else
        {
             MythDB::DBError("loading channel sources", sourcequery);
             return FILLDB_EXIT_DB_ERROR;
        }

        if (!fill_data.Run(sourcelist))
        {
             VERBOSE(VB_IMPORTANT, "Failed to fetch some program info");
             gCoreContext->LogEntry("mythfilldatabase", LP_WARNING,
                                "Failed to fetch some program info", "");
        }
        else
            VERBOSE(VB_IMPORTANT, "Data fetching complete.");
    }

    if (fill_data.only_update_channels && !fill_data.need_post_grab_proc)
    {
        return FILLDB_EXIT_OK;
    }

    if (reset_iconmap)
    {
        fill_data.icon_data.ResetIconMap(reset_iconmap_icons);
    }

    if (import_iconmap)
    {
        fill_data.icon_data.ImportIconMap(import_icon_data_filename);
    }

    if (export_iconmap)
    {
        fill_data.icon_data.ExportIconMap(export_icon_data_filename);
    }

    if (update_icon_data)
    {
        MSqlQuery query(MSqlQuery::InitCon());
        query.prepare("SELECT sourceid FROM videosource ORDER BY sourceid");
        if (!query.exec())
        {
            MythDB::DBError("Querying sources", query);
            return FILLDB_EXIT_DB_ERROR;
        }

        while (query.next())
            fill_data.icon_data.UpdateSourceIcons(query.value(0).toInt());
    }

    if (grab_data)
    {
        VERBOSE(VB_GENERAL, "Adjusting program database end times.");
        int update_count = ProgramData::fix_end_times();
        if (update_count == -1)
            VERBOSE(VB_IMPORTANT, "fix_end_times failed!");
        else
            VERBOSE(VB_GENERAL,
                    QString("    %1 replacements made").arg(update_count));

        gCoreContext->LogEntry("mythfilldatabase", LP_INFO,
                           "Listings Download Finished", "");
    }

    if (grab_data)
    {
        VERBOSE(VB_GENERAL, "Marking generic episodes.");

        MSqlQuery query(MSqlQuery::InitCon());
        query.prepare("UPDATE program SET generic = 1 WHERE "
            "((programid = '' AND subtitle = '' AND description = '') OR "
            " (programid <> '' AND category_type = 'series' AND "
            "  program.programid LIKE '%0000'));");

        if (!query.exec())
            MythDB::DBError("mark generic", query);
        else
            VERBOSE(VB_GENERAL,
                    QString("    Found %1").arg(query.numRowsAffected()));
    }

    if (grab_data)
    {
        VERBOSE(VB_GENERAL, "Fudging non-unique programids "
                "with multiple parts.");

        int found = 0;
        MSqlQuery sel(MSqlQuery::InitCon());
        sel.prepare("SELECT DISTINCT programid, partnumber, parttotal "
                    "FROM program WHERE partnumber > 0 AND parttotal > 0 AND "
                    "programid LIKE '%0000'");
        if (sel.exec())
        {
            MSqlQuery repl(MSqlQuery::InitCon());

            while (sel.next())
            {
                QString orig_programid = sel.value(0).toString();
                QString new_programid = orig_programid.left(10);
                int     partnum, parttotal;
                QString part;

                partnum   = sel.value(1).toInt();
                parttotal = sel.value(2).toInt();

                part.setNum(parttotal);
                new_programid.append(part.rightJustified(2, '0'));
                part.setNum(partnum);
                new_programid.append(part.rightJustified(2, '0'));

                VERBOSE(VB_GENERAL,
                        QString("    %1 -> %2 (part %3 of %4)")
                        .arg(orig_programid).arg(new_programid)
                        .arg(partnum).arg(parttotal));

                repl.prepare("UPDATE program SET programid = :NEWID "
                             "WHERE programid = :OLDID AND "
                             "partnumber = :PARTNUM AND "
                             "parttotal = :PARTTOTAL");
                repl.bindValue(":NEWID", new_programid);
                repl.bindValue(":OLDID", orig_programid);
                repl.bindValue(":PARTNUM",   partnum);
                repl.bindValue(":PARTTOTAL", parttotal);
                if (!repl.exec())
                {
                    VERBOSE(VB_GENERAL,
                            QString("Fudging programid from '%1' to '%2'")
                            .arg(orig_programid)
                            .arg(new_programid));
                }
                else
                    found += repl.numRowsAffected();
            }
        }

        VERBOSE(VB_GENERAL, QString("    Found %1").arg(found));
    }

    if (mark_repeats)
    {
        VERBOSE(VB_GENERAL, "Marking repeats.");

        int newEpiWindow = gCoreContext->GetNumSetting( "NewEpisodeWindow", 14);

        MSqlQuery query(MSqlQuery::InitCon());
        query.prepare("UPDATE program SET previouslyshown = 1 "
                      "WHERE previouslyshown = 0 "
                      "AND originalairdate is not null "
                      "AND (to_days(starttime) - to_days(originalairdate)) "
                      "    > :NEWWINDOW;");
        query.bindValue(":NEWWINDOW", newEpiWindow);

        if (query.exec())
            VERBOSE(VB_GENERAL,
                    QString("    Found %1").arg(query.numRowsAffected()));

        VERBOSE(VB_GENERAL, "Unmarking new episode rebroadcast repeats.");
        query.prepare("UPDATE program SET previouslyshown = 0 "
                      "WHERE previouslyshown = 1 "
                      "AND originalairdate is not null "
                      "AND (to_days(starttime) - to_days(originalairdate)) "
                      "    <= :NEWWINDOW;");
        query.bindValue(":NEWWINDOW", newEpiWindow);

        if (query.exec())
            VERBOSE(VB_GENERAL,
                    QString("    Found %1").arg(query.numRowsAffected()));
    }

    // Mark first and last showings

    if (grab_data)
    {
        MSqlQuery updt(MSqlQuery::InitCon());
        updt.prepare("UPDATE program SET first = 0, last = 0;");
        if (!updt.exec())
            MythDB::DBError("Clearing first and last showings", updt);

        VERBOSE(VB_GENERAL, "Marking episode first showings.");

        MSqlQuery query(MSqlQuery::InitCon());
        query.prepare("SELECT MIN(starttime),programid FROM program "
                      "WHERE programid > '' GROUP BY programid;");
        if (query.exec())
        {
            while(query.next())
            {
                updt.prepare("UPDATE program set first = 1 "
                             "WHERE starttime = :STARTTIME "
                             "  AND programid = :PROGRAMID;");
                updt.bindValue(":STARTTIME", query.value(0).toDateTime());
                updt.bindValue(":PROGRAMID", query.value(1).toString());
                if (!updt.exec())
                    MythDB::DBError("Marking first showings by id", updt);
            }
        }
        int found = query.size();
        query.prepare("SELECT MIN(starttime),title,subtitle,description "
                      "FROM program WHERE programid = '' "
                      "GROUP BY title,subtitle,description;");
        if (query.exec())
        {
            while(query.next())
            {
                updt.prepare("UPDATE program set first = 1 "
                             "WHERE starttime = :STARTTIME "
                             "  AND title = :TITLE "
                             "  AND subtitle = :SUBTITLE "
                             "  AND description = :DESCRIPTION");
                updt.bindValue(":STARTTIME", query.value(0).toDateTime());
                updt.bindValue(":TITLE", query.value(1).toString());
                updt.bindValue(":SUBTITLE", query.value(2).toString());
                updt.bindValue(":DESCRIPTION", query.value(3).toString());
                if (!updt.exec())
                    MythDB::DBError("Marking first showings", updt);
            }
        }
        found += query.size();
        VERBOSE(VB_GENERAL, QString("    Found %1").arg(found));

        VERBOSE(VB_GENERAL, "Marking episode last showings.");
        query.prepare("SELECT MAX(starttime),programid FROM program "
                      "WHERE programid > '' GROUP BY programid;");
        if (query.exec())
        {
            while(query.next())
            {
                updt.prepare("UPDATE program set last = 1 "
                             "WHERE starttime = :STARTTIME "
                             "  AND programid = :PROGRAMID;");
                updt.bindValue(":STARTTIME", query.value(0).toDateTime());
                updt.bindValue(":PROGRAMID", query.value(1).toString());
                if (!updt.exec())
                    MythDB::DBError("Marking last showings by id", updt);
            }
        }
        found = query.size();
        query.prepare("SELECT MAX(starttime),title,subtitle,description "
                      "FROM program WHERE programid = '' "
                      "GROUP BY title,subtitle,description;");
        if (query.exec())
        {
            while(query.next())
            {
                updt.prepare("UPDATE program set last = 1 "
                             "WHERE starttime = :STARTTIME "
                             "  AND title = :TITLE "
                             "  AND subtitle = :SUBTITLE "
                             "  AND description = :DESCRIPTION");
                updt.bindValue(":STARTTIME", query.value(0).toDateTime());
                updt.bindValue(":TITLE", query.value(1).toString());
                updt.bindValue(":SUBTITLE", query.value(2).toString());
                updt.bindValue(":DESCRIPTION", query.value(3).toString());
                if (!updt.exec())
                    MythDB::DBError("Marking last showings", updt);
            }
        }
        found += query.size();
        VERBOSE(VB_GENERAL, QString("    Found %1").arg(found));
    }

    if (1) // limit MSqlQuery's lifetime
    {
        MSqlQuery query(MSqlQuery::InitCon());
        query.prepare("SELECT count(previouslyshown) "
                      "FROM program WHERE previouslyshown = 1;");
        if (query.exec() && query.next())
        {
            if (query.value(0).toInt() != 0)
            {
                query.prepare("UPDATE settings SET data = '1' "
                              "WHERE value = 'HaveRepeats';");
                if (!query.exec())
                    MythDB::DBError("Setting HaveRepeats", query);
            }
            else
            {
                query.prepare("UPDATE settings SET data = '0' "
                              "WHERE value = 'HaveRepeats';");
                if (!query.exec())
                    MythDB::DBError("Clearing HaveRepeats", query);
            }
        }
    }

    if ((usingDataDirect) &&
        (gCoreContext->GetNumSetting("MythFillGrabberSuggestsTime", 1)))
    {
        fill_data.ddprocessor.GrabNextSuggestedTime();
    }

    VERBOSE(VB_GENERAL, "\n"
            "===============================================================\n"
            "| Attempting to contact the master backend for rescheduling.  |\n"
            "| If the master is not running, rescheduling will happen when |\n"
            "| the master backend is restarted.                            |\n"
            "===============================================================");

    if (grab_data || mark_repeats)
        ScheduledRecording::signalChange(-1);

    RemoteSendMessage("CLEAR_SETTINGS_CACHE");

    SendMythSystemEvent("MYTHFILLDATABASE_RAN");

    VERBOSE(VB_IMPORTANT, "mythfilldatabase run complete.");

    return FILLDB_EXIT_OK;
}
bool AcquireImages()
{
    // Create a GEV Device finder dialog
    PvDeviceFinderWnd lDeviceFinderWnd;

    // Prompt the user to select a GEV Device
    lDeviceFinderWnd.ShowModal();

    // Get the connectivity information for the selected GEV Device
    PvDeviceInfo* lDeviceInfo = lDeviceFinderWnd.GetSelected();

    // If no device is selected, abort
    if( lDeviceInfo == NULL )
    {
        cout << "No device selected." << endl;
        return false;
    }

    PvString lMACAddress = lDeviceInfo->GetMACAddress();
    PvString lIPAddress = lDeviceInfo->GetIPAddress();

    // Connect to the GEV Device
    PvDevice lDevice;
    cout << "Connecting to " << lMACAddress.GetAscii() << endl;
    // if ( !lDevice.Connect( lDeviceInfo ).IsOK() )
    if ( !lDevice.Connect( lDeviceInfo ).IsOK() )
    {
        cout << "Unable to connect to " << lMACAddress.GetAscii() << endl;
        return false;
    }
    cout << "Successfully connected to " << lMACAddress.GetAscii() << endl;

    cout << endl;

    SourceList lSources;

    // Get source selector
    PvGenEnum *lSourceSelector = lDevice.GetGenParameters()->GetEnum( "SourceSelector" );
    if ( lSourceSelector != NULL )
    {
        // Go through all sources, create source objects
        PvInt64 lCount = 0;
        lSourceSelector->GetEntriesCount( lCount );
        for ( PvInt64 i = 0; i < lCount; i++ )
        {
            // Get source enum entry
            const PvGenEnumEntry *lEE = NULL;
            lSourceSelector->GetEntryByIndex( i, &lEE );

            // If available, create source
            if ( ( lEE != NULL ) && lEE->IsAvailable() )
            {
                // Get source name
                PvString lSourceName;
                lEE->GetName( lSourceName );

                // Create source
                Source *lSource = new Source( &lDevice, lIPAddress, lSourceName );
                lSource->Open();

                // Add to sources list
                lSources.push_back( lSource );

                cout << endl;
            }
        }
    }
    else
    {
        // If no source selector, just create a single source
        Source *lSource = new Source( &lDevice, lIPAddress, "" );
        lSource->Open();

        // Add to sources list
        lSources.push_back( lSource );

        cout << endl;
    }

    // Start the acquisiton on all sources
    SourceList::iterator lIt = lSources.begin();
    while ( lIt != lSources.end() )
    {
        ( *( lIt++ ) )->StartAcquisition();
        cout << endl;
    }

    // Aggressive initial value, will be adjusted vs frame rate
    PvUInt32 lTimeout = 1;

    // Acquire images until the user instructs us to stop
    cout << "<press a key to stop streaming>" << endl;
    while ( !PvKbHit() )
    {
        double lNewTimeout = 1000.0;

        lIt = lSources.begin();
        while ( lIt != lSources.end() )
        {
            ( *lIt )->RetrieveImages( lTimeout );
            ( *lIt )->PrintStatistics();

            // Always use the smallest recommended timeout
            double lRecommendedTimeout = ( *lIt )->GetRecommendedTimeout();
            if ( lRecommendedTimeout < lNewTimeout )
            {
                lNewTimeout = lRecommendedTimeout;
            }

            lIt++;
        }

        // Update timeout for next round - smallest recommended divided by number of sources
        lTimeout = static_cast<PvUInt32>( lNewTimeout / static_cast<double>( lSources.size() ) + 0.5 );

        cout << "\r";
    }

    PvGetChar(); // Flush key buffer for next stop
    cout << endl << endl;

    // Stop the acquisiton on all sources
    lIt = lSources.begin();
    while ( lIt != lSources.end() )
    {
        ( *( lIt++ ) )->StopAcquisition();
        cout << endl;
    }

    // Close and delete sources
    lIt = lSources.begin();
    while ( lIt != lSources.end() )
    {
        ( *lIt )->Close();
        cout << endl;

        delete *lIt;

        lIt++;
    }

    // Finally disconnect the device. Optional, still nice to have
    cout << "Disconnecting device" << endl;
    lDevice.Disconnect();

    return true;
}
Exemple #12
0
void CSourceSaver::SaveSources(CPartFile* file, SourceList* prevsources, LPCTSTR slsfile, UINT maxSourcesToSave)
{
	SourceList srcstosave;
	CSourceData* sourcedata;

	ASSERT(srcstosave.IsEmpty());

	POSITION pos2,pos;								
	CUpDownClient* cur_src;
	// Choose best sources for the file
	for(pos = file->srclist.GetHeadPosition();pos!=0;){
		cur_src = file->srclist.GetNext(pos);
		if (cur_src->GetDownloadState() != DS_ONQUEUE &&
			cur_src->GetDownloadState() != DS_DOWNLOADING &&
			cur_src->GetDownloadState() != DS_NONEEDEDPARTS ||
			cur_src->IsEd2kClient() == false)
			continue;
		if (srcstosave.IsEmpty()) {
			sourcedata = new CSourceData(cur_src, CalcExpiration(EXPIREIN));
			srcstosave.AddHead(sourcedata);
			continue;
		}
		// Skip also Required Obfuscation, because we don't save the userhash (and we don't know if all settings are still valid on next restart)
		if (cur_src->RequiresCryptLayer() ||thePrefs.IsClientCryptLayerRequired())
			continue;
		if ((UINT)srcstosave.GetCount() < maxSourcesToSave || (cur_src->GetAvailablePartCount() > srcstosave.GetTail()->partsavailable) || (cur_src->GetSourceExchange1Version() > srcstosave.GetTail()->nSrcExchangeVer)) {
			if ((UINT)srcstosave.GetCount() == maxSourcesToSave)
				delete srcstosave.RemoveTail();
			ASSERT((UINT)srcstosave.GetCount() < maxSourcesToSave);
			bool bInserted = false;
			for (pos2 = srcstosave.GetTailPosition();pos2 != 0;srcstosave.GetPrev(pos2)){
				CSourceData* cur_srctosave = srcstosave.GetAt(pos2);
				// khaos::kmod+ Source Exchange Version
				if (file->GetAvailableSrcCount() > (maxSourcesToSave*2) &&
					cur_srctosave->nSrcExchangeVer > cur_src->GetSourceExchange1Version())
				{
					bInserted = true;
				}
				else if (file->GetAvailableSrcCount() > (maxSourcesToSave*2) && 
							cur_srctosave->nSrcExchangeVer == cur_src->GetSourceExchange1Version() &&
							cur_srctosave->partsavailable > cur_src->GetAvailablePartCount())
				{
					bInserted = true;
				}
				else if (file->GetAvailableSrcCount() <= (maxSourcesToSave*2) &&
							cur_srctosave->partsavailable > cur_src->GetAvailablePartCount())
				{
					bInserted = true;
				}
				const uint8* srcstatus = cur_src->GetPartStatus();
				if (srcstatus){
					if (cur_src->GetPartCount() == file->GetPartCount()){
						// only save sources which have needed parts
						for (uint16 x = 0; x < file->GetPartCount(); x++){
							//MORPH - Changed by SiRoB, ICS merged into partstatus
							/*
							if (srcstatus[x] && !file->IsPartShareable(x)){
							*/
							if ((srcstatus[x]&SC_AVAILABLE) && !file->IsPartShareable(x)){
								bInserted = true;
								break;
							}
						}
					}
				}
				if (bInserted)
				{
					sourcedata = new CSourceData(cur_src, CalcExpiration(EXPIREIN));
					srcstosave.InsertAfter(pos2, sourcedata);
					break;
				}
				// khaos::kmod-
			}
			if (!bInserted) {
				sourcedata = new CSourceData(cur_src, CalcExpiration(EXPIREIN));
				srcstosave.AddHead(sourcedata);
			}
		}
	}
	
	// Add previously saved sources if found sources does not reach the limit
	for (pos = prevsources->GetHeadPosition(); pos; prevsources->GetNext(pos)) {
		CSourceData* cur_sourcedata = prevsources->GetAt(pos);
		if ((UINT)srcstosave.GetCount() == maxSourcesToSave)
			break;
		ASSERT((UINT)srcstosave.GetCount() <= maxSourcesToSave);

		bool bFound = false;
		for (pos2 = srcstosave.GetHeadPosition(); pos2; srcstosave.GetNext(pos2)) {
			if (srcstosave.GetAt(pos2)->Compare(cur_sourcedata)) {
				bFound = true;
				break;
			}
		}
		if (!bFound) {
			srcstosave.AddTail(new CSourceData(cur_sourcedata));
		}
			
	}

	//DEBUG_ONLY(AddLogLine(/*TBN_NONOTIFY, */false, "Saving %i sources for file %s", srcstosave.GetCount(), file->GetFileName()));	

	CString strLine;
	CStdioFile f;
	if (!f.Open(slsfile, CFile::modeCreate | CFile::modeWrite | CFile::typeText))
		return;
	f.WriteString(_T("#format: a.b.c.d:port,expirationdate(yymmddhhmm);\r\n"));
	f.WriteString(_T("#") + file->GetED2kLink() + _T("\r\n")); //MORPH - Added by IceCream, Storing ED2K link in Save Source files, To recover corrupted met by skynetman
	while (!srcstosave.IsEmpty()) {
		CSourceData* cur_src = srcstosave.RemoveHead();
		uint32 dwID = cur_src->sourceID;
		uint16 wPort = cur_src->sourcePort;
		uint32 dwserverip = cur_src->serverip;
		uint16 wserverport = cur_src->serverport;
		strLine.Format(_T("%s:%i,%s,%i,%s:%i;\r\n"), ipstr(dwID), wPort, cur_src->expiration, cur_src->nSrcExchangeVer, ipstr(dwserverip), wserverport);
		delete cur_src;
		f.WriteString(strLine);
	}
	f.Close();
}
// Watch current set of sources and process events
void
XmlRpcDispatch::work(double timeout_in_seconds)
{
  // Compute end time
    _endTime = (timeout_in_seconds < 0.0) ? -1.0 : (getTime() + timeout_in_seconds);
  _doClear = false;
  _inWork = true;

  // Only work while there is something to monitor
  while (_sources.size() > 0) {
      // // Construct the sets of descriptors we are interested in
      // fd_set inFd, outFd, excFd;
      //       FD_ZERO(&inFd);
      //       FD_ZERO(&outFd);
      //       FD_ZERO(&excFd);

      //    int maxFd = -1;     // Not used on windows
      //    SourceList::iterator it;
    int fds_size = _sources.size();
    std::vector<struct pollfd> fds(fds_size);

    {

        int __offset = 0;
        for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
        {
            fds[__offset].fd = it->getSource()->getfd();
            fds[__offset].events = 0;
            fds[__offset].revents = 0;
            if (it->getMask() & ReadableEvent) fds[__offset].events |= POLLIN;
            if (it->getMask() & WritableEvent) fds[__offset].events |= POLLOUT;
            if (it->getMask() & Exception)     fds[__offset].events |= POLLERR;
            //  2      if (it->getMask() && fd > maxFd)   maxFd = fd;
            ++__offset;
        }
    }

    // Check for events
    returnhereoninterruptedsyscall:
    int nEvents;
    if (timeout_in_seconds < 0.0)
        nEvents = poll(&fds[0], fds_size, -1);
    else
    {
        nEvents = poll(&fds[0],fds_size, timeout_in_seconds * 1000);
    }
    if(nEvents == -1 and errno == EINTR)
        goto returnhereoninterruptedsyscall;

    if (nEvents < 0)
    {
        LOG_ERROR("Error in XmlRpcDispatch::work: error in select " <<  strerror(errno));
       //        LOG_ERROR(strerror(errno));

//        XmlRpcUtil::error("Error in XmlRpcDispatch::work: error in select (%d).", nEvents);
        _inWork = false;
        return;
    }

    // Process events
    {

        size_t __offset = 0;

        for (SourceList::iterator it = _sources.begin(); it != _sources.end(); )
        {
            SourceList::iterator thisIt = it++;
            XmlRpcSource* src = thisIt->getSource();
            unsigned newMask = (unsigned) -1;

            // accepting a new connection (XmlRpcServer::handleEvent)
            // will add a new entry to _sources but we don't have an
            // entry in the fds around.
            if (__offset < fds.size())
            {
                assert(fds[__offset].fd == src->getfd());
                // if (fd <= maxFd)
                // {
                // If you select on multiple event types this could be ambiguous
                if (fds[__offset].revents bitand POLLIN)
                {
                    newMask &= src->handleEvent(ReadableEvent);
                }
                if (fds[__offset].revents bitand POLLOUT)
                {
                    newMask &= src->handleEvent(WritableEvent);
                }
                if (fds[__offset].revents bitand POLLERR)
                {
                    newMask &= src->handleEvent(Exception);
                }
            }

            if (newMask == 0)
            {
                _sources.erase(thisIt);  // Stop monitoring this one
                if (!src->getKeepOpen())
                {
                    src->close();
                }

            }
            else if (newMask != (unsigned) -1)
            {
                thisIt->getMask() = newMask;
            }
            __offset++;
        }
    }

    // Check whether to clear all sources
    if (_doClear)
    {
      SourceList closeList = _sources;
      _sources.clear();
      for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it) {
	XmlRpcSource *src = it->getSource();
        src->close();
      }

      _doClear = false;
    }

    // Check whether end time has passed
    if (0 <= _endTime && getTime() > _endTime)
      break;
  }

  _inWork = false;
}