about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Navigation.tsx6
-rw-r--r--src/components/VideoDownloadScreen.native.tsx4
-rw-r--r--src/components/VideoDownloadScreen.tsx215
-rw-r--r--src/lib/routes/types.ts1
-rw-r--r--src/routes.ts1
-rw-r--r--src/view/screens/Storybook/index.tsx46
6 files changed, 1 insertions, 272 deletions
diff --git a/src/Navigation.tsx b/src/Navigation.tsx
index 0d151427f..79856879c 100644
--- a/src/Navigation.tsx
+++ b/src/Navigation.tsx
@@ -50,7 +50,6 @@ import {
   StarterPackScreenShort,
 } from '#/screens/StarterPack/StarterPackScreen'
 import {Wizard} from '#/screens/StarterPack/Wizard'
-import {VideoDownloadScreen} from '#/components/VideoDownloadScreen'
 import {Referrer} from '../modules/expo-bluesky-swiss-army'
 import {init as initAnalytics} from './lib/analytics/analytics'
 import {useWebScrollRestoration} from './lib/hooks/useWebScrollRestoration'
@@ -365,11 +364,6 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
         getComponent={() => Wizard}
         options={{title: title(msg`Edit your starter pack`), requireAuth: true}}
       />
-      <Stack.Screen
-        name="VideoDownload"
-        getComponent={() => VideoDownloadScreen}
-        options={{title: title(msg`Download video`)}}
-      />
     </>
   )
 }
