From 10efcaddb4bc33644b259bc64e2eb1cc52a21c58 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Tue, 5 Oct 2021 12:23:34 +0530 Subject: [PATCH 01/42] added downloadFile util --- src/components/PhotoSwipe/PhotoSwipe.tsx | 21 +++++---------------- src/utils/file/index.ts | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/components/PhotoSwipe/PhotoSwipe.tsx b/src/components/PhotoSwipe/PhotoSwipe.tsx index acbd5f16e..845d3cc08 100644 --- a/src/components/PhotoSwipe/PhotoSwipe.tsx +++ b/src/components/PhotoSwipe/PhotoSwipe.tsx @@ -7,16 +7,15 @@ import { addToFavorites, removeFromFavorites, } from 'services/collectionService'; -import { File, FILE_TYPE } from 'services/fileService'; +import { File } from 'services/fileService'; import constants from 'utils/strings/constants'; -import DownloadManger from 'services/downloadManager'; import exifr from 'exifr'; import Modal from 'react-bootstrap/Modal'; import Button from 'react-bootstrap/Button'; import Form from 'react-bootstrap/Form'; import styled from 'styled-components'; import events from './events'; -import { fileNameWithoutExtension, formatDateTime } from 'utils/file'; +import { downloadFile, formatDateTime } from 'utils/file'; import { FormCheck } from 'react-bootstrap'; import { prettyPrintExif } from 'utils/exif'; @@ -296,21 +295,11 @@ function PhotoSwipe(props: Iprops) { setShowInfo(true); }; - const downloadFile = async (file) => { + const downloadFileHelper = async (file) => { const { loadingBar } = props; - const a = document.createElement('a'); - a.style.display = 'none'; loadingBar.current.continuousStart(); - a.href = await DownloadManger.getFile(file); + await downloadFile(file); loadingBar.current.complete(); - if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) { - a.download = fileNameWithoutExtension(file.metadata.title) + '.zip'; - } else { - a.download = file.metadata.title; - } - document.body.appendChild(a); - a.click(); - a.remove(); }; const { id } = props; let { className } = props; @@ -344,7 +333,7 @@ function PhotoSwipe(props: Iprops) { className="pswp-custom download-btn" title={constants.DOWNLOAD} onClick={() => - downloadFile(photoSwipe.currItem) + downloadFileHelper(photoSwipe.currItem) } /> diff --git a/src/utils/file/index.ts b/src/utils/file/index.ts index 66f0e3816..154639c32 100644 --- a/src/utils/file/index.ts +++ b/src/utils/file/index.ts @@ -11,6 +11,7 @@ import { import { decodeMotionPhoto } from 'services/motionPhotoService'; import { getMimeTypeFromBlob } from 'services/upload/readFileService'; import { EncryptionResult } from 'services/upload/uploadService'; +import DownloadManger from 'services/downloadManager'; import { logError } from 'utils/sentry'; import { User } from 'services/userService'; import CryptoWorker from 'utils/crypto'; @@ -36,6 +37,20 @@ export function downloadAsFile(filename: string, content: string) { a.remove(); } +export async function downloadFile(file) { + const a = document.createElement('a'); + a.style.display = 'none'; + a.href = await DownloadManger.getFile(file); + if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) { + a.download = fileNameWithoutExtension(file.metadata.title) + '.zip'; + } else { + a.download = file.metadata.title; + } + document.body.appendChild(a); + a.click(); + a.remove(); +} + export function fileIsHEIC(mimeType: string) { return ( mimeType.toLowerCase().endsWith(TYPE_HEIC) || From 9c0dfde01d7051a7e6c0e997f9d5ab60ae1648a0 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Tue, 5 Oct 2021 12:24:21 +0530 Subject: [PATCH 02/42] added better download option for when playback failed --- src/components/PhotoFrame.tsx | 89 +++++++++-------------------------- src/pages/_app.tsx | 23 ++++++++- src/utils/photoFrame/index.ts | 15 ++++++ 3 files changed, 59 insertions(+), 68 deletions(-) create mode 100644 src/utils/photoFrame/index.ts diff --git a/src/components/PhotoFrame.tsx b/src/components/PhotoFrame.tsx index faeae4cff..66dc07f2f 100644 --- a/src/components/PhotoFrame.tsx +++ b/src/components/PhotoFrame.tsx @@ -18,7 +18,6 @@ import { VariableSizeList as List } from 'react-window'; import PhotoSwipe from 'components/PhotoSwipe/PhotoSwipe'; import { isInsideBox, isSameDay as isSameDayAnyYear } from 'utils/search'; import { SetDialogMessage } from './MessageDialog'; -import { CustomError } from 'utils/common/errorUtil'; import { GAP_BTW_TILES, DATE_CONTAINER_HEIGHT, @@ -30,10 +29,10 @@ import { import { fileIsArchived } from 'utils/file'; import { ALL_SECTION, ARCHIVE_SECTION } from './pages/gallery/Collections'; import { isSharedFile } from 'utils/file'; +import { isPlaybackPossible } from 'utils/photoFrame'; const NO_OF_PAGES = 2; const A_DAY = 24 * 60 * 60 * 1000; -const WAIT_FOR_VIDEO_PLAYBACK = 1 * 1000; interface TimeStampListItem { itemType: ITEM_TYPE; @@ -169,7 +168,6 @@ const PhotoFrame = ({ search, setSearchStats, deleted, - setDialogMessage, activeCollection, isSharedCollection, }: Props) => { @@ -225,21 +223,33 @@ const PhotoFrame = ({ setFiles(files); }; - const updateSrcUrl = (index: number, url: string) => { + const updateSrcUrl = async (index: number, url: string) => { files[index] = { ...files[index], - src: url, w: window.innerWidth, h: window.innerHeight, }; if (files[index].metadata.fileType === FILE_TYPE.VIDEO) { - files[index].html = ` + if (await isPlaybackPossible(url)) { + files[index].html = ` `; - delete files[index].src; + } else { + files[index].html = ` +
+ +
+ ${constants.VIDEO_PLAYBACK_FAILED_DOWNLOAD_INSTEAD} + Download +
+
+ `; + } + } else { + files[index].src = url; } setFiles(files); }; @@ -313,66 +323,11 @@ const PhotoFrame = ({ url = await DownloadManager.getFile(item, true); galleryContext.files.set(item.id, url); } - updateSrcUrl(item.dataIndex, url); - if (item.metadata.fileType === FILE_TYPE.VIDEO) { - try { - await new Promise((resolve, reject) => { - const video = document.createElement('video'); - video.addEventListener('timeupdate', function () { - clearTimeout(t); - resolve(null); - }); - video.preload = 'metadata'; - video.src = url; - video.currentTime = 3; - const t = setTimeout(() => { - reject( - Error( - `${CustomError.VIDEO_PLAYBACK_FAILED} err: wait time exceeded` - ) - ); - }, WAIT_FOR_VIDEO_PLAYBACK); - }); - item.html = ` - - `; - delete item.src; - } catch (e) { - const downloadFile = async () => { - const a = document.createElement('a'); - a.style.display = 'none'; - a.href = url; - a.download = item.metadata.title; - document.body.appendChild(a); - a.click(); - a.remove(); - setOpen(false); - }; - setDialogMessage({ - title: constants.VIDEO_PLAYBACK_FAILED, - content: - constants.VIDEO_PLAYBACK_FAILED_DOWNLOAD_INSTEAD, - staticBackdrop: true, - proceed: { - text: constants.DOWNLOAD, - action: downloadFile, - variant: 'success', - }, - close: { - text: constants.CLOSE, - action: () => setOpen(false), - }, - }); - return; - } - } else { - item.src = url; - } - item.w = window.innerWidth; - item.h = window.innerHeight; + await updateSrcUrl(item.dataIndex, url); + item.html = files[item.dataIndex].html; + item.src = files[item.dataIndex].src; + item.w = files[item.dataIndex].w; + item.h = files[item.dataIndex].h; try { instance.invalidateCurrItems(); instance.updateSize(true); diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 00b11549a..7680cabcf 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -79,12 +79,33 @@ const GlobalStyles = createGlobalStyle` height: 100%; } - .video-loading > div { + .video-loading > div.spinner-border { position: relative; top: -50vh; left: 50vw; } + + + .video-loading > div.download-message { + position: relative; + top: -60vh; + left: 0; + height: 20vh; + padding:2vh 0; + background-color: #151414; + color:#ddd; + display: flex; + flex-direction:column; + align-items: center; + justify-content: space-around; + opacity: 0.8; + font-size:20px; + } + .download-message > a{ + width: 130px; + } + :root { --primary: #e26f99, }; diff --git a/src/utils/photoFrame/index.ts b/src/utils/photoFrame/index.ts new file mode 100644 index 000000000..fdaeb8557 --- /dev/null +++ b/src/utils/photoFrame/index.ts @@ -0,0 +1,15 @@ +const WAIT_FOR_VIDEO_PLAYBACK = 1 * 1000; + +export async function isPlaybackPossible(url: string): Promise { + return await new Promise((resolve) => { + const t = setTimeout(() => { + resolve(false); + }, WAIT_FOR_VIDEO_PLAYBACK); + const video = document.createElement('video'); + video.addEventListener('canplay', function () { + clearTimeout(t); + resolve(true); + }); + video.src = url; + }); +} From 0d62c1e67f4452e4bec67cb319399ea7399435de Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Tue, 5 Oct 2021 12:43:29 +0530 Subject: [PATCH 03/42] make banner thinner --- src/pages/_app.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 7680cabcf..eff5d1866 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -91,7 +91,7 @@ const GlobalStyles = createGlobalStyle` position: relative; top: -60vh; left: 0; - height: 20vh; + height: 16vh; padding:2vh 0; background-color: #151414; color:#ddd; From 2edce610f832945f87ac0302ef761f146e089233 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Tue, 5 Oct 2021 14:08:26 +0530 Subject: [PATCH 04/42] fix download file name bug --- src/components/PhotoFrame.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PhotoFrame.tsx b/src/components/PhotoFrame.tsx index 66dc07f2f..951859102 100644 --- a/src/components/PhotoFrame.tsx +++ b/src/components/PhotoFrame.tsx @@ -243,7 +243,7 @@ const PhotoFrame = ({ `; From f6af345421a32675ce787fccefe9d67aadabdf2b Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Tue, 5 Oct 2021 15:18:05 +0530 Subject: [PATCH 05/42] remove states for isSharedCollectionActive and isFavCollectionActive. Interfering with colletion Chip auto scroll to searched item --- src/pages/gallery/index.tsx | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 08beb7d24..59b307568 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -184,11 +184,6 @@ export default function Gallery() { useState>(); const [activeCollection, setActiveCollection] = useState(undefined); - const [isSharedCollectionActive, setIsSharedCollectionActive] = - useState(false); - - const [isFavCollectionActive, setIsFavCollectionActive] = useState(false); - useEffect(() => { const key = getKey(SESSION_KEYS.ENCRYPTION_KEY); if (!key) { @@ -246,14 +241,6 @@ export default function Gallery() { } const href = `/gallery${collectionURL}`; router.push(href, undefined, { shallow: true }); - - setIsSharedCollectionActive( - isSharedCollection(activeCollection, collections) - ); - - setIsFavCollectionActive( - isFavoriteCollection(activeCollection, collections) - ); }, [activeCollection]); const syncWithRemote = async (force = false, silent = false) => { @@ -623,7 +610,10 @@ export default function Gallery() { deleted={deleted} setDialogMessage={setDialogMessage} activeCollection={activeCollection} - isSharedCollection={isSharedCollectionActive} + isSharedCollection={isSharedCollection( + activeCollection, + collections + )} /> {selected.count > 0 && selected.collectionID === activeCollection && ( @@ -651,7 +641,10 @@ export default function Gallery() { count={selected.count} clearSelection={clearSelection} activeCollection={activeCollection} - isFavoriteCollection={isFavCollectionActive} + isFavoriteCollection={isFavoriteCollection( + activeCollection, + collections + )} /> )} From 52fe27263c9215226c5c73cdbcdf639634428879 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Thu, 7 Oct 2021 11:24:21 +0530 Subject: [PATCH 06/42] search in all section instead of the collection user opened search on --- src/components/SearchBar.tsx | 6 +++--- src/components/pages/gallery/Collections.tsx | 2 +- src/pages/gallery/index.tsx | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx index e854e2639..3d12b0322 100644 --- a/src/components/SearchBar.tsx +++ b/src/components/SearchBar.tsx @@ -177,12 +177,12 @@ export default function SearchBar(props: Props) { break; case SuggestionType.COLLECTION: props.setActiveCollection(selectedOption.value as number); - resetSearch(true); + setValue(null); break; } }; - const resetSearch = async (force?: boolean) => { - if (props.isOpen || force) { + const resetSearch = () => { + if (props.isOpen) { props.loadingBar.current?.continuousStart(); props.setSearch({}); setTimeout(() => { diff --git a/src/components/pages/gallery/Collections.tsx b/src/components/pages/gallery/Collections.tsx index 7277f2c18..05bb5610e 100644 --- a/src/components/pages/gallery/Collections.tsx +++ b/src/components/pages/gallery/Collections.tsx @@ -119,7 +119,7 @@ export default function Collections(props: CollectionProps) { useEffect(() => { updateScrollObj(); - }, [collectionWrapperRef.current]); + }, [collectionWrapperRef.current, props.searchMode]); useEffect(() => { if (!collectionWrapperRef?.current) { diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 08beb7d24..4c27607d8 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -492,6 +492,7 @@ export default function Gallery() { }; const updateSearch = (search: Search) => { + setActiveCollection(ALL_SECTION); setSearch(search); setSearchStats(null); }; From afbcda58928bc685442401faadadfebc4f1827ab Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Thu, 7 Oct 2021 13:52:25 +0530 Subject: [PATCH 07/42] renamed searchMode to isInSearchMode state --- src/components/PhotoFrame.tsx | 10 +++++----- src/components/pages/gallery/Collections.tsx | 6 +++--- src/pages/gallery/index.tsx | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/components/PhotoFrame.tsx b/src/components/PhotoFrame.tsx index faeae4cff..403571317 100644 --- a/src/components/PhotoFrame.tsx +++ b/src/components/PhotoFrame.tsx @@ -146,7 +146,7 @@ interface Props { isFirstLoad; openFileUploader; loadingBar; - searchMode: boolean; + isInSearchMode: boolean; search: Search; setSearchStats: setSearchStats; deleted?: number[]; @@ -165,7 +165,7 @@ const PhotoFrame = ({ isFirstLoad, openFileUploader, loadingBar, - searchMode, + isInSearchMode, search, setSearchStats, deleted, @@ -181,7 +181,7 @@ const PhotoFrame = ({ const listRef = useRef(null); useEffect(() => { - if (searchMode) { + if (isInSearchMode) { setSearchStats({ resultCount: filteredData.length, timeTaken: (Date.now() - startTime) / 1000, @@ -515,7 +515,7 @@ const PhotoFrame = ({ return ( <> - {!isFirstLoad && files.length === 0 && !searchMode ? ( + {!isFirstLoad && files.length === 0 && !isInSearchMode ? (
@@ -635,7 +635,7 @@ const PhotoFrame = ({ return sum; })(); files.length < 30 && - !searchMode && + !isInSearchMode && timeStampList.push({ itemType: ITEM_TYPE.BANNER, banner: ( diff --git a/src/components/pages/gallery/Collections.tsx b/src/components/pages/gallery/Collections.tsx index 05bb5610e..5131e2a25 100644 --- a/src/components/pages/gallery/Collections.tsx +++ b/src/components/pages/gallery/Collections.tsx @@ -35,7 +35,7 @@ interface CollectionProps { syncWithRemote: () => Promise; setCollectionNamerAttributes: SetCollectionNamerAttributes; startLoadingBar: () => void; - searchMode: boolean; + isInSearchMode: boolean; collectionFilesCount: Map; } @@ -119,7 +119,7 @@ export default function Collections(props: CollectionProps) { useEffect(() => { updateScrollObj(); - }, [collectionWrapperRef.current, props.searchMode]); + }, [collectionWrapperRef.current, props.isInSearchMode]); useEffect(() => { if (!collectionWrapperRef?.current) { @@ -184,7 +184,7 @@ export default function Collections(props: CollectionProps) { }; return ( - !props.searchMode && ( + !props.isInSearchMode && ( <> Date: Thu, 7 Oct 2021 14:02:07 +0530 Subject: [PATCH 08/42] remember prevCollection before search and redirect to it after search --- src/pages/gallery/index.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 6ba61d431..9271979a2 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -106,6 +106,7 @@ export type setSearchStats = React.Dispatch>; export type Search = { date?: DateValue; location?: Bbox; + prevCollection?: number; }; export interface SearchStats { resultCount: number; @@ -491,9 +492,11 @@ export default function Gallery() { } }; - const updateSearch = (search: Search) => { - setActiveCollection(ALL_SECTION); - setSearch(search); + const updateSearch = (newSearch: Search) => { + const prevCollection = search.prevCollection ?? ALL_SECTION; + const currentCollection = activeCollection; + setActiveCollection(prevCollection); + setSearch({ ...newSearch, prevCollection: currentCollection }); setSearchStats(null); }; From afce424396d66c4f93476389741c2bf8dfa50d2b Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Thu, 7 Oct 2021 14:44:39 +0530 Subject: [PATCH 09/42] hide collection instead of removing it form dom in searhch mode --- src/components/pages/gallery/Collections.tsx | 202 +++++++++---------- 1 file changed, 100 insertions(+), 102 deletions(-) diff --git a/src/components/pages/gallery/Collections.tsx b/src/components/pages/gallery/Collections.tsx index 5131e2a25..db2a417bb 100644 --- a/src/components/pages/gallery/Collections.tsx +++ b/src/components/pages/gallery/Collections.tsx @@ -87,6 +87,11 @@ const Chip = styled.button<{ active: boolean }>` } `; +const Hider = styled.div<{ hide: boolean }>` + opacity: ${(props) => (props.hide ? '0' : '100')}; + height: ${(props) => (props.hide ? '0' : 'auto')}; +`; + export default function Collections(props: CollectionProps) { const { activeCollection, collections, setActiveCollection } = props; const [selectedCollectionID, setSelectedCollectionID] = @@ -184,111 +189,104 @@ export default function Collections(props: CollectionProps) { }; return ( - !props.isInSearchMode && ( - <> - setCollectionShareModalView(false)} - collection={getSelectedCollection( - selectedCollectionID, - props.collections + + setCollectionShareModalView(false)} + collection={getSelectedCollection( + selectedCollectionID, + props.collections + )} + syncWithRemote={props.syncWithRemote} + /> + + + {scrollObj.scrollLeft > 0 && ( + )} - syncWithRemote={props.syncWithRemote} - /> - - - {scrollObj.scrollLeft > 0 && ( - + + {constants.ALL} +
- )} - - - {constants.ALL} -
- - {sortCollections( - collections, - props.collectionAndTheirLatestFile, - collectionSortBy - ).map((item) => ( - - - {item.name} - {item.type !== - CollectionType.favorites && - item.owner.id === user?.id ? ( - - - setSelectedCollectionID( - item.id - ) - } - /> - - ) : ( -
+ {sortCollections( + collections, + props.collectionAndTheirLatestFile, + collectionSortBy + ).map((item) => ( + + + {item.name} + {item.type !== CollectionType.favorites && + item.owner.id === user?.id ? ( + + + setSelectedCollectionID( + item.id + ) + } /> - )} - - - ))} - - {constants.ARCHIVE} -
- - - {scrollObj.scrollLeft < - scrollObj.scrollWidth - scrollObj.clientWidth && ( - + ) : ( +
+ )} + + + ))} + + {constants.ARCHIVE} +
- )} - - - - - ) + + + {scrollObj.scrollLeft < + scrollObj.scrollWidth - scrollObj.clientWidth && ( + + )} + + + + ); } From 57ff20029f94f017c4ef85f07a298daf1a897b47 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Thu, 7 Oct 2021 15:02:31 +0530 Subject: [PATCH 10/42] set intial prevCollection to ALL_SECTION to avoid null check on searchUpdate --- src/pages/gallery/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 9271979a2..ab5e3f1f5 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -160,6 +160,7 @@ export default function Gallery() { const [search, setSearch] = useState({ date: null, location: null, + prevCollection: ALL_SECTION, }); const [uploadInProgress, setUploadInProgress] = useState(false); const { @@ -493,7 +494,7 @@ export default function Gallery() { }; const updateSearch = (newSearch: Search) => { - const prevCollection = search.prevCollection ?? ALL_SECTION; + const prevCollection = search.prevCollection; const currentCollection = activeCollection; setActiveCollection(prevCollection); setSearch({ ...newSearch, prevCollection: currentCollection }); From 950adae9b3ca9870fc5c6fa0999d1cc297a87ea0 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Wed, 6 Oct 2021 11:24:05 +0530 Subject: [PATCH 11/42] Adds file search by name --- src/components/PhotoFrame.tsx | 3 +++ src/components/SearchBar.tsx | 39 +++++++++++++++++++++++++----- src/components/icons/ImageIcon.tsx | 21 ++++++++++++++++ src/components/icons/VideoIcon.tsx | 20 +++++++++++++++ src/pages/gallery/index.tsx | 3 +++ src/services/searchService.ts | 11 +++++++++ 6 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/components/icons/ImageIcon.tsx create mode 100644 src/components/icons/VideoIcon.tsx diff --git a/src/components/PhotoFrame.tsx b/src/components/PhotoFrame.tsx index 403571317..a7598b10d 100644 --- a/src/components/PhotoFrame.tsx +++ b/src/components/PhotoFrame.tsx @@ -187,6 +187,9 @@ const PhotoFrame = ({ timeTaken: (Date.now() - startTime) / 1000, }); } + if (search.fileIndex || search.fileIndex === 0) { + onThumbnailClick(search.fileIndex)(); + } }, [search]); useEffect(() => { diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx index 3d12b0322..2463ffa75 100644 --- a/src/components/SearchBar.tsx +++ b/src/components/SearchBar.tsx @@ -10,6 +10,7 @@ import { getYearSuggestion, parseHumanDate, searchCollection, + searchFiles, searchLocation, } from 'services/searchService'; import { getFormattedDate } from 'utils/search'; @@ -20,6 +21,9 @@ import SearchIcon from './icons/SearchIcon'; import CrossIcon from './icons/CrossIcon'; import { Collection } from 'services/collectionService'; import CollectionIcon from './icons/CollectionIcon'; +import { File, FILE_TYPE } from 'services/fileService'; +import ImageIcon from './icons/ImageIcon'; +import VideoIcon from './icons/VideoIcon'; const Wrapper = styled.div<{ isDisabled: boolean; isOpen: boolean }>` position: fixed; @@ -74,6 +78,8 @@ export enum SuggestionType { DATE, LOCATION, COLLECTION, + IMAGE, + VIDEO, } export interface DateValue { date?: number; @@ -94,6 +100,7 @@ interface Props { searchStats: SearchStats; collections: Collection[]; setActiveCollection: (id: number) => void; + files: File[]; } export default function SearchBar(props: Props) { const [value, setValue] = useState(null); @@ -112,14 +119,14 @@ export default function SearchBar(props: Props) { if (!searchPhrase?.length) { return []; } - const option = [ + const options = [ ...getHolidaySuggestion(searchPhrase), ...getYearSuggestion(searchPhrase), ]; const searchedDates = parseHumanDate(searchPhrase); - option.push( + options.push( ...searchedDates.map((searchedDate) => ({ type: SuggestionType.DATE, value: searchedDate, @@ -131,7 +138,7 @@ export default function SearchBar(props: Props) { searchPhrase, props.collections ); - option.push( + options.push( ...collectionResults.map( (searchResult) => ({ @@ -141,8 +148,20 @@ export default function SearchBar(props: Props) { } as Suggestion) ) ); + const fileResults = searchFiles(searchPhrase, props.files); + options.push( + ...fileResults.map((file) => ({ + type: + file.type === FILE_TYPE.IMAGE + ? SuggestionType.IMAGE + : SuggestionType.VIDEO, + value: file.index, + label: file.title, + })) + ); + const locationResults = await searchLocation(searchPhrase); - option.push( + options.push( ...locationResults.map( (searchResult) => ({ @@ -152,7 +171,7 @@ export default function SearchBar(props: Props) { } as Suggestion) ) ); - return option; + return options; }; const getOptions = debounce(getAutoCompleteSuggestions, 250); @@ -161,7 +180,6 @@ export default function SearchBar(props: Props) { if (!selectedOption) { return; } - switch (selectedOption.type) { case SuggestionType.DATE: props.setSearch({ @@ -179,6 +197,11 @@ export default function SearchBar(props: Props) { props.setActiveCollection(selectedOption.value as number); setValue(null); break; + case SuggestionType.IMAGE: + case SuggestionType.VIDEO: + props.setSearch({ fileIndex: selectedOption.value as number }); + setValue(null); + break; } }; const resetSearch = () => { @@ -205,6 +228,10 @@ export default function SearchBar(props: Props) { return ; case SuggestionType.COLLECTION: return ; + case SuggestionType.IMAGE: + return ; + case SuggestionType.VIDEO: + return ; default: return ; } diff --git a/src/components/icons/ImageIcon.tsx b/src/components/icons/ImageIcon.tsx new file mode 100644 index 000000000..6e2d6f8de --- /dev/null +++ b/src/components/icons/ImageIcon.tsx @@ -0,0 +1,21 @@ +import React from 'react'; + +export default function ImageIcon(props) { + return ( + + + + + ); +} + +ImageIcon.defaultProps = { + height: 24, + width: 24, + viewBox: '0 0 24 24', +}; diff --git a/src/components/icons/VideoIcon.tsx b/src/components/icons/VideoIcon.tsx new file mode 100644 index 000000000..510367881 --- /dev/null +++ b/src/components/icons/VideoIcon.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +export default function VideoIcon(props) { + return ( + + + + ); +} + +VideoIcon.defaultProps = { + height: 24, + width: 24, + viewBox: '0 0 24 24', +}; diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index ab5e3f1f5..fa615031d 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -107,6 +107,7 @@ export type Search = { date?: DateValue; location?: Bbox; prevCollection?: number; + fileIndex?: number; }; export interface SearchStats { resultCount: number; @@ -161,6 +162,7 @@ export default function Gallery() { date: null, location: null, prevCollection: ALL_SECTION, + fileIndex: null, }); const [uploadInProgress, setUploadInProgress] = useState(false); const { @@ -548,6 +550,7 @@ export default function Gallery() { loadingBar={loadingBar} isFirstFetch={isFirstFetch} collections={collections} + files={files} setActiveCollection={setActiveCollection} setSearch={updateSearch} searchStats={searchStats} diff --git a/src/services/searchService.ts b/src/services/searchService.ts index d5832fd84..393d07fb0 100644 --- a/src/services/searchService.ts +++ b/src/services/searchService.ts @@ -4,6 +4,7 @@ import { getToken } from 'utils/common/key'; import { DateValue, Suggestion, SuggestionType } from 'components/SearchBar'; import HTTPService from './HTTPService'; import { Collection } from './collectionService'; +import { File } from './fileService'; const ENDPOINT = getEndpoint(); const DIGITS = new Set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']); @@ -110,3 +111,13 @@ export function searchCollection( collection.name.toLowerCase().includes(searchPhrase) ); } + +export function searchFiles(searchPhrase: string, files: File[]) { + return files + .map((file, idx) => ({ + title: file.metadata.title, + index: idx, + type: file.metadata.fileType, + })) + .filter(({ title }) => title.toLowerCase().includes(searchPhrase)); +} From 828844151c57eb89bed1a05d75ca109af4e67bcd Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Wed, 6 Oct 2021 12:51:17 +0530 Subject: [PATCH 12/42] show only four file search results --- src/services/searchService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/searchService.ts b/src/services/searchService.ts index 393d07fb0..d90cfddf2 100644 --- a/src/services/searchService.ts +++ b/src/services/searchService.ts @@ -119,5 +119,6 @@ export function searchFiles(searchPhrase: string, files: File[]) { index: idx, type: file.metadata.fileType, })) - .filter(({ title }) => title.toLowerCase().includes(searchPhrase)); + .filter(({ title }) => title.toLowerCase().includes(searchPhrase)) + .slice(0, 4); } From 6d8028ae991799613ebf5a1b8a309db43d3a2272 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Wed, 6 Oct 2021 12:51:46 +0530 Subject: [PATCH 13/42] find filteredData index and then open that item --- src/components/PhotoFrame.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/PhotoFrame.tsx b/src/components/PhotoFrame.tsx index a7598b10d..28de2cdc6 100644 --- a/src/components/PhotoFrame.tsx +++ b/src/components/PhotoFrame.tsx @@ -188,7 +188,12 @@ const PhotoFrame = ({ }); } if (search.fileIndex || search.fileIndex === 0) { - onThumbnailClick(search.fileIndex)(); + const filteredDataIdx = filteredData.findIndex( + (data) => data.dataIndex === search.fileIndex + ); + if (filteredDataIdx) { + onThumbnailClick(filteredDataIdx)(); + } } }, [search]); From 9afd224a231ad58c9ee1dddd10d9ab23b90312b2 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Thu, 7 Oct 2021 11:17:22 +0530 Subject: [PATCH 14/42] dont show shared files in options --- src/services/searchService.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/services/searchService.ts b/src/services/searchService.ts index d90cfddf2..d24e2d239 100644 --- a/src/services/searchService.ts +++ b/src/services/searchService.ts @@ -5,6 +5,8 @@ import { DateValue, Suggestion, SuggestionType } from 'components/SearchBar'; import HTTPService from './HTTPService'; import { Collection } from './collectionService'; import { File } from './fileService'; +import { User } from './userService'; +import { getData, LS_KEYS } from 'utils/storage/localStorage'; const ENDPOINT = getEndpoint(); const DIGITS = new Set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']); @@ -113,7 +115,9 @@ export function searchCollection( } export function searchFiles(searchPhrase: string, files: File[]) { + const user: User = getData(LS_KEYS.USER) ?? {}; return files + .filter((file) => file.ownerID === user.id) .map((file, idx) => ({ title: file.metadata.title, index: idx, From 9fa1c1fc0988f049fb025ea91aedfbfdb2556f65 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Thu, 7 Oct 2021 11:42:54 +0530 Subject: [PATCH 15/42] fix owner photo filtering --- src/services/searchService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/searchService.ts b/src/services/searchService.ts index d24e2d239..0469ebf21 100644 --- a/src/services/searchService.ts +++ b/src/services/searchService.ts @@ -117,12 +117,13 @@ export function searchCollection( export function searchFiles(searchPhrase: string, files: File[]) { const user: User = getData(LS_KEYS.USER) ?? {}; return files - .filter((file) => file.ownerID === user.id) .map((file, idx) => ({ title: file.metadata.title, index: idx, type: file.metadata.fileType, + ownerID: file.ownerID, })) + .filter((file) => file.ownerID === user.id) .filter(({ title }) => title.toLowerCase().includes(searchPhrase)) .slice(0, 4); } From cbe1d8ce88fae3c302820959d4b7e5f957f6a713 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Thu, 7 Oct 2021 12:49:37 +0530 Subject: [PATCH 16/42] show only one instance of a file --- src/components/PhotoFrame.tsx | 2 +- src/services/searchService.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/PhotoFrame.tsx b/src/components/PhotoFrame.tsx index 28de2cdc6..750ef4cf0 100644 --- a/src/components/PhotoFrame.tsx +++ b/src/components/PhotoFrame.tsx @@ -191,7 +191,7 @@ const PhotoFrame = ({ const filteredDataIdx = filteredData.findIndex( (data) => data.dataIndex === search.fileIndex ); - if (filteredDataIdx) { + if (filteredDataIdx || filteredDataIdx === 0) { onThumbnailClick(filteredDataIdx)(); } } diff --git a/src/services/searchService.ts b/src/services/searchService.ts index 0469ebf21..34c5c06b9 100644 --- a/src/services/searchService.ts +++ b/src/services/searchService.ts @@ -116,14 +116,22 @@ export function searchCollection( export function searchFiles(searchPhrase: string, files: File[]) { const user: User = getData(LS_KEYS.USER) ?? {}; + const idSet = new Set(); return files .map((file, idx) => ({ title: file.metadata.title, index: idx, type: file.metadata.fileType, ownerID: file.ownerID, + id: file.id, })) - .filter((file) => file.ownerID === user.id) + .filter((file) => { + if (file.ownerID === user.id && !idSet.has(file.id)) { + idSet.add(file.id); + return true; + } + return false; + }) .filter(({ title }) => title.toLowerCase().includes(searchPhrase)) .slice(0, 4); } From 76351c38ab82c9a9c47b9b7621d967007d7cf2ec Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Thu, 7 Oct 2021 20:40:41 +0530 Subject: [PATCH 17/42] remove prev collection redirecting --- src/pages/gallery/index.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index ab5e3f1f5..50a3f1977 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -494,10 +494,8 @@ export default function Gallery() { }; const updateSearch = (newSearch: Search) => { - const prevCollection = search.prevCollection; - const currentCollection = activeCollection; - setActiveCollection(prevCollection); - setSearch({ ...newSearch, prevCollection: currentCollection }); + setActiveCollection(ALL_SECTION); + setSearch(newSearch); setSearchStats(null); }; From 515266bc93133e00570ebf283eb4b5062a750f17 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Thu, 7 Oct 2021 20:46:21 +0530 Subject: [PATCH 18/42] remove prev collection from search --- src/pages/gallery/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 50a3f1977..92d25ae2f 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -106,7 +106,6 @@ export type setSearchStats = React.Dispatch>; export type Search = { date?: DateValue; location?: Bbox; - prevCollection?: number; }; export interface SearchStats { resultCount: number; @@ -160,7 +159,6 @@ export default function Gallery() { const [search, setSearch] = useState({ date: null, location: null, - prevCollection: ALL_SECTION, }); const [uploadInProgress, setUploadInProgress] = useState(false); const { From 3de8b0bfbea9c7197142ae445a06108d6da8d69a Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Fri, 8 Oct 2021 13:20:54 +0530 Subject: [PATCH 19/42] generate jpeg thumbnail with 512*512 resolution and jpeg format --- src/services/ffmpegService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/ffmpegService.ts b/src/services/ffmpegService.ts index 52522a6af..13b7bde7e 100644 --- a/src/services/ffmpegService.ts +++ b/src/services/ffmpegService.ts @@ -45,7 +45,7 @@ class FFmpegService { async function generateThumbnailHelper(ffmpeg: FFmpeg, file: File) { try { const inputFileName = `${Date.now().toString}-${file.name}`; - const thumbFileName = `${Date.now().toString}-thumb.png`; + const thumbFileName = `${Date.now().toString}-thumb.jpeg`; ffmpeg.FS( 'writeFile', inputFileName, @@ -62,6 +62,7 @@ async function generateThumbnailHelper(ffmpeg: FFmpeg, file: File) { `00:00:0${seekTime.toFixed(3)}`, '-vframes', '1', + '-vf scale=512:512', thumbFileName ); thumb = ffmpeg.FS('readFile', thumbFileName); From 11eb962f7944a7e956853ab113d1199fd550baab Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Fri, 8 Oct 2021 13:46:11 +0530 Subject: [PATCH 20/42] compress thumbnail generated from ffmpeg using canvas method --- src/services/upload/thumbnailService.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index e63df1f8a..434de1461 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -26,7 +26,12 @@ export async function generateThumbnail( } else { try { const thumb = await FFmpegService.generateThumbnail(file); - return { thumbnail: thumb, hasStaticThumbnail: false }; + const dummyImageFile = new File([thumb], file.name); + canvas = await generateImageThumbnail( + worker, + dummyImageFile, + isHEIC + ); } catch (e) { canvas = await generateVideoThumbnail(file); } From c095031b8e817873c204059bababcd8f535c9a7e Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Sat, 9 Oct 2021 15:19:33 +0530 Subject: [PATCH 21/42] add newly created favorite collection to localCollections --- src/services/collectionService.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/services/collectionService.ts b/src/services/collectionService.ts index 7ec6e7587..d7738116f 100644 --- a/src/services/collectionService.ts +++ b/src/services/collectionService.ts @@ -23,7 +23,6 @@ export enum CollectionType { } const COLLECTION_UPDATION_TIME = 'collection-updation-time'; -const FAV_COLLECTION = 'fav-collection'; const COLLECTIONS = 'collections'; export interface Collection { @@ -340,7 +339,11 @@ export const addToFavorites = async (file: File) => { 'Favorites', CollectionType.favorites ); - await localForage.setItem(FAV_COLLECTION, favCollection); + const localCollections = await getLocalCollections(); + await localForage.setItem(COLLECTIONS, [ + ...localCollections, + favCollection, + ]); } await addToCollection(favCollection, [file]); } catch (e) { From 6262b6e781e3cf5b14b7e85bc3e5ac1976f7fec7 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Sat, 9 Oct 2021 15:38:30 +0530 Subject: [PATCH 22/42] send rootCause message to sentry --- src/utils/sentry/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/sentry/index.ts b/src/utils/sentry/index.ts index fb889439d..97743da27 100644 --- a/src/utils/sentry/index.ts +++ b/src/utils/sentry/index.ts @@ -9,7 +9,7 @@ export const logError = ( ) => { const err = errorWithContext(e, msg); if (!process.env.NEXT_PUBLIC_SENTRY_ENV) { - console.log(err); + console.log(e); } Sentry.captureException(err, { level: Sentry.Severity.Info, @@ -17,6 +17,7 @@ export const logError = ( contexts: { ...(info && { info: info, + rootCause: { message: e?.message }, }), }, }); From dbbe5a1d9c3d14c89533f67ddfda72ddd8bfbfe0 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Sat, 9 Oct 2021 16:23:22 +0530 Subject: [PATCH 23/42] always send root cause message --- src/utils/sentry/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/sentry/index.ts b/src/utils/sentry/index.ts index 97743da27..aef44d4e5 100644 --- a/src/utils/sentry/index.ts +++ b/src/utils/sentry/index.ts @@ -17,8 +17,8 @@ export const logError = ( contexts: { ...(info && { info: info, - rootCause: { message: e?.message }, }), + rootCause: { message: e?.message }, }, }); }; From 78a69a6d33e16cd6882c3b5bb9613353d50176af Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Tue, 19 Oct 2021 13:58:10 +0530 Subject: [PATCH 24/42] if compression more than min compression diff keep on compressing --- src/services/upload/thumbnailService.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index 434de1461..6da775027 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -5,8 +5,8 @@ import { BLACK_THUMBNAIL_BASE64 } from '../../../public/images/black-thumbnail-b import FFmpegService from 'services/ffmpegService'; const THUMBNAIL_HEIGHT = 720; -const MAX_ATTEMPTS = 3; -const MIN_THUMBNAIL_SIZE = 50000; +const MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF = 10; +export const MAX_THUMBNAIL_SIZE = 50 * 1024; const WAIT_TIME_THUMBNAIL_GENERATION = 10 * 1000; @@ -171,11 +171,14 @@ export async function generateVideoThumbnail(file: globalThis.File) { } async function thumbnailCanvasToBlob(canvas: HTMLCanvasElement) { - let thumbnailBlob = null; - let attempts = 0; + let thumbnailBlob: Blob = null; + let prevSize = Number.MAX_SAFE_INTEGER; let quality = 1; do { + if (thumbnailBlob) { + prevSize = thumbnailBlob.size; + } thumbnailBlob = await new Promise((resolve) => { canvas.toBlob( function (blob) { @@ -186,12 +189,19 @@ async function thumbnailCanvasToBlob(canvas: HTMLCanvasElement) { ); }); thumbnailBlob = thumbnailBlob ?? new Blob([]); - attempts++; quality /= 2; } while ( - thumbnailBlob.size > MIN_THUMBNAIL_SIZE && - attempts <= MAX_ATTEMPTS + thumbnailBlob.size > MAX_THUMBNAIL_SIZE && + percentageSizeDiff(thumbnailBlob.size, prevSize) >= + MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF ); return thumbnailBlob; } + +function percentageSizeDiff( + newThumbnailSize: number, + oldThumbnailSize: number +) { + return ((oldThumbnailSize - newThumbnailSize) * 100) / oldThumbnailSize; +} From 175e323c4742ed5da56ada49f65d83ab2c82767a Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Tue, 19 Oct 2021 14:02:11 +0530 Subject: [PATCH 25/42] log thumbnail size greater than max limit --- src/services/upload/thumbnailService.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index 6da775027..8b41c739e 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -195,6 +195,12 @@ async function thumbnailCanvasToBlob(canvas: HTMLCanvasElement) { percentageSizeDiff(thumbnailBlob.size, prevSize) >= MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF ); + if (thumbnailBlob.size > MAX_THUMBNAIL_SIZE) { + logError( + Error('thumbnail_too_large'), + 'thumbnail greater than max limit' + ); + } return thumbnailBlob; } From 47914f5281b6685cff065e32234104a05969804a Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Tue, 19 Oct 2021 15:46:15 +0530 Subject: [PATCH 26/42] reduce quality linearly --- src/services/upload/thumbnailService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index 8b41c739e..39fd9449d 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -189,8 +189,9 @@ async function thumbnailCanvasToBlob(canvas: HTMLCanvasElement) { ); }); thumbnailBlob = thumbnailBlob ?? new Blob([]); - quality /= 2; + quality -= 0.1; } while ( + quality > 0 && thumbnailBlob.size > MAX_THUMBNAIL_SIZE && percentageSizeDiff(thumbnailBlob.size, prevSize) >= MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF From 1373a955aab14a1b5a5e80e2ce6edfa3a212214a Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Tue, 19 Oct 2021 17:11:34 +0530 Subject: [PATCH 27/42] make downloadThumb private correctly --- src/services/downloadManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/downloadManager.ts b/src/services/downloadManager.ts index af2c72e92..a4eb2545c 100644 --- a/src/services/downloadManager.ts +++ b/src/services/downloadManager.ts @@ -24,7 +24,7 @@ class DownloadManager { return URL.createObjectURL(await cacheResp.blob()); } if (!this.thumbnailObjectUrlPromise.get(file.id)) { - const downloadPromise = this._downloadThumb( + const downloadPromise = this.downloadThumb( token, thumbnailCache, file @@ -38,7 +38,7 @@ class DownloadManager { } } - _downloadThumb = async ( + private downloadThumb = async ( token: string, thumbnailCache: Cache, file: File From d3b73eaa6bf4393cabd51444bf3ce6778c97a0bd Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Tue, 19 Oct 2021 17:12:56 +0530 Subject: [PATCH 28/42] fix file not retrying download after a fail --- src/services/downloadManager.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/services/downloadManager.ts b/src/services/downloadManager.ts index a4eb2545c..577cd8037 100644 --- a/src/services/downloadManager.ts +++ b/src/services/downloadManager.ts @@ -67,6 +67,7 @@ class DownloadManager { }; getFile = async (file: File, forPreview = false) => { + const fileUID = `${file.id}_${forPreview}`; try { const getFilePromise = (async () => { const fileStream = await this.downloadFile(file); @@ -76,16 +77,12 @@ class DownloadManager { } return URL.createObjectURL(fileBlob); })(); - if (!this.fileObjectUrlPromise.get(`${file.id}_${forPreview}`)) { - this.fileObjectUrlPromise.set( - `${file.id}_${forPreview}`, - getFilePromise - ); + if (!this.fileObjectUrlPromise.get(fileUID)) { + this.fileObjectUrlPromise.set(fileUID, getFilePromise); } - return await this.fileObjectUrlPromise.get( - `${file.id}_${forPreview}` - ); + return await this.fileObjectUrlPromise.get(fileUID); } catch (e) { + this.fileObjectUrlPromise.delete(fileUID); logError(e, 'Failed to get File'); } }; From 89707411583ae26adc13faaa6726514513c14996 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Tue, 19 Oct 2021 17:59:31 +0530 Subject: [PATCH 29/42] fix file download even if present in local bug --- src/services/downloadManager.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/downloadManager.ts b/src/services/downloadManager.ts index 577cd8037..380841e7d 100644 --- a/src/services/downloadManager.ts +++ b/src/services/downloadManager.ts @@ -69,16 +69,16 @@ class DownloadManager { getFile = async (file: File, forPreview = false) => { const fileUID = `${file.id}_${forPreview}`; try { - const getFilePromise = (async () => { + const getFilePromise = async () => { const fileStream = await this.downloadFile(file); let fileBlob = await new Response(fileStream).blob(); if (forPreview) { fileBlob = await convertForPreview(file, fileBlob); } return URL.createObjectURL(fileBlob); - })(); + }; if (!this.fileObjectUrlPromise.get(fileUID)) { - this.fileObjectUrlPromise.set(fileUID, getFilePromise); + this.fileObjectUrlPromise.set(fileUID, getFilePromise()); } return await this.fileObjectUrlPromise.get(fileUID); } catch (e) { From 6097e76fad89d5f9701493fa87b6501df8174c82 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Thu, 21 Oct 2021 13:47:11 +0530 Subject: [PATCH 30/42] fixed thumbnail and file download not retried after fail --- src/components/PhotoFrame.tsx | 76 +++++++++++--------- src/components/pages/gallery/PreviewCard.tsx | 20 +++--- src/services/downloadManager.ts | 2 + 3 files changed, 57 insertions(+), 41 deletions(-) diff --git a/src/components/PhotoFrame.tsx b/src/components/PhotoFrame.tsx index 40bd25788..ed087b9a9 100644 --- a/src/components/PhotoFrame.tsx +++ b/src/components/PhotoFrame.tsx @@ -301,46 +301,56 @@ const PhotoFrame = ({ const getSlideData = async (instance: any, index: number, item: File) => { if (!item.msrc) { - let url: string; - if (galleryContext.thumbs.has(item.id)) { - url = galleryContext.thumbs.get(item.id); - } else { - url = await DownloadManager.getPreview(item); - galleryContext.thumbs.set(item.id, url); - } - updateUrl(item.dataIndex)(url); - item.msrc = url; - if (!item.src) { - item.src = url; - } - item.w = window.innerWidth; - item.h = window.innerHeight; try { - instance.invalidateCurrItems(); - instance.updateSize(true); + let url: string; + if (galleryContext.thumbs.has(item.id)) { + url = galleryContext.thumbs.get(item.id); + } else { + url = await DownloadManager.getPreview(item); + galleryContext.thumbs.set(item.id, url); + } + updateUrl(item.dataIndex)(url); + item.msrc = url; + if (!item.src) { + item.src = url; + } + item.w = window.innerWidth; + item.h = window.innerHeight; + try { + instance.invalidateCurrItems(); + instance.updateSize(true); + } catch (e) { + // ignore + } } catch (e) { - // ignore + // no-op } } if (!fetching[item.dataIndex]) { - fetching[item.dataIndex] = true; - let url: string; - if (galleryContext.files.has(item.id)) { - url = galleryContext.files.get(item.id); - } else { - url = await DownloadManager.getFile(item, true); - galleryContext.files.set(item.id, url); - } - await updateSrcUrl(item.dataIndex, url); - item.html = files[item.dataIndex].html; - item.src = files[item.dataIndex].src; - item.w = files[item.dataIndex].w; - item.h = files[item.dataIndex].h; try { - instance.invalidateCurrItems(); - instance.updateSize(true); + fetching[item.dataIndex] = true; + let url: string; + if (galleryContext.files.has(item.id)) { + url = galleryContext.files.get(item.id); + } else { + url = await DownloadManager.getFile(item, true); + galleryContext.files.set(item.id, url); + } + await updateSrcUrl(item.dataIndex, url); + item.html = files[item.dataIndex].html; + item.src = files[item.dataIndex].src; + item.w = files[item.dataIndex].w; + item.h = files[item.dataIndex].h; + try { + instance.invalidateCurrItems(); + instance.updateSize(true); + } catch (e) { + // ignore + } } catch (e) { - // ignore + // no-op + } finally { + fetching[item.dataIndex] = false; } } }; diff --git a/src/components/pages/gallery/PreviewCard.tsx b/src/components/pages/gallery/PreviewCard.tsx index 5c698ffb0..bacbff199 100644 --- a/src/components/pages/gallery/PreviewCard.tsx +++ b/src/components/pages/gallery/PreviewCard.tsx @@ -128,15 +128,19 @@ export default function PreviewCard(props: IProps) { useLayoutEffect(() => { if (file && !file.msrc) { const main = async () => { - const url = await DownloadManager.getPreview(file); - if (isMounted.current) { - setImgSrc(url); - thumbs.set(file.id, url); - file.msrc = url; - if (!file.src) { - file.src = url; + try { + const url = await DownloadManager.getPreview(file); + if (isMounted.current) { + setImgSrc(url); + thumbs.set(file.id, url); + file.msrc = url; + if (!file.src) { + file.src = url; + } + updateUrl(url); } - updateUrl(url); + } catch (e) { + // no-op } }; diff --git a/src/services/downloadManager.ts b/src/services/downloadManager.ts index 380841e7d..40448fd51 100644 --- a/src/services/downloadManager.ts +++ b/src/services/downloadManager.ts @@ -35,6 +35,7 @@ class DownloadManager { } catch (e) { this.thumbnailObjectUrlPromise.delete(file.id); logError(e, 'get preview Failed'); + throw e; } } @@ -84,6 +85,7 @@ class DownloadManager { } catch (e) { this.fileObjectUrlPromise.delete(fileUID); logError(e, 'Failed to get File'); + throw e; } }; From 18b27f5f088c111ef0eb70cc14dde19cc4e44af4 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Thu, 21 Oct 2021 16:12:00 +0530 Subject: [PATCH 31/42] dont have seperate preview file entry for video --- src/services/downloadManager.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/services/downloadManager.ts b/src/services/downloadManager.ts index 40448fd51..a0545ea85 100644 --- a/src/services/downloadManager.ts +++ b/src/services/downloadManager.ts @@ -68,7 +68,12 @@ class DownloadManager { }; getFile = async (file: File, forPreview = false) => { - const fileUID = `${file.id}_${forPreview}`; + let fileUID: string; + if (file.metadata.fileType === FILE_TYPE.VIDEO) { + fileUID = file.id.toString(); + } else { + fileUID = `${file.id}_forPreview=${forPreview}`; + } try { const getFilePromise = async () => { const fileStream = await this.downloadFile(file); From dac5ea727ad03296f8073ab3e09b31e397cace91 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Mon, 25 Oct 2021 20:07:51 +0530 Subject: [PATCH 32/42] updated min and max compression quality and MAX_THUMBNAIL_SIZE --- src/services/upload/thumbnailService.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index 39fd9449d..0e2949343 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -6,7 +6,9 @@ import FFmpegService from 'services/ffmpegService'; const THUMBNAIL_HEIGHT = 720; const MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF = 10; -export const MAX_THUMBNAIL_SIZE = 50 * 1024; +export const MAX_THUMBNAIL_SIZE = 100 * 1024; +const MIN_COMPRESSION_QUALITY = 0.7; +const MAX_COMPRESSION_QUALITY = 0.1; const WAIT_TIME_THUMBNAIL_GENERATION = 10 * 1000; @@ -173,7 +175,7 @@ export async function generateVideoThumbnail(file: globalThis.File) { async function thumbnailCanvasToBlob(canvas: HTMLCanvasElement) { let thumbnailBlob: Blob = null; let prevSize = Number.MAX_SAFE_INTEGER; - let quality = 1; + let quality = MIN_COMPRESSION_QUALITY; do { if (thumbnailBlob) { @@ -191,7 +193,7 @@ async function thumbnailCanvasToBlob(canvas: HTMLCanvasElement) { thumbnailBlob = thumbnailBlob ?? new Blob([]); quality -= 0.1; } while ( - quality > 0 && + quality > MAX_COMPRESSION_QUALITY && thumbnailBlob.size > MAX_THUMBNAIL_SIZE && percentageSizeDiff(thumbnailBlob.size, prevSize) >= MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF From 192229e1e1901f88d280d06ba975c527640a529a Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 26 Oct 2021 11:36:58 +0530 Subject: [PATCH 33/42] reduce max-compression quality to 50% --- src/services/upload/thumbnailService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index 0e2949343..725bc0e4e 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -8,7 +8,7 @@ const THUMBNAIL_HEIGHT = 720; const MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF = 10; export const MAX_THUMBNAIL_SIZE = 100 * 1024; const MIN_COMPRESSION_QUALITY = 0.7; -const MAX_COMPRESSION_QUALITY = 0.1; +const MAX_COMPRESSION_QUALITY = 0.5; const WAIT_TIME_THUMBNAIL_GENERATION = 10 * 1000; From e984eb9be9f9d00521407dee53aa373eae512fca Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 26 Oct 2021 12:10:05 +0530 Subject: [PATCH 34/42] improve variable names and fix compression loop condition --- src/services/upload/thumbnailService.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index 725bc0e4e..a0a9a5517 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -7,8 +7,8 @@ import FFmpegService from 'services/ffmpegService'; const THUMBNAIL_HEIGHT = 720; const MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF = 10; export const MAX_THUMBNAIL_SIZE = 100 * 1024; -const MIN_COMPRESSION_QUALITY = 0.7; -const MAX_COMPRESSION_QUALITY = 0.5; +const MIN_QUALITY = 0.5; +const MAX_QUALITY = 0.7; const WAIT_TIME_THUMBNAIL_GENERATION = 10 * 1000; @@ -175,7 +175,7 @@ export async function generateVideoThumbnail(file: globalThis.File) { async function thumbnailCanvasToBlob(canvas: HTMLCanvasElement) { let thumbnailBlob: Blob = null; let prevSize = Number.MAX_SAFE_INTEGER; - let quality = MIN_COMPRESSION_QUALITY; + let quality = MAX_QUALITY; do { if (thumbnailBlob) { @@ -193,7 +193,7 @@ async function thumbnailCanvasToBlob(canvas: HTMLCanvasElement) { thumbnailBlob = thumbnailBlob ?? new Blob([]); quality -= 0.1; } while ( - quality > MAX_COMPRESSION_QUALITY && + quality >= MIN_QUALITY && thumbnailBlob.size > MAX_THUMBNAIL_SIZE && percentageSizeDiff(thumbnailBlob.size, prevSize) >= MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF From 23356bf1328382d8e80f104c9b1a80b3e522151a Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 27 Oct 2021 08:46:06 +0530 Subject: [PATCH 35/42] update thubnail dimension calculation --- src/services/upload/thumbnailService.ts | 53 ++++++++++++++++++------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index a0a9a5517..85ab21193 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -4,14 +4,18 @@ import { logError } from 'utils/sentry'; import { BLACK_THUMBNAIL_BASE64 } from '../../../public/images/black-thumbnail-b64'; import FFmpegService from 'services/ffmpegService'; -const THUMBNAIL_HEIGHT = 720; +const MAX_THUMBNAIL_HEIGHT = 720; +const MAX_THUMBNAIL_WIDTH = 1280; const MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF = 10; export const MAX_THUMBNAIL_SIZE = 100 * 1024; const MIN_QUALITY = 0.5; const MAX_QUALITY = 0.7; const WAIT_TIME_THUMBNAIL_GENERATION = 10 * 1000; - +interface Dimension { + width: number; + height: number; +} export async function generateThumbnail( worker, file: globalThis.File, @@ -81,16 +85,18 @@ export async function generateImageThumbnail( await new Promise((resolve, reject) => { image.onload = () => { try { - const thumbnailWidth = - (image.width * THUMBNAIL_HEIGHT) / image.height; - canvas.width = thumbnailWidth; - canvas.height = THUMBNAIL_HEIGHT; + const thumbnailDimension = calculateThumbnailDimension({ + width: image.width, + height: image.height, + }); + canvas.width = thumbnailDimension.width; + canvas.height = thumbnailDimension.height; canvasCTX.drawImage( image, 0, 0, - thumbnailWidth, - THUMBNAIL_HEIGHT + thumbnailDimension.width, + thumbnailDimension.height ); image = null; clearTimeout(timeout); @@ -133,16 +139,18 @@ export async function generateVideoThumbnail(file: globalThis.File) { if (!video) { throw Error('video load failed'); } - const thumbnailWidth = - (video.videoWidth * THUMBNAIL_HEIGHT) / video.videoHeight; - canvas.width = thumbnailWidth; - canvas.height = THUMBNAIL_HEIGHT; + const thumbnailDimension = calculateThumbnailDimension({ + width: video.videoWidth, + height: video.videoHeight, + }); + canvas.width = thumbnailDimension.width; + canvas.height = thumbnailDimension.height; canvasCTX.drawImage( video, 0, 0, - thumbnailWidth, - THUMBNAIL_HEIGHT + thumbnailDimension.width, + thumbnailDimension.height ); video = null; clearTimeout(timeout); @@ -214,3 +222,20 @@ function percentageSizeDiff( ) { return ((oldThumbnailSize - newThumbnailSize) * 100) / oldThumbnailSize; } + +function calculateThumbnailDimension(OriginalDimension: Dimension): Dimension { + if (OriginalDimension.height === 0 || OriginalDimension.width === 0) { + return { width: 0, height: 0 }; + } + const widthScaleFactor = MAX_THUMBNAIL_WIDTH / OriginalDimension.width; + const heightScaleFactor = MAX_THUMBNAIL_HEIGHT / OriginalDimension.height; + const scaleFactor = Math.min(widthScaleFactor, heightScaleFactor); + const thumbnailDimension = { + width: Math.round(OriginalDimension.width * scaleFactor), + height: Math.round(OriginalDimension.height * scaleFactor), + }; + if (thumbnailDimension.width === 0 || thumbnailDimension.height === 0) { + return { width: 0, height: 0 }; + } + return thumbnailDimension; +} From 01dc6142d0d314e96ead5069800772f7e79497a5 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 27 Oct 2021 08:53:29 +0530 Subject: [PATCH 36/42] log thumbnail dimension too --- src/services/upload/thumbnailService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index 85ab21193..b2725d3d1 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -3,6 +3,7 @@ import { CustomError, errorWithContext } from 'utils/common/errorUtil'; import { logError } from 'utils/sentry'; import { BLACK_THUMBNAIL_BASE64 } from '../../../public/images/black-thumbnail-b64'; import FFmpegService from 'services/ffmpegService'; +import { convertToHumanReadable } from 'utils/billingUtil'; const MAX_THUMBNAIL_HEIGHT = 720; const MAX_THUMBNAIL_WIDTH = 1280; @@ -209,7 +210,8 @@ async function thumbnailCanvasToBlob(canvas: HTMLCanvasElement) { if (thumbnailBlob.size > MAX_THUMBNAIL_SIZE) { logError( Error('thumbnail_too_large'), - 'thumbnail greater than max limit' + 'thumbnail greater than max limit', + { thumbnailSize: convertToHumanReadable(thumbnailBlob.size) } ); } From 60c820a9be3e42e667a32ad94b7bb6a218039a21 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 27 Oct 2021 08:59:02 +0530 Subject: [PATCH 37/42] refactor code --- src/services/upload/thumbnailService.ts | 28 +++++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index b2725d3d1..0bf7642ff 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -5,8 +5,7 @@ import { BLACK_THUMBNAIL_BASE64 } from '../../../public/images/black-thumbnail-b import FFmpegService from 'services/ffmpegService'; import { convertToHumanReadable } from 'utils/billingUtil'; -const MAX_THUMBNAIL_HEIGHT = 720; -const MAX_THUMBNAIL_WIDTH = 1280; +const MAX_THUMBNAIL_DIMENSION: Dimension = { width: 1280, height: 720 }; const MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF = 10; export const MAX_THUMBNAIL_SIZE = 100 * 1024; const MIN_QUALITY = 0.5; @@ -86,10 +85,14 @@ export async function generateImageThumbnail( await new Promise((resolve, reject) => { image.onload = () => { try { - const thumbnailDimension = calculateThumbnailDimension({ + const imageDimension = { width: image.width, height: image.height, - }); + }; + const thumbnailDimension = calculateThumbnailDimension( + imageDimension, + MAX_THUMBNAIL_DIMENSION + ); canvas.width = thumbnailDimension.width; canvas.height = thumbnailDimension.height; canvasCTX.drawImage( @@ -140,10 +143,14 @@ export async function generateVideoThumbnail(file: globalThis.File) { if (!video) { throw Error('video load failed'); } - const thumbnailDimension = calculateThumbnailDimension({ + const videoDimension = { width: video.videoWidth, height: video.videoHeight, - }); + }; + const thumbnailDimension = calculateThumbnailDimension( + videoDimension, + MAX_THUMBNAIL_DIMENSION + ); canvas.width = thumbnailDimension.width; canvas.height = thumbnailDimension.height; canvasCTX.drawImage( @@ -225,12 +232,15 @@ function percentageSizeDiff( return ((oldThumbnailSize - newThumbnailSize) * 100) / oldThumbnailSize; } -function calculateThumbnailDimension(OriginalDimension: Dimension): Dimension { +function calculateThumbnailDimension( + OriginalDimension: Dimension, + maxDimension: Dimension +): Dimension { if (OriginalDimension.height === 0 || OriginalDimension.width === 0) { return { width: 0, height: 0 }; } - const widthScaleFactor = MAX_THUMBNAIL_WIDTH / OriginalDimension.width; - const heightScaleFactor = MAX_THUMBNAIL_HEIGHT / OriginalDimension.height; + const widthScaleFactor = maxDimension.width / OriginalDimension.width; + const heightScaleFactor = maxDimension.height / OriginalDimension.height; const scaleFactor = Math.min(widthScaleFactor, heightScaleFactor); const thumbnailDimension = { width: Math.round(OriginalDimension.width * scaleFactor), From 81c77790dfbe1dc93a69813e67e0cf1f93825790 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 27 Oct 2021 09:06:27 +0530 Subject: [PATCH 38/42] add comments --- src/services/upload/thumbnailService.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index 0bf7642ff..568621d29 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -232,6 +232,8 @@ function percentageSizeDiff( return ((oldThumbnailSize - newThumbnailSize) * 100) / oldThumbnailSize; } +// method to calculate new size of image for limiting it to maximum width and height, maintaining aspect ratio +// returns {0,0} for invalid inputs function calculateThumbnailDimension( OriginalDimension: Dimension, maxDimension: Dimension From 242deebb4c48ed602b65db92143b0f37e81249be Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 27 Oct 2021 10:30:57 +0530 Subject: [PATCH 39/42] make max dimension(width or height) = 720px --- src/services/upload/thumbnailService.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index 568621d29..a30a31af4 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -5,17 +5,19 @@ import { BLACK_THUMBNAIL_BASE64 } from '../../../public/images/black-thumbnail-b import FFmpegService from 'services/ffmpegService'; import { convertToHumanReadable } from 'utils/billingUtil'; -const MAX_THUMBNAIL_DIMENSION: Dimension = { width: 1280, height: 720 }; +const MAX_THUMBNAIL_DIMENSION = 720; const MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF = 10; export const MAX_THUMBNAIL_SIZE = 100 * 1024; const MIN_QUALITY = 0.5; const MAX_QUALITY = 0.7; const WAIT_TIME_THUMBNAIL_GENERATION = 10 * 1000; + interface Dimension { width: number; height: number; } + export async function generateThumbnail( worker, file: globalThis.File, @@ -236,13 +238,13 @@ function percentageSizeDiff( // returns {0,0} for invalid inputs function calculateThumbnailDimension( OriginalDimension: Dimension, - maxDimension: Dimension + maxDimension: number ): Dimension { if (OriginalDimension.height === 0 || OriginalDimension.width === 0) { return { width: 0, height: 0 }; } - const widthScaleFactor = maxDimension.width / OriginalDimension.width; - const heightScaleFactor = maxDimension.height / OriginalDimension.height; + const widthScaleFactor = maxDimension / OriginalDimension.width; + const heightScaleFactor = maxDimension / OriginalDimension.height; const scaleFactor = Math.min(widthScaleFactor, heightScaleFactor); const thumbnailDimension = { width: Math.round(OriginalDimension.width * scaleFactor), From e850c8c24286212719a18ff5de8d35269a6dfe31 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 27 Oct 2021 10:55:43 +0530 Subject: [PATCH 40/42] fix typo --- src/services/upload/thumbnailService.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index a30a31af4..586a396af 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -237,18 +237,18 @@ function percentageSizeDiff( // method to calculate new size of image for limiting it to maximum width and height, maintaining aspect ratio // returns {0,0} for invalid inputs function calculateThumbnailDimension( - OriginalDimension: Dimension, + originalDimension: Dimension, maxDimension: number ): Dimension { - if (OriginalDimension.height === 0 || OriginalDimension.width === 0) { + if (originalDimension.height === 0 || originalDimension.width === 0) { return { width: 0, height: 0 }; } - const widthScaleFactor = maxDimension / OriginalDimension.width; - const heightScaleFactor = maxDimension / OriginalDimension.height; + const widthScaleFactor = maxDimension / originalDimension.width; + const heightScaleFactor = maxDimension / originalDimension.height; const scaleFactor = Math.min(widthScaleFactor, heightScaleFactor); const thumbnailDimension = { - width: Math.round(OriginalDimension.width * scaleFactor), - height: Math.round(OriginalDimension.height * scaleFactor), + width: Math.round(originalDimension.width * scaleFactor), + height: Math.round(originalDimension.height * scaleFactor), }; if (thumbnailDimension.width === 0 || thumbnailDimension.height === 0) { return { width: 0, height: 0 }; From b587ea70faaddca167e7f96512b547b4cec98fa3 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 27 Oct 2021 12:43:03 +0530 Subject: [PATCH 41/42] fix file name of ffmpeg in-memory file --- src/services/ffmpegService.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/services/ffmpegService.ts b/src/services/ffmpegService.ts index 13b7bde7e..fb0e1d2e3 100644 --- a/src/services/ffmpegService.ts +++ b/src/services/ffmpegService.ts @@ -44,8 +44,8 @@ class FFmpegService { async function generateThumbnailHelper(ffmpeg: FFmpeg, file: File) { try { - const inputFileName = `${Date.now().toString}-${file.name}`; - const thumbFileName = `${Date.now().toString}-thumb.jpeg`; + const inputFileName = `${Date.now().toString()}-${file.name}`; + const thumbFileName = `${Date.now().toString()}-thumb.jpeg`; ffmpeg.FS( 'writeFile', inputFileName, @@ -62,7 +62,8 @@ async function generateThumbnailHelper(ffmpeg: FFmpeg, file: File) { `00:00:0${seekTime.toFixed(3)}`, '-vframes', '1', - '-vf scale=512:512', + '-vf', + 'scale=512:512', thumbFileName ); thumb = ffmpeg.FS('readFile', thumbFileName); From b07ffbd820be99a0e1fc7a7c5ffb1125a30d398e Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 27 Oct 2021 12:51:15 +0530 Subject: [PATCH 42/42] make ffmpeg thumbnail output height to 720 --- src/services/ffmpegService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/ffmpegService.ts b/src/services/ffmpegService.ts index fb0e1d2e3..4cfcdf9be 100644 --- a/src/services/ffmpegService.ts +++ b/src/services/ffmpegService.ts @@ -63,7 +63,7 @@ async function generateThumbnailHelper(ffmpeg: FFmpeg, file: File) { '-vframes', '1', '-vf', - 'scale=512:512', + 'scale=-1:720', thumbFileName ); thumb = ffmpeg.FS('readFile', thumbFileName);