Repository: Flexget/Flexget

Issue:
Issue with multiple color range HDR and DV
### Expected behaviour: File detected as HDR and dolbyvision color range
### Actual behaviour: File is detected only as dolbyvision

### Steps to reproduce:
- Step 1: Filter any series that the episode have both DV and HDR color range
- Step 2: The episode will be identified only as DV color range and not both.
- Example of rejected entry:
SeriesNameHere.S02E02.TitleHere.2160p.ATVP.WEB-DL.DDP5.1.Atmos.DV.HDR10+.H.265-Group
SeriesNameHere S02E02 TitleHere 2160p ATVP WEB-DL DDP5 1 DV HDR H 265-Group

#### Config:
```yaml
web_server:
  bind: 0.0.0.0
  port: 5050
  web_ui: yes

schedules:
  - tasks: [doit]
    interval:
      minutes: 15

templates:
  tv:
    series:
      settings:
        2160pHDR:
          quality: 2160p webrip+ hdr|hdrplus
          specials: no
      2160pHDR:
        - SeriesNameHere
    deluge:
      host: xxxxxxxxx
      username: xxxxxxxxx
      password: xxxxxxxxx
      path: /mnt/seriados/{{series_name}}/

tasks:
  doit:
    rss:
      url: xxxxxxxxx
      all_entries: no
    priority: 1
    template: tv
```
### Additional information:
- FlexGet version: 3.11.58
- Python version: 3.11.10
- Installation method: Docker (linuxserver/docker-flexget)
- Using daemon (yes/no): yes
- OS and version: Alpine 3.20


Discussion:
That's not how flexget works, quality of a release is the greatest in each category, in that case is Dolby vision.

You'll have to improvise a little, instead of using quality, try using regexp to accept "hdr".
already did a workaround with regexp, maybe it should not be a issue but a suggestion for a new quality like dolbyvisionHDR when it have both (.DV.HDR) as nowadays there are several releases with both.
There's no standard, so you'd have to nail down the order in which they appear and cover every possible variation in the regular expression.
> There's no standard, so you'd have to nail down the order in which they appear and cover every possible variation in the regular expression.

i dont see it, a regex like this could find when it have both and set it to a new quality like DVHDR

(DV|HDR)(?:.*)(HDR|DV)

