forked from githubdulong/Script
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPhotos.scriptable
More file actions
15 lines (15 loc) · 10.5 KB
/
Copy pathPhotos.scriptable
File metadata and controls
15 lines (15 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"always_run_in_app" : false,
"icon" : {
"color" : "cyan",
"glyph" : "images"
},
"name" : "Photos",
"script" : "\/**\n *\n * @version 1.0.0\n * @author Honye\n *\/\n\n\/**\n * @param {object} options\n * @param {string} [options.title]\n * @param {string} [options.message]\n * @param {Array<{ title: string; [key: string]: any }>} options.options\n * @param {boolean} [options.showCancel = true]\n * @param {string} [options.cancelText = 'Cancel']\n *\/\nasync function presentSheet (options) {\n options = {\n showCancel: true,\n cancelText: 'Cancel',\n ...options\n };\n const alert = new Alert();\n if (options.title) {\n alert.title = options.title;\n }\n if (options.message) {\n alert.message = options.message;\n }\n if (!options.options) {\n throw new Error('The \"options\" property of the parameter cannot be empty')\n }\n for (const option of options.options) {\n alert.addAction(option.title);\n }\n if (options.showCancel) {\n alert.addCancelAction(options.cancelText);\n }\n const value = await alert.presentSheet();\n return {\n value,\n option: options.options[value]\n }\n}\n\n\/**\n * @param {{[language: string]: string} | string[]} langs\n *\/\nconst i18n = (langs) => {\n const language = Device.language();\n if (Array.isArray(langs)) {\n langs = {\n en: langs[0],\n zh: langs[1],\n others: langs[0]\n };\n } else {\n langs.others = langs.others || langs.en;\n }\n return langs[language] || langs.others\n};\n\nconst localFile = FileManager.local();\nconst APP_ROOT = localFile.joinPath(localFile.documentsDirectory(), Script.name());\nconst PHOTOS_DIR = localFile.joinPath(APP_ROOT, 'photos');\n\nconst main = async () => {\n if (!localFile.fileExists(PHOTOS_DIR)) {\n localFile.createDirectory(PHOTOS_DIR, true);\n }\n\n if (config.runsInActionExtension) {\n choosePhotos();\n return\n }\n\n if (config.runsInApp) {\n const {\n option: { key } = {}\n } = await presentSheet({\n options: [\n {\n title: i18n(['Preview', '预览']),\n key: 'preview'\n },\n {\n title: i18n(['Photos', '查看图片']),\n key: 'photos'\n }\n ],\n cancelText: i18n(['Cancel', '取消'])\n });\n if (key === 'preview') {\n const widget = createWidget();\n widget.presentSmall();\n Script.complete();\n return\n }\n if (key === 'photos') {\n presentAlbums();\n return\n }\n }\n\n if (config.runsInWidget) {\n const widget = createWidget();\n Script.setWidget(widget);\n Script.complete();\n }\n};\n\n\/** 通过分享菜单选择照片 *\/\nconst choosePhotos = async () => {\n const albums = getAlbums();\n let album;\n const { option } = await presentSheet({\n message: i18n([\n 'Choose Album',\n '选择相册'\n ]),\n options: [\n ...albums.map((name) => ({ title: name, type: 'album' })),\n {\n title: i18n(['New Album', '新建相册']),\n type: 'new'\n }\n ]\n });\n if (option) {\n if (option.type === 'album') {\n album = option.title;\n }\n if (option.type === 'new') {\n album = await createAlbum();\n }\n }\n const albumDir = localFile.joinPath(PHOTOS_DIR, album);\n\n const filePaths = args.fileURLs;\n const images = args.images;\n if (filePaths && filePaths.length) { \/\/ 图片文件分享\n for (const filePath of filePaths) {\n const filename = localFile.fileName(filePath, true);\n const copyPath = localFile.joinPath(albumDir, filename);\n try {\n localFile.copy(filePath, copyPath);\n } catch (e) {\n await alert(e.message);\n }\n }\n } else if (images && images.length) { \/\/ 图片分享\n for (const image of images) {\n const filePath = localFile.joinPath(albumDir, `${Date.now()}.jpg`);\n localFile.writeImage(filePath, image);\n }\n }\n\n presentPhotos(album);\n};\n\n\/**\n * @param {string} album\n *\/\nconst _choosePhoto = async (album) => {\n const {\n option: { key } = {}\n } = await presentSheet({\n options: [\n {\n title: i18n(['Camera', '拍照']),\n key: 'camera'\n },\n {\n title: i18n(['Albums', '相册']),\n key: 'album'\n }\n ]\n });\n const image = await (async () => {\n if (key === 'camera') {\n return await Photos.fromCamera()\n }\n if (key === 'album') {\n return await Photos.fromLibrary()\n }\n })();\n const filename = `${Date.now().toString()}.jpg`;\n const albumDir = localFile.joinPath(PHOTOS_DIR, album);\n const filePath = localFile.joinPath(albumDir, filename);\n localFile.writeImage(filePath, image);\n return filePath\n};\n\nconst getAlbums = () => {\n const albums = localFile.listContents(PHOTOS_DIR)\n .filter((name) => localFile.isDirectory(localFile.joinPath(PHOTOS_DIR, name)));\n return albums\n};\n\n\/** 添加相册 *\/\nconst createAlbum = async () => {\n const alert = new Alert();\n alert.title = i18n(['New Album', '新建相册']);\n alert.addTextField(i18n(['Input the album name', '输入相册名']));\n alert.addAction(i18n(['Save', '保存']));\n alert.addCancelAction(i18n(['Cancel', '取消']));\n const index = await alert.presentAlert();\n if (index === 0) {\n const name = alert.textFieldValue(0);\n localFile.createDirectory(\n localFile.joinPath(PHOTOS_DIR, name),\n true\n );\n return { name }\n }\n};\n\n\/**\n * @param {string} album\n *\/\nconst getPhotos = (album) => {\n const dir = localFile.joinPath(PHOTOS_DIR, album);\n return localFile.listContents(dir)\n .map((filename) => {\n const albumDir = localFile.joinPath(PHOTOS_DIR, album);\n return localFile.joinPath(albumDir, filename)\n })\n};\n\nconst createWidget = () => {\n let [album] = (args.widgetParameter || '').split(',').map(str => str.trim());\n const widget = new ListWidget();\n if (!album) {\n const albums = getAlbums();\n if (albums.length > 0) {\n album = albums[0];\n } else {\n widget.addText(i18n(['Go to APP set photos', '请先去 APP 选择照片']));\n return widget\n }\n }\n const photos = getPhotos(album);\n const length = photos.length;\n if (length > 0) {\n const index = Math.floor(Math.random() * length);\n const image = localFile.readImage(photos[index]);\n widget.backgroundImage = image;\n } else {\n widget.addText(i18n([`Album \"${album}\" is empty`, `相册\"${album}\"是空的`]));\n }\n return widget\n};\n\n\/** 展示相册列表 *\/\nconst presentAlbums = () => {\n const albums = localFile.listContents(PHOTOS_DIR)\n .filter((name) => localFile.isDirectory(localFile.joinPath(PHOTOS_DIR, name)));\n const table = new UITable();\n const head = new UITableRow();\n table.addRow(head);\n head.isHeader = true;\n head.addText(i18n(['Albums', '相册']));\n \/\/ 添加相册\n const cellNew = head.addButton(i18n(['New Album', '新建相册']));\n cellNew.rightAligned();\n cellNew.onTap = async () => {\n const alert = new Alert();\n alert.title = i18n(['New Album', '新建相册']);\n alert.addTextField(i18n(['Input the album name', '输入相册名']));\n alert.addAction(i18n(['Save', '保存']));\n alert.addCancelAction(i18n(['Cancel', '取消']));\n const index = await alert.presentAlert();\n if (index === 0) {\n const name = alert.textFieldValue(0);\n localFile.createDirectory(\n localFile.joinPath(PHOTOS_DIR, name),\n true\n );\n addRow(name);\n table.reload();\n }\n };\n const addRow = (album) => {\n const row = new UITableRow();\n table.addRow(row);\n const count = localFile.listContents(\n localFile.joinPath(PHOTOS_DIR, album)\n ).length;\n const cellName = row.addText(album, `${count} photos`);\n cellName.subtitleColor = new Color('#888888');\n const cellView = row.addButton(i18n(['View', '查看']));\n cellView.onTap = () => presentPhotos(album);\n const cellDelete = row.addButton(i18n(['Delete', '删除']));\n cellDelete.onTap = async () => {\n const alert = new Alert();\n alert.message = i18n([`Are you sure delete \"${album}\"?`, `确定删除\"${album}\"吗?`]);\n alert.addAction(i18n(['Delete', '删除']));\n alert.addCancelAction(i18n(['Cancel', '取消']));\n const value = await alert.presentAlert();\n if (value === 0) {\n localFile.remove(localFile.joinPath(PHOTOS_DIR, album));\n table.removeRow(row);\n table.reload();\n }\n };\n };\n for (const [, album] of albums.entries()) {\n addRow(album);\n }\n table.present();\n};\n\n\/**\n * 展示相册照片\n * @param {string}\n *\/\nconst presentPhotos = (album) => {\n const photos = getPhotos(album);\n const table = new UITable();\n const head = new UITableRow();\n table.addRow(head);\n head.isHeader = true;\n head.addText(i18n(['Photos', '照片']));\n const cellChoose = head.addButton(i18n(['Choose photos', '选择图片']));\n cellChoose.rightAligned();\n cellChoose.onTap = async () => {\n const filePath = await _choosePhoto(album);\n addRow(filePath);\n table.reload();\n };\n\n const addRow = (filePath) => {\n const row = new UITableRow();\n table.addRow(row);\n const image = Image.fromFile(filePath);\n const cellImage = row.addImage(image);\n cellImage.widthWeight = 4;\n const dfm = new DateFormatter();\n dfm.dateFormat = 'yy-MM-dd HH:mm:ss';\n const cellName = row.addText(\n localFile.fileName(filePath, true),\n dfm.string(localFile.modificationDate(filePath))\n );\n cellName.widthWeight = 10;\n cellName.titleFont = Font.systemFont(14);\n cellName.subtitleFont = Font.lightSystemFont(10);\n const buttonPreview = row.addButton(i18n(['Preview', '查看大图']));\n buttonPreview.widthWeight = 6;\n buttonPreview.rightAligned();\n buttonPreview.onTap = () => {\n QuickLook.present(image, true);\n };\n const buttonDelete = row.addButton(i18n(['Delete', '删除']));\n buttonDelete.widthWeight = 4;\n buttonDelete.rightAligned();\n buttonDelete.onTap = () => {\n localFile.remove(filePath);\n table.removeRow(row);\n table.reload();\n };\n };\n\n for (const filePath of photos) {\n addRow(filePath);\n }\n QuickLook.present(table);\n};\n\nconst alert = (message, title = '') => {\n const alertIns = new Alert();\n alertIns.title = title;\n alertIns.message = String(message);\n return alertIns.present()\n};\n\nawait main();\n",
"share_sheet_inputs" : [
"file-url",
"url",
"image",
"plain-text"
]
}