Quality Recognization Error
Summary
Issue Summary
Two releases are being parsed differently even though one of them contains a strictly better HDR profile:
-
Name: Pluribus S01E05 2160p WEB-DL DD+5.1 DoVi HDR10+ HEVC-NTb
Detected: 2160p webdl h265 hdr dd+5.1 (wrong) -
Name: Pluribus S01E05 2160p WEB-DL DD+5.1 DoVi HEVC-NTb
Detected: 2160p webdl h265 dolbyvision dd+5.1 (correct)
The first release contains Dolby Vision + HDR10+, but is only recognized as standard hdr (rather than hdrplus or dolbyvision or hybrid_hdr) , causing the quality comparer to incorrectly allow a downgrade when an upgrade check is performed. (Flexget will make second one a upgrade of first one)
Proposed Improvement
The first one should be recognized as hybird_hdr. After that there is a issue that hybird_hdr do not have internal logic does not distinguish different mixed HDR formats by relative quality.
I suggest enhancing the hybrid_hdr handling with a simple scoring-based model so that hybrid HDR stacks evaluate correctly.
Example Scoring:
- Dolby Vision = 40
- HDR10+ = 20
- HDR10 = 10
Applied to the above releases:
- DoVi + HDR10+ → 60 (correctly highest)
- DoVi + HDR10 → 50
- DoVi only → 40
This prevents scenarios where a lower-quality DoVi-only release is treated as an upgrade over a DoVi+HDR10+ release.
Additional Suggestion
reorder_quality should support assigning Hybrid_HDR qualities based on this scoring structure.
This ensures the comparer can reliably rank hybrid HDR releases and avoid unintended downgrades.
Minimal reproducible config
Log
Additional information
FlexGet Version: 3.18.28 Python Version: OS Version: Installation Method: Docker Using Daemon (yes/no): Yes
The parsing is already scored https://github.com/Flexget/Flexget/blob/f73d6fa46e78af3aeec6ba5a0f1e2b6a714ca9b3/flexget/utils/qualities.py#L158-L169
Also, cannot repro the issue, hybrid was recognized as expected
tasks:
test:
mock:
- Pluribus S01E05 2160p WEB-DL DD+5.1 DoVi HDR10+ HEVC-NTb
- Pluribus S01E05 2160p WEB-DL DD+5.1 DoVi HEVC-NTb
series:
- Pluribus
title : Pluribus S01E05 2160p WEB-DL DD+5.1 DoVi HDR10+ HEVC-NTb
quality : 2160p webdl h265 hybrid_hdr dd+5.1
title : Pluribus S01E05 2160p WEB-DL DD+5.1 DoVi HDR10+ HEVC-NTb
quality : 2160p webdl h265 dolbyvision dd+5.1
The parsing is already scored
Flexget/flexget/utils/qualities.py
Lines 158 to 169 in f73d6fa
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?|sdr'), QualityComponent('color_range', 20, '10bit', r'10[^\w]?bits?|hi10p?'), QualityComponent('color_range', 30, 'hdr', hdr), QualityComponent('color_range', 40, 'hdrplus', hdr_plus), QualityComponent('color_range', 50, 'dolbyvision', dovi), QualityComponent('color_range', 60, 'hybrid_hdr', f'(({dovi}|{hdr_plus}|{hdr})\W?){{2,3}}'), ]
Thanks for sharing the code and example, from my understanding hybrid_hdr is currently treated as a single fixed value (60), so it can’t differentiate combinations (e.g., DoVi+HDR10+ vs DoVi+HDR10). So if it supports combo-aware/additive scoring for this field, hybrid formats can be ranked more accurately and future proof if more combination is possible.
Also, cannot repro the issue, hybrid was recognized as expected
tasks: test: mock: - Pluribus S01E05 2160p WEB-DL DD+5.1 DoVi HDR10+ HEVC-NTb - Pluribus S01E05 2160p WEB-DL DD+5.1 DoVi HEVC-NTb series: - Pluribus
title : Pluribus S01E05 2160p WEB-DL DD+5.1 DoVi HDR10+ HEVC-NTb quality : 2160p webdl h265 hybrid_hdr dd+5.1 title : Pluribus S01E05 2160p WEB-DL DD+5.1 DoVi HDR10+ HEVC-NTb quality : 2160p webdl h265 dolbyvision dd+5.1
Thanks for clarification, I rerun the test it's recognized correctly with 3.18.28.
@BrutuZ After another experiment, I found something strange.
When I using flexget exec --task task_name --dump trace --no-cache --now the dump result show correct quality
quality : 2160p webdl h265 hybrid_hdr dd+5.1 reason : target quality release_group : None rss_pubdate : 2025-12-05 02:14:54+00:00 season_pack : None series_episode : 6 series_episodes : 1 series_exact : False series_guessed : True series_id : S01E06 series_id_type : ep series_identified_by : ep series_name : Pluribus series_parser : <SeriesParseResult(data=Pluribus S01E06 2160p WEB-DL DD+5.1 DoVi HDR10+ HEVC-NTb,name=Pluribus,id=(1, 6),season=1,season_pack=None,episode=6,quality=2160p webdl h265 hybrid_hdr dd+5.1,proper=0,special=False,status=OK)>
But after the entry has been accept I run flexget series show Pluribus to confirm what series plugin record, and it show a different record.
The Table show a different quality result
| Identifier | Last seen | Release titles | Quality | Proper |
|---|---|---|---|---|
| S01E06 | 0h | Pluribus S01E06 2160p WEB-DL DD+5.1 DoVi HDR10+ HEVC-NTb * | 2160p webdl h265 hdr dd+5.1 |
Here is my configuration that related to this task
templates:
site_general:
transmission:
host: transmission
username: REPLACE_ME
password: REPLACE_ME
path: /data/SITE
tasks:
site_watchlist_shows:
no_entries_ok: yes
template: site_general
rss:
url: "REPLACE_WITH_PRIVATE_RSS_URL"
all_entries: no
priority: 5
trakt_lookup: yes
imdb_lookup: yes
tmdb_lookup: yes
all_series:
timeframe: 6 hours
quality: 1080p+ webdl
target: 2160p+ dolbyvision+ webdl
upgrade: yes
season_packs: always
propers: yes
reorder_quality:
webdl:
above: bluray
sort_by:
field: quality
reverse: yes
best_quality:
identified_by: "{{ media_id }} {{ series_id|default('') }}"
on_best: do_nothing
on_lower: reject
single_best: no
set:
path: "/data/SITE/{{series_name}}/Season {{series_season}}/"
bandwidth_priority: 1
exists_series:
path: "/data/SITE/{{series_name}}/"
allow_different_qualities: better
Not sure why series plugin log the quality difference than what tasks emitting.
That also the reason I find originally believe it's a mismatch.
Based on my initial analysis, the root cause appears to be:
- It originally correctly detected as
2160p webdl h265 hybrid_hdr dd+5.1. - It was saved into the database using the detected results
2160p webdl h265 hybrid_hdr dd+5.1rather than the original input. - When retrieving from the database,
2160p webdl h265 hybrid_hdr dd+5.1will convert intohdrdue to the matching rule. (hybrid_hdr will be based on hdr rather than hybrid_hdr) If we change add hybird_hdr matching to it should quickly solve the problem
https://github.com/Flexget/Flexget/blob/f73d6fa46e78af3aeec6ba5a0f1e2b6a714ca9b3/flexget/utils/qualities.py#L167
QualityComponent('color_range', 60, 'hybrid_hdr', f'(({dovi}|{hdr_plus}|{hdr})\\W?){{2,3}}|hybrid[\\W_]?hdr'),
My local test passes with this patch: running flexget series show Pluribus will print a table that quality is hybrid_hdr
That said, I’m not fully confident this is the best fix yet—it may have unintended side effects in other components.
When retrieving from the database, 2160p webdl h265 hybrid_hdr dd+5.1 will convert into hdr due to the matching rule. (hybrid_hdr will be based on hdr rather than hybrid_hdr)
No idea how that could be the case, the RegEx matching is done on the title, not on the string representation of the recognized quality
If I’m understanding correctly, the EpisodeRelease class reads data from the dataset via SQLAlchemy ORM, including: id, title, identifier, quality, series_id.
Looking at the series-related file: the quality column read from the database becomes _quality, is wrapped by quality_property, and is exposed as quality. That means when quality is accessed, it does not read from title.
https://github.com/Flexget/Flexget/blob/35c1cef147d403ea16efa980a64d64f782d7b9b0/flexget/components/series/db.py#L418-L419
quality_property sends the stored attribute through the Qualities plugin:
https://github.com/Flexget/Flexget/blob/35c1cef147d403ea16efa980a64d64f782d7b9b0/flexget/utils/database.py#L148-L156
So, when a record is read, it starts from the database quality column, gets processed through quality_property, and becomes release.quality.
However, when it is saved, the quality has already been set using quality: Quality, and when accessing quality.name, it returns a hybird_hdr name rather than the original name.
https://github.com/Flexget/Flexget/blob/35c1cef147d403ea16efa980a64d64f782d7b9b0/flexget/components/series/db.py#L1507
And since quality has a backing variable _quality, the setter shown above uses quality.name to set _quality, which is ultimately what gets saved into the database.
So the full chain maps quality through the Qualities plugin twice. For hybird_hdr, the repeated process is not idempotent, but for the others it is (e.g., DoVi -> dolbyvision -> dolbyvision -> ..., HDR10 -> hdr -> hdr -> ..., instead of DoVi HDR -> hybird_hdr -> hdr -> hdr -> ....)
That means, if I’m not misunderstanding (I’m new to this project’s source code, so I may be interpreting it wrong): when a record is fetched from the dataset, the qualities are based on the stored quality string (not the title), and that quality string is then sent through the Qualities plugin again for processing. From that process, only hybird_hdr has an issue, since it replaces the original DoVi HDR with hybird_hdr, and the next time it won’t match as hybird_hdr but as hdr.
That also explains what I saw earlier: when dumping, it was recognized as hybird_hdr, but when running flexget series show Pluribus, the table shows a different result.
I applied a quick fix:
- I patched it to
QualityComponent('color_range', 60, 'hybrid_hdr', f'(({dovi}|{hdr_plus}|{hdr})\\W?){{2,3}}|hybrid[\\W_]?hdr'),by addinghybrid[\\W_]?hdrat score 60 to make the mapping idempotent. - Restarted the FlexGet Docker container, and
- Ran
flexget series show Pluribusagain — it returnedhybird_hdrin the result table.
In other words, after the patch I didn’t need to rerun any tasks or modify the database. Just reading the existing table now produces the correct result in the CLI and Web page.
I see, so the issue is not the expression per-se, but the way it's saved on the DB as a string and then re-parsed with the RegEx instead of using the names directly.
I suppose this could be a better approach to hard-coding the title in the RegEx? https://github.com/Flexget/Flexget/blob/35c1cef147d403ea16efa980a64d64f782d7b9b0/flexget/utils/database.py#L150
- return qualities.Quality(getattr(self, text_attr))
+ return qualities.get(getattr(self, text_attr))
https://github.com/Flexget/Flexget/issues/4760#issuecomment-3621527351 Yes — that would be a more fundamental fix. Thanks for the suggestion/change. 👍
The core issue isn’t really the regex itself, but that the value gets processed twice: it’s stored in the DB as a string though Quality(...), and then later parsed again via Quality(...). For most quality strings that’s effectively idempotent, but hybrid_hdr isn’t, so the second pass can change the content.
Since I’m still new to this repo, I wasn’t confident that changing the behavior around the DB-backed values wouldn’t introduce side effects in other parts of the project. So I went with a safer workaround in my own running environment by make hybrid_hdr idempotent.
I generated a pull request https://github.com/Flexget/Flexget/pull/4779. To apply suggested change on https://github.com/Flexget/Flexget/issues/4760#issuecomment-3621527351