#include "FileSelector.hpp" #include #include #include #include #include #include namespace fs = std::filesystem; FileSelector::FileSelector(QObject* parent): QObject(parent) { QObject::connect(&this->timer, &QTimer::timeout, this, &FileSelector::onTimeout); } QString FileSelector::directory() const { return QString::fromStdString(this->mDirectory->string()); } void FileSelector::setDirectory(QString directory) { this->mDirectory = directory.toStdString(); if (this->mDirectory && this->mEpoch) this->update(); emit this->directoryChanged(); } unsigned int FileSelector::epoch() const { return std::chrono::duration_cast(*this->mEpoch).count(); } void FileSelector::setEpoch(unsigned int epoch) { this->mEpoch = std::chrono::milliseconds{epoch}; if (this->mDirectory && this->mEpoch) this->update(); emit this->epochChanged(); } QString FileSelector::seed() const { return this->mSeed; } void FileSelector::setSeed(QString seed) { this->mSeed = seed; emit this->seedChanged(); } QString FileSelector::selected() const { if (!this->mDirectory || !this->mEpoch) return QString(); std::vector shuffled(this->mFiles.begin(), this->mFiles.end()); std::sort(shuffled.begin(), shuffled.end()); auto currentTime = std::chrono::system_clock::now(); uint64_t currentEpoch = currentTime.time_since_epoch() / *this->mEpoch; std::chrono::milliseconds timeInEpoch = std::chrono::duration_cast(currentTime.time_since_epoch()) % *this->mEpoch; std::ostringstream seed; seed << this->mSeed.size() << ";" << this->mSeed.toStdString() << ";"; seed << *this->mEpoch << ";"; seed << currentEpoch << ";"; seed << this->mDirectory->string().size() << ";" << *this->mDirectory << ";"; seed << this->mFiles.size() << ";"; for (const fs::path& p: this->mFiles) seed << p.string().size() << ";" << p << ";"; std::vector v; v.reserve(seed.str().size()); for (const char& c: seed.str()) v.push_back(c); std::seed_seq engine_seed(v.begin(), v.end()); std::mt19937 g(engine_seed); std::shuffle(shuffled.begin(), shuffled.end(), g); std::vector::size_type ix = shuffled.size() * timeInEpoch / *this->mEpoch; return QString::fromStdString((*this->mDirectory / shuffled[ix]).string()); } void FileSelector::onTimeout() { if (!this->mFiles.size()) return; auto currentTime = std::chrono::system_clock::now(); uint64_t currentMinorEpoch = currentTime.time_since_epoch() / (*this->mEpoch / this->mFiles.size()); auto nextTime = std::chrono::time_point((2 * currentMinorEpoch + 3) * (*this->mEpoch / (this->mFiles.size() * 2))); this->timer.start(std::chrono::duration_cast(nextTime - currentTime).count()); emit this->selectedChanged(); } void FileSelector::update() { this->mFiles = std::set{}; for (const fs::directory_entry& entry: fs::recursive_directory_iterator(*this->mDirectory, fs::directory_options::follow_directory_symlink)) { this->mFiles.insert(fs::relative(entry, *this->mDirectory)); } this->onTimeout(); }