diff --git a/src/routes/player/Player.tsx b/src/routes/player/Player.tsx
index 211dc2c11362190fa789afbbe4aa7c4cef024836..4b93910cac8c0b8a7d564c347e450a8bc193a9b7 100644
--- a/src/routes/player/Player.tsx
+++ b/src/routes/player/Player.tsx
@@ -5,15 +5,14 @@ import {ContentMeta} from "../../api/models/dto/ContentMeta";
 import {Media} from "../../api/models/Media";
 import {getLocalizedDescription, getLocalizedName, getLocalizedRating} from "../../api/models/Content";
 import {useLocale} from "../../util/locale/LocalizedContext";
-import {SeekBar} from "./SeekBar";
+import {SeekBarContainer} from "./SeekBarContainer";
 import {VideoElement} from "./video/VideoElement";
 import {PlayerApi} from "./video/PlayerApi";
 import {Subtitle} from "../../api/models/Subtitle";
 import {MousePosition} from "../../util/mouse/MousePosition";
-import {VideoProvider} from "./video/VideoContext";
+import {PlayerProvider} from "./video/VideoContext";
 import {SubtitleRenderer} from "./subtitles/SubtitleRenderer";
 import {useShowEpisodes} from "../../api/ApiHooks";
-import {useDuration} from "../../util/media/useDuration";
 import {AudioSelection} from "./video/AudioSelection";
 import {SubtitleSelection} from "./video/SubtitleSelection";
 import {EpisodeSelection} from "./video/EpisodeSelection";
@@ -45,10 +44,8 @@ export function Player(
     const [playerApi, setPlayerApi] = useState<PlayerApi | null>(null);
     const [mousePosition, setMousePosition] = useState<MousePosition | null>(null);
 
-    const duration = useDuration(playerApi);
-
     return (
-        <VideoProvider value={playerApi?.getVideoElement() || null}>
+        <PlayerProvider value={playerApi}>
             <div>
                 <Link to="/">Back</Link>
                 <h2>{name?.name}</h2>
@@ -78,29 +75,26 @@ export function Player(
                         />
                         <SubtitleRenderer
                             className={classes.subtitleCanvas}
-                            videoElement={playerApi?.getVideoElement() || null}
                             subtitle={subtitle}
-                            duration={duration}
                         />
                     </div>
                 </div>
-                <PlayerControls playerApi={playerApi} />
+                <PlayerControls/>
                 <h3>Audio</h3>
-                <AudioSelection playerApi={playerApi} />
+                <AudioSelection/>
                 <h3>Subtitles</h3>
                 <SubtitleSelection
                     subtitles={[null, ...content.subtitles]}
                     subtitle={subtitle}
                     setSubtitle={setSubtitle}
                 />
-                <SeekBar
-                    videoApi={playerApi}
+                <SeekBarContainer
                     previewSrc={content.preview}
                     mousePosition={mousePosition}
                     setMousePosition={setMousePosition}
                 />
             </div>
-        </VideoProvider>
+        </PlayerProvider>
     );
 }
 
diff --git a/src/routes/player/PreviewBar.tsx b/src/routes/player/PreviewBar.tsx
index 58dd9fcef9a836b05b1b4333a6641a94a16a3a84..a3dee23dee95b628e9848d2b219021a5cfdc3a3b 100644
--- a/src/routes/player/PreviewBar.tsx
+++ b/src/routes/player/PreviewBar.tsx
@@ -13,7 +13,6 @@ interface Props {
 }
 
 export function PreviewBar({previewSrc, duration, position, hidden}: Props) {
-    //console.log("Rendering PreviewBar")
     const classes = useStyles();
 
     const [previewTrack, setPreviewTrack] = useState<HTMLTrackElement | null>(null);
diff --git a/src/routes/player/PreviewViewer.tsx b/src/routes/player/PreviewViewer.tsx
index 71ba1a376af67c5640252afdd4d599d402f29493..21ae663eac6d2a2e6464c5ca6cfdc59c183b0c73 100644
--- a/src/routes/player/PreviewViewer.tsx
+++ b/src/routes/player/PreviewViewer.tsx
@@ -1,4 +1,4 @@
-import { Fragment, useMemo } from "react";
+import {Fragment, useMemo} from "react";
 import {createUseStyles} from "react-jss";
 import {HeadPortal} from "../../util/head/HeadPortal";
 import {useImage} from "../../util/media/useImage";
@@ -12,23 +12,28 @@ interface Props {
 }
 
 export function PreviewViewer({previewTrack, position}: Props) {
-    //console.log("Rendering PreviewViewer#1")
-
     const classes = useStyles();
 
     const cues = useTextTrackCues(previewTrack);
-    const activeCue = position === null ? null : cues.find(it => it.startTime <= position && it.endTime >= position);
-    const activeUrl = previewTrack && activeCue ? new URL(activeCue.text, previewTrack.src).toString() : null;
+    const activeCue = position === null
+        ? null
+        : cues.find(it => it.startTime <= position && it.endTime >= position);
+    const activeUrl = previewTrack && activeCue
+        ? new URL(activeCue.text, previewTrack.src).toString()
+        : null;
     const imageSprite = useMemo(() => parseImageSprite(activeUrl), [activeUrl]);
     const image = useImage(imageSprite?.src || null);
     const sprite = useImageSprite(imageSprite, image);
-    const sources = useMemo(() => previewTrack === null ? null : Array.from(new Set(cues.map(it => {
-        const url = new URL(it.text, previewTrack.src);
-        url.hash = "";
-        return url.toString();
-    }))), [cues, previewTrack]);
+    const sources = useMemo(() => previewTrack === null
+        ? null
+        : Array.from(new Set(cues.map(it => {
+            const url = new URL(it.text, previewTrack.src);
+            url.hash = "";
+            return url.toString();
+        }))),
+        [cues, previewTrack]
+    );
     return useMemo(() => {
-        //console.log("Rendering PreviewViewer#2")
         return (
             <Fragment>
                 <HeadPortal>
diff --git a/src/routes/player/SeekBar.tsx b/src/routes/player/SeekBar.tsx
index 84540693e4903461e87ee9c58ba19beb5d483ac4..033c30fc3b88f9f263c7ea9e78cc6aebba446dd9 100644
--- a/src/routes/player/SeekBar.tsx
+++ b/src/routes/player/SeekBar.tsx
@@ -1,34 +1,33 @@
-import {Fragment, MouseEvent, useCallback, useMemo, useState} from "react";
+import {MouseEvent, useCallback, useMemo, useState} from "react";
 import {createUseStyles} from "react-jss";
-import {getMousePosition} from "../../util/mouse/getMousePosition";
-import {MousePosition} from "../../util/mouse/MousePosition";
 import {useOffsetAbsolute} from "../../util/offset/useOffsetAbsolute";
 import {useOffsetRelative} from "../../util/offset/useOffsetRelative";
-import {PreviewBar} from "./PreviewBar";
-import {PlayerApi} from "./video/PlayerApi";
-import {formatDuration} from "../../util/formatDuration";
+import {getMousePosition} from "../../util/mouse/getMousePosition";
+import {MousePosition} from "../../util/mouse/MousePosition";
+import {usePlayerApi} from "./video/VideoContext";
 import {useCurrentTime} from "../../util/media/useCurrentTime";
 import {useDuration} from "../../util/media/useDuration";
 
 interface Props {
-    videoApi: PlayerApi | null,
-    previewSrc: string | null,
     mousePosition: MousePosition | null,
     setMousePosition: (position: MousePosition | null) => void,
 }
 
-export function SeekBar({videoApi, previewSrc, mousePosition, setMousePosition}: Props) {
+export function SeekBar(
+    {mousePosition, setMousePosition}: Props
+) {
+    const videoApi = usePlayerApi();
     const classes = useStyles();
 
     const isVisible = mousePosition !== null;
 
+    const position = useCurrentTime(videoApi)
+    const duration = useDuration(videoApi);
+
     const [seekBarRef, setSeekBarRef] = useState<HTMLDivElement | null>(null);
     const [seekHeadRef, setSeekHeadRef] = useState<HTMLDivElement | null>(null);
     const [playHeadRef, setPlayHeadRef] = useState<HTMLDivElement | null>(null);
 
-    const position = useCurrentTime(videoApi)
-    const duration = useDuration(videoApi);
-
     const seekHeadOffset = useOffsetAbsolute(seekBarRef, seekHeadRef, mousePosition?.absolute || 0);
     const playHeadOffset = useOffsetRelative(seekBarRef, playHeadRef, position / duration);
 
@@ -73,7 +72,7 @@ export function SeekBar({videoApi, previewSrc, mousePosition, setMousePosition}:
         />
     ), [classes.playHead, playHeadOffset]);
 
-    const seekBar = useMemo(() => (
+    return (
         <div
             ref={setSeekBarRef}
             className={classes.seekBar}
@@ -84,21 +83,6 @@ export function SeekBar({videoApi, previewSrc, mousePosition, setMousePosition}:
             {seekHead}
             {playHead}
         </div>
-    ), [classes.seekBar, onClick, onMouseLeave, onMouseMove, playHead, seekHead]);
-
-    return (
-        <Fragment>
-            <p style={{fontVariant: "tabular-nums"}}>
-                {formatDuration(mousePosition ? (mousePosition.relative * duration) : position)} / {formatDuration(duration)}
-            </p>
-            <PreviewBar
-                previewSrc={previewSrc}
-                duration={duration}
-                position={mousePosition}
-                hidden={mousePosition === null}
-            />
-            {seekBar}
-        </Fragment>
     );
 }
 
diff --git a/src/routes/player/SeekBarContainer.tsx b/src/routes/player/SeekBarContainer.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..290c16d025d6ade574692448729686f8754f9066
--- /dev/null
+++ b/src/routes/player/SeekBarContainer.tsx
@@ -0,0 +1,41 @@
+import {Fragment} from "react";
+import {MousePosition} from "../../util/mouse/MousePosition";
+import {PreviewBar} from "./PreviewBar";
+import {formatDuration} from "../../util/formatDuration";
+import {useCurrentTime} from "../../util/media/useCurrentTime";
+import {useDuration} from "../../util/media/useDuration";
+import {usePlayerApi} from "./video/VideoContext";
+import {SeekBar} from "./SeekBar";
+
+interface Props {
+    previewSrc: string | null,
+    mousePosition: MousePosition | null,
+    setMousePosition: (position: MousePosition | null) => void,
+}
+
+export function SeekBarContainer({previewSrc, mousePosition, setMousePosition}: Props) {
+    const videoApi = usePlayerApi();
+
+    const position = useCurrentTime(videoApi)
+    const duration = useDuration(videoApi);
+
+    return (
+        <Fragment>
+            <p style={{fontVariant: "tabular-nums"}}>
+                {formatDuration(mousePosition
+                    ? (mousePosition.relative * duration)
+                    : position)} / {formatDuration(duration)}
+            </p>
+            <PreviewBar
+                previewSrc={previewSrc}
+                duration={duration}
+                position={mousePosition}
+                hidden={mousePosition === null}
+            />
+            <SeekBar
+                mousePosition={mousePosition}
+                setMousePosition={setMousePosition}
+            />
+        </Fragment>
+    );
+}
diff --git a/src/routes/player/subtitles/SubtitleRenderer.tsx b/src/routes/player/subtitles/SubtitleRenderer.tsx
index 8c3a2273c64c3f4d333e3c23f41760d4e4ffa3d6..6d2d36a1f0c1d09031948515131e8859da0c317c 100644
--- a/src/routes/player/subtitles/SubtitleRenderer.tsx
+++ b/src/routes/player/subtitles/SubtitleRenderer.tsx
@@ -2,22 +2,38 @@ import {Subtitle} from "../../../api/models/Subtitle";
 import {Fragment} from "react";
 import {TtmlRenderer} from "./TtmlRenderer";
 import {SsaRenderer} from "./SsaRenderer";
+import {usePlayerApi} from "../video/VideoContext";
+import {useDuration} from "../../../util/media/useDuration";
 
 interface Props {
-    videoElement: HTMLVideoElement | null,
     subtitle: Subtitle | null,
-    duration: number,
     className?: string,
 }
 
 export function SubtitleRenderer(
     props: Props
 ) {
+    const playerApi = usePlayerApi();
+    const videoElement = playerApi?.getVideoElement() || null;
+    const duration = useDuration(playerApi);
+
     switch (props.subtitle?.format) {
         case "ttml":
-            return (<TtmlRenderer {...props} />);
+            return (
+                <TtmlRenderer
+                    videoElement={videoElement}
+                    duration={duration}
+                    {...props}
+                />
+            );
         case "ass":
-            return (<SsaRenderer {...props} />);
+            return (
+                <SsaRenderer
+                    videoElement={videoElement}
+                    duration={duration}
+                    {...props}
+                />
+            );
         default:
             return (<Fragment/>);
     }
diff --git a/src/routes/player/video/AudioSelection.tsx b/src/routes/player/video/AudioSelection.tsx
index d70f24559722d8d52a98332b34d5741311ae3f6b..1c0f735f31353ef6c1f62c4aff5bfe289d21a084 100644
--- a/src/routes/player/video/AudioSelection.tsx
+++ b/src/routes/player/video/AudioSelection.tsx
@@ -1,13 +1,9 @@
-import {PlayerApi} from "./PlayerApi";
 import {useAudioTracks} from "../../../util/media/useAudioTracks";
+import {usePlayerApi} from "./VideoContext";
 
-interface Props {
-    playerApi: PlayerApi | null
-}
+export function AudioSelection() {
+    const playerApi = usePlayerApi();
 
-export function AudioSelection(
-    {playerApi}: Props
-) {
     const [audioTracks, currentTrack, setCurrentTrack] = useAudioTracks(playerApi);
 
     return (
diff --git a/src/routes/player/video/PlayerControls.tsx b/src/routes/player/video/PlayerControls.tsx
index 8548d3ba2d9bf3d81dea45cbb1068668691c49d3..20b4d498f9980985f770787ed5b5f39e59d883bf 100644
--- a/src/routes/player/video/PlayerControls.tsx
+++ b/src/routes/player/video/PlayerControls.tsx
@@ -1,14 +1,10 @@
 import {ChangeEvent, Fragment, useCallback, useState} from "react";
-import {PlayerApi} from "./PlayerApi";
 import {usePaused} from "../../../util/media/usePaused";
+import {usePlayerApi} from "./VideoContext";
 
-interface Props {
-    playerApi: PlayerApi | null,
-}
+export function PlayerControls() {
+    const playerApi = usePlayerApi();
 
-export function PlayerControls(
-    {playerApi}: Props
-) {
     const [volume, setVolume] = useState<number>(1);
     const paused = usePaused(playerApi);
 
diff --git a/src/routes/player/video/Track.tsx b/src/routes/player/video/Track.tsx
index c3a922f2c34d9e1e5516d54f344aa575eabb4635..f48bb4b3aceb9fea505370683dab18d28b1ea6ed 100644
--- a/src/routes/player/video/Track.tsx
+++ b/src/routes/player/video/Track.tsx
@@ -1,15 +1,16 @@
 import {forwardRef, Fragment, HTMLProps} from "react";
 import {createPortal} from "react-dom";
-import {useVideo} from "./VideoContext";
+import {usePlayerApi} from "./VideoContext";
 
 export const Track = forwardRef<HTMLTrackElement, HTMLProps<HTMLTrackElement>>(function (
     props, ref
 ) {
-    const video = useVideo();
-    if (video) {
+    const playerApi = usePlayerApi();
+    const videoElement = playerApi?.getVideoElement();
+    if (videoElement) {
         return createPortal(
             <track ref={ref} {...props} />,
-            video
+            videoElement
         );
     } else {
         return <Fragment/>;
diff --git a/src/routes/player/video/VideoContext.tsx b/src/routes/player/video/VideoContext.tsx
index af8de15228071a4ea8f34b4961cc5ce04f385e19..1d11ed07236b801187758b2612223dea6bf1576c 100644
--- a/src/routes/player/video/VideoContext.tsx
+++ b/src/routes/player/video/VideoContext.tsx
@@ -1,5 +1,6 @@
 import {createContext, useContext} from "react";
+import {PlayerApi} from "./PlayerApi";
 
-const videoContext = createContext<HTMLVideoElement | null>(null);
-export const VideoProvider = videoContext.Provider;
-export const useVideo = () => useContext<HTMLVideoElement | null>(videoContext);
+const playerContext = createContext<PlayerApi | null>(null);
+export const PlayerProvider = playerContext.Provider;
+export const usePlayerApi = () => useContext<PlayerApi | null>(playerContext);