✌️
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 { stream } from '@/stream'; | ||||||
| import { defaultStore } from '@/store'; | import { defaultStore } from '@/store'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
|  | import { uploadFile, uploads } from '@/scripts/upload'; | ||||||
| 
 | 
 | ||||||
| const props = withDefaults(defineProps<{ | const props = withDefaults(defineProps<{ | ||||||
| 	initialFolder?: Misskey.entities.DriveFolder; | 	initialFolder?: Misskey.entities.DriveFolder; | ||||||
|  | @ -127,8 +128,9 @@ const moreFolders = ref(false); | ||||||
| const hierarchyFolders = ref<Misskey.entities.DriveFolder[]>([]); | const hierarchyFolders = ref<Misskey.entities.DriveFolder[]>([]); | ||||||
| const selectedFiles = ref<Misskey.entities.DriveFile[]>([]); | const selectedFiles = ref<Misskey.entities.DriveFile[]>([]); | ||||||
| const selectedFolders = ref<Misskey.entities.DriveFolder[]>([]); | const selectedFolders = ref<Misskey.entities.DriveFolder[]>([]); | ||||||
| const uploadings = os.uploads; | const uploadings = uploads; | ||||||
| const connection = stream.useChannel('drive'); | const connection = stream.useChannel('drive'); | ||||||
|  | let keepOriginal = $ref<boolean>(defaultStore.state.keepOriginalUploading); | ||||||
| 
 | 
 | ||||||
| // ドロップされようとしているか | // ドロップされようとしているか | ||||||
| const draghover = ref(false); | const draghover = ref(false); | ||||||
|  | @ -355,7 +357,7 @@ function onChangeFileInput() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function upload(file: File, folderToUpload?: Misskey.entities.DriveFolder | null) { | 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); | 		addFile(res, true); | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
|  | @ -562,6 +564,10 @@ function fetchMoreFiles() { | ||||||
| 
 | 
 | ||||||
| function getMenu() { | function getMenu() { | ||||||
| 	return [{ | 	return [{ | ||||||
|  | 		type: 'switch', | ||||||
|  | 		text: i18n.ts.keepOriginalUploading, | ||||||
|  | 		ref: keepOriginal, | ||||||
|  | 	}, null, { | ||||||
| 		text: i18n.ts.addFile, | 		text: i18n.ts.addFile, | ||||||
| 		type: 'label' | 		type: 'label' | ||||||
| 	}, { | 	}, { | ||||||
|  |  | ||||||
|  | @ -87,6 +87,7 @@ import MkInfo from '@/components/ui/info.vue'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import { instance } from '@/instance'; | import { instance } from '@/instance'; | ||||||
| import { $i, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account'; | import { $i, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account'; | ||||||
|  | import { uploadFile } from '@/scripts/upload'; | ||||||
| 
 | 
 | ||||||
| const modal = inject('modal'); | const modal = inject('modal'); | ||||||
| 
 | 
 | ||||||
|  | @ -366,7 +367,7 @@ function updateFileName(file, name) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function upload(file: File, name?: string) { | 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); | 		files.push(res); | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -10,8 +10,6 @@ import MkWaitingDialog from '@/components/waiting-dialog.vue'; | ||||||
| import { MenuItem } from '@/types/menu'; | import { MenuItem } from '@/types/menu'; | ||||||
| import { resolve } from '@/router'; | import { resolve } from '@/router'; | ||||||
| import { $i } from '@/account'; | import { $i } from '@/account'; | ||||||
| import { defaultStore } from '@/store'; |  | ||||||
| import { readAndCompressImage } from 'browser-image-resizer'; |  | ||||||
| 
 | 
 | ||||||
| export const pendingApiRequestsCount = ref(0); | export const pendingApiRequestsCount = ref(0); | ||||||
| 
 | 
 | ||||||
|  | @ -536,90 +534,6 @@ export function post(props: Record<string, any> = {}) { | ||||||
| 
 | 
 | ||||||
| export const deckGlobalEvents = new EventEmitter(); | 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> { | export function checkExistence(fileData: ArrayBuffer): Promise<any> { | ||||||
| 	return new Promise((resolve, reject) => { | 	return new Promise((resolve, reject) => { | ||||||
|  |  | ||||||
|  | @ -31,6 +31,7 @@ import * as os from '@/os'; | ||||||
| import { stream } from '@/stream'; | import { stream } from '@/stream'; | ||||||
| import { Autocomplete } from '@/scripts/autocomplete'; | import { Autocomplete } from '@/scripts/autocomplete'; | ||||||
| import { throttle } from 'throttle-debounce'; | import { throttle } from 'throttle-debounce'; | ||||||
|  | import { uploadFile } from '@/scripts/upload'; | ||||||
| 
 | 
 | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
| 	props: { | 	props: { | ||||||
|  | @ -164,7 +165,7 @@ export default defineComponent({ | ||||||
| 		}, | 		}, | ||||||
| 
 | 
 | ||||||
| 		upload(file: File, name?: string) { | 		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; | 				this.file = res; | ||||||
| 			}); | 			}); | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ import { stream } from '@/stream'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import { defaultStore } from '@/store'; | import { defaultStore } from '@/store'; | ||||||
| import { DriveFile } from 'misskey-js/built/entities'; | import { DriveFile } from 'misskey-js/built/entities'; | ||||||
|  | import { uploadFile } from '@/scripts/upload'; | ||||||
| 
 | 
 | ||||||
| function select(src: any, label: string | null, multiple: boolean): Promise<DriveFile | DriveFile[]> { | function select(src: any, label: string | null, multiple: boolean): Promise<DriveFile | DriveFile[]> { | ||||||
| 	return new Promise((res, rej) => { | 	return new Promise((res, rej) => { | ||||||
|  | @ -14,7 +15,7 @@ function select(src: any, label: string | null, multiple: boolean): Promise<Driv | ||||||
| 			input.type = 'file'; | 			input.type = 'file'; | ||||||
| 			input.multiple = multiple; | 			input.multiple = multiple; | ||||||
| 			input.onchange = () => { | 			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 => { | 				Promise.all(promises).then(driveFiles => { | ||||||
| 					res(multiple ? driveFiles : driveFiles[0]); | 					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"> | <script lang="ts"> | ||||||
| import { defineAsyncComponent, defineComponent } from 'vue'; | 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 * as sound from '@/scripts/sound'; | ||||||
| import { $i } from '@/account'; | import { $i } from '@/account'; | ||||||
| import { stream } from '@/stream'; | import { stream } from '@/stream'; | ||||||
|  |  | ||||||
|  | @ -20,8 +20,8 @@ | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
| import { } from 'vue'; | import { } from 'vue'; | ||||||
| import * as os from '@/os'; | import * as os from '@/os'; | ||||||
|  | import { uploads } from '@/scripts/upload'; | ||||||
| 
 | 
 | ||||||
| const uploads = os.uploads; |  | ||||||
| const zIndex = os.claimZIndex('high'); | const zIndex = os.claimZIndex('high'); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue