summaryrefslogtreecommitdiff
path: root/packages/client/src/scripts/upload.ts
diff options
context:
space:
mode:
authortamaina <tamaina@hotmail.co.jp>2022-04-28 11:14:03 +0900
committerGitHub <noreply@github.com>2022-04-28 11:14:03 +0900
commit12a3c6872f0a31c923bf0cd7c183cb8776d58dda (patch)
tree7269d836ee2390cfb1cbb86b49338265d4234794 /packages/client/src/scripts/upload.ts
parentfix(client): fix lint issues in autocomplete (#8548) (diff)
downloadsharkey-12a3c6872f0a31c923bf0cd7c183cb8776d58dda.tar.gz
sharkey-12a3c6872f0a31c923bf0cd7c183cb8776d58dda.tar.bz2
sharkey-12a3c6872f0a31c923bf0cd7c183cb8776d58dda.zip
enhance: ドライブに画像ファイルをアップロードするときオリジナル画像を破棄してwebpublicのみ保持するオプション (#8216)
* wip * Update packages/client/src/os.ts Co-authored-by: tamaina <tamaina@hotmail.co.jp> * メニューをComposition API化、switchアイテム追加 クライアントサイド画像圧縮の準備 * メニュー型定義を分離 (TypeScriptの型支援が効かないので) * disabled * make keepOriginal to follow setting value * :v: * fix * fix * :v: * WEBP * aaa * :v: * webp * lazy load browser-image-resizer * rename * rename 2 * Fix * clean up * add comment * clean up * jpeg, pngにもどす * fix * fix name * webpでなくする ただしサムネやプレビューはwebpのまま (テスト) * 動画サムネイルはjpegに * エラーハンドリング * :v: * v2.2.1-misskey-beta.2 * browser-image-resizer#v2.2.1-misskey.1 * :v: * fix alert * update browser-image-resizer to v2.2.1-misskey.2 * lockfile Co-authored-by: mei23 <m@m544.net> Co-authored-by: MeiMei <30769358+mei23@users.noreply.github.com>
Diffstat (limited to 'packages/client/src/scripts/upload.ts')
-rw-r--r--packages/client/src/scripts/upload.ts114
1 files changed, 114 insertions, 0 deletions
diff --git a/packages/client/src/scripts/upload.ts b/packages/client/src/scripts/upload.ts
new file mode 100644
index 0000000000..7e4f793b44
--- /dev/null
+++ b/packages/client/src/scripts/upload.ts
@@ -0,0 +1,114 @@
+import { reactive, ref } from 'vue';
+import { defaultStore } from '@/store';
+import { apiUrl } from '@/config';
+import * as Misskey from 'misskey-js';
+import { $i } from '@/account';
+import { readAndCompressImage } from 'browser-image-resizer';
+import { alert } from '@/os';
+
+type Uploading = {
+ id: string;
+ name: string;
+ progressMax: number | undefined;
+ progressValue: number | undefined;
+ img: string;
+};
+export const uploads = ref<Uploading[]>([]);
+
+const compressTypeMap = {
+ 'image/jpeg': { quality: 0.85, mimeType: 'image/jpeg' },
+ 'image/webp': { quality: 0.85, mimeType: 'image/jpeg' },
+ 'image/svg+xml': { quality: 1, mimeType: 'image/png' },
+} as const;
+
+const mimeTypeMap = {
+ 'image/webp': 'webp',
+ 'image/jpeg': 'jpg',
+ 'image/png': 'png',
+} as const;
+
+export function uploadFile(
+ file: File,
+ folder?: any,
+ name?: string,
+ keepOriginal: boolean = defaultStore.state.keepOriginalUploading
+): Promise<Misskey.entities.DriveFile> {
+ if (folder && typeof folder == 'object') folder = folder.id;
+
+ return new Promise((resolve, reject) => {
+ const id = Math.random().toString();
+
+ const reader = new FileReader();
+ reader.onload = async (e) => {
+ const ctx = reactive<Uploading>({
+ id: id,
+ name: name || file.name || 'untitled',
+ progressMax: undefined,
+ progressValue: undefined,
+ img: window.URL.createObjectURL(file)
+ });
+
+ uploads.value.push(ctx);
+
+ let resizedImage: any;
+ if (!keepOriginal && file.type in compressTypeMap) {
+ const imgConfig = compressTypeMap[file.type];
+
+ const config = {
+ maxWidth: 2048,
+ maxHeight: 2048,
+ debug: true,
+ ...imgConfig,
+ };
+
+ try {
+ resizedImage = await readAndCompressImage(file, config);
+ ctx.name = file.type !== imgConfig.mimeType ? `${ctx.name}.${mimeTypeMap[compressTypeMap[file.type].mimeType]}` : ctx.name;
+ } catch (e) {
+ console.error('Failed to resize image', e);
+ }
+ }
+
+ const data = new FormData();
+ data.append('i', $i.token);
+ data.append('force', 'true');
+ data.append('file', resizedImage || file);
+ data.append('name', ctx.name);
+ if (folder) data.append('folderId', folder);
+
+ const xhr = new XMLHttpRequest();
+ xhr.open('POST', apiUrl + '/drive/files/create', true);
+ xhr.onload = (ev) => {
+ if (xhr.status !== 200 || ev.target == null || ev.target.response == null) {
+ // TODO: 消すのではなくて再送できるようにしたい
+ uploads.value = uploads.value.filter(x => x.id != id);
+
+ alert({
+ type: 'error',
+ title: 'Failed to upload',
+ text: `${JSON.stringify(ev.target?.response)}, ${JSON.stringify(xhr.response)}`
+ });
+
+ reject();
+ return;
+ }
+
+ const driveFile = JSON.parse(ev.target.response);
+
+ resolve(driveFile);
+
+ uploads.value = uploads.value.filter(x => x.id != id);
+ };
+
+ xhr.upload.onprogress = e => {
+ if (e.lengthComputable) {
+ ctx.progressMax = e.total;
+ ctx.progressValue = e.loaded;
+ }
+ };
+
+ xhr.send(data);
+ };
+ reader.readAsArrayBuffer(file);
+ });
+}