feat(tunein): dynamic TuneIn stream resolution + remove preset overwrite confirmation#117
Merged
feat(tunein): dynamic TuneIn stream resolution + remove preset overwrite confirmation#117
Conversation
TuneIn stations have empty stream URLs (resolved lazily via Tune.ashx). Previously, the empty URL was stored in the preset base64 payload, causing the Bose device to load forever. Now store tuneinId in preset data and resolve fresh stream URLs via TuneIn API when the device requests playback. Also apply HTTPS-to-HTTP conversion on TuneIn stream URLs (Bose limitation). Extract convert_https_to_http into shared bmx/stream_utils module.
… screenshot tests
9817edc to
30d420c
Compare
… issues - fix(security): remove user-controlled data from logger calls in client_adapter.py - fix(a11y): replace role=dialog div with native dialog element in BugReportModal - fix(a11y): add readonly props to BugReportModal interface - refactor(multiroom): use useZoneBuilder hook with i18n messages to eliminate duplication - test: add coverage for bugReport API, logBuffer, BugReportModal, useZoneBuilder - chore: add html2canvas mock for test environment
- fix(security): add NOSONAR comment for intentional HTTPS-to-HTTP in stream_utils.py - fix(a11y): remove onClick from non-interactive overlay div in BugReportModal - test: expand BugReportModal tests to 13 (submit flow, error handling, toggleDevice)
…closure) msgs strings are destructured as primitives before callbacks so ESLint exhaustive-deps can verify them and closures always use current values. ci: update sonarqube-scan-action v5 -> v6 (security patch)
Cypress 15's built-in webpack/ts-loader sets downlevelIteration:true which TypeScript 6.0 treats as error TS5101 (deprecated option), crashing all 14 e2e specs. Fix: use @cypress/webpack-preprocessor with transpileOnly:true to bypass TypeScript type-checker during test bundling. Full type safety is preserved via tsc --noEmit in the Lint Code step.
In CI (Ubuntu headless Chrome), navigator.language='en' so the app loaded
in English while tests assert German text (weiter, Zurück, Willkommen, etc).
Fix: set localStorage 'oct-lang'='de' before every page load via the global
Cypress window:before:load handler.
wizard-i18n.cy.ts English tests opt out by setting Cypress.env('e2e_locale', 'en')
in their beforeEach, which the global handler respects.
…ish tests The global window:before:load hook sets 'de' locale for all tests (CI defaults to English which broke German text assertions). wizard-i18n.cy.ts English tests use a visitEn() helper that overrides to 'en' per-visit, avoiding the Cypress.env() incompatibility with allowCypressEnv:false.
Remove unreliable global window:before:load hook (cy.visit onBeforeLoad cannot override it). Instead, each spec that asserts German text uses a visitDe() helper that sets oct-lang=de via onBeforeLoad per-visit. localStorage persists within a test, so only the first visit per test needs onBeforeLoad; subsequent cy.visit calls inherit the locale. Affected specs: device-offline, manual-ip-configuration, wizard-device-persistence, wizard-full-flow. wizard-i18n.cy.ts reverted to plain cy.visit (CI default is English, German switch is done via UI in the German describe block).
…viceOffline=true
useNowPlaying polls the real mock device (192.168.1.x) which is unreachable
in CI, causing markDeviceOffline(). The error-message div has condition
{error && !deviceOffline} so it never renders when device is offline.
Fix: intercept now-playing and volume in Error Handling beforeEach.
…d internal cy.visit)
- wizard-ui-rendering: fix TS syntax error (replace ASCII 0x22 with \\u201D
in MOJIBAKE_PATTERNS for 🔌 exact pattern); fix all URLs from
/setup/wizard?step=N to /setup-wizard?step=N; add cy.wait('@getDevices')
- ux-wizard-screenshots: add visitDe() helper and use it for all wizard
cy.visit calls so CI Chrome gets German locale (fixes /weiter/i not found)
- device-offline: add cy.reload() before cy.wait('@nowPlaying503') in
'should show device name' test so 503 intercept is active on initial
component mount (avoids polling-cycle race condition)
- preset-management-advanced: add scrollIntoView() and increase timeout
to 10000ms on error-message visibility assertions
- wizard-i18n: replace UI-click language switch in German describe block
with visitDe() helper (selector not present on wizard pages, unreliable)
- wizard-ui-rendering: add now-playing/volume mocks to setupBasicMocks preventing 503→offline cascade that blocked Preset Search Modal tests - wizard-i18n: fix German nav test (Presets label same in DE/EN, check Zonen/Einstellungen instead), update dropdown from 4 to 10 languages, add now-playing/volume/presets mocks to setupWizardMocks - preset-management-advanced: add scrollIntoView + increase timeout for dismiss error messages test (same overflow:hidden fix pattern)
- Change /api/presets* to /api/presets/* so it matches the actual API
path /api/presets/{deviceId} (minimatch * does not match /)
- Move cy.wait(@getPresets) into beforeEach since the root page loads
presets on mount, remove redundant cy.contains(Presets).click() nav
clicks from each test
- Add __OCT_EXT_RESOLVER__ Vite define flag (default: true) - Create capabilities.ts as single source of truth - Gate RadioSearch provider chips, CloudBadge, NowPlaying badge - Add backend OCT_EXTENDED_RESOLVER env var guard on /api/radio/search - Dead-code elimination removes all TuneIn code when flag=false - Add tests for both flag states (frontend + backend) Co-authored-by: Christian Scheil <christian@scheils.de>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
feat(tunein): Resolve TuneIn streams dynamically at playback time
TuneIn stations provide stream URLs that expire or change over time. Previously, the stream URL was resolved once at preset-save time and stored statically. This caused playback failures after the URL expired.
Fix: TuneIn station presets now store only the station UUID ( uneinId). At playback time, the Orion adapter detects the uneinId and resolves a fresh stream URL from the TuneIn API on demand.
Changed files:
outes.py)
feat(presets): Remove overwrite confirmation for occupied presets
The confirmation dialog when overwriting an occupied preset slot added friction without meaningful benefit — users already selected a station and a preset slot intentionally. Dialog removed; occupied slots are overwritten directly.
Changed file:
fix(e2e): Add missing intercepts to wizard tests
Wizard E2E and UX screenshot tests were missing \detect-strategy\ and \server-info\ intercepts, causing intermittent failures in CI.
Changed files:
Test Coverage
Breaking Changes
None. TuneIn stations saved before this change may need to be re-assigned to pick up the \ uneinId-based storage format.