Skip to content

Commit

Permalink
初始化v2-dev仓库
Browse files Browse the repository at this point in the history
  • Loading branch information
im3x-dev committed Nov 2, 2020
0 parents commit 3c94f9a
Show file tree
Hide file tree
Showing 7 changed files with 996 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
package-lock.json
Widget.js
「源码」*.js
.DS_File
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# 「小件件」开发框架

> iOS 小组件快速开发框架+模板
> for [Scriptable]()
## 简介
[Scriptable]() 是一款可以自定义 iOS 桌面小组件的 App。
这个框架可以让你快速便捷地在电脑上进行连接手机,并采用 `VSCode` 编辑器进行编写、测试小组件,支持语法高亮、自动补全等功能。

`「小件件」开发环境.js` 是基础开发库,开发小组件请采用 `「小件件」组件模板.js` 进行修改编写
120 changes: 120 additions & 0 deletions app.js
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)
9 changes: 9 additions & 0 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"checkJs": true
},
"exclude": [
"node_modules",
"**/node_modules/*"
]
}
18 changes: 18 additions & 0 deletions package.json
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"
}
}
103 changes: 103 additions & 0 deletions 「小件件」小组件示例.js
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)
Loading

0 comments on commit 3c94f9a

Please sign in to comment.