mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-18 17:16:26 +00:00
refactor(stats): simplify channel logo handling in stats data
This update refactors the logic for building timeshift statistics by removing unnecessary `select_related` calls and the `logo_url` field from the connections. The changes streamline the data retrieval process and ensure that only the `logo_id` is exposed in the session data. Corresponding tests have been updated to reflect these modifications.
This commit is contained in:
parent
b24f39d9f8
commit
0aed30253b
4 changed files with 102 additions and 13 deletions
|
|
@ -490,9 +490,7 @@ def build_timeshift_stats_data(redis_client):
|
|||
channel_ids = {conn["channel_id"] for conn in connections if conn.get("channel_id")}
|
||||
channels_by_id = {}
|
||||
if channel_ids:
|
||||
for channel in Channel.objects.select_related("logo", "epg_data").filter(
|
||||
id__in=channel_ids,
|
||||
):
|
||||
for channel in Channel.objects.filter(id__in=channel_ids):
|
||||
channels_by_id[channel.id] = channel
|
||||
|
||||
profile_ids = {
|
||||
|
|
@ -516,8 +514,6 @@ def build_timeshift_stats_data(redis_client):
|
|||
conn["channel_name"] = channel.name
|
||||
if channel.logo_id:
|
||||
conn["logo_id"] = channel.logo_id
|
||||
if channel.logo:
|
||||
conn["logo_url"] = channel.logo.url
|
||||
|
||||
profile = profiles_by_id.get(conn.get("m3u_profile_id"))
|
||||
if profile:
|
||||
|
|
@ -546,7 +542,6 @@ def build_timeshift_stats_data(redis_client):
|
|||
"channel_uuid": conn.get("channel_uuid", ""),
|
||||
"channel_name": conn["channel_name"],
|
||||
"logo_id": conn.get("logo_id"),
|
||||
"logo_url": conn.get("logo_url"),
|
||||
"programme_start": conn["programme_start"],
|
||||
"position_anchor_at": position_anchor_at,
|
||||
"playback_base_secs": playback_base_secs,
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ class BuildTimeshiftStatsDataTests(TestCase):
|
|||
channel.uuid = "00000000-0000-0000-0000-000000000042"
|
||||
channel.logo_id = None
|
||||
channel.logo = None
|
||||
mock_channel_model.objects.select_related.return_value.filter.return_value = [
|
||||
mock_channel_model.objects.filter.return_value = [
|
||||
channel,
|
||||
]
|
||||
payload = build_timeshift_stats_data(self.redis)
|
||||
|
|
@ -317,6 +317,18 @@ class BuildTimeshiftStatsDataTests(TestCase):
|
|||
self.assertFalse(session["paused"])
|
||||
self.assertEqual(session["connections"][0]["ip_address"], "10.0.0.5")
|
||||
|
||||
@patch("apps.timeshift.stats.Channel")
|
||||
def test_build_timeshift_stats_exposes_logo_id_only(self, mock_channel_model):
|
||||
channel = MagicMock()
|
||||
channel.id = self.channel_id
|
||||
channel.name = "Catch-up Stats Channel"
|
||||
channel.uuid = "00000000-0000-0000-0000-000000000042"
|
||||
channel.logo_id = 77
|
||||
mock_channel_model.objects.filter.return_value = [channel]
|
||||
session = build_timeshift_stats_data(self.redis)["timeshift_sessions"][0]
|
||||
self.assertEqual(session["logo_id"], 77)
|
||||
self.assertNotIn("logo_url", session)
|
||||
|
||||
def test_find_stats_channel_for_session(self):
|
||||
found = find_stats_channel_for_session(self.redis, self.session_id)
|
||||
self.assertEqual(found, self.stats_channel_id)
|
||||
|
|
@ -344,7 +356,7 @@ class BuildTimeshiftStatsDataTests(TestCase):
|
|||
channel.uuid = "00000000-0000-0000-0000-000000000042"
|
||||
channel.logo_id = None
|
||||
channel.logo = None
|
||||
mock_channel_model.objects.select_related.return_value.filter.return_value = [
|
||||
mock_channel_model.objects.filter.return_value = [
|
||||
channel,
|
||||
]
|
||||
client_key = RedisKeys.client_metadata(self.stats_channel_id, self.session_id)
|
||||
|
|
@ -355,7 +367,7 @@ class BuildTimeshiftStatsDataTests(TestCase):
|
|||
|
||||
@patch("apps.timeshift.stats.Channel")
|
||||
def test_skips_clients_missing_required_metadata(self, mock_channel_model):
|
||||
mock_channel_model.objects.select_related.return_value.filter.return_value = []
|
||||
mock_channel_model.objects.filter.return_value = []
|
||||
orphan_key = RedisKeys.client_metadata(self.stats_channel_id, "orphan")
|
||||
self.redis.hset(orphan_key, mapping={"user_agent": "VLC"})
|
||||
self.redis.sadd(RedisKeys.clients(self.stats_channel_id), "orphan")
|
||||
|
|
|
|||
|
|
@ -135,10 +135,7 @@ const TimeshiftConnectionCard = ({
|
|||
timeshiftSession.individual_connection ||
|
||||
(timeshiftSession.connections && timeshiftSession.connections[0]);
|
||||
|
||||
const logoUrl =
|
||||
timeshiftSession.logo_url ||
|
||||
getLogoUrl(timeshiftSession.logo_id, logos) ||
|
||||
logo;
|
||||
const logoUrl = getLogoUrl(timeshiftSession.logo_id, logos) || logo;
|
||||
|
||||
const programmePreview = useMemo(() => {
|
||||
if (currentProgram?.title) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
vi.mock('../../../utils/dateTimeUtils.js', () => ({
|
||||
useDateTimeFormat: vi.fn(() => ({ fullDateTimeFormat: 'MM/DD/YYYY h:mm A' })),
|
||||
}));
|
||||
|
||||
vi.mock('../../../store/users.jsx', () => ({
|
||||
default: vi.fn(() => []),
|
||||
}));
|
||||
|
||||
vi.mock('../../../images/logo.png', () => ({ default: 'default-logo.png' }));
|
||||
|
||||
vi.mock('../../../utils/cards/StreamConnectionCardUtils.js', () => ({
|
||||
getLogoUrl: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../../utils/cards/TimeshiftConnectionCardUtils.js', () => ({
|
||||
calculateConnectionDuration: vi.fn(() => '5m'),
|
||||
calculateConnectionStartTime: vi.fn(() => 'Jan 1 2024 10:00 AM'),
|
||||
computeCatchupPlaybackSeconds: vi.fn(() => 0),
|
||||
getConnectionDurationSeconds: vi.fn(() => 0),
|
||||
}));
|
||||
|
||||
vi.mock('@mantine/core', () => ({
|
||||
ActionIcon: ({ children }) => <button type="button">{children}</button>,
|
||||
Badge: ({ children }) => <span>{children}</span>,
|
||||
Box: ({ children }) => <div>{children}</div>,
|
||||
Card: ({ children }) => <div data-testid="timeshift-connection-card">{children}</div>,
|
||||
Center: ({ children }) => <div>{children}</div>,
|
||||
Group: ({ children }) => <div>{children}</div>,
|
||||
Stack: ({ children }) => <div>{children}</div>,
|
||||
Text: ({ children }) => <span>{children}</span>,
|
||||
Tooltip: ({ children }) => <>{children}</>,
|
||||
}));
|
||||
|
||||
vi.mock('lucide-react', () => ({
|
||||
ChevronDown: () => null,
|
||||
HardDriveUpload: () => null,
|
||||
History: () => null,
|
||||
SquareX: () => null,
|
||||
Timer: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('../../ProgramPreview.jsx', () => ({
|
||||
default: () => <div data-testid="program-preview" />,
|
||||
}));
|
||||
|
||||
import TimeshiftConnectionCard from '../TimeshiftConnectionCard.jsx';
|
||||
import { getLogoUrl } from '../../../utils/cards/StreamConnectionCardUtils.js';
|
||||
|
||||
describe('TimeshiftConnectionCard logos', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
getLogoUrl.mockReturnValue('/api/channels/logos/77/cache/');
|
||||
});
|
||||
|
||||
it('resolves the channel logo via logo_id and the logos store', () => {
|
||||
render(
|
||||
<TimeshiftConnectionCard
|
||||
timeshiftSession={{
|
||||
session_id: 'sess-1',
|
||||
channel_name: 'US | A&E',
|
||||
logo_id: 77,
|
||||
programme_start: '2026-07-17:20-00-00',
|
||||
connections: [
|
||||
{
|
||||
session_id: 'sess-1',
|
||||
client_id: 'sess-1',
|
||||
ip_address: '10.0.0.5',
|
||||
connected_at: 1_700_000_000,
|
||||
},
|
||||
],
|
||||
}}
|
||||
logos={{ 77: { cache_url: '/api/channels/logos/77/cache/' } }}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(getLogoUrl).toHaveBeenCalledWith(77, {
|
||||
77: { cache_url: '/api/channels/logos/77/cache/' },
|
||||
});
|
||||
const img = screen.getByAltText('channel logo');
|
||||
expect(img.getAttribute('src')).toBe('/api/channels/logos/77/cache/');
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue