Skip to content

Commit

Permalink
Import: Add option case sensitive tags
Browse files Browse the repository at this point in the history
If option is active the behaviour is as before.
Turning the option off handles every tag in virtual layout as lowercase even if it is displayed uppercase
  • Loading branch information
KarlStraussberger committed May 1, 2024
1 parent 4e867f5 commit 5da4105
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 22 deletions.
15 changes: 15 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
## Gerbera - UPnP AV Mediaserver.

### HEAD

- Adding consistent album artist support
- Build: Allow build of ffmpegthumbnailer without ffmpeg
- CI: Drop excluded ubuntu versions as CMake PPA now supports those combinations
- CI: Pass publish-deb secrets via env instead
- CI: Upload debs to pkg.gerbera.io
- clang-tidy: don't cast through void
- docs: Update Arch Linux installs
- Docs: Update Ubuntu/Debian repo instructions
- Import: fix single file update
- Playlist: Allow configuration of directory depth
- TagLib: Use DebugListener to suppress messages
- UI: Tidy up login and homepage

### 2.1.0

- Add ctypes include
Expand Down
18 changes: 18 additions & 0 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Gerbera - UPnP AV Mediaserver.

## HEAD

This is a really small update that brings better logging for TagLib and a new repository for ubuntu and debian getting rid of jfrog.

### NEW Features

- TagLib messages are logged with gerbera now. They also show up with `debug-mode="taglib"`.
- Configuration for case sensitive media tags (allow making them insensitive)
- Configuration options for playlist layout
- WebUI: New design for home page and login screen

### FIXES

- Album artist handling in default js layout
- Build with ffmpegthumbnailer but without ffmpeg
- Changed repository for ubuntu and debian to https://pkg.gerbera.io/


## 2.1.0

This release started out as a mere bugfix release but gathered some nice features along the way.
Expand Down
1 change: 1 addition & 0 deletions config/config2.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@
<xs:attribute name="default-date" type="boolean" default="yes"/>
<xs:attribute name="nomedia-file" type="xs:string" default=".nomedia"/>
<xs:attribute name="readable-names" type="boolean" default="yes"/>
<xs:attribute name="case-sensitive-tags" type="boolean" default="yes"/>
<xs:attribute name="import-mode" default="mt">
<xs:simpleType>
<xs:restriction base="xs:string">
Expand Down
16 changes: 16 additions & 0 deletions doc/config-import.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ The import settings define various options on how to aggregate the content.
``import``
~~~~~~~~~~

.. Note::

Whenever config entries in this section are changed, it is recommended to clear the database and restart a full import again. Otherwise the virtual layout can be broken or in some
mixed state.

::

<import hidden-files="no" follow-symlinks="no">
Expand Down Expand Up @@ -165,6 +170,17 @@ This tag defines the import section.

This attribute defines that filenames are made readable on import, i.e. underscores are replaced by space and extensions are removed. This changes the title of the entry if no metadata is available

::

case-sensitive-tags="yes|no"

* Optional

* Default: **yes**

This attribute defines that virtual paths are case sensitive, e.g. artist names like `Ace Of Grace` and `Ace of Grace` are treated as different (``yes``) or identical (``no``).
This changes the location property of created virtual entries.

::

import-mode="mt|grb"
Expand Down
1 change: 1 addition & 0 deletions src/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ enum config_option_t {
CFG_UPNP_TITLE_NAMESPACES,
CFG_UPNP_CAPTION_COUNT,
CFG_IMPORT_READABLE_NAMES,
CFG_IMPORT_CASE_SENSITIVE_TAGS,
CFG_SERVER_DYNAMIC_CONTENT_LIST_ENABLED,
CFG_SERVER_DYNAMIC_CONTENT_LIST,
CFG_IMPORT_RESOURCES_ORDER,
Expand Down
3 changes: 3 additions & 0 deletions src/config/config_definition.cc
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,9 @@ const std::vector<std::shared_ptr<ConfigSetup>> ConfigDefinition::complexOptions
std::make_shared<ConfigBoolSetup>(CFG_IMPORT_READABLE_NAMES,
"/import/attribute::readable-names", "config-import.html#import",
YES),
std::make_shared<ConfigBoolSetup>(CFG_IMPORT_CASE_SENSITIVE_TAGS,
"/import/attribute::case-sensitive-tags", "config-import.html#import",
YES),
std::make_shared<ConfigDictionarySetup>(CFG_IMPORT_MAPPINGS_EXTENSION_TO_MIMETYPE_LIST,
"/import/mappings/extension-mimetype", "config-import.html#extension-mimetype",
ATTR_IMPORT_MAPPINGS_MIMETYPE_MAP, ATTR_IMPORT_MAPPINGS_MIMETYPE_FROM, ATTR_IMPORT_MAPPINGS_MIMETYPE_TO,
Expand Down
47 changes: 26 additions & 21 deletions src/content/import_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ ImportService::ImportService(std::shared_ptr<Context> context)
, database(this->context->getDatabase())
{
hasReadableNames = config->getBoolOption(CFG_IMPORT_READABLE_NAMES);
hasCaseSensitiveNames = config->getBoolOption(CFG_IMPORT_CASE_SENSITIVE_TAGS);
hasDefaultDate = config->getBoolOption(CFG_IMPORT_DEFAULT_DATE);
mimetypeContenttypeMap = config->getDictionaryOption(CFG_IMPORT_MAPPINGS_MIMETYPE_TO_CONTENTTYPE_LIST);
mimetypeUpnpclassMap = config->getDictionaryOption(CFG_IMPORT_MAPPINGS_MIMETYPE_TO_UPNP_CLASS_LIST);
Expand Down Expand Up @@ -212,17 +213,17 @@ void ImportService::clearCache()

void ImportService::doImport(const fs::path& location, AutoScanSetting& settings, std::unordered_set<int>& currentContent, const std::shared_ptr<GenericTask>& task)
{
log_debug("start {}", location.string());
log_debug("start {} root '{}'", location.string(), rootPath.string());
if (activeScan.empty()) {
contentStateCache.clear();
activeScan = location;
} else {
log_debug("Additional scan {}, already active {}", location.c_str(), activeScan.c_str());
}

if (!this->rootPath.empty()) {
auto rootDirEntry = fs::directory_entry(this->rootPath);
cacheState(this->rootPath, rootDirEntry, ImportState::New, toSeconds(rootDirEntry.last_write_time(ec)));
if (!rootPath.empty()) {
auto rootDirEntry = fs::directory_entry(rootPath);
cacheState(rootPath, rootDirEntry, ImportState::New, toSeconds(rootDirEntry.last_write_time(ec)));
}
auto rootEntry = fs::directory_entry(location);
if (ec) {
Expand Down Expand Up @@ -714,25 +715,25 @@ void ImportService::assignFanArt(const std::shared_ptr<CdsContainer>& container,
}
}
if (!fanart || fanart->getHandlerType() != ContentHandler::CONTAINERART) {
if (fanart) {
container->clearResources();
}
metadataService->getHandler(ContentHandler::CONTAINERART)->fillMetadata(container);
auto containerart = container->getResource(ResourcePurpose::Thumbnail);
if (containerart) {
container->clearResources();
container->addResource(containerart); // overwrite all other resources by container art
database->updateObject(container, nullptr);
fanart = containerart;
}
log_debug("fanart from dir {}", containerart != nullptr);
}

auto location = container->getLocation();
if (refObj) {
if (!fanart && (refObj->isContainer() || (count < containerImageParentCount && container->getParentID() != CDS_ID_ROOT && std::distance(location.begin(), location.end()) > containerImageMinDepth))) {
fanart = refObj->getResource(ResourcePurpose::Thumbnail);
if (fanart) {
if (refObj && !fanart) {
auto location = container->getLocation();
if (refObj->isContainer() || (count < containerImageParentCount && container->getParentID() != CDS_ID_ROOT && std::distance(location.begin(), location.end()) > containerImageMinDepth)) {
auto refFanArt = refObj->getResource(ResourcePurpose::Thumbnail);
if (refFanArt) {
auto fanArtObj = refObj;
auto fanArtObjId = refObj->getID();
auto fanArtResId = fanart->getResId();
auto fanArtResId = refFanArt->getResId();
if (refObj->getID() <= CDS_ID_ROOT) {
fanArtObj = database->loadObject(refObj->getRefID());
auto fanartRef = fanArtObj->getResource(ResourcePurpose::Thumbnail);
Expand All @@ -745,22 +746,23 @@ void ImportService::assignFanArt(const std::shared_ptr<CdsContainer>& container,
fanArtResId++;
}
}
if (fanart->getAttribute(ResourceAttribute::RESOURCE_FILE).empty()) {
if (refFanArt->getAttribute(ResourceAttribute::RESOURCE_FILE).empty()) {
if (fanArtObjId > CDS_ID_ROOT) {
fanart->addAttribute(ResourceAttribute::FANART_OBJ_ID, fmt::to_string(fanArtObjId));
fanart->addAttribute(ResourceAttribute::FANART_RES_ID, fmt::to_string(fanArtResId));
} else {
fanart = nullptr;
refFanArt->addAttribute(ResourceAttribute::FANART_OBJ_ID, fmt::to_string(fanArtObjId));
refFanArt->addAttribute(ResourceAttribute::FANART_RES_ID, fmt::to_string(fanArtResId));
fanart = refFanArt;
}
} else {
fanart = refFanArt;
}
if (fanart)
container->addResource(fanart);
log_debug("fanart from ref {}", fanart != nullptr);
database->updateObject(container, nullptr);
}
}
}
if (fanart) {
container->clearResources();
container->addResource(fanart); // overwrite all other resources
database->updateObject(container, nullptr);
containersWithFanArt[container->getID()] = container;
}
}
Expand Down Expand Up @@ -833,6 +835,9 @@ std::pair<int, bool> ImportService::addContainerTree(
} else {
subTree = tree;
}
if (!hasCaseSensitiveNames) {
subTree = toLower(subTree);
}
if (containerMap.find(subTree) == containerMap.end() || !containerMap[subTree]) {
auto cont = database->findObjectByPath(subTree, DbFileType::Virtual);
if (cont && cont->isContainer())
Expand Down
1 change: 1 addition & 0 deletions src/content/import_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ class ImportService {
fs::path rootPath;
std::string noMediaName;
bool hasReadableNames { false };
bool hasCaseSensitiveNames { true };
bool hasDefaultDate { true };
int containerImageParentCount { 2 };
int containerImageMinDepth { 2 };
Expand Down
3 changes: 2 additions & 1 deletion src/content/scripting/script.cc
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ Script::Script(const std::shared_ptr<ContentManager>& content, const std::string
, contextName(fmt::format("{}_{}", name, parent))
, objectName(std::move(objName))
{
hasCaseSensitiveNames = config->getBoolOption(CFG_IMPORT_CASE_SENSITIVE_TAGS);
entrySeparator = config->getOption(CFG_IMPORT_LIBOPTS_ENTRY_SEP);
/* create a context and associate it with the JS run time */
ScriptingRuntime::AutoLock lock(runtime->getMutex());
Expand Down Expand Up @@ -778,7 +779,7 @@ std::shared_ptr<CdsObject> Script::dukObject2cdsObject(const std::shared_ptr<Cds
}
duk_pop(ctx); // metaData

fs::path location = getProperty("location");
fs::path location = !hasCaseSensitiveNames && obj->isContainer() ? toLower(getProperty("location")) : getProperty("location");
if (!location.empty()) {
// location must not be touched by character conversion!
obj->setLocation(location);
Expand Down
1 change: 1 addition & 0 deletions src/content/scripting/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class Script {
std::unique_ptr<StringConverter> sc;

private:
bool hasCaseSensitiveNames;
std::string entrySeparator;
std::string contextName;
std::string objectName;
Expand Down
5 changes: 5 additions & 0 deletions web/gerbera-config-expert.json
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,11 @@
"caption": "Set Default Date",
"editable": true
},
{
"item": "/import/attribute::case-sensitive-tags",
"caption": "Handle Media Tags Case Sensitive",
"editable": true
},
{
"item": "/import/attribute::follow-symlinks",
"caption": "Follow Symlinks",
Expand Down
5 changes: 5 additions & 0 deletions web/gerbera-config-standard.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,11 @@
"caption": "Import Mode",
"editable": true
},
{
"item": "/import/attribute::case-sensitive-tags",
"caption": "Handle Media Tags Case Sensitive",
"editable": true
},
{
"item": "/import/attribute::follow-symlinks",
"caption": "Follow Symlinks",
Expand Down

0 comments on commit 5da4105

Please sign in to comment.