From 27eacaad9f060c52198e4d41960af8d171134017 Mon Sep 17 00:00:00 2001 From: Reinaldo Neto Date: Mon, 15 May 2023 14:16:08 -0300 Subject: [PATCH] refactor audioFile to handleMediaDownload and fixed the audio download --- app/containers/message/Audio.tsx | 20 ++++-- app/definitions/IAttachment.ts | 1 + app/lib/methods/audioFile.ts | 65 ------------------ app/lib/methods/handleMediaDownload.ts | 95 ++++++++++++++++++++++++++ app/views/SettingsView/index.tsx | 4 +- 5 files changed, 112 insertions(+), 73 deletions(-) delete mode 100644 app/lib/methods/audioFile.ts create mode 100644 app/lib/methods/handleMediaDownload.ts diff --git a/app/containers/message/Audio.tsx b/app/containers/message/Audio.tsx index a93f6e394..a6355649a 100644 --- a/app/containers/message/Audio.tsx +++ b/app/containers/message/Audio.tsx @@ -19,7 +19,7 @@ import { withDimensions } from '../../dimensions'; import { TGetCustomEmoji } from '../../definitions/IEmoji'; import { IAttachment, IUserMessage } from '../../definitions'; import { TSupportedThemes } from '../../theme'; -import { downloadAudioFile, searchAudioFileAsync } from '../../lib/methods/audioFile'; +import { MediaTypes, downloadMediaFile, searchMediaFileAsync } from '../../lib/methods/handleMediaDownload'; import EventEmitter from '../../lib/methods/helpers/events'; import { PAUSE_AUDIO } from './constants'; import { isAutoDownloadEnabled } from './helpers/mediaDownload/autoDownloadPreference'; @@ -161,12 +161,16 @@ class MessageAudio extends React.Component { - const { messageId, author } = this.props; + const { messageId, author, file } = this.props; const { user } = this.context; const url = this.getUrl(); try { if (url) { - const fileSearch = await searchAudioFileAsync(url, messageId); + const fileSearch = await searchMediaFileAsync({ + type: MediaTypes.audio, + mimeType: file.audio_type, + messageId + }); if (fileSearch?.file?.exists) { await this.sound.loadAsync({ uri: fileSearch.file.uri }); return this.setState({ loading: false }); @@ -277,15 +281,19 @@ class MessageAudio extends React.Component { - const { messageId } = this.props; + const { messageId, file } = this.props; const { user } = this.context; this.setState({ loading: true }); const url = this.getUrl(); if (url) { - const fileSearch = await searchAudioFileAsync(url, messageId); - const audio = await downloadAudioFile(`${url}?rc_uid=${user.id}&rc_token=${user.token}`, fileSearch.filePath); + const fileSearch = await searchMediaFileAsync({ + type: MediaTypes.audio, + mimeType: file.audio_type, + messageId + }); + const audio = await downloadMediaFile(`${url}?rc_uid=${user.id}&rc_token=${user.token}`, fileSearch.filePath); await this.sound.loadAsync({ uri: audio }); return this.setState({ loading: false, toDownload: false }); } diff --git a/app/definitions/IAttachment.ts b/app/definitions/IAttachment.ts index 3e4d38850..9e7cca2fb 100644 --- a/app/definitions/IAttachment.ts +++ b/app/definitions/IAttachment.ts @@ -28,6 +28,7 @@ export interface IAttachment { color?: string; thumb_url?: string; collapsed?: boolean; + audio_type?: string; } export interface IServerAttachment { diff --git a/app/lib/methods/audioFile.ts b/app/lib/methods/audioFile.ts deleted file mode 100644 index 21abb17df..000000000 --- a/app/lib/methods/audioFile.ts +++ /dev/null @@ -1,65 +0,0 @@ -import * as FileSystem from 'expo-file-system'; - -import { sanitizeLikeString } from '../database/utils'; -import { store } from '../store/auxStore'; -import log from './helpers/log'; - -const DEFAULT_EXTENSION = 'mp3'; - -const sanitizeString = (value: string) => sanitizeLikeString(value.substring(value.lastIndexOf('/') + 1)); - -const getExtension = (value: string) => { - let extension = DEFAULT_EXTENSION; - const filename = value.split('/').pop(); - if (filename?.includes('.')) { - extension = value.substring(value.lastIndexOf('.') + 1); - } - return extension; -}; - -const ensureDirAsync = async (dir: string, intermediates = true): Promise => { - const info = await FileSystem.getInfoAsync(dir); - if (info.exists && info.isDirectory) { - return; - } - await FileSystem.makeDirectoryAsync(dir, { intermediates }); - return ensureDirAsync(dir, intermediates); -}; - -export const searchAudioFileAsync = async (fileUrl: string, messageId: string) => { - let file; - let filePath = ''; - try { - const serverUrl = store.getState().server.server; - const serverUrlParsed = sanitizeString(serverUrl); - const folderPath = `${FileSystem.documentDirectory}audios/${serverUrlParsed}`; - const filename = `${messageId}.${getExtension(fileUrl)}`; - filePath = `${folderPath}/${filename}`; - await ensureDirAsync(folderPath); - file = await FileSystem.getInfoAsync(filePath); - } catch (e) { - log(e); - } - return { file, filePath }; -}; - -export const downloadAudioFile = async (url: string, filePath: string) => { - let uri = ''; - try { - const downloadedFile = await FileSystem.downloadAsync(url, filePath); - uri = downloadedFile.uri; - } catch (error) { - log(error); - } - return uri; -}; - -export const deleteAllAudioFiles = async (serverUrl: string): Promise => { - try { - const serverUrlParsed = sanitizeString(serverUrl); - const path = `${FileSystem.documentDirectory}audios/${serverUrlParsed}`; - await FileSystem.deleteAsync(path, { idempotent: true }); - } catch (error) { - log(error); - } -}; diff --git a/app/lib/methods/handleMediaDownload.ts b/app/lib/methods/handleMediaDownload.ts new file mode 100644 index 000000000..f359eee5e --- /dev/null +++ b/app/lib/methods/handleMediaDownload.ts @@ -0,0 +1,95 @@ +import * as FileSystem from 'expo-file-system'; +import * as mime from 'react-native-mime-types'; + +import { sanitizeLikeString } from '../database/utils'; +import { store } from '../store/auxStore'; +import log from './helpers/log'; + +export enum MediaTypes { + audio = 'audio', + image = 'image', + video = 'video' +} +const typeString = { + [MediaTypes.audio]: 'audios/', + [MediaTypes.image]: 'images/', + [MediaTypes.video]: 'videos/' +}; + +const defaultType = { + [MediaTypes.audio]: 'mp3', + [MediaTypes.image]: 'jpg', + [MediaTypes.video]: 'mp4' +}; + +const sanitizeString = (value: string) => sanitizeLikeString(value.substring(value.lastIndexOf('/') + 1)); + +const getExtension = (type: MediaTypes, mimeType?: string) => { + if (!mimeType) { + return defaultType[type]; + } + // The library is returning mpag instead of mp3 for audio/mpeg + const extensionFromMime = mimeType === 'audio/mpeg' ? 'mp3' : mime.extension(mimeType); + return extensionFromMime; +}; + +const ensureDirAsync = async (dir: string, intermediates = true): Promise => { + const info = await FileSystem.getInfoAsync(dir); + if (info.exists && info.isDirectory) { + return; + } + await FileSystem.makeDirectoryAsync(dir, { intermediates }); + return ensureDirAsync(dir, intermediates); +}; + +export const searchMediaFileAsync = async ({ + type, + mimeType, + messageId +}: { + type: MediaTypes; + mimeType?: string; + messageId: string; +}) => { + let file; + let filePath = ''; + + try { + const serverUrl = store.getState().server.server; + const serverUrlParsed = sanitizeString(serverUrl); + const folderPath = `${FileSystem.documentDirectory}${typeString[type]}${serverUrlParsed}`; + const filename = `${messageId}.${getExtension(type, mimeType)}`; + filePath = `${folderPath}/${filename}`; + await ensureDirAsync(folderPath); + file = await FileSystem.getInfoAsync(filePath); + } catch (e) { + log(e); + } + return { file, filePath }; +}; + +export const downloadMediaFile = async (url: string, filePath: string, downloadResumable?: FileSystem.DownloadResumable) => { + let uri = ''; + try { + if (downloadResumable) { + const downloadFile = await downloadResumable.downloadAsync(); + uri = downloadFile?.uri || ''; + } else { + const downloadedFile = await FileSystem.downloadAsync(url, filePath); + uri = downloadedFile.uri; + } + } catch (error) { + log(error); + } + return uri; +}; + +export const deleteAllSpecificMediaFiles = async (type: MediaTypes, serverUrl: string): Promise => { + try { + const serverUrlParsed = sanitizeString(serverUrl); + const path = `${FileSystem.documentDirectory}${typeString[type]}${serverUrlParsed}`; + await FileSystem.deleteAsync(path, { idempotent: true }); + } catch (error) { + log(error); + } +}; diff --git a/app/views/SettingsView/index.tsx b/app/views/SettingsView/index.tsx index 4d30e0fbb..d39bdcf30 100644 --- a/app/views/SettingsView/index.tsx +++ b/app/views/SettingsView/index.tsx @@ -21,7 +21,7 @@ import { APP_STORE_LINK, FDROID_MARKET_LINK, isFDroidBuild, LICENSE_LINK, PLAY_M import database from '../../lib/database'; import { useAppSelector } from '../../lib/hooks'; import { clearCache } from '../../lib/methods'; -import { deleteAllAudioFiles } from '../../lib/methods/audioFile'; +import { deleteAllSpecificMediaFiles, MediaTypes } from '../../lib/methods/handleMediaDownload'; import { getDeviceModel, getReadableVersion, isAndroid } from '../../lib/methods/helpers'; import EventEmitter from '../../lib/methods/helpers/events'; import { showConfirmationAlert, showErrorAlert } from '../../lib/methods/helpers/info'; @@ -99,7 +99,7 @@ const SettingsView = (): React.ReactElement => { confirmationText: I18n.t('Clear'), onPress: async () => { dispatch(appStart({ root: RootEnum.ROOT_LOADING, text: I18n.t('Clear_cache_loading') })); - await deleteAllAudioFiles(server); + await deleteAllSpecificMediaFiles(MediaTypes.audio, server); await clearCache({ server }); await FastImage.clearMemoryCache(); await FastImage.clearDiskCache();