diff --git a/src/components/VideoDownloadScreen.native.tsx b/src/components/VideoDownloadScreen.native.tsx
deleted file mode 100644
index a1f6466fd..000000000
--- a/src/components/VideoDownloadScreen.native.tsx
+++ /dev/null
@@ -1,4 +0,0 @@
-export function VideoDownloadScreen() {
-  // @TODO redirect
-  return null
-}
diff --git a/src/components/VideoDownloadScreen.tsx b/src/components/VideoDownloadScreen.tsx
deleted file mode 100644
index 3169d265d..000000000
--- a/src/components/VideoDownloadScreen.tsx
+++ /dev/null
@@ -1,215 +0,0 @@
-import React from 'react'
-import {parse} from 'hls-parser'
-import {MasterPlaylist, MediaPlaylist, Variant} from 'hls-parser/types'
-
-interface PostMessageData {
-  action: 'progress' | 'error'
-  messageStr?: string
-  messageFloat?: number
-}
-
-function postMessage(data: PostMessageData) {
-  // @ts-expect-error safari webview only
-  if (window?.webkit) {
-    // @ts-expect-error safari webview only
-    window.webkit.messageHandlers.onMessage.postMessage(JSON.stringify(data))
-    // @ts-expect-error android webview only
-  } else if (AndroidInterface) {
-    // @ts-expect-error android webview only
-    AndroidInterface.onMessage(JSON.stringify(data))
-  }
-}
-
-function createSegementUrl(originalUrl: string, newFile: string) {
-  const parts = originalUrl.split('/')
-  parts[parts.length - 1] = newFile
-  return parts.join('/')
-}
-
-export function VideoDownloadScreen() {
-  const ffmpegRef = React.useRef<any>(null)
-  const fetchFileRef = React.useRef<any>(null)
-
-  const [dataUrl, setDataUrl] = React.useState<any>(null)
-
-  const load = React.useCallback(async () => {
-    const ffmpegLib = await import('@ffmpeg/ffmpeg')
-    const ffmpeg = new ffmpegLib.FFmpeg()
-    ffmpegRef.current = ffmpeg
-
-    const ffmpegUtilLib = await import('@ffmpeg/util')
-    fetchFileRef.current = ffmpegUtilLib.fetchFile
-
-    const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm'
-
-    await ffmpeg.load({
-      coreURL: await ffmpegUtilLib.toBlobURL(
-        `${baseURL}/ffmpeg-core.js`,
-        'text/javascript',
-      ),
-      wasmURL: await ffmpegUtilLib.toBlobURL(
-        `${baseURL}/ffmpeg-core.wasm`,
-        'application/wasm',
-      ),
-    })
-  }, [])
-
-  const createMp4 = React.useCallback(async (videoUrl: string) => {
-    // Get the master playlist and find the best variant
-    const masterPlaylistRes = await fetch(videoUrl)
-    const masterPlaylistText = await masterPlaylistRes.text()
-    const masterPlaylist = parse(masterPlaylistText) as MasterPlaylist
-
-    // If URL given is not a master playlist, we probably cannot handle this.
-    if (!masterPlaylist.isMasterPlaylist) {
-      postMessage({
-        action: 'error',
-        messageStr: 'A master playlist was not found in the provided playlist.',
-      })
-      return
-    }
-
-    // Figure out what the best quality is. These should generally be in order, but we'll check them all just in case
-    let bestVariant: Variant | undefined
-    for (const variant of masterPlaylist.variants) {
-      if (!bestVariant || variant.bandwidth > bestVariant.bandwidth) {
-        bestVariant = variant
-      }
-    }
-
-    // Should only happen if there was no variants at all given to us. Mostly for types.
-    if (!bestVariant) {
-      postMessage({
-        action: 'error',
-        messageStr: 'No variants were found in the provided master playlist.',
-      })
-      return
-    }
-
-    const urlParts = videoUrl.split('/')
-    urlParts[urlParts.length - 1] = bestVariant?.uri
-    const bestVariantUrl = urlParts.join('/')
-
-    // Download and parse m3u8
-    const hlsFileRes = await fetch(bestVariantUrl)
-    const hlsPlainText = await hlsFileRes.text()
-    const playlist = parse(hlsPlainText) as MediaPlaylist
-
-    // This one shouldn't be a master playlist - again just for types really
-    if (playlist.isMasterPlaylist) {
-      postMessage({
-        action: 'error',
-        messageStr: 'An unknown error has occurred.',
-      })
-      return
-    }
-
-    const ffmpeg = ffmpegRef.current
-
-    // Get the correctly ordered file names. We need to remove the tracking info from the end of the file name
-    const segments = playlist.segments.map(segment => {
-      return segment.uri.split('?')[0]
-    })
-
-    // Download each segment
-    let error: string | null = null
-    let completed = 0
-    await Promise.all(
-      playlist.segments.map(async segment => {
-        const uri = createSegementUrl(bestVariantUrl, segment.uri)
-        const filename = segment.uri.split('?')[0]
-
-        const res = await fetch(uri)
-        if (!res.ok) {
-          error = 'Failed to download playlist segment.'
-        }
-
-        const blob = await res.blob()
-        try {
-          await ffmpeg.writeFile(filename, await fetchFileRef.current(blob))
-        } catch (e: unknown) {
-          error = 'Failed to write file.'
-        } finally {
-          completed++
-          const progress = completed / playlist.segments.length
-          postMessage({
-            action: 'progress',
-            messageFloat: progress,
-          })
-        }
-      }),
-    )
-
-    // Do something if there was an error
-    if (error) {
-      postMessage({
-        action: 'error',
-        messageStr: error,
-      })
-      return
-    }
-
-    // Put the segments together
-    await ffmpeg.exec([
-      '-i',
-      `concat:${segments.join('|')}`,
-      '-c:v',
-      'copy',
-      'output.mp4',
-    ])
-
-    const fileData = await ffmpeg.readFile('output.mp4')
-    const blob = new Blob([fileData.buffer], {type: 'video/mp4'})
-    const dataUrl = await new Promise<string | null>(resolve => {
-      const reader = new FileReader()
-      reader.onloadend = () => resolve(reader.result as string)
-      reader.onerror = () => resolve(null)
-      reader.readAsDataURL(blob)
-    })
-    return dataUrl
-  }, [])
-
-  const download = React.useCallback(
-    async (videoUrl: string) => {
-      await load()
-      const mp4Res = await createMp4(videoUrl)
-
-      if (!mp4Res) {
-        postMessage({
-          action: 'error',
-          messageStr: 'An error occurred while creating the MP4.',
-        })
-        return
-      }
-
-      setDataUrl(mp4Res)
-    },
-    [createMp4, load],
-  )
-
-  React.useEffect(() => {
-    const url = new URL(window.location.href)
-    const videoUrl = url.searchParams.get('videoUrl')
-
-    if (!videoUrl) {
-      postMessage({action: 'error', messageStr: 'No video URL provided'})
-    } else {
-      setDataUrl(null)
-      download(videoUrl)
-    }
-  }, [download])
-
-  if (!dataUrl) return null
-
-  return (
-    <div>
-      <a
-        href={dataUrl}
-        ref={el => {
-          el?.click()
-        }}
-        download="video.mp4"
-      />
-    </div>
-  )
-}
diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts
index 77e7266a4..0cc83b475 100644
--- a/src/lib/routes/types.ts
+++ b/src/lib/routes/types.ts
@@ -50,7 +50,6 @@ export type CommonNavigatorParams = {
   StarterPackShort: {code: string}
   StarterPackWizard: undefined
   StarterPackEdit: {rkey?: string}
-  VideoDownload: undefined
 }
 
 export type BottomTabNavigatorParams = CommonNavigatorParams & {
diff --git a/src/routes.ts b/src/routes.ts
index bda2d98e4..c9e23e08c 100644
--- a/src/routes.ts
+++ b/src/routes.ts
@@ -48,5 +48,4 @@ export const router = new Router({
   StarterPack: '/starter-pack/:name/:rkey',
   StarterPackShort: '/starter-pack-short/:code',
   StarterPackWizard: '/starter-pack/create',
-  VideoDownload: '/video-download',
 })
diff --git a/src/view/screens/Storybook/index.tsx b/src/view/screens/Storybook/index.tsx
index c6da63314..71dbe8839 100644
--- a/src/view/screens/Storybook/index.tsx
+++ b/src/view/screens/Storybook/index.tsx
@@ -1,17 +1,12 @@
 import React from 'react'
 import {ScrollView, View} from 'react-native'
-import {deleteAsync} from 'expo-file-system'
-import {saveToLibraryAsync} from 'expo-media-library'
 
 import {useSetThemePrefs} from '#/state/shell'
-import {useVideoLibraryPermission} from 'lib/hooks/usePermissions'
-import {isIOS, isWeb} from 'platform/detection'
+import {isWeb} from 'platform/detection'
 import {CenteredView} from '#/view/com/util/Views'
-import * as Toast from 'view/com/util/Toast'
 import {ListContained} from 'view/screens/Storybook/ListContained'
 import {atoms as a, ThemeProvider, useTheme} from '#/alf'
 import {Button, ButtonText} from '#/components/Button'
-import {HLSDownloadView} from '../../../../modules/expo-bluesky-swiss-army'
 import {Breakpoints} from './Breakpoints'
 import {Buttons} from './Buttons'
 import {Dialogs} from './Dialogs'
@@ -38,49 +33,10 @@ function StorybookInner() {
   const t = useTheme()
   const {setColorMode, setDarkTheme} = useSetThemePrefs()
   const [showContainedList, setShowContainedList] = React.useState(false)
-  const hlsDownloadRef = React.useRef<HLSDownloadView>(null)
-
-  const {requestVideoAccessIfNeeded} = useVideoLibraryPermission()
 
   return (
     <CenteredView style={[t.atoms.bg]}>
       <View style={[a.p_xl, a.gap_5xl, {paddingBottom: 100}]}>
-        <HLSDownloadView
-          ref={hlsDownloadRef}
-          downloaderUrl={
-            isIOS
-              ? 'http://localhost:19006/video-download'
-              : 'http://10.0.2.2:19006/video-download'
-          }
-          onSuccess={async e => {
-            const uri = e.nativeEvent.uri
-            const permsRes = await requestVideoAccessIfNeeded()
-            if (!permsRes) return
-
-            await saveToLibraryAsync(uri)
-            try {
-              deleteAsync(uri)
-            } catch (err) {
-              console.error('Failed to delete file', err)
-            }
-            Toast.show('Video saved to library')
-          }}
-          onStart={() => console.log('Download is starting')}
-          onError={e => console.log(e.nativeEvent.message)}
-          onProgress={e => console.log(e.nativeEvent.progress)}
-        />
-        <Button
-          variant="solid"
-          color="primary"
-          size="small"
-          onPress={async () => {
-            hlsDownloadRef.current?.startDownloadAsync(
-              'https://lumi.jazco.dev/watch/did:plc:q6gjnaw2blty4crticxkmujt/Qmc8w93UpTa2adJHg4ZhnDPrBs1EsbzrekzPcqF5SwusuZ/playlist.m3u8?download=true',
-            )
-          }}
-          label="Video download test">
-          <ButtonText>Video download test</ButtonText>
-        </Button>
         {!showContainedList ? (
           <>
             <View style={[a.flex_row, a.align_start, a.gap_md]}>