![Captura de tela 2024-12-02 180853](https://github.com/user-attachments/assets/edfa02d9-9124-4618-8a23-8cef6671b403)

I've started to come up against the same problem with Dolby Vision HDR videos that are encoded as Profile 8 which has the the HDR / HDR10+ streams in the BL (Base Layer) and the Dolby Vision data in the RPU stream and are often labeled as "DV HDR" or "DoVi HDR" to allow playback on HDR and/or DV televisions.

The problem is the files that are only labeled as "DV" or "DoVi" solo without any "HDR*" suffix are usually encoded as Dolby Vision Profile 5 or 7 with that in the RPU stream which uses a proprietary IPTPQc2 color space that even my 2019 LG OLED TV which is designed to work with Profile 5 and 7 and has the proper licensing doesn't want to decode and that is often seen as the Green & Purple color output and the files end up being deleted since I don't want to bother converting the color spaces with a dozen different tools and utilities such as DDVT Demuxer https://forum.doom9.org/showthread.php?t=183479

The problem is as explained above as shown in the source code below.  Once the `qualities.py` utility runs and the "dolbyvision" regexp runs last in the qualities determination it always wins above all "hdr" and "hdrplus" color ranges in the `qualities` field because of the highest value '50' rank, so it overwrites and ignores the "hdr" and "hdrplus" labels.

The best way to solve this is to update the source code with a line to recognize this quality combitation and create a new quality to mark it to allow folks to filter properly to avoid the solo "DVp5/7" Green/Purpose releases and get the "DVp8 & HDR+" releases which are becoming the most common ones for combined DV & HDR.

### References

Dolby Vision - Profiles: https://en.wikipedia.org/wiki/Dolby_Vision
ICtCp - https://en.wikipedia.org/wiki/ICtCp#IPTPQc2
DDVT Demux - https://forum.doom9.org/showthread.php?t=183479

### Source Code

https://github.com/Flexget/Flexget/blob/050ea7c9084ab631fcac6ec2d1594f37e9565f59/flexget/utils/qualities.py#L156-L162

### Source Code Update

Note: The order of the "DV HDR" and "HDR DV" is duplicated and written explicitly even though after the alternation | operator it would be possible to substitute `\2\b.*\b\1` but I found some back reference groups not working if doing complex wildcard matches

```
QualityComponent('color_range', 60, 'dvhdr', r'(dolby[^\w]?vision|dv|do[^\w]?vi)\b.*\bhdr[^\w]?((10)?[^\w]?(\+|p|plus)?)?|hdr[^\w]?((10)?[^\w]?(\+|p|plus)?)?\b.*\b(dolby[^\w]?vision|dv|do[^\w]?vi)'),
```

### Workaround Filter

Below is a filter that you can use so that if you specified the 'dolbyvision' in your quality requirements you can use the filter below to ensure that it only accept titles that have HDR* in it since it will likely be Dolby Vision Profile 8 and actually watchable with proper colors instead of Profile 5 with Green & Purple color problems.

`config.yml`

```
if:
  - 'quality is defined and "dolbyvision" in quality and title is defined and not "hdr" in title | re_search( "(?i)\\bHDR\\W*(?:(?:10)?\\W*(?:\\+|P|Plus)?)?\\b" ) | lower' : reject
```
### HLG (Hybrid-Log Gamma)

There are a few files out there that are labeled as 'HLG' for the "color_range" and creating a `hlg` string might be desirable, but it would probably have to be placed somewhere between HDR and DV.

There's also this additional "color_range" setting that is quite rare but sometimes shows up.  This format can also show up as a HLG BL (Base-Layer) for Dolby Vision Profile 8 (dvhe.08) format for the HEVC (H.265) codec and also as Profile 10 level 4 (dvav.10) for the AV1 codec.  So creating a `dvhlg` setting might also be required in the future if the format becomes more popular, but it isn't very popular now and it is mostly used in the UK and Japan and these are over-the-air broadcast captures so they are mostly labeled as 'HLG' alone.

Something to keep in mind if someone wants to touch the "color_range" settings.

### References

Wikipedia: https://en.wikipedia.org/wiki/Hybrid_log%E2%80%93gamma

Dolby Vision: https://professionalsupport.dolby.com/s/article/What-is-Dolby-Vision-Profile?language=en_US

Profiles: https://dolby.my.salesforce.com/sfc/p/#700000009YuG/a/4u000000l6G4/4R18riPaaW3gxpVx7XwyQLdEITLFjB.w.Si0LoQR5j8

MediaInfo: https://mediaarea.net/en/MediaInfo
### MediaInfo Output


### Dolby Vision Profile 5 = Green & Purple

`mediainfo`

```
Video
ID                                       : 1
Format                                   : HEVC
Format/Info                              : High Efficiency Video Coding
Format profile                           : Main 10@L5.1@Main
HDR format                               : Dolby Vision, Version 1.0, Profile 5, dvhe.05.06, BL+RPU, no metadata compression
Codec ID                                 : V_MPEGH/ISO/HEVC
Duration                                 : 48 min 46 s
Bit rate                                 : 20.9 Mb/s
Width                                    : 3 840 pixels
Height                                   : 1 920 pixels
Display aspect ratio                     : 2.000
Frame rate mode                          : Constant
Frame rate                               : 23.976 (24000/1001) FPS
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 10 bits
Bits/(Pixel*Frame)                       : 0.118
Stream size                              : 7.12 GiB (95%)
Writing library                          : x265 3.5+1-f0c1022b6:[Linux][GCC 10.2.1][64 bit] 10bit
Default                                  : Yes
Forced                                   : No
Color range                              : Full
Conformance errors                       : 1
 HEVC                                    : Yes
```

### Dolby Vision Profile 8 = HDR Correct Colors

`mediainfo`

```
Video
ID                                       : 1
Format                                   : HEVC
Format/Info                              : High Efficiency Video Coding
Format profile                           : Main 10@L5@Main
HDR format                               : Dolby Vision, Version 1.0, Profile 8.1, dvhe.08.06, BL+RPU, HDR10 compatible / SMPTE ST 2094 App 4, Version HDR10+ Profile B, HDR10+ Profile B compatible
Codec ID                                 : V_MPEGH/ISO/HEVC
Duration                                 : 1 h 11 min
Bit rate                                 : 14.0 Mb/s
Width                                    : 3 840 pixels
Height                                   : 1 600 pixels
Display aspect ratio                     : 2.40:1
Frame rate mode                          : Constant
Frame rate                               : 23.976 (24000/1001) FPS
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 10 bits
Bits/(Pixel*Frame)                       : 0.095
Stream size                              : 7.01 GiB (96%)
Language                                 : English (US)
Default                                  : Yes
Forced                                   : No
Color range                              : Limited
Color primaries                          : BT.2020
Transfer characteristics                 : PQ
Matrix coefficients                      : BT.2020 non-constant
Mastering display color primaries        : Display P3
Mastering display luminance              : min: 0.0001 cd/m2, max: 1000 cd/m2
Maximum Content Light Level              : 992 cd/m2
Maximum Frame-Average Light Level        : 623 cd/m2
```



Patch:
diff --git a/flexget/utils/qualities.py b/flexget/utils/qualities.py
index 9e982c9bf0..fceccd9b09 100644
--- a/flexget/utils/qualities.py
+++ b/flexget/utils/qualities.py
@@ -153,12 +153,17 @@ def __deepcopy__(self, memo=None):
     QualityComponent('codec', 50, 'av1', 'av-?1'),
 ]
 
