diff --git a/src/backend/index.ts b/src/backend/index.ts
index 5e4f7989..bb752003 100644
--- a/src/backend/index.ts
+++ b/src/backend/index.ts
@@ -4,6 +4,7 @@ import { initializeScraperStore } from "./helpers/register";
 import "./providers/gdriveplayer";
 import "./providers/flixhq";
 import "./providers/superstream";
+import "./providers/netfilm";
 
 // embeds
 // -- nothing here yet
diff --git a/src/backend/providers/netfilm.ts b/src/backend/providers/netfilm.ts
new file mode 100644
index 00000000..6d773974
--- /dev/null
+++ b/src/backend/providers/netfilm.ts
@@ -0,0 +1,120 @@
+import { proxiedFetch } from "../helpers/fetch";
+import { registerProvider } from "../helpers/register";
+import { MWStreamType } from "../helpers/streams";
+import { MWMediaType } from "../metadata/types";
+
+const netfilmBase = "https://net-film.vercel.app";
+
+registerProvider({
+  id: "netfilm",
+  displayName: "NetFilm",
+  rank: 999,
+  type: [MWMediaType.MOVIE, MWMediaType.SERIES],
+
+  async scrape({ media, episode, progress }) {
+    // // search for relevant item
+    const searchResponse = await proxiedFetch<any>(
+      `/api/search?keyword=${encodeURIComponent(media.meta.title)}`,
+      {
+        baseURL: netfilmBase,
+      }
+    );
+
+    const searchResults = searchResponse.data.results;
+    progress(25);
+
+    if (media.meta.type === MWMediaType.MOVIE) {
+      const foundItem = searchResults.find((v: any) => {
+        return v.name === media.meta.title && v.releaseTime === media.meta.year;
+      });
+      if (!foundItem) throw new Error("No watchable item found");
+      const netfilmId = foundItem.id;
+
+      // get stream info from media
+      progress(75);
+      const watchInfo = await proxiedFetch<any>(
+        `/api/episode?id=${netfilmId}`,
+        {
+          baseURL: netfilmBase,
+        }
+      );
+
+      const { qualities } = watchInfo.data;
+
+      // get best quality source
+      const source = qualities.reduce((p: any, c: any) =>
+        c.quality > p.quality ? c : p
+      );
+
+      return {
+        embeds: [],
+        stream: {
+          streamUrl: source.url,
+          quality: source.quality,
+          type: MWStreamType.HLS,
+          // captions: [],
+        },
+      };
+    }
+
+    if (media.meta.type !== MWMediaType.SERIES)
+      throw new Error("Unsupported type");
+
+    const desiredSeason = media.meta.seasonData.number;
+
+    const searchItems = searchResults
+      .filter((v: any) => {
+        return v.name.includes(media.meta.title);
+      })
+      .map((v: any) => {
+        return {
+          ...v,
+          season: parseInt(v.name.split(" ").at(-1), 10),
+        };
+      });
+
+    const foundItem = searchItems.find((v: any) => {
+      return v.season === desiredSeason;
+    });
+
+    progress(50);
+    const seasonDetail = await proxiedFetch<any>(
+      `/api/detail?id=${foundItem.id}&category=${foundItem.categoryTag[0].id}`,
+      {
+        baseURL: netfilmBase,
+      }
+    );
+
+    const episodeNo = media.meta.seasonData.episodes.find(
+      (v: any) => v.id === episode
+    )?.number;
+    const episodeData = seasonDetail.data.episodeVo.find(
+      (v: any) => v.seriesNo === episodeNo
+    );
+
+    progress(75);
+    const episodeStream = await proxiedFetch<any>(
+      `/api/episode?id=${foundItem.id}&category=1&episode=${episodeData.id}`,
+      {
+        baseURL: netfilmBase,
+      }
+    );
+
+    const { qualities } = episodeStream.data;
+
+    // get best quality source
+    const source = qualities.reduce((p: any, c: any) =>
+      c.quality > p.quality ? c : p
+    );
+
+    return {
+      embeds: [],
+      stream: {
+        streamUrl: source.url,
+        quality: source.quality,
+        type: MWStreamType.HLS,
+        // captions: [],
+      },
+    };
+  },
+});
diff --git a/src/components/video/hooks/controlVideo.ts b/src/components/video/hooks/controlVideo.ts
index 7a34543c..a8552b0b 100644
--- a/src/components/video/hooks/controlVideo.ts
+++ b/src/components/video/hooks/controlVideo.ts
@@ -178,7 +178,7 @@ export function populateControls(
             return;
           }
 
-          const hls = new Hls();
+          const hls = new Hls({ enableWorker: false });
 
           hls.on(Hls.Events.ERROR, (event, data) => {
             if (data.fatal) {