QStringList OverviewPlaylistWidget::LetUserSelectMediaFile(QWidget *pParent, QString pDescription, bool pMultipleFiles)
{
    QStringList tResult;
    LOGEX(OverviewPlaylistWidget, LOG_VERBOSE, "Current data directory is \"%s\"", CONF.GetDataDirectory().toStdString().c_str());

    if (pMultipleFiles)
        tResult = QFileDialog::getOpenFileNames(pParent,  pDescription,
                                                                CONF.GetDataDirectory(),
                                                                sLoadMediaFilters,
                                                                &sAllLoadMediaFilter,
                                                                CONF_NATIVE_DIALOGS);
    else
    {
        tResult = QStringList(QFileDialog::getOpenFileName(pParent,  pDescription,
                                                                CONF.GetDataDirectory(),
                                                                sLoadMediaFilters,
                                                                &sAllLoadMediaFilter,
                                                                CONF_NATIVE_DIALOGS));

        // use the file parser to avoid playlists and resolve them to one single entry
        if (!tResult.isEmpty())
        {
			Playlist tPlaylist = Parse(tResult.first(), "");
			if (tPlaylist.size() > 0)
				tResult = QStringList(tPlaylist.first().Location);
			else
				tResult.clear();
        }
	}
    if (!tResult.isEmpty())
        CONF.SetDataDirectory(tResult.first().left(tResult.first().lastIndexOf('/')));

    return tResult;
}
bool OverviewPlaylistWidget::IsVideoFile(QString pFileName)
{
    pFileName = QString(pFileName.toLocal8Bit());

    int tPos = pFileName.lastIndexOf('.', -1);
    if (tPos == -1)
    {
        LOGEX(OverviewPlaylistWidget, LOG_ERROR, "Video file %s name lacks a correct format selecting end", pFileName.toStdString().c_str());
        return false;
    }

    QString tExt = pFileName.right(pFileName.size() - tPos).toLower();
    LOGEX(OverviewPlaylistWidget, LOG_VERBOSE, "Checking for video content in file %s of type %s", pFileName.toStdString().c_str(), tExt.toStdString().c_str());

    if (sLoadVideoFilters.indexOf(tExt, 0) != -1)
        return true;
    else
        return false;
}
static void
_MetadataCallback(void* aAppleATDecoder,
                  AudioFileStreamID aStream,
                  AudioFileStreamPropertyID aProperty,
                  UInt32* aFlags)
{
  AppleATDecoder* decoder = static_cast<AppleATDecoder*>(aAppleATDecoder);
  MOZ_RELEASE_ASSERT(decoder->mTaskQueue->IsCurrentThreadIn());

  LOGEX(decoder, "MetadataCallback receiving: '%s'", FourCC2Str(aProperty));
  if (aProperty == kAudioFileStreamProperty_MagicCookieData) {
    UInt32 size;
    Boolean writeable;
    OSStatus rv = AudioFileStreamGetPropertyInfo(aStream,
                                                 aProperty,
                                                 &size,
                                                 &writeable);
    if (rv) {
      LOGEX(decoder,
            "Couldn't get property info for '%s' (%s)",
            FourCC2Str(aProperty),
            FourCC2Str(rv));
      decoder->mFileStreamError = true;
      return;
    }
    auto data = MakeUnique<uint8_t[]>(size);
    rv = AudioFileStreamGetProperty(aStream, aProperty,
                                    &size, data.get());
    if (rv) {
      LOGEX(decoder,
            "Couldn't get property '%s' (%s)",
            FourCC2Str(aProperty),
            FourCC2Str(rv));
      decoder->mFileStreamError = true;
      return;
    }
    decoder->mMagicCookie.AppendElements(data.get(), size);
  }
}
bool OverviewPlaylistWidget::IsAudioFile(QString pFileName)
{
    // explicitly allow audio streams
    if (pFileName.startsWith("http://"))
        return true;

    pFileName = QString(pFileName.toLocal8Bit());

    int tPos = pFileName.lastIndexOf('.', -1);
    if (tPos == -1)
    {
        LOGEX(OverviewPlaylistWidget, LOG_ERROR, "Audio file %s name lacks a correct format selecting end", pFileName.toStdString().c_str());
        return false;
    }

    QString tExt = pFileName.right(pFileName.size() - tPos).toLower();
    LOGEX(OverviewPlaylistWidget, LOG_VERBOSE, "Checking for audio content in file %s of type %s", pFileName.toStdString().c_str(), tExt.toStdString().c_str());

    if (sLoadAudioFilters.indexOf(tExt, 0) != -1)
        return true;
    else
        return false;
}
ECode CxxSourceCrcTask::operator()()
{
    const auto& path = apply_visitor(doim::vst::path(), cxxSource());

    defer(LOGEX(tags(),
                "{} for {} is {:x}",
                depth() == EDepth::kOne ? "Crc" : "Deep Crc",
                path,
                mCrcsum));

    auto origin =
        apply_visitor([](auto const& element) { return element->origin(); }, cxxSource());

    if (!apply_visitor(vst::isNullptr, origin))
    {
        if (origin.type() == typeid(doim::ProtobufFileSPtr))
        {
            auto originTask =
                ProtobufFileCrcTask::valid(boost::get<doim::ProtobufFileSPtr>(origin));
            gTPool->ensureScheduled(originTask);
            EHTest(originTask->join());
            mCrcsum = originTask->crc();
        }
        else
            ASSERT(false);
        EHEnd;
    }

    if (depth() == EDepth::kOne)
    {
        EHTest(one());
        EHEnd;
    }

    auto crcTask = valid(EDepth::kOne, cxxSource(), currentIncludeDirectory());
    gTPool->ensureScheduled(crcTask);

    auto headersTask = CxxSourceHeadersTask::valid(CxxSourceHeadersTask::EDepth::kAll,
                                                   cxxSource(),
                                                   currentIncludeDirectory());
    gTPool->ensureScheduled(headersTask);
    EHTest(headersTask->join());

    const auto& headersInfo = headersTask->headersInfo();
    std::vector<CxxSourceCrcTaskSPtr> tasks;
    tasks.reserve(headersInfo.size() + 1);

    tasks.push_back(crcTask);

    for (const auto& headerInfo : headersInfo)
    {
        if (headerInfo.mHeader->type() == doim::CxxHeader::EType::kSystem)
            continue;

        auto task = CxxSourceCrcTask::valid(CxxSourceCrcTask::EDepth::kOne,
                                            headerInfo.mHeader,
                                            headerInfo.mIncludeDirectory);
        task::gTPool->ensureScheduled(task);
        tasks.push_back(task);
    }

    auto group = tpool::TaskGroup::make(task::gTPool, 0, tasks);
    task::gTPool->ensureScheduled(group);

    EHTest(group->join());

    unordered_set<math::Crcsum> crcs;

    math::Crcsum x = 0;
    for (const auto& task : tasks)
    {
        auto n = task->crc();
        if (n == 0)
        {
            mCrcsum = 0;
            EHEnd;
        }
        auto unique = crcs.insert(n).second;
        if (!unique)
            EHBan(kTooMany, "There are at least two items with the same crc");

        x ^= n;
    }

    mCrcsum = math::obfuscate(x);
    EHEnd;
}