✌️
This commit is contained in:
		
							parent
							
								
									0ed6f4d86c
								
							
						
					
					
						commit
						323d020caf
					
				
					 8 changed files with 115 additions and 93 deletions
				
			
		|  | @ -97,6 +97,7 @@ import * as os from '@/os'; | |||
| import { stream } from '@/stream'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import { uploadFile, uploads } from '@/scripts/upload'; | ||||
| 
 | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	initialFolder?: Misskey.entities.DriveFolder; | ||||
|  | @ -127,8 +128,9 @@ const moreFolders = ref(false); | |||
| const hierarchyFolders = ref<Misskey.entities.DriveFolder[]>([]); | ||||
| const selectedFiles = ref<Misskey.entities.DriveFile[]>([]); | ||||
| const selectedFolders = ref<Misskey.entities.DriveFolder[]>([]); | ||||
| const uploadings = os.uploads; | ||||
| const uploadings = uploads; | ||||
| const connection = stream.useChannel('drive'); | ||||
| let keepOriginal = $ref<boolean>(defaultStore.state.keepOriginalUploading); | ||||
| 
 | ||||
| // ドロップされようとしているか | ||||
| const draghover = ref(false); | ||||
|  | @ -355,7 +357,7 @@ function onChangeFileInput() { | |||
| } | ||||
| 
 | ||||
| function upload(file: File, folderToUpload?: Misskey.entities.DriveFolder | null) { | ||||
| 	os.upload(file, (folderToUpload && typeof folderToUpload == 'object') ? folderToUpload.id : null).then(res => { | ||||
| 	uploadFile(file, (folderToUpload && typeof folderToUpload == 'object') ? folderToUpload.id : null, undefined, keepOriginal).then(res => { | ||||
| 		addFile(res, true); | ||||
| 	}); | ||||
| } | ||||
|  | @ -562,6 +564,10 @@ function fetchMoreFiles() { | |||
| 
 | ||||
| function getMenu() { | ||||
| 	return [{ | ||||
| 		type: 'switch', | ||||
| 		text: i18n.ts.keepOriginalUploading, | ||||
| 		ref: keepOriginal, | ||||
| 	}, null, { | ||||
| 		text: i18n.ts.addFile, | ||||
| 		type: 'label' | ||||
| 	}, { | ||||
|  |  | |||
|  | @ -87,6 +87,7 @@ import MkInfo from '@/components/ui/info.vue'; | |||
| import { i18n } from '@/i18n'; | ||||
| import { instance } from '@/instance'; | ||||
| import { $i, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account'; | ||||
| import { uploadFile } from '@/scripts/upload'; | ||||
| 
 | ||||
| const modal = inject('modal'); | ||||
| 
 | ||||
|  | @ -366,7 +367,7 @@ function updateFileName(file, name) { | |||
| } | ||||
| 
 | ||||
| function upload(file: File, name?: string) { | ||||
| 	os.upload(file, defaultStore.state.uploadFolder, name).then(res => { | ||||
| 	uploadFile(file, defaultStore.state.uploadFolder, name).then(res => { | ||||
| 		files.push(res); | ||||
| 	}); | ||||
| } | ||||
|  |  | |||
|  | @ -10,8 +10,6 @@ import MkWaitingDialog from '@/components/waiting-dialog.vue'; | |||
| import { MenuItem } from '@/types/menu'; | ||||
| import { resolve } from '@/router'; | ||||
| import { $i } from '@/account'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import { readAndCompressImage } from 'browser-image-resizer'; | ||||
| 
 | ||||
| export const pendingApiRequestsCount = ref(0); | ||||
| 
 | ||||
|  | @ -536,90 +534,6 @@ export function post(props: Record<string, any> = {}) { | |||
| 
 | ||||
| export const deckGlobalEvents = new EventEmitter(); | ||||
| 
 | ||||
| export const uploads = ref<{ | ||||
| 	id: string; | ||||
| 	name: string; | ||||
| 	progressMax: number | undefined; | ||||
| 	progressValue: number | undefined; | ||||
| 	img: string; | ||||
| }[]>([]); | ||||
| 
 | ||||
| export function upload(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({ | ||||
| 				id: id, | ||||
| 				name: name || file.name || 'untitled', | ||||
| 				progressMax: undefined, | ||||
| 				progressValue: undefined, | ||||
| 				img: window.URL.createObjectURL(file) | ||||
| 			}); | ||||
| 
 | ||||
| 			let resizedImage: any; | ||||
| 			if (file.type === 'image/jpeg') { | ||||
| 				const config = { | ||||
| 					quality: 0.85, | ||||
| 					maxWidth: 2048, | ||||
| 					maxHeight: 2048, | ||||
| 					autoRotate: true, | ||||
| 					debug: true | ||||
| 				}; | ||||
| 				resizedImage = await readAndCompressImage(file, config); | ||||
| 			} | ||||
| 
 | ||||
| 			uploads.value.push(ctx); | ||||
| 
 | ||||
| 			console.log(keepOriginal); | ||||
| 
 | ||||
| 			const data = new FormData(); | ||||
| 			data.append('i', $i.token); | ||||
| 			data.append('force', 'true'); | ||||
| 			data.append('file', resizedImage || file); | ||||
| 
 | ||||
| 			if (folder) data.append('folderId', folder); | ||||
| 			if (name) data.append('name', name); | ||||
| 
 | ||||
| 			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', | ||||
| 						text: 'upload failed' | ||||
| 					}); | ||||
| 
 | ||||
| 					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); | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| export function checkExistence(fileData: ArrayBuffer): Promise<any> { | ||||
| 	return new Promise((resolve, reject) => { | ||||
|  |  | |||
|  | @ -31,6 +31,7 @@ import * as os from '@/os'; | |||
| import { stream } from '@/stream'; | ||||
| import { Autocomplete } from '@/scripts/autocomplete'; | ||||
| import { throttle } from 'throttle-debounce'; | ||||
| import { uploadFile } from '@/scripts/upload'; | ||||
| 
 | ||||
| export default defineComponent({ | ||||
| 	props: { | ||||
|  | @ -164,7 +165,7 @@ export default defineComponent({ | |||
| 		}, | ||||
| 
 | ||||
| 		upload(file: File, name?: string) { | ||||
| 			os.upload(file, this.$store.state.uploadFolder, name).then(res => { | ||||
| 			uploadFile(file, this.$store.state.uploadFolder, name).then(res => { | ||||
| 				this.file = res; | ||||
| 			}); | ||||
| 		}, | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ import { stream } from '@/stream'; | |||
| import { i18n } from '@/i18n'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import { DriveFile } from 'misskey-js/built/entities'; | ||||
| import { uploadFile } from '@/scripts/upload'; | ||||
| 
 | ||||
| function select(src: any, label: string | null, multiple: boolean): Promise<DriveFile | DriveFile[]> { | ||||
| 	return new Promise((res, rej) => { | ||||
|  | @ -14,7 +15,7 @@ function select(src: any, label: string | null, multiple: boolean): Promise<Driv | |||
| 			input.type = 'file'; | ||||
| 			input.multiple = multiple; | ||||
| 			input.onchange = () => { | ||||
| 				const promises = Array.from(input.files).map(file => os.upload(file, defaultStore.state.uploadFolder, undefined, keepOriginal.value)); | ||||
| 				const promises = Array.from(input.files).map(file => uploadFile(file, defaultStore.state.uploadFolder, undefined, keepOriginal.value)); | ||||
| 
 | ||||
| 				Promise.all(promises).then(driveFiles => { | ||||
| 					res(multiple ? driveFiles : driveFiles[0]); | ||||
|  |  | |||
							
								
								
									
										98
									
								
								packages/client/src/scripts/upload.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								packages/client/src/scripts/upload.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,98 @@ | |||
| import { reactive, ref } from 'vue'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import { readAndCompressImage } from 'browser-image-resizer'; | ||||
| import { apiUrl } from '@/config'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { $i } from '@/account'; | ||||
| 
 | ||||
| type Uploading = { | ||||
| 	id: string; | ||||
| 	name: string; | ||||
| 	progressMax: number | undefined; | ||||
| 	progressValue: number | undefined; | ||||
| 	img: string; | ||||
| }; | ||||
| export const uploads = ref<Uploading[]>([]); | ||||
| 
 | ||||
| const compressTypeMap = new Map([ | ||||
| 	// [圧縮前の形式, 圧縮後の形式],
 | ||||
| 	['image/jpeg', 'image/jpeg'], | ||||
| 	['image/webp', 'image/jpeg'], | ||||
| 	['image/png', 'image/png'], | ||||
| 	['image/svg', 'image/png'], | ||||
| ]); | ||||
| 
 | ||||
| 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) | ||||
| 			}); | ||||
| 
 | ||||
| 			let resizedImage: any; | ||||
| 			if (!keepOriginal && compressTypeMap.has(file.type)) { | ||||
| 				const config = { | ||||
| 					quality: 0.85, | ||||
| 					maxWidth: 2048, | ||||
| 					maxHeight: 2048, | ||||
| 					autoRotate: true, | ||||
| 					mimeType: compressTypeMap.get(file.type), | ||||
| 					debug: true, | ||||
| 				}; | ||||
| 				resizedImage = await readAndCompressImage(file, config); | ||||
| 			} | ||||
| 
 | ||||
| 			uploads.value.push(ctx); | ||||
| 
 | ||||
| 			const data = new FormData(); | ||||
| 			data.append('i', $i.token); | ||||
| 			data.append('force', 'true'); | ||||
| 			data.append('file', resizedImage || file); | ||||
| 
 | ||||
| 			if (folder) data.append('folderId', folder); | ||||
| 			if (name) data.append('name', name); | ||||
| 
 | ||||
| 			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', | ||||
| 						text: 'upload failed' | ||||
| 					}); | ||||
| 
 | ||||
| 					reject(); | ||||
| 					return; | ||||
| 				} | ||||
| 
 | ||||
| 				const driveFile = JSON.parse(ev.target.response); | ||||
| 				console.log(driveFile) | ||||
| 				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); | ||||
| 	}); | ||||
| } | ||||
|  | @ -15,7 +15,8 @@ | |||
| 
 | ||||
| <script lang="ts"> | ||||
| import { defineAsyncComponent, defineComponent } from 'vue'; | ||||
| import { popup, popups, uploads, pendingApiRequestsCount } from '@/os'; | ||||
| import { popup, popups, pendingApiRequestsCount } from '@/os'; | ||||
| import { uploads } from '@/scripts/upload'; | ||||
| import * as sound from '@/scripts/sound'; | ||||
| import { $i } from '@/account'; | ||||
| import { stream } from '@/stream'; | ||||
|  |  | |||
|  | @ -20,8 +20,8 @@ | |||
| <script lang="ts" setup> | ||||
| import { } from 'vue'; | ||||
| import * as os from '@/os'; | ||||
| import { uploads } from '@/scripts/upload'; | ||||
| 
 | ||||
| const uploads = os.uploads; | ||||
| const zIndex = os.claimZIndex('high'); | ||||
| </script> | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue