diff --git a/src/routes/player/PreviewViewer.tsx b/src/routes/player/PreviewViewer.tsx
index fdca963f27e32be1e7dee91502e77e7e91bcb4ca..3ba98292639a73a600964c19443fd6988c07217f 100644
--- a/src/routes/player/PreviewViewer.tsx
+++ b/src/routes/player/PreviewViewer.tsx
@@ -1,7 +1,7 @@
 import React, {useMemo} from "react";
+import {useImage} from "../../util/media/useImage";
 import {useTextTrackCues} from "../../util/media/useTextTrackCues";
 import {parseImageSprite} from "../../util/sprite/parseImageSprite";
-import {useImage} from "../../util/media/useImage";
 import {useImageSprite} from "../../util/sprite/useImageSprite";
 
 interface Props {
@@ -14,10 +14,9 @@ export function PreviewViewer({previewTrack, position}: Props) {
     const activeCue = cues.find(it => it.startTime <= position && it.endTime >= position)
     const activeUrl = activeCue ? new URL(activeCue.text, previewTrack.src).toString() : null;
     const imageSprite = useMemo(() => parseImageSprite(activeUrl), [activeUrl]);
-    console.log("active", activeUrl, imageSprite);
     const image = useImage(imageSprite?.src || null);
     const sprite = useImageSprite(imageSprite, image);
     return useMemo(() => (
-        <img src={sprite || undefined}/>
+        <img alt="" src={sprite || undefined}/>
     ), [sprite]);
 }
diff --git a/src/routes/player/SeekBar.tsx b/src/routes/player/SeekBar.tsx
index 792c0ff120f7d3a32288667256e2fab45ff4cf2b..3a38e70d72ee720f5a9887238403108973dadfd3 100644
--- a/src/routes/player/SeekBar.tsx
+++ b/src/routes/player/SeekBar.tsx
@@ -13,9 +13,10 @@ interface MousePosition {
     relative: number
 }
 
-function getMousePosition(event: React.MouseEvent<HTMLDivElement>): MousePosition {
+function getMousePosition(event: React.MouseEvent<HTMLDivElement>): MousePosition | null {
     const position = event.clientX - event.currentTarget.offsetLeft;
     const width = event.currentTarget.offsetWidth;
+    if (position > width) return null;
     return {
         absolute: position,
         relative: position / width
@@ -35,12 +36,18 @@ export function SeekBar({video, previewTrack, duration}: Props) {
             onMouseLeave={() => setSeekPosition(null)}
             onClick={(event) => {
                 const position = getMousePosition(event);
+                if (position === null) {
+                    return;
+                }
                 if (video) {
                     video.currentTime = position.relative * duration;
                 }
             }}
             onMouseMove={(event) => {
                 const position = getMousePosition(event);
+                if (position === null) {
+                    return;
+                }
                 if (seekHeadRef.current) {
                     seekHeadRef.current.style.transform = `translate3d(${position.absolute}px, 0, 0)`
                 }
@@ -57,7 +64,7 @@ export function SeekBar({video, previewTrack, duration}: Props) {
                 }}
             />
         </div>
-    ), [classes.seekBar, classes.seekHead, duration, isVisible]);
+    ), [classes.seekBar, classes.seekHead, duration, isVisible, video]);
 
     return (
         <div>
@@ -80,7 +87,7 @@ const useStyles = createUseStyles({
         position: "absolute",
         top: 0,
         bottom: 0,
-        left: 0,
+        left: "-0.05rem",
         width: "0.1rem",
         background: "#f00",
     }
diff --git a/src/util/media/useImage.ts b/src/util/media/useImage.ts
index 7ec2d7e72f054410617a2a0df1ce53ca23ba1841..4ac4010a68fd4df8ce43c7d52a0837d8ef12bb37 100644
--- a/src/util/media/useImage.ts
+++ b/src/util/media/useImage.ts
@@ -1,18 +1,30 @@
-import {useEffect, useRef, useState} from "react";
+import {useEffect, useMemo, useState} from "react";
 
 export const useImage = (url: string | null): HTMLImageElement | null => {
-    const image = useRef(new Image())
-    image.current.setAttribute("crossorigin", "anonymous");
     const [imageData, setImageData] = useState<HTMLImageElement | null>(null);
-    useEffect(() => {
-        try {
-            image.current.src = url || "";
-            image.current.decode().then(() => {
-                setImageData(image.current);
-            })
-        } catch (_) {
+    const image = useMemo(() => {
+        if (url === null) {
+            return null;
+        } else {
+            const image = new Image();
+            image.setAttribute("crossorigin", "anonymous");
+            image.src = url;
+            return image;
         }
     }, [url]);
+    useEffect(() => {
+        let isCancelled = false;
+        image?.decode().then(() => {
+            if (!isCancelled) {
+                setImageData(image);
+            }
+        }).catch(err => {
+            console.error("Error while decoding image " + url + ": ", err);
+        });
+        return () => {
+            isCancelled = true;
+        }
+    }, [image, url]);
 
     return imageData;
 }
diff --git a/src/util/media/usePosition.ts b/src/util/media/usePosition.ts
index 770ea75bbbc42644f2927e9c15eca2825ff5d2c8..fb1b390d09dfce0efbec4d7443405a745aaaa559 100644
--- a/src/util/media/usePosition.ts
+++ b/src/util/media/usePosition.ts
@@ -9,9 +9,9 @@ export const usePosition = (video: HTMLVideoElement | null) => {
                     setPosition(video.currentTime);
                 })
             };
-            video.addEventListener("progress", listener)
+            video.addEventListener("timeupdate", listener)
             return () => {
-                video.removeEventListener("progress", listener)
+                video.removeEventListener("timeupdate", listener)
             }
         }
     }, [video]);
diff --git a/src/util/media/useTextTrackCues.ts b/src/util/media/useTextTrackCues.ts
index 136cab655cf2ed2fd0b3680650b55d3c06ebb2b7..1309d104f1ba5fafef51cbf46d4ae2f0d6aa4922 100644
--- a/src/util/media/useTextTrackCues.ts
+++ b/src/util/media/useTextTrackCues.ts
@@ -7,14 +7,18 @@ export const useTextTrackCues = (track: HTMLTrackElement) => {
         if (track.readyState >= 1) {
             setCues(Array.from(track.track.cues || []))
         } else {
+            let animationFrame: number | null = null;
             const listener = () => {
-                window.requestAnimationFrame(() => {
+                animationFrame = window.requestAnimationFrame(() => {
                     setCues(Array.from(track.track.cues || []))
                 })
             };
             track.addEventListener("load", listener)
             return () => {
-                track.removeEventListener("load", listener)
+                track.removeEventListener("load", listener);
+                if (animationFrame) {
+                    window.cancelAnimationFrame(animationFrame);
+                }
             }
         }
     }, [track]);