mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-17 16:50:53 +00:00
fix: Preserve base path in URL normalization for XC server and transform credentials. (Fixes #1218)
Some checks failed
CI Pipeline / prepare (push) Has been cancelled
Build and Push Multi-Arch Docker Image / build-and-push (push) Has been cancelled
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Has been cancelled
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Has been cancelled
CI Pipeline / create-manifest (push) Has been cancelled
Some checks failed
CI Pipeline / prepare (push) Has been cancelled
Build and Push Multi-Arch Docker Image / build-and-push (push) Has been cancelled
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Has been cancelled
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Has been cancelled
CI Pipeline / create-manifest (push) Has been cancelled
This commit is contained in:
parent
f4dce6db01
commit
21913306c4
3 changed files with 19 additions and 16 deletions
|
|
@ -69,9 +69,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- **Selection summary in the bulk edit modal.** The bulk edit form shows `Selection: X auto-synced, Y manual` at the top so users can see how a single set of changes will route between override rows and direct writes.
|
||||
- **Delete-Playlist preview.** A new `GET /api/m3u/accounts/{id}/auto-created-channels-count/` endpoint returns the count and up to 5 sample names of auto-created channels owned by the account. The Delete Playlist confirmation dialog uses this to show the user exactly how many channels will cascade away before they confirm.
|
||||
- **Custom `Channel.objects` manager.** A thin manager wraps the existing `with_effective_values()` helper so new code can call `Channel.objects.with_effective_values(...)` directly. The module-level helper remains the canonical implementation; existing call sites are unchanged.
|
||||
|
||||
### Changed
|
||||
|
||||
- **Frontend unit tests added for form components.** `GroupManager`, `LiveGroupFilter`, `LoginForm`, and `Logo` now have Vitest + Testing Library test suites covering rendering, user interactions, API integration, and edge cases (144 tests total). Business logic that was extracted into utility modules (`ChannelGroupUtils`, `LiveGroupFilterUtils`, `LogoUtils`, `M3uUtils`, `M3uFilterUtils`, `M3uGroupFilterUtils`, `M3uProfileUtils`, `AutoSyncAdvancedUtils`, `AutoSyncBasicUtils`) is also exercised through these tests. — Thanks [@nick4810](https://github.com/nick4810)
|
||||
- **Global Network Access settings use tag-style inputs**: the IP/CIDR range fields in the Network Access settings panel now use tag-style chip inputs instead of a plain text field, making it easier to add, review, and remove individual addresses or ranges. — Thanks [@sethwv](https://github.com/sethwv)
|
||||
- **Auto-sync overhaul** sync and channel behavior changes for the new override system. — Thanks [@CodeBormen](https://github.com/CodeBormen)
|
||||
|
|
@ -83,6 +80,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Fixed
|
||||
|
||||
- **XC server sub-path URLs now work correctly.** When a provider serves its XC API from a sub-path (e.g. `http://server/Pluto/gb/player_api.php`), Dispatcharr was stripping the path entirely and hitting the root (`/player_api.php`) instead. `_normalize_url` now preserves sub-path components and only strips any trailing `.php` segment (covering `player_api.php`, `get.php`, `xmltv.php`, and any future endpoint without a maintained list). The same fix is applied to `get_transformed_credentials` in the M3U profile transformation path. (Fixes #1218)
|
||||
- **M3U filter delete confirmation showed wrong field name and had a typo.** The confirmation dialog for deleting an M3U filter read `filter.type` (always `undefined`) instead of `filter.filter_type`, leaving the "Type:" line blank, and displayed "Patter:" instead of "Pattern:". Both are corrected. — Thanks [@nick4810](https://github.com/nick4810)
|
||||
- **M3U form FileInput expanded the modal width on long filenames.** Uploading a local M3U file with a long name caused the `FileInput` to expand beyond the modal's layout bounds. The input now clips overflow with `textOverflow: ellipsis`. — Thanks [@nick4810](https://github.com/nick4810)
|
||||
- **Login loading spinner not cleared on successful login.** `setIsLoading(false)` was inside the `catch` block only, so a successful login that immediately navigated away left the loading state as `true` if the component re-mounted. Moved to a `finally` block so it always resets. — Thanks [@nick4810](https://github.com/nick4810)
|
||||
|
|
|
|||
|
|
@ -2830,10 +2830,11 @@ def get_transformed_credentials(account, profile=None):
|
|||
transformed_username = path_parts[-3]
|
||||
transformed_password = path_parts[-2]
|
||||
|
||||
# Rebuild server URL without the username/password path
|
||||
transformed_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
|
||||
if parsed_url.port:
|
||||
transformed_url = f"{parsed_url.scheme}://{parsed_url.hostname}:{parsed_url.port}"
|
||||
# Rebuild server URL: preserve any sub-path that precedes
|
||||
# /live/username/password/1234.ts (path_parts[:-4]).
|
||||
base_path_parts = path_parts[:-4]
|
||||
base_path = ('/' + '/'.join(base_path_parts)) if base_path_parts else ''
|
||||
transformed_url = f"{parsed_url.scheme}://{parsed_url.netloc}{base_path}"
|
||||
|
||||
logger.debug(f"Extracted transformed credentials:")
|
||||
logger.debug(f" Server URL: {transformed_url}")
|
||||
|
|
|
|||
|
|
@ -43,18 +43,22 @@ class Client:
|
|||
self.server_info = None
|
||||
|
||||
def _normalize_url(self, url):
|
||||
"""Normalize server URL by removing trailing slashes and paths"""
|
||||
"""Normalize server URL: strip XC API endpoints and query params, preserve base path."""
|
||||
if not url:
|
||||
raise ValueError("Server URL cannot be empty")
|
||||
|
||||
url = url.rstrip('/')
|
||||
# Remove any path after domain - we'll construct proper API URLs
|
||||
# Split by protocol first to preserve it
|
||||
if '://' in url:
|
||||
protocol, rest = url.split('://', 1)
|
||||
domain = rest.split('/', 1)[0]
|
||||
return f"{protocol}://{domain}"
|
||||
return url
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
|
||||
parsed = urlparse(url.strip())
|
||||
path = parsed.path.rstrip('/')
|
||||
|
||||
# XC API endpoints are always .php files; legitimate base paths never are.
|
||||
# Stripping the trailing segment when it ends in .php handles any pasted API URL.
|
||||
last_segment = path.rsplit('/', 1)[-1]
|
||||
if last_segment.endswith('.php'):
|
||||
path = path[:-(len(last_segment) + 1)] if '/' in path else ''
|
||||
|
||||
return urlunparse((parsed.scheme, parsed.netloc, path, '', '', ''))
|
||||
|
||||
def _make_request(self, endpoint, params=None):
|
||||
"""Make request with detailed error handling"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue