Skip to content
This repository has been archived by the owner on Dec 27, 2024. It is now read-only.

Commit

Permalink
chore: fix HTML sanitization issue; add browse button for files; impr…
Browse files Browse the repository at this point in the history
…ove drop zone
  • Loading branch information
sircharlo committed Jun 19, 2024
1 parent eeda50e commit 57e76a0
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 71 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"AYFM",
"cctv",
"docid",
"dompurify",
"fileformat",
"fileurl",
"firefox",
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"axios": "^1.6.8",
"better-sqlite3": "^9.6.0",
"decompress": "^4.2.1",
"dompurify": "^3.1.5",
"electron-updater": "^6.2.1",
"fs-extra": "^11.2.0",
"heic-convert": "^2.1.0",
Expand All @@ -47,6 +48,7 @@
"@types/axios": "^0.14.0",
"@types/better-sqlite3": "^7.6.10",
"@types/decompress": "^4.2.7",
"@types/dompurify": "^3.0.5",
"@types/fs-extra": "^11.0.4",
"@types/heic-convert": "^1.2.3",
"@types/klaw-sync": "^6.0.5",
Expand Down
7 changes: 4 additions & 3 deletions src-electron/electron-preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { BrowserWindow, app, dialog, screen } from '@electron/remote';
import * as sqlite3 from 'better-sqlite3';
import decompress from 'decompress';
import { contextBridge } from 'electron';
import { PathLike } from 'fs';
import fs from 'fs-extra';
import convert from 'heic-convert';
import klawSync from 'klaw-sync';
Expand Down Expand Up @@ -227,7 +228,7 @@ contextBridge.exposeInMainWorld('electronApi', {
return {};
}
},
fileUrlToPath: (fileurl: string) => {
fileUrlToPath: (fileurl: PathLike) => {
const url = require('node:url');
return url.fileURLToPath(fileurl);
},
Expand All @@ -241,8 +242,8 @@ contextBridge.exposeInMainWorld('electronApi', {
},
klawSync,
moveMediaWindow,
openFileDialog: () => {
return dialog.showOpenDialogSync({
openFileDialog: async () => {
return await dialog.showOpenDialog({
properties: ['openFile', 'multiSelections'],
});
},
Expand Down
5 changes: 3 additions & 2 deletions src/helpers/electron-api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { PathLike } from 'fs';
import { QueryResponseItem } from 'src/types/sqlite';

export interface ElectronFileFilter {
Expand All @@ -9,7 +10,7 @@ export interface ElectronApi {
convert: typeof import('heic-convert');
decompress: typeof import('decompress');
executeQuery: (dbPath: string, query: string) => QueryResponseItem[];
fileUrlToPath: (url: string) => string;
fileUrlToPath: (url: PathLike) => string;
fs: typeof import('fs-extra');
getAllScreens: (
type?: string,
Expand All @@ -25,7 +26,7 @@ export interface ElectronApi {
targetScreen?: number;
windowedMode?: boolean;
}) => void;
openFileDialog: () => string[];
openFileDialog: () => Promise<Electron.OpenDialogReturnValue>;
openFolderDialog: () => string[];
path: typeof import('path');
setAutoStartAtLogin: (value: boolean) => void;
Expand Down
19 changes: 13 additions & 6 deletions src/helpers/fs.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Buffer } from 'buffer';
import { Item } from 'klaw-sync';
import { FULL_HD } from 'src/helpers/converters';
import { electronApi } from 'src/helpers/electron-api';
Expand Down Expand Up @@ -79,9 +80,10 @@ const getDurationFromMediaPath: (mediaPath: string) => Promise<number> = (
});
};

const getThumbnailFromVideoPath: (videoPath: string) => Promise<string> = (
const getThumbnailFromVideoPath: (
videoPath: string,
) => {
thumbnailPath: string,
) => Promise<string> = (videoPath: string, thumbnailPath: string) => {
return new Promise((resolve, reject) => {
if (!videoPath) {
reject(new Error('No video path provided'));
Expand Down Expand Up @@ -109,12 +111,17 @@ const getThumbnailFromVideoPath: (videoPath: string) => Promise<string> = (
if (ctx) {
ctx.drawImage(videoRef, 0, 0, canvas.width, canvas.height);
const imageUrl = canvas.toDataURL('image/jpeg');
// save to file
fs.writeFileSync(
thumbnailPath,
Buffer.from(imageUrl.split(',')[1], 'base64'),
);

// Cleanup
canvas.remove();
videoRef.remove();

resolve(imageUrl);
resolve(thumbnailPath);
} else {
// Cleanup in case of error
canvas.remove();
Expand All @@ -137,7 +144,7 @@ const getThumbnailFromVideoPath: (videoPath: string) => Promise<string> = (
});
};

const getThumbnailUrl = async (filepath: string) => {
const getThumbnailUrl = async (filepath: string, forceRefresh?: boolean) => {
let thumbnailUrl = '';
if (isImage(filepath)) {
thumbnailUrl = getFileUrl(filepath);
Expand All @@ -146,10 +153,10 @@ const getThumbnailUrl = async (filepath: string) => {
if (fs.existsSync(thumbnailPath)) {
thumbnailUrl = getFileUrl(thumbnailPath);
} else {
thumbnailUrl = await getThumbnailFromVideoPath(filepath);
thumbnailUrl = await getThumbnailFromVideoPath(filepath, thumbnailPath);
}
}
return thumbnailUrl;
return thumbnailUrl + (forceRefresh ? '?timestamp=' + Date.now() : '');
};

const getSubtitlesUrl = async (
Expand Down
3 changes: 2 additions & 1 deletion src/i18n/en-US/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -172,5 +172,6 @@
"setup-wizard": "Setup Wizard",
"footnote": "Footnote",
"windowed": "Windowed",
"you-can-also-use-the-button-below-to-browse-for-files": "You can also use the button below to browse for files."
"you-can-also-use-the-button-below-to-browse-for-files": "You can also browse for files manually if you prefer.",
"browse": "Browse"
}
2 changes: 1 addition & 1 deletion src/i18n/fr-CA/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -356,5 +356,5 @@
"congregationMeetings": "Réunions de l'assemblée locale",
"applicationConfigurationDescription": "Personnaliser le comportement et l'apparence de cette application",
"applicationConfiguration": "Configuration de l'application",
"you-can-also-use-the-button-below-to-browse-for-files": "Vous pouvez également utiliser le bouton ci-dessous pour sélectionner des fichiers."
"you-can-also-use-the-button-below-to-browse-for-files": "Vous pouvez également parcourir et sélectionner des fichiers manuellement, si vous le désirez."
}
55 changes: 41 additions & 14 deletions src/layouts/MainLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@
</q-item-section>
<q-item-section>{{ $t('song') }}</q-item-section>
</q-item>
<q-item @click="localUpload = true" clickable v-close-popup>
<q-item
@click="localUploadPopup = true"
clickable
v-close-popup
>
<q-item-section avatar>
<q-icon color="primary" name="mdi-movie-open-play" />
</q-item-section>
Expand All @@ -49,7 +53,11 @@
['mdi-playlist-play', 'JW Playlist'],
]"
>
<q-item @click="localUpload = true" clickable v-close-popup>
<q-item
@click="localUploadPopup = true"
clickable
v-close-popup
>
<q-item-section avatar>
<q-icon :name="icon" color="primary" />
</q-item-section>
Expand Down Expand Up @@ -104,7 +112,10 @@
</q-date>
</q-popup-proxy>
</q-btn>
<q-dialog @dragenter="localUpload = false" v-model="localUpload">
<q-dialog
@dragenter="localUploadPopup = false"
v-model="localUploadPopup"
>
<q-card>
<q-card-section horizontal>
<q-card-section>
Expand All @@ -115,30 +126,29 @@
text-color="white"
/></q-card-section>
<q-card-section>
<div class="text-h6">{{ $t('add-media-files') }}</div>
<p>
{{
$t(
'to-add-files-from-your-computer-drag-and-drop-them-directly-into-this-window',
)
}}
</p>
<p>
{{
$t(
'you-can-also-use-the-button-below-to-browse-for-files',
)
}}
</p></q-card-section
>
</p>
</q-card-section>
</q-card-section>
<q-card-actions align="right">
<q-btn @click="localUpload = false" label="Browse" />
<q-btn
:label="$t('got-it')"
:label="$t('browse')"
@click="getLocalFiles()"
color="primary"
flat
v-close-popup
/>
<q-btn :label="$t('got-it')" color="primary" v-close-popup />
</q-card-actions>
</q-card>
</q-dialog>
Expand Down Expand Up @@ -331,7 +341,7 @@ jwStore.$subscribe((_, state) => {
// Ref and reactive initializations
const chooseSong = ref(false);
const mediaSortForDay = ref(true);
const { setAutoStartAtLogin } = electronApi;
const { openFileDialog, setAutoStartAtLogin } = electronApi;
const { locale, t } = useI18n({ useScope: 'global' });
const drawer = ref(true);
Expand Down Expand Up @@ -404,8 +414,8 @@ watch(
watch(
() => currentSettings.value?.autoStartAtLogin,
(newautoStartAtLogin) => {
setAutoStartAtLogin(!!newautoStartAtLogin);
(newAutoStartAtLogin) => {
setAutoStartAtLogin(!!newAutoStartAtLogin);
},
);
Expand Down Expand Up @@ -442,7 +452,7 @@ const getEventDates = () => {
};
// Ref for UI states
const localUpload = ref(false);
const localUploadPopup = ref(false);
const importMediaMenuActive = ref(false);
const datePickerActive = ref(false);
Expand All @@ -459,6 +469,23 @@ if (!migrations.value.includes('firstRun')) {
}
}
const getLocalFiles = async () => {
openFileDialog().then((result) => {
if (result.filePaths.length > 0) {
window.dispatchEvent(
new CustomEvent('localFiles-browsed', {
detail: result.filePaths.map((path) => {
return {
path,
};
}),
}),
);
}
localUploadPopup.value = false;
});
};
onMounted(() => {
document.title = 'Meeting Media Manager';
console.log(currentSettings.value);
Expand Down
Loading

0 comments on commit 57e76a0

Please sign in to comment.