From 73956924f5f17740c0c4a059f43c7cfa13478240 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Thu, 18 Dec 2025 15:26:08 -0600 Subject: [PATCH] =?UTF-8?q?Enhancement:=20Stream=20group=20as=20available?= =?UTF-8?q?=20hash=20option:=20Users=20can=20now=20select=20'Group'=20as?= =?UTF-8?q?=20a=20hash=20key=20option=20in=20Settings=20=E2=86=92=20Stream?= =?UTF-8?q?=20Settings=20=E2=86=92=20M3U=20Hash=20Key,=20allowing=20stream?= =?UTF-8?q?s=20to=20be=20differentiated=20by=20their=20group=20membership?= =?UTF-8?q?=20in=20addition=20to=20name,=20URL,=20TVG-ID,=20and=20M3U=20ID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + apps/channels/models.py | 4 ++-- apps/m3u/tasks.py | 4 ++-- core/tasks.py | 3 ++- frontend/src/pages/Settings.jsx | 4 ++++ 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5532173..b6ff642d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - VOD client stop button in Stats page: Users can now disconnect individual VOD clients from the Stats view, similar to the existing channel client disconnect functionality. - Automated configuration backup/restore system with scheduled backups, retention policies, and async task processing - Thanks [@stlalpha](https://github.com/stlalpha) (Closes #153) +- Stream group as available hash option: Users can now select 'Group' as a hash key option in Settings → Stream Settings → M3U Hash Key, allowing streams to be differentiated by their group membership in addition to name, URL, TVG-ID, and M3U ID ### Changed diff --git a/apps/channels/models.py b/apps/channels/models.py index 3dfb392b..88df3661 100644 --- a/apps/channels/models.py +++ b/apps/channels/models.py @@ -119,11 +119,11 @@ class Stream(models.Model): return self.name or self.url or f"Stream ID {self.id}" @classmethod - def generate_hash_key(cls, name, url, tvg_id, keys=None, m3u_id=None): + def generate_hash_key(cls, name, url, tvg_id, keys=None, m3u_id=None, group=None): if keys is None: keys = CoreSettings.get_m3u_hash_key().split(",") - stream_parts = {"name": name, "url": url, "tvg_id": tvg_id, "m3u_id": m3u_id} + stream_parts = {"name": name, "url": url, "tvg_id": tvg_id, "m3u_id": m3u_id, "group": group} hash_parts = {key: stream_parts[key] for key in keys if key in stream_parts} diff --git a/apps/m3u/tasks.py b/apps/m3u/tasks.py index cb82402e..87759ab9 100644 --- a/apps/m3u/tasks.py +++ b/apps/m3u/tasks.py @@ -792,7 +792,7 @@ def process_xc_category_direct(account_id, batch, groups, hash_keys): group_title = group_name stream_hash = Stream.generate_hash_key( - name, url, tvg_id, hash_keys, m3u_id=account_id + name, url, tvg_id, hash_keys, m3u_id=account_id, group=group_title ) stream_props = { "name": name, @@ -966,7 +966,7 @@ def process_m3u_batch_direct(account_id, batch, groups, hash_keys): ) continue - stream_hash = Stream.generate_hash_key(name, url, tvg_id, hash_keys, m3u_id=account_id) + stream_hash = Stream.generate_hash_key(name, url, tvg_id, hash_keys, m3u_id=account_id, group=group_title) stream_props = { "name": name, "url": url, diff --git a/core/tasks.py b/core/tasks.py index f757613b..207e7c5e 100644 --- a/core/tasks.py +++ b/core/tasks.py @@ -513,7 +513,8 @@ def rehash_streams(keys): for obj in batch: # Generate new hash - new_hash = Stream.generate_hash_key(obj.name, obj.url, obj.tvg_id, keys, m3u_id=obj.m3u_account_id) + group_name = obj.channel_group.name if obj.channel_group else None + new_hash = Stream.generate_hash_key(obj.name, obj.url, obj.tvg_id, keys, m3u_id=obj.m3u_account_id, group=group_name) # Check if this hash already exists in our tracking dict or in database if new_hash in hash_keys: diff --git a/frontend/src/pages/Settings.jsx b/frontend/src/pages/Settings.jsx index 74de842e..46ad4710 100644 --- a/frontend/src/pages/Settings.jsx +++ b/frontend/src/pages/Settings.jsx @@ -1056,6 +1056,10 @@ const SettingsPage = () => { value: 'm3u_id', label: 'M3U ID', }, + { + value: 'group', + label: 'Group', + }, ]} {...form.getInputProps('m3u-hash-key')} key={form.key('m3u-hash-key')}