From 248ef90629b0a96740f33a14ebb11533078e3415 Mon Sep 17 00:00:00 2001 From: Nicolas Znamenski Date: Mon, 28 Apr 2025 14:08:04 -0400 Subject: [PATCH 01/21] Fixed minor typo --- frontend/src/components/tables/UserAgentsTable.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/tables/UserAgentsTable.jsx b/frontend/src/components/tables/UserAgentsTable.jsx index 2ea2d3b7..4ab1eb34 100644 --- a/frontend/src/components/tables/UserAgentsTable.jsx +++ b/frontend/src/components/tables/UserAgentsTable.jsx @@ -55,7 +55,7 @@ const UserAgentsTable = () => { ), }, { - header: 'Desecription', + header: 'Description', accessorKey: 'description', enableSorting: false, Cell: ({ cell }) => ( From d61de87fffed000b5d30a410c567b274be19648f Mon Sep 17 00:00:00 2001 From: Jean-Paul Acneaux Date: Wed, 30 Apr 2025 05:10:31 +0200 Subject: [PATCH 02/21] Fix channel issues that i have with m3u files comming form tvheaden. And add tvg-chno tag for finding channel numbers. --- apps/channels/api_views.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/channels/api_views.py b/apps/channels/api_views.py index ccd942d6..36a5b0e1 100644 --- a/apps/channels/api_views.py +++ b/apps/channels/api_views.py @@ -267,6 +267,8 @@ class ChannelViewSet(viewsets.ModelViewSet): channel_number = None if 'tv-chno' in stream_custom_props: channel_number = int(stream_custom_props['tv-chno']) + elif 'tvg-chno' in stream_custom_props: + channel_number = int(stream_custom_props['tvg-chno']) elif 'channel-number' in stream_custom_props: channel_number = int(stream_custom_props['channel-number']) @@ -388,6 +390,8 @@ class ChannelViewSet(viewsets.ModelViewSet): channel_number = None if 'tv-chno' in stream_custom_props: channel_number = int(stream_custom_props['tv-chno']) + elif 'tvg-chno' in stream_custom_props: + channel_number = int(stream_custom_props['tvg-chno']) elif 'channel-number' in stream_custom_props: channel_number = int(stream_custom_props['channel-number']) From 4f0c8333c6196c1246550518753ace3fb18b755f Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Wed, 30 Apr 2025 14:42:32 -0500 Subject: [PATCH 03/21] Add return statement in get_cache_file method of EPGSource model --- apps/epg/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/epg/models.py b/apps/epg/models.py index 2f7d5990..e020821a 100644 --- a/apps/epg/models.py +++ b/apps/epg/models.py @@ -40,6 +40,8 @@ class EPGSource(models.Model): cache_dir = os.path.join(settings.MEDIA_ROOT, "cached_epg") cache = os.path.join(cache_dir, filename) + return cache + class EPGData(models.Model): # Removed the Channel foreign key. We now just store the original tvg_id # and a name (which might simply be the tvg_id if no real channel exists). From 91f5e2ad7c5c1c82588186da86ae6a30307d7914 Mon Sep 17 00:00:00 2001 From: dekzter Date: Wed, 30 Apr 2025 16:15:00 -0400 Subject: [PATCH 04/21] fixed stream URL sample for search / replace pattersn --- frontend/src/components/forms/M3UProfile.jsx | 21 ++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/forms/M3UProfile.jsx b/frontend/src/components/forms/M3UProfile.jsx index 2de99750..d1052c07 100644 --- a/frontend/src/components/forms/M3UProfile.jsx +++ b/frontend/src/components/forms/M3UProfile.jsx @@ -21,20 +21,33 @@ const RegexFormAndView = ({ profile = null, m3u, isOpen, onClose }) => { const profileSearchPreview = usePlaylistsStore((s) => s.profileSearchPreview); const profileResult = usePlaylistsStore((s) => s.profileResult); + const [streamUrl, setStreamUrl] = useState(''); const [searchPattern, setSearchPattern] = useState(''); const [replacePattern, setReplacePattern] = useState(''); const [debouncedPatterns, setDebouncedPatterns] = useState({}); + useEffect(() => { + async function fetchStreamUrl() { + const params = new URLSearchParams(); + params.append('page', 1); + params.append('page_size', 1); + params.append('m3u_account', m3u.id); + const response = await API.queryStreams(params); + setStreamUrl(response.results[0].url); + } + fetchStreamUrl(); + }, []); + useEffect(() => { sendMessage( JSON.stringify({ type: 'm3u_profile_test', - url: m3u.server_url, + url: streamUrl, search: debouncedPatterns['search'] || '', replace: debouncedPatterns['replace'] || '', }) ); - }, [m3u, debouncedPatterns]); + }, [m3u, debouncedPatterns, streamUrl]); useEffect(() => { const handler = setTimeout(() => { @@ -155,7 +168,7 @@ const RegexFormAndView = ({ profile = null, m3u, isOpen, onClose }) => { Search @@ -163,7 +176,7 @@ const RegexFormAndView = ({ profile = null, m3u, isOpen, onClose }) => { Replace - {profileResult || m3u.server_url} + {profileResult || streamUrl} ); From a9ea30d862c791ff5f0c275f624450e09ade9292 Mon Sep 17 00:00:00 2001 From: dekzter Date: Wed, 30 Apr 2025 16:36:16 -0400 Subject: [PATCH 05/21] channel number sorting restored, reset stream table default page size --- frontend/src/components/tables/ChannelsTable.jsx | 5 +++-- frontend/src/components/tables/StreamsTable.jsx | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/tables/ChannelsTable.jsx b/frontend/src/components/tables/ChannelsTable.jsx index c3ab40cc..7982817c 100644 --- a/frontend/src/components/tables/ChannelsTable.jsx +++ b/frontend/src/components/tables/ChannelsTable.jsx @@ -523,9 +523,9 @@ const ChannelsTable = ({}) => { }, }, { + id: 'channel_number', accessorKey: 'channel_number', - size: 30, - header: () => #, + size: 40, cell: ({ getValue }) => ( {getValue()} @@ -706,6 +706,7 @@ const ChannelsTable = ({}) => { }, headerCellRenderFns: { name: renderHeaderCell, + channel_number: renderHeaderCell, channel_group: renderHeaderCell, enabled: renderHeaderCell, }, diff --git a/frontend/src/components/tables/StreamsTable.jsx b/frontend/src/components/tables/StreamsTable.jsx index c899fda9..276ce189 100644 --- a/frontend/src/components/tables/StreamsTable.jsx +++ b/frontend/src/components/tables/StreamsTable.jsx @@ -177,7 +177,7 @@ const StreamsTable = ({}) => { // const [allRowsSelected, setAllRowsSelected] = useState(false); const [pagination, setPagination] = useState({ pageIndex: 0, - pageSize: 250, + pageSize: 50, }); const [filters, setFilters] = useState({ name: '', From 79392bb129f69d8f3fca27c76e90fc95f1f5a47c Mon Sep 17 00:00:00 2001 From: dekzter Date: Wed, 30 Apr 2025 16:58:16 -0400 Subject: [PATCH 06/21] fixed channel form not updating some properties after saving --- frontend/src/components/forms/Channel.jsx | 1 + frontend/src/components/tables/ChannelsTable.jsx | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/forms/Channel.jsx b/frontend/src/components/forms/Channel.jsx index 33eca5ea..3253d67b 100644 --- a/frontend/src/components/forms/Channel.jsx +++ b/frontend/src/components/forms/Channel.jsx @@ -161,6 +161,7 @@ const Channel = ({ channel = null, isOpen, onClose }) => { console.error('Error saving channel:', error); } + formik.resetForm(); API.requeryChannels(); setSubmitting(false); setTvgFilter(''); diff --git a/frontend/src/components/tables/ChannelsTable.jsx b/frontend/src/components/tables/ChannelsTable.jsx index 7982817c..bdca0722 100644 --- a/frontend/src/components/tables/ChannelsTable.jsx +++ b/frontend/src/components/tables/ChannelsTable.jsx @@ -95,19 +95,19 @@ const ChannelRowActions = React.memo( }) => { const onEdit = useCallback(() => { editChannel(row.original); - }, []); + }, [row.original]); const onDelete = useCallback(() => { deleteChannel(row.original.id); - }, []); + }, [row.original]); const onPreview = useCallback(() => { handleWatchStream(row.original); - }, []); + }, [row.original]); const onRecord = useCallback(() => { createRecording(row.original); - }, []); + }, [row.original]); return ( From e8355a78c670b46700c9ec54129edb7c0ed1bc94 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Wed, 30 Apr 2025 16:51:48 -0500 Subject: [PATCH 07/21] Fetch channels when auto-match is complete. --- apps/channels/api_views.py | 2 ++ frontend/src/WebSocket.jsx | 3 --- frontend/src/api.js | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/channels/api_views.py b/apps/channels/api_views.py index ccd942d6..65b2a39c 100644 --- a/apps/channels/api_views.py +++ b/apps/channels/api_views.py @@ -600,6 +600,8 @@ class ChannelViewSet(viewsets.ModelViewSet): parse_programs_for_tvg_id.delay(epg_id) programs_refreshed += 1 + + return Response({ 'success': True, 'channels_updated': channels_updated, diff --git a/frontend/src/WebSocket.jsx b/frontend/src/WebSocket.jsx index 0f5c4404..f538ee29 100644 --- a/frontend/src/WebSocket.jsx +++ b/frontend/src/WebSocket.jsx @@ -128,9 +128,6 @@ export const WebsocketProvider = ({ children }) => { // Check if we have associations data and use the more efficient batch API if (event.data.associations && event.data.associations.length > 0) { API.batchSetEPG(event.data.associations); - } else { - // Fall back to legacy full refresh method - API.requeryChannels(); } break; diff --git a/frontend/src/api.js b/frontend/src/api.js index 8e1fe46c..3cec6e38 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -1290,6 +1290,9 @@ export default class API { color: 'blue', }); + // First fetch the complete channel data + await useChannelsStore.getState().fetchChannels(); + // Then refresh the current table view this.requeryChannels(); } From c058c4ed10b94bf0361cc0b0c7bf682a56a6cdfe Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Wed, 30 Apr 2025 17:03:36 -0500 Subject: [PATCH 08/21] Fixes spacing and padding in epg and m3u tables. --- frontend/src/components/tables/EPGsTable.jsx | 36 ++++++++++++++++---- frontend/src/components/tables/M3UsTable.jsx | 24 +++++++++++-- frontend/src/pages/ContentSources.jsx | 2 ++ 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/tables/EPGsTable.jsx b/frontend/src/components/tables/EPGsTable.jsx index 07f4128d..1f76eb33 100644 --- a/frontend/src/components/tables/EPGsTable.jsx +++ b/frontend/src/components/tables/EPGsTable.jsx @@ -42,20 +42,39 @@ const EPGsTable = () => { { header: 'Name', accessorKey: 'name', + size: 150, + minSize: 100, }, { header: 'Source Type', accessorKey: 'source_type', + size: 120, + minSize: 100, }, { header: 'URL / API Key', accessorKey: 'url', + size: 200, + minSize: 120, enableSorting: false, + Cell: ({ cell }) => ( +
+ {cell.getValue()} +
+ ), }, { header: 'Active', accessorKey: 'is_active', - size: 100, + size: 80, + minSize: 60, sortingFn: 'basic', mantineTableBodyCellProps: { align: 'left', @@ -73,6 +92,8 @@ const EPGsTable = () => { { header: 'Updated', accessorFn: (row) => dayjs(row.updated_at).format('MMMM D, YYYY h:mma'), + size: 180, + minSize: 100, enableSorting: false, }, ], @@ -144,6 +165,13 @@ const EPGsTable = () => { density: 'compact', }, enableRowActions: true, + positionActionsColumn: 'last', + displayColumnDefOptions: { + 'mrt-row-actions': { + size: 120, // Make action column wider + minSize: 120, // Ensure minimum width for action buttons + }, + }, renderRowActions: ({ row }) => ( <> { mantineTableContainerProps: { style: { height: 'calc(40vh - 10px)', - }, - }, - displayColumnDefOptions: { - 'mrt-row-actions': { - size: 10, + overflowX: 'auto', // Ensure horizontal scrolling works }, }, }); diff --git a/frontend/src/components/tables/M3UsTable.jsx b/frontend/src/components/tables/M3UsTable.jsx index 9765ca66..63a25118 100644 --- a/frontend/src/components/tables/M3UsTable.jsx +++ b/frontend/src/components/tables/M3UsTable.jsx @@ -99,16 +99,21 @@ const M3UTable = () => { { header: 'Name', accessorKey: 'name', + size: 150, + minSize: 100, // Minimum width }, { header: 'URL / File', accessorKey: 'server_url', + size: 200, + minSize: 120, Cell: ({ cell }) => (
{cell.getValue()} @@ -118,7 +123,8 @@ const M3UTable = () => { { header: 'Max Streams', accessorKey: 'max_streams', - size: 200, + size: 120, + minSize: 80, }, { header: 'Status', @@ -132,12 +138,14 @@ const M3UTable = () => { return generateStatusString(refreshProgress[row.id]); }, - size: 200, + size: 150, + minSize: 80, }, { header: 'Active', accessorKey: 'is_active', - size: 100, + size: 80, + minSize: 60, sortingFn: 'basic', mantineTableBodyCellProps: { align: 'left', @@ -155,6 +163,8 @@ const M3UTable = () => { { header: 'Updated', accessorFn: (row) => dayjs(row.updated_at).format('MMMM D, YYYY h:mma'), + size: 180, + minSize: 100, enableSorting: false, }, ], @@ -239,6 +249,13 @@ const M3UTable = () => { density: 'compact', }, enableRowActions: true, + positionActionsColumn: 'last', + displayColumnDefOptions: { + 'mrt-row-actions': { + size: 120, // Make action column wider + minSize: 120, // Ensure minimum width for action buttons + }, + }, renderRowActions: ({ row }) => ( <> { mantineTableContainerProps: { style: { height: 'calc(40vh - 10px)', + overflowX: 'auto', // Ensure horizontal scrolling works }, }, }); diff --git a/frontend/src/pages/ContentSources.jsx b/frontend/src/pages/ContentSources.jsx index eb62fe49..24e736d4 100644 --- a/frontend/src/pages/ContentSources.jsx +++ b/frontend/src/pages/ContentSources.jsx @@ -15,7 +15,9 @@ const M3UPage = () => { From 6adda8209f2cbc09930ef9ac459f972e08b6dcfe Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Wed, 30 Apr 2025 17:54:48 -0500 Subject: [PATCH 09/21] Ensure cache directory exists before saving EPG data --- apps/epg/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/epg/models.py b/apps/epg/models.py index e020821a..a0e5343b 100644 --- a/apps/epg/models.py +++ b/apps/epg/models.py @@ -38,6 +38,10 @@ class EPGSource(models.Model): # Build full path in MEDIA_ROOT/cached_epg cache_dir = os.path.join(settings.MEDIA_ROOT, "cached_epg") + + # Create directory if it doesn't exist + os.makedirs(cache_dir, exist_ok=True) + cache = os.path.join(cache_dir, filename) return cache From a50a7372c1df3a4ca69ab14d47a025fe53729eb3 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Wed, 30 Apr 2025 18:22:27 -0500 Subject: [PATCH 10/21] Removed unnecessary elif for invalid flag. --- apps/channels/api_views.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/channels/api_views.py b/apps/channels/api_views.py index 42334b44..ab206afb 100644 --- a/apps/channels/api_views.py +++ b/apps/channels/api_views.py @@ -265,9 +265,7 @@ class ChannelViewSet(viewsets.ModelViewSet): stream_custom_props = json.loads(stream.custom_properties) if stream.custom_properties else {} channel_number = None - if 'tv-chno' in stream_custom_props: - channel_number = int(stream_custom_props['tv-chno']) - elif 'tvg-chno' in stream_custom_props: + if 'tvg-chno' in stream_custom_props: channel_number = int(stream_custom_props['tvg-chno']) elif 'channel-number' in stream_custom_props: channel_number = int(stream_custom_props['channel-number']) @@ -388,9 +386,7 @@ class ChannelViewSet(viewsets.ModelViewSet): stream_custom_props = json.loads(stream.custom_properties) if stream.custom_properties else {} channel_number = None - if 'tv-chno' in stream_custom_props: - channel_number = int(stream_custom_props['tv-chno']) - elif 'tvg-chno' in stream_custom_props: + if 'tvg-chno' in stream_custom_props: channel_number = int(stream_custom_props['tvg-chno']) elif 'channel-number' in stream_custom_props: channel_number = int(stream_custom_props['channel-number']) From a6087d1010cebd49a3e0780c6fbb257c0ef257f8 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 30 Apr 2025 23:27:49 +0000 Subject: [PATCH 11/21] Release v0.4.0 --- version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.py b/version.py index 9339fcbd..25e27d60 100644 --- a/version.py +++ b/version.py @@ -1,5 +1,5 @@ """ Dispatcharr version information. """ -__version__ = '0.3.3' # Follow semantic versioning (MAJOR.MINOR.PATCH) +__version__ = '0.4.0' # Follow semantic versioning (MAJOR.MINOR.PATCH) __timestamp__ = None # Set during CI/CD build process From 2b44c122e787116a9a0a8a54e71067ed3e17c26c Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Wed, 30 Apr 2025 18:46:10 -0500 Subject: [PATCH 12/21] Update version display to include timestamp instead of build --- docker/entrypoint.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 478d94d0..d2afb3a3 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -40,8 +40,14 @@ export DISPATCHARR_PORT=${DISPATCHARR_PORT:-9191} # Extract version information from version.py export DISPATCHARR_VERSION=$(python -c "import sys; sys.path.append('/app'); import version; print(version.__version__)") -export DISPATCHARR_BUILD=$(python -c "import sys; sys.path.append('/app'); import version; print(version.__build__)") -echo "📦 Dispatcharr version: ${DISPATCHARR_VERSION}-${DISPATCHARR_BUILD}" +export DISPATCHARR_TIMESTAMP=$(python -c "import sys; sys.path.append('/app'); import version; print(version.__timestamp__ or '')") + +# Display version information with timestamp if available +if [ -n "$DISPATCHARR_TIMESTAMP" ]; then + echo "📦 Dispatcharr version: ${DISPATCHARR_VERSION} (build: ${DISPATCHARR_TIMESTAMP})" +else + echo "📦 Dispatcharr version: ${DISPATCHARR_VERSION}" +fi # READ-ONLY - don't let users change these export POSTGRES_DIR=/data/db @@ -64,7 +70,7 @@ if [[ ! -f /etc/profile.d/dispatcharr.sh ]]; then echo "export POSTGRES_DIR=$POSTGRES_DIR" >> /etc/profile.d/dispatcharr.sh echo "export DISPATCHARR_PORT=$DISPATCHARR_PORT" >> /etc/profile.d/dispatcharr.sh echo "export DISPATCHARR_VERSION=$DISPATCHARR_VERSION" >> /etc/profile.d/dispatcharr.sh - echo "export DISPATCHARR_BUILD=$DISPATCHARR_BUILD" >> /etc/profile.d/dispatcharr.sh + echo "export DISPATCHARR_TIMESTAMP=$DISPATCHARR_TIMESTAMP" >> /etc/profile.d/dispatcharr.sh fi chmod +x /etc/profile.d/dispatcharr.sh From 3381cb8695708b66ccc8b18f60fe7e8e75997af4 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Wed, 30 Apr 2025 19:14:18 -0500 Subject: [PATCH 13/21] Switch to yarn for building frontend. --- docker/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 4d313e2c..f145fe2e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -44,8 +44,9 @@ RUN cd /app && \ FROM node:20-slim AS frontend-builder WORKDIR /app/frontend COPY --from=builder /app /app -RUN npm install --legacy-peer-deps && \ - npm run build && \ +RUN corepack enable && corepack prepare yarn@stable --activate && \ + yarn install && \ + yarn build && \ find . -maxdepth 1 ! -name '.' ! -name 'dist' -exec rm -rf '{}' \; FROM python:3.13-slim From 7a67479e387fe39c07459ebb81677678dfbf4c3c Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Wed, 30 Apr 2025 19:21:22 -0500 Subject: [PATCH 14/21] Back to NPM but use ignore scripts and rebuild. --- docker/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index f145fe2e..f73cfb84 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -44,9 +44,9 @@ RUN cd /app && \ FROM node:20-slim AS frontend-builder WORKDIR /app/frontend COPY --from=builder /app /app -RUN corepack enable && corepack prepare yarn@stable --activate && \ - yarn install && \ - yarn build && \ +RUN npm install --ignore-scripts && \ + npm rebuild && \ + npm run build && \ find . -maxdepth 1 ! -name '.' ! -name 'dist' -exec rm -rf '{}' \; FROM python:3.13-slim From da1fae89a9092526216ab233fb53da01c40c9422 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 1 May 2025 00:30:25 +0000 Subject: [PATCH 15/21] Release v0.5.0 --- version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.py b/version.py index 25e27d60..18a1ef5d 100644 --- a/version.py +++ b/version.py @@ -1,5 +1,5 @@ """ Dispatcharr version information. """ -__version__ = '0.4.0' # Follow semantic versioning (MAJOR.MINOR.PATCH) +__version__ = '0.5.0' # Follow semantic versioning (MAJOR.MINOR.PATCH) __timestamp__ = None # Set during CI/CD build process From e975a13c0f5cc9d9661417a3cdd1f74e7f7a6c71 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Wed, 30 Apr 2025 19:30:53 -0500 Subject: [PATCH 16/21] Another attempt at using yarn. --- docker/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index f73cfb84..26b54975 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -41,12 +41,12 @@ RUN cd /app && \ pip install --no-cache-dir -r requirements.txt # Use a dedicated Node.js stage for frontend building -FROM node:20-slim AS frontend-builder +FROM node:20 AS frontend-builder WORKDIR /app/frontend COPY --from=builder /app /app -RUN npm install --ignore-scripts && \ - npm rebuild && \ - npm run build && \ +RUN corepack enable && corepack prepare yarn@stable --activate && \ + yarn install && \ + yarn build && \ find . -maxdepth 1 ! -name '.' ! -name 'dist' -exec rm -rf '{}' \; FROM python:3.13-slim From 8219773a68b24e34c8865f94292cf80851a11e72 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 1 May 2025 00:54:35 +0000 Subject: [PATCH 17/21] Release v0.6.0 --- version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.py b/version.py index 18a1ef5d..6c008d2b 100644 --- a/version.py +++ b/version.py @@ -1,5 +1,5 @@ """ Dispatcharr version information. """ -__version__ = '0.5.0' # Follow semantic versioning (MAJOR.MINOR.PATCH) +__version__ = '0.6.0' # Follow semantic versioning (MAJOR.MINOR.PATCH) __timestamp__ = None # Set during CI/CD build process From c65b431ebaf97afd1faef6abad52e670cbf8c580 Mon Sep 17 00:00:00 2001 From: SergeantPanda <61642231+SergeantPanda@users.noreply.github.com> Date: Wed, 30 Apr 2025 20:05:37 -0500 Subject: [PATCH 18/21] Rolled back after failed release. --- version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.py b/version.py index 6c008d2b..772064dd 100644 --- a/version.py +++ b/version.py @@ -1,5 +1,5 @@ """ Dispatcharr version information. """ -__version__ = '0.6.0' # Follow semantic versioning (MAJOR.MINOR.PATCH) +__version__ = '0.3.0' # Follow semantic versioning (MAJOR.MINOR.PATCH) __timestamp__ = None # Set during CI/CD build process From c6c5662472771612e4db0720e214a0c0020f3864 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 1 May 2025 01:09:08 +0000 Subject: [PATCH 19/21] Release v0.4.0 --- version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.py b/version.py index 772064dd..25e27d60 100644 --- a/version.py +++ b/version.py @@ -1,5 +1,5 @@ """ Dispatcharr version information. """ -__version__ = '0.3.0' # Follow semantic versioning (MAJOR.MINOR.PATCH) +__version__ = '0.4.0' # Follow semantic versioning (MAJOR.MINOR.PATCH) __timestamp__ = None # Set during CI/CD build process From a86ae715b9d41f0fe99dc783857c1342c1a2fb4b Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Wed, 30 Apr 2025 21:11:41 -0500 Subject: [PATCH 20/21] Fixes add streams to channel to follow correct logic of being disabled. --- .../src/components/tables/StreamsTable.jsx | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/tables/StreamsTable.jsx b/frontend/src/components/tables/StreamsTable.jsx index 276ce189..078e24d9 100644 --- a/frontend/src/components/tables/StreamsTable.jsx +++ b/frontend/src/components/tables/StreamsTable.jsx @@ -156,7 +156,7 @@ const StreamRowActions = ({ ); }; -const StreamsTable = ({}) => { +const StreamsTable = ({ }) => { const theme = useMantineTheme(); /** @@ -606,23 +606,22 @@ const StreamsTable = ({}) => { {/* Top toolbar with Remove, Assign, Auto-match, and Add buttons */} - {selectedStreamIds.length > 0 && ( - - )} + Date: Thu, 1 May 2025 09:05:51 -0500 Subject: [PATCH 21/21] More sleep events. --- apps/proxy/ts_proxy/views.py | 5 +++-- docker/uwsgi.ini | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/proxy/ts_proxy/views.py b/apps/proxy/ts_proxy/views.py index 35ca3648..ef232fd2 100644 --- a/apps/proxy/ts_proxy/views.py +++ b/apps/proxy/ts_proxy/views.py @@ -24,6 +24,7 @@ from .services.channel_service import ChannelService from .url_utils import generate_stream_url, transform_url, get_stream_info_for_switch, get_stream_object, get_alternate_streams from .utils import get_logger from uuid import UUID +import gevent logger = get_logger() @@ -119,7 +120,7 @@ def stream_ts(request, channel_id): # Wait before retrying (using exponential backoff with a cap) wait_time = min(0.5 * (2 ** attempt), 2.0) # Caps at 2 seconds logger.info(f"[{client_id}] Waiting {wait_time:.1f}s for a connection to become available (attempt {attempt+1}/{max_retries})") - time.sleep(wait_time) + gevent.sleep(wait_time) # FIXED: Using gevent.sleep instead of time.sleep if stream_url is None: # Make sure to release any stream locks that might have been acquired @@ -258,7 +259,7 @@ def stream_ts(request, channel_id): proxy_server.stop_channel(channel_id) return JsonResponse({'error': 'Failed to connect'}, status=502) - time.sleep(0.1) + gevent.sleep(0.1) # FIXED: Using gevent.sleep instead of time.sleep logger.info(f"[{client_id}] Successfully initialized channel {channel_id}") channel_initializing = True diff --git a/docker/uwsgi.ini b/docker/uwsgi.ini index 326f4b5d..b1ff362b 100644 --- a/docker/uwsgi.ini +++ b/docker/uwsgi.ini @@ -41,6 +41,7 @@ lazy-apps = true # Improve memory efficiency # Async mode (use gevent for high concurrency) gevent = 100 async = 100 +gevent-monkey-patch = true ; Ensure all blocking operations are patched (especially important for Ryzen CPUs) # Performance tuning thunder-lock = true