-
Notifications
You must be signed in to change notification settings - Fork 244
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 3c94f9a
Showing
7 changed files
with
996 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
node_modules/ | ||
package-lock.json | ||
Widget.js | ||
「源码」*.js | ||
.DS_File |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# 「小件件」开发框架 | ||
|
||
> iOS 小组件快速开发框架+模板 | ||
> for [Scriptable]() | ||
## 简介 | ||
[Scriptable]() 是一款可以自定义 iOS 桌面小组件的 App。 | ||
这个框架可以让你快速便捷地在电脑上进行连接手机,并采用 `VSCode` 编辑器进行编写、测试小组件,支持语法高亮、自动补全等功能。 | ||
|
||
`「小件件」开发环境.js` 是基础开发库,开发小组件请采用 `「小件件」组件模板.js` 进行修改编写 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
const fs = require('fs') | ||
const os = require('os') | ||
const path = require('path') | ||
const express = require('express') | ||
const child_process = require('child_process') | ||
const multer = require('multer') | ||
const bodyParser = require('body-parser') | ||
|
||
const HTTP_PORT = 5566 | ||
const WORK_DIR = path.dirname(__filename) | ||
|
||
const app = express() | ||
const upload = multer({ | ||
dest: os.tmpdir() | ||
}) | ||
app.use(upload.any()) | ||
app.use(bodyParser.urlencoded({ | ||
extended: false | ||
})) | ||
app.use(bodyParser.json()) | ||
|
||
app.get('/ping', (req, res) => { | ||
console.log('[-] ping..') | ||
setTimeout(() => { | ||
res.send("pong").end() | ||
}, 1000) | ||
}) | ||
|
||
let FILE_DATE = null | ||
// const WIDGET_FILE = path.join(WORK_DIR, "Widget.js") | ||
|
||
app.get('/sync', (req, res) => { | ||
// console.log('[-] 等待同步到手机..') | ||
const { name } = req.query | ||
|
||
const WIDGET_FILE = path.join(WORK_DIR, name + '.js') | ||
|
||
setTimeout(() => { | ||
// 判断文件时间 | ||
const _time = fs.statSync(WIDGET_FILE).mtimeMs | ||
if (_time === FILE_DATE) { | ||
res.send("no").end() | ||
return | ||
// return console.log("[!] 文件没有更改,不同步") | ||
} | ||
// 同步 | ||
res.sendFile(WIDGET_FILE) | ||
console.log('[+] 同步到手机完毕') | ||
FILE_DATE = _time | ||
|
||
}, 1000) | ||
}) | ||
|
||
|
||
app.post("/sync", (req, res) => { | ||
if (req.files.length !== 1) return res.send("no") | ||
console.log('[+] Scriptalbe App 已连接') | ||
const _file = req.files[0] | ||
const FILE_NAME = _file['originalname'] + '.js' | ||
const WIDGET_FILE = path.join(WORK_DIR, FILE_NAME) | ||
fs.renameSync(_file['path'], WIDGET_FILE) | ||
res.send("ok") | ||
console.log(`[*] 小组件源码(${_file['originalname']})已同步,请打开编辑`) | ||
FILE_DATE = fs.statSync(WIDGET_FILE).mtimeMs | ||
// 尝试打开 | ||
let cmd = `code ./"${FILE_NAME}"` | ||
if (os.platform() === "win32") { | ||
cmd = `cmd.exe /c ${cmd}` | ||
} else if (os.platform() === "linux") { | ||
let shell = process.env["SHELL"] | ||
cmd = `${shell} -c ${cmd}` | ||
} else { | ||
cmd = `"/Applications/Visual Studio Code.app/Contents/MacOS/Electron" ./"${FILE_NAME}"` | ||
} | ||
child_process.execSync(cmd) | ||
}) | ||
|
||
// 远程 console,调试中把调试输出内容传送到服务端控制台输出 | ||
app.post('/console', (req, res) => { | ||
const { t, data } = req.body | ||
const _time = new Date().toLocaleString().split(' ')[1] | ||
switch (t) { | ||
case 'warn': | ||
console.warn(`[console.warn / ${_time}]`, typeof data === 'string' ? data : '') | ||
if (typeof data === 'object') console.warn(data) | ||
break | ||
case 'error': | ||
console.error(`[console.error / ${_time}]`, typeof data === 'string' ? data : '') | ||
if (typeof data === 'object') console.error(data) | ||
break | ||
default: | ||
console.log(`[console.log / ${_time}]`, typeof data === 'string' ? data : '') | ||
if (typeof data === 'object') console.log(data) | ||
} | ||
res.send("ok") | ||
}) | ||
|
||
// 获取当前电脑IP | ||
function getIPAdress() { | ||
var interfaces = os.networkInterfaces(); | ||
for (var devName in interfaces) { | ||
var iface = interfaces[devName]; | ||
for (var i = 0; i < iface.length; i++) { | ||
var alias = iface[i]; | ||
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) { | ||
return alias.address; | ||
} | ||
} | ||
} | ||
} | ||
|
||
const _ip = getIPAdress() | ||
const _host = `http://${_ip}:${HTTP_PORT}` | ||
|
||
console.log('[*] 「小件件」开发服务运行中') | ||
console.log(`[-] 地址:${_host}`) | ||
console.log(`[-] 如果你的手机还没有配置开发环境,请手机 Safari 访问上述地址,查看引导`) | ||
console.log('[+] 如果你的手机已经安装好环境和小组件模板,请在 Scriptable 里点击小组件模板->远程开发,服务器地址输入:', _ip) | ||
console.log('[*] 更多帮助:https://github.com/im3x/scriptables') | ||
app.listen(HTTP_PORT) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"compilerOptions": { | ||
"checkJs": true | ||
}, | ||
"exclude": [ | ||
"node_modules", | ||
"**/node_modules/*" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"name": "v2-dev", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"start": "node app" | ||
}, | ||
"author": "", | ||
"license": "ISC", | ||
"dependencies": { | ||
"@types/scriptable-ios": "^1.5.0", | ||
"body-parser": "^1.19.0", | ||
"express": "^4.17.1", | ||
"multer": "^1.4.2" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// Variables used by Scriptable. | ||
// These must be at the very top of the file. Do not edit. | ||
// icon-color: orange; icon-glyph: comments; | ||
// | ||
// iOS 桌面组件脚本 @「小件件」 | ||
// 开发说明:请从 Widget 类开始编写,注释请勿修改 | ||
// https://x.im3x.cn | ||
// | ||
|
||
// 添加require,是为了vscode中可以正确引入包,以获得自动补全等功能 | ||
if (typeof require === 'undefined') require = importModule | ||
const { Base } = require("./「小件件」开发环境") | ||
|
||
// @组件代码开始 | ||
class Widget extends Base { | ||
/** | ||
* 传递给组件的参数,可以是桌面 Parameter 数据,也可以是外部如 URLScheme 等传递的数据 | ||
* @param {string} arg 自定义参数 | ||
*/ | ||
constructor (arg) { | ||
super(arg) | ||
this.name = '示例小组件' | ||
this.desc = '「小件件」—— 强大的 iOS 小组件!' | ||
} | ||
|
||
/** | ||
* 渲染函数,函数名固定 | ||
* 可以根据 this.widgetFamily 来判断小组件尺寸,以返回不同大小的内容 | ||
*/ | ||
async render () { | ||
const data = await this.getData() | ||
switch (this.widgetFamily) { | ||
case 'large': | ||
return await this.renderLarge(data) | ||
case 'medium': | ||
return await this.renderMedium(data) | ||
default: | ||
return await this.renderSmall(data) | ||
} | ||
} | ||
|
||
/** | ||
* 渲染小尺寸组件 | ||
*/ | ||
async renderSmall (data) { | ||
let w = new ListWidget() | ||
this.renderHeader(w, data['logo'], data['title']) | ||
const t = w.addText(data['content']) | ||
t.font = Font.lightSystemFont(16) | ||
w.addSpacer() | ||
w.url = this.actionUrl('open-url', data['url']) | ||
return w | ||
} | ||
/** | ||
* 渲染中尺寸组件 | ||
*/ | ||
async renderMedium (data, num = 3) { | ||
let w = new ListWidget() | ||
this.renderHeader(w, data['logo'], data['title']) | ||
data['data'].slice(0, num).map(d => { | ||
const cell = w.addStack() | ||
cell.centerAlignContent() | ||
const cell_box = cell.addStack() | ||
cell_box.size = new Size(3, 15) | ||
cell_box.backgroundColor = new Color('#ff837a', 0.6) | ||
cell.addSpacer(10) | ||
const cell_text = cell.addText(d['title']) | ||
cell_text.font = Font.lightSystemFont(16) | ||
cell.url = this.actionUrl("open-url", d['url']) | ||
cell.addSpacer() | ||
w.addSpacer(10) | ||
}) | ||
w.addSpacer() | ||
return w | ||
} | ||
/** | ||
* 渲染大尺寸组件 | ||
*/ | ||
async renderLarge (data) { | ||
return await this.renderMedium(data, 10) | ||
} | ||
|
||
/** | ||
* 获取数据函数,函数名可不固定 | ||
*/ | ||
async getData () { | ||
const api = 'https://x.im3x.cn/v1/test-api.json' | ||
return await this.httpGet(api, true, false) | ||
} | ||
|
||
/** | ||
* 自定义注册点击事件,用 actionUrl 生成一个触发链接,点击后会执行下方对应的 action | ||
* @param {string} url 打开的链接 | ||
*/ | ||
async actionOpenUrl (url) { | ||
Safari.openInApp(url, false) | ||
} | ||
|
||
} | ||
// @组件代码结束 | ||
|
||
const { Testing } = require("./「小件件」开发环境") | ||
await Testing(Widget) |
Oops, something went wrong.