about summary refs log tree commit diff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/hooks/usePermissions.ts29
-rw-r--r--src/lib/hooks/usePermissions.web.ts8
-rw-r--r--src/lib/media/video/compress.ts30
-rw-r--r--src/lib/media/video/compress.web.ts28
-rw-r--r--src/lib/media/video/errors.ts6
-rw-r--r--src/lib/statsig/gates.ts1
6 files changed, 102 insertions, 0 deletions
diff --git a/src/lib/hooks/usePermissions.ts b/src/lib/hooks/usePermissions.ts
index 9f1f8fb6f..d248e1975 100644
--- a/src/lib/hooks/usePermissions.ts
+++ b/src/lib/hooks/usePermissions.ts
@@ -48,6 +48,35 @@ export function usePhotoLibraryPermission() {
   return {requestPhotoAccessIfNeeded}
 }
 
+export function useVideoLibraryPermission() {
+  const [res, requestPermission] = MediaLibrary.usePermissions({
+    granularPermissions: ['video'],
+  })
+  const requestVideoAccessIfNeeded = async () => {
+    // On the, we use <input type="file"> to produce a filepicker
+    // This does not need any permission granting.
+    if (isWeb) {
+      return true
+    }
+
+    if (res?.granted) {
+      return true
+    } else if (!res || res.status === 'undetermined' || res?.canAskAgain) {
+      const {canAskAgain, granted, status} = await requestPermission()
+
+      if (!canAskAgain && status === 'undetermined') {
+        openPermissionAlert('video library')
+      }
+
+      return granted
+    } else {
+      openPermissionAlert('video library')
+      return false
+    }
+  }
+  return {requestVideoAccessIfNeeded}
+}
+
 export function useCameraPermission() {
   const [res, requestPermission] = Camera.useCameraPermissions()
 
diff --git a/src/lib/hooks/usePermissions.web.ts b/src/lib/hooks/usePermissions.web.ts
index c550a7d6d..b65bbc414 100644
--- a/src/lib/hooks/usePermissions.web.ts
+++ b/src/lib/hooks/usePermissions.web.ts
@@ -14,3 +14,11 @@ export function useCameraPermission() {
 
   return {requestCameraAccessIfNeeded}
 }
+
+export function useVideoLibraryPermission() {
+  const requestVideoAccessIfNeeded = async () => {
+    return true
+  }
+
+  return {requestVideoAccessIfNeeded}
+}
diff --git a/src/lib/media/video/compress.ts b/src/lib/media/video/compress.ts
new file mode 100644
index 000000000..60e5e94a0
--- /dev/null
+++ b/src/lib/media/video/compress.ts
@@ -0,0 +1,30 @@
+import {getVideoMetaData, Video} from 'react-native-compressor'
+
+export type CompressedVideo = {
+  uri: string
+  size: number
+}
+
+export async function compressVideo(
+  file: string,
+  opts?: {
+    getCancellationId?: (id: string) => void
+    onProgress?: (progress: number) => void
+  },
+): Promise<CompressedVideo> {
+  const {onProgress, getCancellationId} = opts || {}
+
+  const compressed = await Video.compress(
+    file,
+    {
+      getCancellationId,
+      compressionMethod: 'manual',
+      bitrate: 3_000_000, // 3mbps
+      maxSize: 1920,
+    },
+    onProgress,
+  )
+
+  const info = await getVideoMetaData(compressed)
+  return {uri: compressed, size: info.size}
+}
diff --git a/src/lib/media/video/compress.web.ts b/src/lib/media/video/compress.web.ts
new file mode 100644
index 000000000..968f2b157
--- /dev/null
+++ b/src/lib/media/video/compress.web.ts
@@ -0,0 +1,28 @@
+import {VideoTooLargeError} from 'lib/media/video/errors'
+
+const MAX_VIDEO_SIZE = 1024 * 1024 * 100 // 100MB
+
+export type CompressedVideo = {
+  uri: string
+  size: number
+}
+
+// doesn't actually compress, but throws if >100MB
+export async function compressVideo(
+  file: string,
+  _callbacks?: {
+    onProgress: (progress: number) => void
+  },
+): Promise<CompressedVideo> {
+  const blob = await fetch(file).then(res => res.blob())
+  const video = URL.createObjectURL(blob)
+
+  if (blob.size > MAX_VIDEO_SIZE) {
+    throw new VideoTooLargeError()
+  }
+
+  return {
+    size: blob.size,
+    uri: video,
+  }
+}
diff --git a/src/lib/media/video/errors.ts b/src/lib/media/video/errors.ts
new file mode 100644
index 000000000..701a7e235
--- /dev/null
+++ b/src/lib/media/video/errors.ts
@@ -0,0 +1,6 @@
+export class VideoTooLargeError extends Error {
+  constructor() {
+    super('Videos cannot be larger than 100MB')
+    this.name = 'VideoTooLargeError'
+  }
+}
diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts
index 6a4081185..378b27349 100644
--- a/src/lib/statsig/gates.ts
+++ b/src/lib/statsig/gates.ts
@@ -11,3 +11,4 @@ export type Gate =
   | 'suggested_feeds_interstitial'
   | 'suggested_follows_interstitial'
   | 'ungroup_follow_backs'
+  | 'videos'