void ExportNative::runScript() { QString tempDir = getTempDirectory(); QString logDir = tempDir + "logs"; QString configDir = tempDir + "config"; QString commandline; // remove existing progress.log if present if (QFile::exists(logDir + "/progress.log")) QFile::remove(logDir + "/progress.log"); // remove cancel flag file if present if (QFile::exists(logDir + "/mythburncancel.lck")) QFile::remove(logDir + "/mythburncancel.lck"); createConfigFile(configDir + "/mydata.xml"); commandline = "mytharchivehelper --nativearchive --outfile " + configDir + "/mydata.xml"; // job file commandline += logPropagateArgs; if (!logPropagateQuiet()) commandline += " --quiet"; commandline += " > " + logDir + "/progress.log 2>&1 &"; // Logs uint flags = kMSRunBackground | kMSDontBlockInputDevs | kMSDontDisableDrawing; uint retval = myth_system(commandline, flags); if (retval != GENERIC_EXIT_RUNNING && retval != GENERIC_EXIT_OK) { ShowOkPopup(QObject::tr("It was not possible to create the DVD. " "An error occured when running the scripts") ); return; } showLogViewer(); }
QString ThumbFinder::createThumbDir(void) { QString thumbDir = getTempDirectory() + "config/thumbs"; // make sure the thumb directory exists QDir dir(thumbDir); if (!dir.exists()) { dir.mkdir(thumbDir); if( chmod(qPrintable(thumbDir), 0777) ) LOG(VB_GENERAL, LOG_ERR, "ThumbFinder: Failed to change permissions" " on thumb directory: " + ENO); } QString path; for (int x = 1; dir.exists(); x++) { path = thumbDir + QString("/%1").arg(x); dir.setPath(path); } dir.mkdir(path); if( chmod(qPrintable(path), 0777) ) LOG(VB_GENERAL, LOG_ERR, "ThumbFinder: Failed to change permissions on " "thumb directory: %1" + ENO); return path; }
QString ThumbFinder::createThumbDir(void) { QString thumbDir = getTempDirectory() + "config/thumbs"; // make sure the thumb directory exists QDir dir(thumbDir); if (!dir.exists()) { dir.mkdir(thumbDir); if( !chmod(qPrintable(thumbDir), 0777) ) VERBOSE(VB_IMPORTANT, QString("ThumbFinder: Failed to change permissions on thumb directory: %1") .arg(strerror(errno))); } int x = 0; QString path; do { x++; path = QString(thumbDir + "/%1").arg(x); dir.setPath(path); } while (dir.exists()); dir.mkdir(path); if( !chmod(qPrintable(path), 0777) ) VERBOSE(VB_IMPORTANT, QString("ThumbFinder: Failed to change permissions on thumb directory: %1") .arg(strerror(errno))); return path; }
void ExportNative::runScript() { QString tempDir = getTempDirectory(); QString logDir = tempDir + "logs"; QString configDir = tempDir + "config"; QString commandline; // remove existing progress.log if present if (QFile::exists(logDir + "/progress.log")) QFile::remove(logDir + "/progress.log"); // remove cancel flag file if present if (QFile::exists(logDir + "/mythburncancel.lck")) QFile::remove(logDir + "/mythburncancel.lck"); createConfigFile(configDir + "/mydata.xml"); commandline = "mytharchivehelper -n " + configDir + "/mydata.xml"; // job file commandline += " > " + logDir + "/progress.log 2>&1 &"; // Logs int state = system(qPrintable(commandline)); if (state != 0) { ShowOkPopup(QObject::tr("It was not possible to create the DVD. " "An error occured when running the scripts") ); } else { showLogViewer(); } }
void showLogViewer(void) { MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); QString logDir = getTempDirectory() + "logs"; QString progressLog; QString fullLog; // wait for a log file to be available int tries = 10; while (tries--) { if (QFile::exists(logDir + "/progress.log")) progressLog = logDir + "/progress.log"; if (QFile::exists(logDir + "/mythburn.log")) fullLog = logDir + "/mythburn.log"; // we wait for both the progress.log and mythburn.log if ((!progressLog.isEmpty()) && (!fullLog.isEmpty())) break; // or we wait for a log from mytharchivehelper if (progressLog.isEmpty() && fullLog.isEmpty()) { QStringList logFiles; QStringList filters; filters << "*.log"; QDir d(logDir); logFiles = d.entryList(filters, QDir::Files | QDir::Readable, QDir::Time); if (logFiles.count()) { // the first log file should be the newest one available progressLog = logDir + '/' + logFiles[0]; break; } } sleep(1); } // do any logs exist? if ((!progressLog.isEmpty()) || (!fullLog.isEmpty())) { LogViewer *viewer = new LogViewer(mainStack); viewer->setFilenames(progressLog, fullLog); if (viewer->Create()) mainStack->AddScreen(viewer); } else showWarningDialog(QCoreApplication::translate("LogViewer", "Cannot find any logs to show!")); }
void showLogViewer(void) { MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); QString logDir = getTempDirectory() + "logs"; // do any logs exist? if (QFile::exists(logDir + "/progress.log") || QFile::exists(logDir + "/mythburn.log")) { LogViewer *viewer = new LogViewer(mainStack); viewer->setFilenames(logDir + "/progress.log", logDir + "/mythburn.log"); if (viewer->Create()) mainStack->AddScreen(viewer); } else showWarningDialog(QObject::tr("Cannot find any logs to show!")); }
void iurlstream::open(std::string url) { if (url.empty()) { url = m_url; } // download the entire URL to a temp file, put into stringbuf for reading std::string tempDir = getTempDirectory(); std::string filename = getUrlFilename(url); m_tempFilePath = tempDir + getDirectoryPathSeparator() + filename; m_lastError = pp->url_download(url, filename); if (m_lastError == ERR_MALFORMED_URL) { error("iurlstream::open: malformed URL when downloading " + url + " to " + m_tempFilePath); } else if (m_lastError == ERR_IO_EXCEPTION) { error("iurlstream::open: network I/O error when downloading " + url + " to " + m_tempFilePath); } if (m_lastError == 200) { std::ifstream::open(m_tempFilePath.c_str()); } else { setstate(std::ios::failbit); } }
void ImportFile::OKPressed() { QString configFile = getTempDirectory() + "config/importjob.xml"; createConfigFile(configFile); QString commandline; QString tempDir = gCoreContext->GetSetting("MythArchiveTempDir", ""); if (tempDir == "") return; if (!tempDir.endsWith("/")) tempDir += "/"; QString logDir = tempDir + "logs"; // remove any existing logs myth_system("rm -f " + logDir + "/*.log"); commandline = "mytharchivehelper -v none,jobqueue --logpath " + logDir + " --importfile " "--infile \"" + configFile + "\""; uint flags = kMSRunBackground | kMSDontBlockInputDevs | kMSDontDisableDrawing; uint retval = myth_system(commandline, flags); if (retval != GENERIC_EXIT_RUNNING && retval != GENERIC_EXIT_OK) { ShowOkPopup(tr("It was not possible to import the file. " " An error occured when running 'mytharchivehelper'") ); return; } showLogViewer(); Close(); }
bool ThumbFinder::initAVCodec(const QString &inFile) { // Open recording LOG(VB_JOBQUEUE, LOG_INFO, QString("ThumbFinder: Opening '%1'") .arg(inFile)); if (!m_inputFC.Open(inFile)) { LOG(VB_GENERAL, LOG_ERR, "ThumbFinder, Couldn't open input file" + ENO); return false; } // Getting stream information int ret = avformat_find_stream_info(m_inputFC, nullptr); if (ret < 0) { LOG(VB_GENERAL, LOG_ERR, QString("Couldn't get stream info, error #%1").arg(ret)); return false; } av_dump_format(m_inputFC, 0, qPrintable(inFile), 0); // find the first video stream m_videostream = -1; for (uint i = 0; i < m_inputFC->nb_streams; i++) { AVStream *st = m_inputFC->streams[i]; if (m_inputFC->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { m_startTime = -1; if (m_inputFC->streams[i]->start_time != (int) AV_NOPTS_VALUE) m_startTime = m_inputFC->streams[i]->start_time; else { LOG(VB_GENERAL, LOG_ERR, "ThumbFinder: Failed to get start time"); return false; } m_videostream = i; m_frameWidth = st->codecpar->width; m_frameHeight = st->codecpar->height; if (st->r_frame_rate.den && st->r_frame_rate.num) m_fps = av_q2d(st->r_frame_rate); else m_fps = 1/av_q2d(st->time_base); break; } } if (m_videostream == -1) { LOG(VB_GENERAL, LOG_ERR, "Couldn't find a video stream"); return false; } // get the codec context for the video stream m_codecCtx = gCodecMap->getCodecContext (m_inputFC->streams[m_videostream]); m_codecCtx->debug_mv = 0; m_codecCtx->debug = 0; m_codecCtx->workaround_bugs = 1; m_codecCtx->lowres = 0; m_codecCtx->idct_algo = FF_IDCT_AUTO; m_codecCtx->skip_frame = AVDISCARD_DEFAULT; m_codecCtx->skip_idct = AVDISCARD_DEFAULT; m_codecCtx->skip_loop_filter = AVDISCARD_DEFAULT; m_codecCtx->err_recognition = AV_EF_CAREFUL; m_codecCtx->error_concealment = 3; // get decoder for video stream m_codec = avcodec_find_decoder(m_codecCtx->codec_id); if (m_codec == nullptr) { LOG(VB_GENERAL, LOG_ERR, "ThumbFinder: Couldn't find codec for video stream"); return false; } // open codec if (avcodec_open2(m_codecCtx, m_codec, nullptr) < 0) { LOG(VB_GENERAL, LOG_ERR, "ThumbFinder: Couldn't open codec for video stream"); return false; } // allocate temp buffer int bufflen = m_frameWidth * m_frameHeight * 4; m_outputbuf = new unsigned char[bufflen]; m_frameFile = getTempDirectory() + "work/frame.jpg"; m_deinterlacer.reset(new MythPictureDeinterlacer(m_codecCtx->pix_fmt, m_frameWidth, m_frameHeight)); return true; }
bool ThumbFinder::initAVCodec(const QString &inFile) { av_register_all(); m_inputFC = NULL; // Open recording VERBOSE(VB_JOBQUEUE, QString("ThumbFinder: ") + QString("Opening '%1'").arg(inFile)); QByteArray inFileBA = inFile.toLocal8Bit(); int ret = av_open_input_file( &m_inputFC, inFileBA.constData(), NULL, 0, NULL); if (ret) { VERBOSE(VB_IMPORTANT, QString("ThumbFinder, Error: ") + "Couldn't open input file" + ENO); return false; } // Getting stream information if ((ret = av_find_stream_info(m_inputFC)) < 0) { VERBOSE(VB_IMPORTANT, QString("Couldn't get stream info, error #%1").arg(ret)); av_close_input_file(m_inputFC); m_inputFC = NULL; return false; } av_estimate_timings(m_inputFC, 0); dump_format(m_inputFC, 0, inFileBA.constData(), 0); // find the first video stream m_videostream = -1; for (uint i = 0; i < m_inputFC->nb_streams; i++) { AVStream *st = m_inputFC->streams[i]; if (m_inputFC->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) { m_startTime = -1; if (m_inputFC->streams[i]->start_time != (int) AV_NOPTS_VALUE) m_startTime = m_inputFC->streams[i]->start_time; else { VERBOSE(VB_IMPORTANT, "ThumbFinder: Failed to get start time"); return false; } m_videostream = i; m_frameWidth = st->codec->width; m_frameHeight = st->codec->height; if (st->r_frame_rate.den && st->r_frame_rate.num) m_fps = av_q2d(st->r_frame_rate); else m_fps = 1/av_q2d(st->time_base); break; } } if (m_videostream == -1) { VERBOSE(VB_IMPORTANT, "Couldn't find a video stream"); return false; } // get the codec context for the video stream m_codecCtx = m_inputFC->streams[m_videostream]->codec; m_codecCtx->debug_mv = 0; m_codecCtx->debug = 0; m_codecCtx->workaround_bugs = 1; m_codecCtx->lowres = 0; m_codecCtx->idct_algo = FF_IDCT_AUTO; m_codecCtx->skip_frame = AVDISCARD_DEFAULT; m_codecCtx->skip_idct = AVDISCARD_DEFAULT; m_codecCtx->skip_loop_filter = AVDISCARD_DEFAULT; m_codecCtx->error_recognition = FF_ER_CAREFUL; m_codecCtx->error_concealment = 3; // get decoder for video stream m_codec = avcodec_find_decoder(m_codecCtx->codec_id); if (m_codec == NULL) { VERBOSE(VB_IMPORTANT, "ThumbFinder: Couldn't find codec for video stream"); return false; } // open codec if (avcodec_open(m_codecCtx, m_codec) < 0) { VERBOSE(VB_IMPORTANT, "ThumbFinder: Couldn't open codec for video stream"); return false; } // allocate temp buffer int bufflen = m_frameWidth * m_frameHeight * 4; m_outputbuf = new unsigned char[bufflen]; m_frame = avcodec_alloc_frame(); m_frameFile = getTempDirectory() + "work/frame.jpg"; return true; }
void ImportFile::doGetRecording(void) { MythUIButtonListItem *item = m_recordingButtonList->GetItemCurrent(); if (!item) return; ImportItem *i = item->GetData().value<ImportItem *>(); if (!i) return; uint duration = 60; //i->actualDuration; QString videoFile = getTempDirectory() + "work/video.ts"; QString mxmlFile = getTempDirectory() + "work/video.mxml"; // record the mp4 video stream QString recCommand = QString("mythffmpeg -y -i %1 -t %2 -acodec copy -vcodec copy %3") .arg(STREAMURL).arg(duration).arg(videoFile); QScopedPointer<MythSystem> cmd(MythSystem::Create(recCommand, kMSRunShell)); cmd->Wait(0); if (cmd.data()->GetExitCode() != GENERIC_EXIT_OK) { LOG(VB_GENERAL, LOG_ERR, QString("ERROR - ffmpeg exited with result: %1").arg(cmd.data()->GetExitCode())); return; } // create a mxml file with the metadata for this recording QStringList categories(i->category.split(',')); MetadataLookup *lookup = new MetadataLookup(kMetadataVideo, kProbableTelevision, QVariant(), kLookupSearch, false, false, false, false, false, "", videoFile, i->title, categories, 0.0, i->subtitle, "", i->description, i->season, i->episode, i->startTime, 0, i->chanNo, i->chanSign, i->chanName, i->certification, i->startTime.date().year(), i->startTime.date(), i->duration / 60, i->duration, "", PeopleMap(), "", ArtworkMap(), DownloadMap()); if (i->category == "Movies") lookup->SetVideoContentType(kContentMovie); else lookup->SetVideoContentType(kContentTelevision); QDomDocument mxmlDoc = CreateMetadataXML(lookup); // save the mxml to the file QFile f(mxmlFile); if (!f.open(QIODevice::WriteOnly)) { LOG(VB_GENERAL, LOG_ERR, QString("ImportFile: Failed to open mxml file for writing - %1").arg(mxmlFile)); return; } QTextStream t(&f); t << mxmlDoc.toString(4); f.close(); // workout where to save the file in the Video storage group QString dstFile = filenameFromMetadataLookup(lookup); QString saveFilename; // copy the recording to the Video storage group saveFilename = gCoreContext->GenMythURL(gCoreContext->GetMasterHostName(), 0, dstFile + ".mp4", "Videos"); bool result = RemoteFile::CopyFile(videoFile, saveFilename); if (!result) { LOG(VB_GENERAL, LOG_ERR, QString("ImportFile: Failed to copy video file to %1").arg(saveFilename)); return; } // copy the metadata xml file to the Video storage group saveFilename = gCoreContext->GenMythURL(gCoreContext->GetMasterHostName(), 0, dstFile + ".mxml", "Videos"); result = RemoteFile::CopyFile(mxmlFile, saveFilename); if (!result) { LOG(VB_GENERAL, LOG_ERR, QString("ImportFile: Failed to copy xml file to %1").arg(saveFilename)); return; } }
void ImportFile::getRecordingList(void) { while (!m_recordingList.isEmpty()) delete m_recordingList.takeFirst(); QString xmlFile = getTempDirectory() + "work/recordings.xml"; QFileInfo fi(xmlFile); if (!fi.exists() || QDateTime::currentDateTime() > fi.lastModified().addSecs(3600)) { // run the script to get list of recordings from the External Box QString command = gCoreContext->GetSetting("MythArchiveGetRecordingList"); command.replace("%XMLFILE%", xmlFile); QScopedPointer<MythSystem> cmd(MythSystem::Create(command)); cmd->Wait(0); if (cmd.data()->GetExitCode() != GENERIC_EXIT_OK) { LOG(VB_GENERAL, LOG_ERR, QString("ERROR - Failed to get recording list")); LOG(VB_GENERAL, LOG_ERR, QString("Command exited with result: %1").arg(cmd.data()->GetExitCode())); LOG(VB_GENERAL, LOG_ERR, QString("Command was: %1").arg(command)); //return; } } // load the xml file contains the recordings list details QDomDocument doc("recordings"); QFile file(xmlFile); if (!file.open(QIODevice::ReadOnly)) { LOG(VB_GENERAL, LOG_ERR, "Could not open recordings file: " + xmlFile); return; } if (!doc.setContent(&file)) { LOG(VB_GENERAL, LOG_ERR, "Could not load recordings file: " + xmlFile); file.close(); return; } file.close(); QDomNodeList recordingNodes = doc.elementsByTagName("recording"); for (int x = 0; x < recordingNodes.count(); x++) { ImportItem *importItem = new ImportItem; QDomNode recordingNode = recordingNodes.item(x); QDomElement recordingElement = recordingNode.toElement(); for (int y = 0; y < recordingElement.childNodes().count(); y++) { QDomNode node = recordingElement.childNodes().at(y); QDomElement e = node.toElement(); if (e.nodeName() == "no") importItem->id = getFirstText(e).toInt(); else if (e.nodeName() == "title") importItem->title = decodeXML(getFirstText(e)); else if (e.nodeName() == "season") importItem->season = decodeXML(getFirstText(e)).toUInt(); else if (e.nodeName() == "episode") importItem->episode = decodeXML(getFirstText(e)).toUInt(); else if (e.nodeName() == "channelno") importItem->chanNo = decodeXML(getFirstText(e)); else if (e.nodeName() == "channelsign") importItem->chanSign = decodeXML(getFirstText(e)); else if (e.nodeName() == "channelname") importItem->chanName = decodeXML(getFirstText(e)); else if (e.nodeName() == "starttime") importItem->startTime = MythDate::fromString(getFirstText(e)); else if (e.nodeName() == "duration") importItem->duration = decodeDuration(getFirstText(e)); else if (e.nodeName() == "actualduration") importItem->actualDuration = decodeDuration(getFirstText(e)); else if (e.nodeName() == "description") importItem->description = decodeXML(getFirstText(e)) + QString("\n\nRecorded from %1 on %2 at %3.") .arg(importItem->chanName).arg(importItem->startTime.toString("dddd dd MMMM yyyy")) .arg(importItem->startTime.toString("hh:mm ap")); else if (e.nodeName() == "filesize") importItem->size = getFirstText(e).toInt(); else if (e.nodeName() == "filename") importItem->filename = getFirstText(e); else if (e.nodeName() == "category") importItem->category = getFirstText(e); } if (importItem->chanSign.isEmpty()) importItem->chanSign = importItem->chanName; if (importItem->category.isEmpty()) importItem->category = importItem->title; if (m_categories.indexOf(importItem->category) == -1) m_categories.append(importItem->category); // default to using the IPEncoder importItem->type = "IPEncoder"; m_recordingList.append(importItem); } }