+hdr = r'hdr([^\w]?10)?'
+hdr_plus = r'hdr(10)?[^\w]?(\+|p|plus)'
+dovi = r'(dolby[^\w]?vision|dv|dovi)'
 _color_ranges = [
     QualityComponent('color_range', 10, '8bit', r'8[^\w]?bits?|hi8p?'),
     QualityComponent('color_range', 20, '10bit', r'10[^\w]?bits?|hi10p?'),
-    QualityComponent('color_range', 30, 'hdr', r'hdr([^\w]?10)?'),
-    QualityComponent('color_range', 40, 'hdrplus', r'hdr(10)?[^\w]?(\+|p|plus)'),
-    QualityComponent('color_range', 50, 'dolbyvision', r'(dolby[^\w]?vision|dv|dovi)'),
+    # Must come before the individual ones since it's stripped from the title
+    QualityComponent('color_range', 60, 'hybrid-hdr', f'(({dovi}|{hdr_plus}|{hdr})\\W?){{2,3}}'),
+    QualityComponent('color_range', 30, 'hdr', hdr),
+    QualityComponent('color_range', 40, 'hdrplus', hdr_plus),
+    QualityComponent('color_range', 50, 'dolbyvision', dovi),
 ]
 
 channels = r'(?:(?:[^\w+]?[1-7][\W_]?(?:0|1|ch)))'


Test patch:
diff --git a/tests/test_qualities.py b/tests/test_qualities.py
index b52a0ff34b..79f6b129a7 100644
--- a/tests/test_qualities.py
+++ b/tests/test_qualities.py
@@ -102,6 +102,8 @@ def parser(self, request):
             ('Test.File.DTSHDMA5.1', 'dtshd'),
             ('Test.File.DD2.0', 'dd5.1', False),
             ('Test.File.AC35.1', 'ac3', False),
+            ('Test.File.HDR.DOVI', 'hybrid-hdr', False),
+            ('Test.File.DV.HDR10+', 'hybrid-hdr', False),
         ],
     )
     def test_quality_failures(self, parser, test_quality):