/*
* Copyright (C) 2024 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see .
*/
#include "ImageFileScanner.hpp"
#include
#include "core/ILogger.hpp"
#include "database/Db.hpp"
#include "database/Image.hpp"
#include "database/MediaLibrary.hpp"
#include "database/Session.hpp"
#include "image/Exception.hpp"
#include "image/Image.hpp"
#include "services/scanner/ScanErrors.hpp"
#include "FileScanOperationBase.hpp"
#include "IFileScanOperation.hpp"
#include "Utils.hpp"
namespace lms::scanner
{
namespace
{
class ImageFileScanOperation : public FileScanOperationBase
{
public:
using FileScanOperationBase::FileScanOperationBase;
private:
core::LiteralString getName() const override { return "ScanImageFile"; }
void scan() override;
OperationResult processResult() override;
std::optional _parsedImageProperties;
};
void ImageFileScanOperation::scan()
{
try
{
_parsedImageProperties = image::probeImage(getFilePath());
}
catch (const image::Exception& e)
{
_parsedImageProperties.reset();
addError(getFilePath());
}
}
ImageFileScanOperation::OperationResult ImageFileScanOperation::processResult()
{
db::Session& dbSession{ getDb().getTLSSession() };
db::Image::pointer image{ db::Image::find(dbSession, getFilePath()) };
if (!_parsedImageProperties)
{
if (image)
{
image.remove();
LMS_LOG(DBUPDATER, DEBUG, "Removed image " << getFilePath());
return OperationResult::Removed;
}
return OperationResult::Skipped;
}
const bool added{ !image };
if (!image)
image = dbSession.create(getFilePath());
image.modify()->setLastWriteTime(getLastWriteTime());
image.modify()->setFileSize(getFileSize());
image.modify()->setHeight(_parsedImageProperties->height);
image.modify()->setWidth(_parsedImageProperties->width);
db::MediaLibrary::pointer mediaLibrary{ db::MediaLibrary::find(dbSession, getMediaLibrary().id) }; // may be null if settings are updated in // => next scan will correct this
image.modify()->setDirectory(utils::getOrCreateDirectory(dbSession, getFilePath().parent_path(), mediaLibrary));
if (added)
{
LMS_LOG(DBUPDATER, DEBUG, "Added image " << getFilePath());
return OperationResult::Added;
}
LMS_LOG(DBUPDATER, DEBUG, "Updated image " << getFilePath());
return OperationResult::Updated;
}
} // namespace
ImageFileScanner::ImageFileScanner(db::Db& db, ScannerSettings& settings)
: _db{ db }
, _settings{ settings }
{
}
core::LiteralString ImageFileScanner::getName() const
{
return "Image scanner";
}
std::span ImageFileScanner::getSupportedFiles() const
{
return {};
}
std::span ImageFileScanner::getSupportedExtensions() const
{
return image::getSupportedFileExtensions();
}
bool ImageFileScanner::needsScan(const FileToScan& file) const
{
db::Session& dbSession{ _db.getTLSSession() };
auto transaction{ _db.getTLSSession().createReadTransaction() };
const db::Image::pointer image{ db::Image::find(dbSession, file.filePath) };
return (!image || image->getLastWriteTime() != file.lastWriteTime);
}
std::unique_ptr ImageFileScanner::createScanOperation(FileToScan&& fileToScan) const
{
return std::make_unique(std::move(fileToScan), _db, _settings);
}
} // namespace lms::scanner