diff --git a/.env.example b/.env.example
index 20a024930..6d7fc767c 100644
--- a/.env.example
+++ b/.env.example
@@ -25,9 +25,6 @@ POSTGRES_DB=bookorbit
# App secrets
JWT_SECRET=change-this-to-a-long-random-secret
-# Fresh installs should generate an independent key with: openssl rand -hex 32
-# Existing installs upgrading from an older release must initially copy their current JWT_SECRET here so existing podcast URLs remain readable.
-PODCAST_ENCRYPTION_KEY=change-this-to-a-different-long-random-secret
# Required for the initial /auth/setup endpoint (x-setup-token header)
SETUP_BOOTSTRAP_TOKEN=change-this-to-a-long-random-secret
@@ -38,7 +35,6 @@ SETUP_BOOTSTRAP_TOKEN=change-this-to-a-long-random-secret
# The file must be mounted into every service that uses it, and must not be empty.
# POSTGRES_PASSWORD_FILE=/run/secrets/bookorbit_postgres_password
# JWT_SECRET_FILE=/run/secrets/bookorbit_jwt_secret
-# PODCAST_ENCRYPTION_KEY_FILE=/run/secrets/bookorbit_podcast_encryption_key
# SETUP_BOOTSTRAP_TOKEN_FILE=/run/secrets/bookorbit_setup_bootstrap_token
# External/public URL used by emails and Kobo endpoints
diff --git a/client/eslint.config.ts b/client/eslint.config.ts
index bd23d49e2..1d4b8d409 100644
--- a/client/eslint.config.ts
+++ b/client/eslint.config.ts
@@ -27,12 +27,11 @@ export default defineConfigWithVueTs(
files: ['src/**/__tests__/*', 'src/**/*.spec.ts', 'src/**/*.test.ts'],
},
- // Named handlers only: an inline arrow in a template cannot be named, reused or tested, and the
- // podcast feature was swept clean of them. The rest of the app still carries several hundred, so
- // widening this is its own task rather than a side effect of one feature's refactor.
+ // Named handlers only: an inline arrow in a template cannot be named, reused or tested. The rest
+ // of the app still carries several hundred, so widening this is its own task rather than a side
+ // effect of one feature's refactor.
{
files: [
- 'src/features/podcast/**/*.vue',
'src/components/FormSheet.vue',
'src/features/collection/components/CollectionMembershipList.vue',
'src/features/book/components/metadata-match/*.vue',
diff --git a/client/src/App.vue b/client/src/App.vue
index 42a4ad743..37d5929de 100644
--- a/client/src/App.vue
+++ b/client/src/App.vue
@@ -2,7 +2,6 @@
import { computed, provide, watch } from 'vue'
import { useRoute } from 'vue-router'
import { INIT_OPTIONS_KEY, THEME_KEY } from 'vue-echarts'
-import { APP_FEATURES } from '@bookorbit/types'
import { useChangePasswordDialog } from '@/composables/useChangePasswordDialog'
import { useChartTokens } from '@/composables/useChartTokens'
import { buildChartTheme } from '@/lib/echarts'
@@ -14,31 +13,20 @@ import { useSessionBootstrap } from '@/features/auth/composables/useSessionBoots
import ServerReconnectScreen from '@/features/auth/components/ServerReconnectScreen.vue'
import TtsMiniPlayer from '@/features/tts/components/TtsMiniPlayer.vue'
import MediaOverlayMiniPlayer from '@/features/reader/media-overlay/components/MediaOverlayMiniPlayer.vue'
-import PodcastMiniPlayer from '@/features/podcast/components/PodcastMiniPlayer.vue'
-import PodcastLiveRegion from '@/features/podcast/components/PodcastLiveRegion.vue'
-import PodcastDownloadWidget from '@/features/podcast/components/PodcastDownloadWidget.vue'
-import PodcastShortcutsDialog from '@/features/podcast/components/PodcastShortcutsDialog.vue'
-import { usePodcastPlayer } from '@/features/podcast/composables/usePodcastPlayer'
-import { usePodcastKeyboardShortcuts } from '@/features/podcast/composables/usePodcastKeyboardShortcuts'
-import { usePodcastDownloadBatches } from '@/features/podcast/composables/usePodcastDownloadBatches'
-import { usePodcastEvents } from '@/features/podcast/composables/usePodcastEvents'
import { Toaster } from '@/components/ui/sonner'
import { TooltipProvider } from '@/components/ui/tooltip'
import { resolveRouteViewKey } from '@/router/view-key'
import LegalNotices from '@/components/legal/LegalNotices.vue'
-// Bottom-edge media and download surfaces publish their measured heights, so the toaster clears
-// whichever one currently sits highest.
+// The bottom-edge TTS player publishes its measured height, so the toaster clears it.
const TOASTER_OFFSET = {
right: '16px',
- bottom:
- 'max(16px, var(--podcast-mini-player-clearance, 0px), var(--tts-mini-player-clearance, 0px), var(--podcast-download-widget-clearance, 0px))',
+ bottom: 'max(16px, var(--tts-mini-player-clearance, 0px))',
}
const TOASTER_MOBILE_OFFSET = {
left: '16px',
right: '16px',
- bottom:
- 'max(16px, var(--podcast-mini-player-clearance, 0px), var(--tts-mini-player-clearance, 0px), var(--podcast-download-widget-clearance, 0px))',
+ bottom: 'max(16px, var(--tts-mini-player-clearance, 0px))',
}
const { isOpen } = useChangePasswordDialog()
@@ -48,29 +36,11 @@ const route = useRoute()
const { user } = useAuth()
const { unreachable: serverUnreachable } = useSessionBootstrap()
const { popupOpen, evaluate, syncPopup } = useWhatsNew()
-const podcastPlayer = APP_FEATURES.podcasts ? usePodcastPlayer() : null
-const podcastDownloads = APP_FEATURES.podcasts ? usePodcastDownloadBatches() : null
-const podcastEvents = APP_FEATURES.podcasts ? usePodcastEvents() : null
-
-if (APP_FEATURES.podcasts) usePodcastKeyboardShortcuts()
watch(
() => user.value,
- async (current, previous) => {
- if (previous && current?.id !== previous.id) {
- await podcastPlayer?.resetForUserChange()
- podcastDownloads?.resetForUserChange()
- podcastEvents?.resetForUserChange()
- }
- if (!current) {
- if (!previous) {
- await podcastPlayer?.resetForUserChange()
- podcastDownloads?.resetForUserChange()
- podcastEvents?.resetForUserChange()
- }
- return
- }
- await podcastPlayer?.loadPreferences()
+ async (current) => {
+ if (!current) return
await evaluate()
syncPopup(route.name as string | undefined)
},
@@ -102,10 +72,6 @@ provide(
{{ t('dashboard.scroller.empty.continuePodcasts') }}
-{{ subtitle }}