Preset subdirs (#385)

Scanning textures/presets dirs for textures and scanning preset dir for presets.
Scanning is now done recursively, so presets and textures can be organized into subdirectories instead of needing to be flattened into a single directory.

On POSIX systems makes use of [ftw](https://linux.die.net/man/3/ftw) which should be relatively efficient. Otherwise falls back to recursing with `dirent` (for windows).

Probably should have made an autoconf check for `ftw` instead of doing `#ifdef WIN32`. 

* Scan subdirectories in presets directory

* remove preset subdir config

* Recursively scan for textures too, add c++-17 compatibility

* Refactor directory scanning code so it's reused by texture loader and preset loader. Make cross-platform (maybe)

* filescanner in makefile

* extension filter for file loader

* make extensions match up'

* need string.h

* Add FileScanner.cpp to win build (maybe)

* scan all dirs

* #ifndef #ifdef is def fun

* bogus comment

* bleh

* bleh

* itunes plugin with c++17

* EyeTunes needs to know about the FileScanner

Co-authored-by: milkdropper.com <milkdropper.com@gmail.com>
Co-authored-by: milkdropper <59471060+milkdropper@users.noreply.github.com>
This commit is contained in:
Mischa Spiegelmock
2020-07-28 22:01:56 +03:00
committed by GitHub
parent e51b2c7d63
commit e49720ecfa
27 changed files with 379 additions and 330 deletions

View File

@ -15,29 +15,19 @@
#include <iostream>
#include <sstream>
#include <set>
#ifdef __unix__
extern "C"
{
#include <errno.h>
}
#endif
#ifdef __APPLE__
extern "C"
{
#include <errno.h>
}
#endif
#include <sys/types.h>
#include <cassert>
#include "fatal.h"
#include "Common.hpp"
PresetLoader::PresetLoader (int gx, int gy, std::string dirname = std::string()) :_dirname ( dirname ), _dir ( 0 )
PresetLoader::PresetLoader (int gx, int gy, std::string dirname = std::string()) :_dirname ( dirname )
{
_presetFactoryManager.initialize(gx,gy);
_presetFactoryManager.initialize(gx,gy);
std::vector<std::string> dirs{_dirname};
std::vector<std::string> extensions = _presetFactoryManager.extensionsHandled();
fileScanner = FileScanner(dirs, extensions);
// Do one scan
if ( _dirname != std::string() )
rescan();
@ -45,106 +35,59 @@ PresetLoader::PresetLoader (int gx, int gy, std::string dirname = std::string())
clear();
}
PresetLoader::~PresetLoader()
{
if ( _dir )
closedir ( _dir );
}
PresetLoader::~PresetLoader() {}
void PresetLoader::setScanDirectory ( std::string dirname )
{
_dirname = dirname;
}
void PresetLoader::addScannedPresetFile(const std::string &path, const std::string &name) {
auto ext = parseExtension(path);
if (ext.empty())
return;
ext = "." + ext;
// Verify extension is projectm or milkdrop
if (!_presetFactoryManager.extensionHandled(ext))
return;
// std::cout << "Loading preset file " << path << std::endl;
_entries.push_back(path);
_presetNames.push_back(name + ext);
}
void PresetLoader::rescan()
{
// std::cerr << "Rescanning..." << std::endl;
// Clear the directory entry collection
clear();
// Clear the directory entry collection
clear();
// If directory already opened, close it first
if ( _dir )
{
closedir ( _dir );
_dir = 0;
}
// Allocate a new a stream given the current directory name
if ( ( _dir = opendir ( _dirname.c_str() ) ) == NULL )
{
handleDirectoryError();
return; // no files loaded. _entries is empty
}
struct dirent * dir_entry;
std::set<std::string> alphaSortedFileSet;
std::set<std::string> alphaSortedPresetNameSet;
while ( ( dir_entry = readdir ( _dir ) ) != NULL )
{
if (dir_entry->d_name[0] == 0)
continue;
std::ostringstream out;
// Convert char * to friendly string
std::string filename ( dir_entry->d_name );
// Verify extension is projectm or milkdrop
if (!_presetFactoryManager.extensionHandled(parseExtension(filename)))
continue;
if ( filename.length() > 0 && filename[0] == '.' )
continue;
// Create full path name
out << _dirname << PATH_SEPARATOR << filename;
// Add to our directory entry collection
alphaSortedFileSet.insert ( out.str() );
alphaSortedPresetNameSet.insert ( filename );
// the directory entry struct is freed elsewhere
}
// Push all entries in order from the file set to the file entries member (which is an indexed vector)
for ( std::set<std::string>::iterator pos = alphaSortedFileSet.begin();
pos != alphaSortedFileSet.end();++pos )
_entries.push_back ( *pos );
// Push all preset names in similar fashion
for ( std::set<std::string>::iterator pos = alphaSortedPresetNameSet.begin();
pos != alphaSortedPresetNameSet.end();++pos )
_presetNames.push_back ( *pos );
// Give all presets equal rating of 3 - why 3? I don't know
_ratings = std::vector<RatingList>(TOTAL_RATING_TYPES, RatingList( _presetNames.size(), 3 ));
_ratingsSums = std::vector<int>(TOTAL_RATING_TYPES, 3 * _presetNames.size());
assert ( _entries.size() == _presetNames.size() );
// scan for presets
using namespace std::placeholders;
fileScanner.scan(std::bind(&PresetLoader::addScannedPresetFile, this, _1, _2));
// Give all presets equal rating of 3 - why 3? I don't know
_ratings = std::vector<RatingList>(TOTAL_RATING_TYPES, RatingList( _presetNames.size(), 3 ));
_ratingsSums = std::vector<int>(TOTAL_RATING_TYPES, 3 *_presetNames.size());
assert ( _entries.size() == _presetNames.size() );
}
std::unique_ptr<Preset> PresetLoader::loadPreset ( unsigned int index ) const
std::unique_ptr<Preset> PresetLoader::loadPreset ( PresetIndex index ) const
{
// Check that index isn't insane
assert ( index < _entries.size() );
return _presetFactoryManager.allocate
( _entries[index], _presetNames[index] );
}
std::unique_ptr<Preset> PresetLoader::loadPreset ( const std::string & url ) const
{
// std::cout << "Loading preset " << url << std::endl;
try {
/// @bug probably should not use url for preset name
return _presetFactoryManager.allocate
@ -157,40 +100,7 @@ std::unique_ptr<Preset> PresetLoader::loadPreset ( const std::string & url ) co
return std::unique_ptr<Preset>();
}
void PresetLoader::handleDirectoryError()
{
#ifdef WIN32
std::cerr << "[PresetLoader] warning: errno unsupported on win32 platforms. fix me" << std::endl;
#else
switch ( errno )
{
case ENOENT:
std::cerr << "[PresetLoader] ENOENT error. The path \"" << this->_dirname << "\" probably does not exist. \"man open\" for more info." << std::endl;
break;
case ENOMEM:
std::cerr << "[PresetLoader] out of memory! Are you running Windows?" << std::endl;
abort();
case ENOTDIR:
std::cerr << "[PresetLoader] directory specified is not a preset directory! Trying to continue..." << std::endl;
break;
case ENFILE:
std::cerr << "[PresetLoader] Your system has reached its open file limit. Trying to continue..." << std::endl;
break;
case EMFILE:
std::cerr << "[PresetLoader] too many files in use by projectM! Bailing!" << std::endl;
break;
case EACCES:
std::cerr << "[PresetLoader] permissions issue reading the specified preset directory." << std::endl;
break;
default:
break;
}
#endif
}
void PresetLoader::setRating(unsigned int index, int rating, const PresetRatingType ratingType)
void PresetLoader::setRating(PresetIndex index, int rating, const PresetRatingType ratingType)
{
const unsigned int ratingTypeIndex = static_cast<unsigned int>(ratingType);
assert (index < _ratings[ratingTypeIndex].size());
@ -199,11 +109,9 @@ void PresetLoader::setRating(unsigned int index, int rating, const PresetRatingT
_ratings[ratingTypeIndex][index] = rating;
_ratingsSums[ratingType] += rating;
}
unsigned int PresetLoader::addPresetURL ( const std::string & url, const std::string & presetName, const std::vector<int> & ratings)
unsigned long PresetLoader::addPresetURL ( const std::string & url, const std::string & presetName, const std::vector<int> & ratings)
{
_entries.push_back(url);
_presetNames.push_back ( presetName );
@ -220,9 +128,8 @@ unsigned int PresetLoader::addPresetURL ( const std::string & url, const std::st
return _entries.size()-1;
}
void PresetLoader::removePreset ( unsigned int index )
void PresetLoader::removePreset ( PresetIndex index )
{
_entries.erase ( _entries.begin() + index );
_presetNames.erase ( _presetNames.begin() + index );
@ -230,21 +137,19 @@ void PresetLoader::removePreset ( unsigned int index )
_ratingsSums[i] -= _ratings[i][index];
_ratings[i].erase ( _ratings[i].begin() + index );
}
}
const std::string & PresetLoader::getPresetURL ( unsigned int index ) const
const std::string & PresetLoader::getPresetURL ( PresetIndex index ) const
{
return _entries[index];
}
const std::string & PresetLoader::getPresetName ( unsigned int index ) const
const std::string & PresetLoader::getPresetName ( PresetIndex index ) const
{
return _presetNames[index];
}
int PresetLoader::getPresetRating ( unsigned int index, const PresetRatingType ratingType ) const
int PresetLoader::getPresetRating ( PresetIndex index, const PresetRatingType ratingType ) const
{
return _ratings[ratingType][index];
}
@ -258,23 +163,19 @@ const std::vector<int> & PresetLoader::getPresetRatingsSums() const {
return _ratingsSums;
}
void PresetLoader::setPresetName(unsigned int index, std::string name) {
void PresetLoader::setPresetName(PresetIndex index, std::string name) {
_presetNames[index] = name;
}
void PresetLoader::insertPresetURL ( unsigned int index, const std::string & url, const std::string & presetName, const RatingList & ratings)
void PresetLoader::insertPresetURL ( PresetIndex index, const std::string & url, const std::string & presetName, const RatingList & ratings)
{
_entries.insert ( _entries.begin() + index, url );
_presetNames.insert ( _presetNames.begin() + index, presetName );
for (unsigned int i = 0; i < _ratingsSums.size();i++) {
_ratingsSums[i] += _ratings[i][index];
_ratings[i].insert ( _ratings[i].begin() + index, ratings[i] );
}
assert ( _entries.size() == _presetNames.size() );
}