mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-01-23 02:35:14 +00:00
Enhancement: Added "Hide Stale" filter to quickly hide streams marked as stale.
Some checks are pending
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
Frontend Tests / test (push) Waiting to run
Some checks are pending
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
Frontend Tests / test (push) Waiting to run
This commit is contained in:
parent
c9b454431c
commit
2fc2486c34
3 changed files with 36 additions and 6 deletions
|
|
@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Only polls when active channel list changes, not on stats refresh
|
- Only polls when active channel list changes, not on stats refresh
|
||||||
- Channel preview button: Added preview functionality to active stream cards on stats page
|
- Channel preview button: Added preview functionality to active stream cards on stats page
|
||||||
- Unassociated streams filter: Added "Only Unassociated" filter option to streams table for quickly finding streams not assigned to any channels - Thanks [@JeffreyBytes](https://github.com/JeffreyBytes) (Closes #667)
|
- Unassociated streams filter: Added "Only Unassociated" filter option to streams table for quickly finding streams not assigned to any channels - Thanks [@JeffreyBytes](https://github.com/JeffreyBytes) (Closes #667)
|
||||||
|
- Streams table: Added "Hide Stale" filter to quickly hide streams marked as stale.
|
||||||
- Client-side logo caching: Added `Cache-Control` and `Last-Modified` headers to logo responses, enabling browsers to cache logos locally for 4 hours (local files) and respecting upstream cache headers (remote logos). This reduces network traffic and nginx load while providing faster page loads through browser-level caching that complements the existing nginx server-side cache - Thanks [@DawtCom](https://github.com/DawtCom)
|
- Client-side logo caching: Added `Cache-Control` and `Last-Modified` headers to logo responses, enabling browsers to cache logos locally for 4 hours (local files) and respecting upstream cache headers (remote logos). This reduces network traffic and nginx load while providing faster page loads through browser-level caching that complements the existing nginx server-side cache - Thanks [@DawtCom](https://github.com/DawtCom)
|
||||||
- DVR recording remux fallback strategy: Implemented two-stage TS→MP4→MKV fallback when direct TS→MKV conversion fails due to timestamp issues. On remux failure, system now attempts TS→MP4 conversion (MP4 container handles broken timestamps better) followed by MP4→MKV conversion, automatically recovering from provider timestamp corruption. Failed conversions now properly clean up partial files and preserve source TS for manual recovery.
|
- DVR recording remux fallback strategy: Implemented two-stage TS→MP4→MKV fallback when direct TS→MKV conversion fails due to timestamp issues. On remux failure, system now attempts TS→MP4 conversion (MP4 container handles broken timestamps better) followed by MP4→MKV conversion, automatically recovering from provider timestamp corruption. Failed conversions now properly clean up partial files and preserve source TS for manual recovery.
|
||||||
- Mature content filtering support:
|
- Mature content filtering support:
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ class StreamViewSet(viewsets.ModelViewSet):
|
||||||
qs = qs.filter(channels__id=assigned)
|
qs = qs.filter(channels__id=assigned)
|
||||||
|
|
||||||
unassigned = self.request.query_params.get("unassigned")
|
unassigned = self.request.query_params.get("unassigned")
|
||||||
if unassigned == "1":
|
if unassigned and str(unassigned).lower() in ("1", "true", "yes", "on"):
|
||||||
# Use annotation with Count for better performance on large datasets
|
# Use annotation with Count for better performance on large datasets
|
||||||
qs = qs.annotate(channel_count=Count('channels')).filter(channel_count=0)
|
qs = qs.annotate(channel_count=Count('channels')).filter(channel_count=0)
|
||||||
|
|
||||||
|
|
@ -158,6 +158,11 @@ class StreamViewSet(viewsets.ModelViewSet):
|
||||||
group_names = channel_group.split(",")
|
group_names = channel_group.split(",")
|
||||||
qs = qs.filter(channel_group__name__in=group_names)
|
qs = qs.filter(channel_group__name__in=group_names)
|
||||||
|
|
||||||
|
# Allow client to hide stale streams (streams marked as is_stale=True)
|
||||||
|
hide_stale = self.request.query_params.get("hide_stale")
|
||||||
|
if hide_stale and str(hide_stale).lower() in ("1", "true", "yes", "on"):
|
||||||
|
qs = qs.filter(is_stale=False)
|
||||||
|
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
def list(self, request, *args, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,8 @@ const StreamsTable = ({ onReady }) => {
|
||||||
name: '',
|
name: '',
|
||||||
channel_group: '',
|
channel_group: '',
|
||||||
m3u_account: '',
|
m3u_account: '',
|
||||||
unassigned: '',
|
unassigned: false,
|
||||||
|
hide_stale: false,
|
||||||
});
|
});
|
||||||
const [columnSizing, setColumnSizing] = useLocalStorage(
|
const [columnSizing, setColumnSizing] = useLocalStorage(
|
||||||
'streams-table-column-sizing',
|
'streams-table-column-sizing',
|
||||||
|
|
@ -398,7 +399,14 @@ const StreamsTable = ({ onReady }) => {
|
||||||
const toggleUnassignedOnly = () => {
|
const toggleUnassignedOnly = () => {
|
||||||
setFilters((prev) => ({
|
setFilters((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
unassigned: prev.unassigned === '1' ? '' : '1',
|
unassigned: !prev.unassigned,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleHideStale = () => {
|
||||||
|
setFilters((prev) => ({
|
||||||
|
...prev,
|
||||||
|
hide_stale: !prev.hide_stale,
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -426,9 +434,13 @@ const StreamsTable = ({ onReady }) => {
|
||||||
params.append('ordering', `${sortDirection}${sortField}`);
|
params.append('ordering', `${sortDirection}${sortField}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply debounced filters
|
// Apply debounced filters; send boolean filters as 'true' when set
|
||||||
Object.entries(debouncedFilters).forEach(([key, value]) => {
|
Object.entries(debouncedFilters).forEach(([key, value]) => {
|
||||||
if (value) params.append(key, value);
|
if (typeof value === 'boolean') {
|
||||||
|
if (value) params.append(key, 'true');
|
||||||
|
} else if (value !== null && value !== undefined && value !== '') {
|
||||||
|
params.append(key, String(value));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -1188,7 +1200,7 @@ const StreamsTable = ({ onReady }) => {
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
onClick={toggleUnassignedOnly}
|
onClick={toggleUnassignedOnly}
|
||||||
leftSection={
|
leftSection={
|
||||||
filters.unassigned === '1' ? (
|
filters.unassigned === true ? (
|
||||||
<SquareCheck size={18} />
|
<SquareCheck size={18} />
|
||||||
) : (
|
) : (
|
||||||
<Square size={18} />
|
<Square size={18} />
|
||||||
|
|
@ -1197,6 +1209,18 @@ const StreamsTable = ({ onReady }) => {
|
||||||
>
|
>
|
||||||
<Text size="xs">Only Unassociated</Text>
|
<Text size="xs">Only Unassociated</Text>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
<Menu.Item
|
||||||
|
onClick={toggleHideStale}
|
||||||
|
leftSection={
|
||||||
|
filters.hide_stale === true ? (
|
||||||
|
<SquareCheck size={18} />
|
||||||
|
) : (
|
||||||
|
<Square size={18} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Text size="xs">Hide Stale</Text>
|
||||||
|
</Menu.Item>
|
||||||
</Menu.Dropdown>
|
</Menu.Dropdown>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue