diff --git a/docsite/docs/configuration/transforms/musicbrainz.mdx b/docsite/docs/configuration/transforms/musicbrainz.mdx
index 57fb3319..315517ca 100644
--- a/docsite/docs/configuration/transforms/musicbrainz.mdx
+++ b/docsite/docs/configuration/transforms/musicbrainz.mdx
@@ -321,6 +321,8 @@ To configure [stage defaults](#stage-configuration) use `MB_PRESETS` with a comm
* `aggressive` - Adds **Free Text Search** (`freetext`) to [`searchOrder`](#search-methods)
* `fields` - Applies [Field Scoring](#field-scoring) to match sorting so match text is baised towards similarity to original scrobble
* `sensible` - Applies the [Sensible Default](#sensible-default) configuration for [sorting releases](#sorting-releases)
+* `musicvideo` - *Allows* music videos as a valid search result (not allowed by default)
+* `audiobook` - *Allows* audiobooks as a valid search result (not allowed by default)
Finally, use ENV `*_TRANSFORMS=musicbrainz` on each Source/Client you wish to apply this stage to. This applies the stage in the [`preTransform` Hook](/configuration/transforms#lifecycle-hooks) with all [Rules](#rules-and-hooks) enabled.
@@ -732,7 +734,7 @@ An easy way to think about this:
* Should a track that belongs to a Compilation album be allowed to match?
* What country do you prefer an album release to be from?
-##### Release Attributes
+#### Release Attributes
These attributes (`attribute_name` in config) are:
@@ -757,11 +759,67 @@ EX to exclude compilations
"releaseGroupSecondaryTypeDeny": ["compilation"]
```
+:::tip[Allow Overrides Deny]
+
+When a release attributes has both types of filter (`allow` and `deny`), only `allow` is used:
+
+```
+"releaseStatusAllow": ["official"],
+"releaseStatusDeny": ["bootleg","promotional"] // this is ignored!
+```
+
+:::
+
+
+
+The [Release Group **Secondary Type**](https://wiki.musicbrainz.org/Release_Group/Type#Secondary_types) (`releaseGroupSecondaryType`) can be `audiobook` which is rarely a desired result.
+
+When `releaseGroupSecondaryTypeDeny` is **not** defined it defaults to:
+
+```
+"releaseGroupSecondaryTypeDeny": ["audiobook"]
+```
+
+which filters out audiobook results.
+
+If you *want* to include audiobook results then explicitly define this and set it to an empty array EX:
+
+```
+"releaseGroupSecondaryTypeDeny": []
+```
+
+
+
+#### Music Videos
+
+Search results can also return Recordings that are **Music Videos**. These are rarely a desired result so they are **filtered out by default.**
+
+If you want to include music videos in results then add this to your config: `"allowMusicVideo": true`
+
+
+
+Example
+
+```json5
+// ...
+"defaults": {
+ //"releaseStatusAllow": ["official"],
+ // ...etc
+ "allowMusicVideo": true
+}
+```
+
+
+
#### Empty Releases
Sometimes a Recording may not have any associated Releases. This may be because there is not enough information about the Recording yet, or it was never included on an actual Release.
-You may want to filter the majority of your matches by releases but allow matching a Recording that has no releases to begin with. To allow this set `releaseAllowEmpty` to `true` in configuration:
+You may want to filter the majority of your matches by releases but allow matching a Recording that has no releases to begin with. To allow this set `releaseAllowEmpty` to `true` in configuration.
+
+
+
+Example
```json5
// ...
@@ -771,6 +829,8 @@ You may want to filter the majority of your matches by releases but allow matchi
}
```
+
+
### Sorting
diff --git a/src/backend/common/transforms/MusicbrainzTransformer.ts b/src/backend/common/transforms/MusicbrainzTransformer.ts
index 7e735306..cecafb0c 100644
--- a/src/backend/common/transforms/MusicbrainzTransformer.ts
+++ b/src/backend/common/transforms/MusicbrainzTransformer.ts
@@ -1,5 +1,5 @@
import { type ArtistCredit, DEFAULT_MISSING_TYPES, type LifecycleInput, type MissingMbidType, type OptionalCacheUsage, type PlayObject, type TrackMetaIsrc } from "../../../core/Atomic.ts";
-import { mBReleaseSecondaryGroupTypesSchema } from "../vendor/musicbrainz/MusicbrainzTypes.ts";
+import { MB_RELEASE_GROUP_SECONDARY_TYPES, mBReleaseSecondaryGroupTypesSchema } from "../vendor/musicbrainz/MusicbrainzTypes.ts";
import { type MBReleaseGroupSecondaryType } from "../vendor/musicbrainz/MusicbrainzTypes.ts";
import { type MBReleaseGroupPrimaryType } from "../vendor/musicbrainz/MusicbrainzTypes.ts";
import { mBReleasePrimaryGroupTypesSchema } from "../vendor/musicbrainz/MusicbrainzTypes.ts";
@@ -113,7 +113,7 @@ export const parseStageConfig = (data: MusicbrainzTransformerData | undefined =
releaseGroupPrimaryTypeDeny,
releaseGroupPrimaryTypePriority,
releaseGroupSecondaryTypeAllow,
- releaseGroupSecondaryTypeDeny,
+ releaseGroupSecondaryTypeDeny = [MB_RELEASE_GROUP_SECONDARY_TYPES.enum.audiobook],
releaseGroupSecondaryTypePriority,
releaseStatusAllow,
releaseStatusDeny,
@@ -131,6 +131,7 @@ export const parseStageConfig = (data: MusicbrainzTransformerData | undefined =
titleWeight,
albumWeight,
artistWeight,
+ allowMusicVideo = false,
...rest
} = data;
@@ -153,6 +154,7 @@ export const parseStageConfig = (data: MusicbrainzTransformerData | undefined =
releaseCountryAllow: maybeStringLowerArrayFromString.parse(releaseCountryAllow),
releaseCountryDeny: maybeStringLowerArrayFromString.parse(releaseCountryDeny),
releaseCountryPriority: maybeStringLowerArrayFromString.parse(releaseCountryPriority),
+ allowMusicVideo,
...rest,
};
@@ -162,6 +164,10 @@ export const parseStageConfig = (data: MusicbrainzTransformerData | undefined =
logger.debug(`Will search if missing: ${config.searchWhenMissing.join(', ')} | Match if (default) score is >= ${config.score}`);
+ if(allowMusicVideo === false) {
+ logger.debug('Disallowing music videos in results');
+ }
+
let soSet = searchOrder.length > 0 ? new Set(searchOrder.map(asSearchType)) : new Set();
const depSearch = [];
@@ -518,7 +524,8 @@ export default class MusicbrainzTransformer extends AtomicPartsTransformer x.video === true)) {
+ hadMusicVideo = true;
+ filteredList = filteredList.filter(x => x.video !== true);
+ }
+
const mergedConfig = Object.assign({}, removeUndefinedKeys({...this.defaults}), removeUndefinedKeys({...stageConfig}));
filteredList = filterByValidReleaseStatus(filteredList, mergedConfig);
filteredList = filterByValidReleaseGroupPrimary(filteredList, mergedConfig);
@@ -547,7 +560,7 @@ export default class MusicbrainzTransformer extends AtomicPartsTransformer = {
default: DEFAULTS_PRESET,
sensible: DEFAULTS_SENSIBLE,
native: DEFAULTS_NATIVE,
aggressive: DEFAULTS_AGGRESSIVE,
fields: DEFAULTS_FIELDS_BIAS,
+ musicvideo: DEFAULTS_MUSIC_VIDEO,
+ audiobook: DEFAULTS_AUDIOBOOK,
'id': DEFAULTS_ID
};