Skip to content

Commit 0b9bab9

Browse files
committed
新增打包、压缩脚本&更新环境脚本
1 parent 679d087 commit 0b9bab9

File tree

6 files changed

+355
-7
lines changed

6 files changed

+355
-7
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
node_modules/
22
package-lock.json
33
Widget.js
4-
.DS_File
4+
.DS_File
5+
Dist/

README.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,33 @@
2121
**然后,配置手机运行环境:**
2222
1. 运行服务后,会输出地址,手机访问该地址即可按照步骤初始化。或手动复制 [install-runtime.js](install-runtime.js) 脚本代码,打开 `Scriptable` 应用,点击右上角➕,粘贴代码,点击运行
2323
2. 如果成功,应该新加了两个插件文件:`「小件件」开发环境`、「`源码」小组件示例`
24-
3. 点击 `「源码」小组件示例` 或者其他任何基于此框架开发的小组件,点击操作菜单的远程开发,即可链接电脑,开始远程编写体验
24+
3. 点击 `「源码」小组件示例` 或者其他任何基于此框架开发的小组件,点击操作菜单的远程开发,即可连接电脑,开启远程开发体验
2525

2626

2727

2828
# 发布
2929

30-
你开发测试小组件完毕后,可以 `pull` 到本分支,小组件源码存放在 [Scrips](Scripts) 目录,你也可以手动复制其他的小组件进行修改使用。
31-
微信小程序「小件件」 后续会开放开发者中心,开发者到时候可以上传、发布、出售自己的原创小组件。目前测试中,敬请关注!
30+
开发测试完毕后,可以 `pull` 到本分支进行开源分享
31+
小组件源码存放在 [Scrips](Scripts) 目录,你也可以复制其他的小组件进行修改使用。
3232

3333

34+
**打包分享**: 你可以使用如下命令,打包你的小组件成一个单独的文件,从而可以分享给其他用户使用:
35+
``` bash
36+
$ node pack.js Scripts/「源码」你的小组件.js
37+
```
38+
> 将会生成在 `Dist` 目录
39+
40+
**压缩代码**:打包的文件过大,如果需要压缩减少体积、加密敏感信息,可以通过如下脚本处理打包后的文件:
41+
``` bash
42+
$ node encode.js Dist/「小件件」你的小组件.js
43+
```
44+
> 将会在 `Dist` 目录生成 `「小件件」你的小组件.enc.js` 文件
45+
> 该脚本需要`javascript-obfuscator`库,如未安装请先在项目目录 `npm install`
46+
47+
48+
微信小程序「小件件」 后续会开放开发者中心,开发者到时候可以上传、发布、出售自己的原创小组件。
49+
目前测试中,敬请关注!
50+
3451
开发讨论交流群:https://x.im3x.cn/images/qun1.jpeg
3552

3653

Scripts/「小件件」开发环境.js

Lines changed: 238 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
//
1010

1111
// 组件基础类
12-
const RUNTIME_VERSION = 20201104
12+
const RUNTIME_VERSION = 20201125
1313

1414
class Base {
1515
constructor (arg="") {
@@ -208,6 +208,182 @@ class Base {
208208
return draw.getImage()
209209
}
210210

211+
async function blurImage(img,style) {
212+
const blur = 150
213+
const js = `
214+
var mul_table=[512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,289,287,285,282,280,278,275,273,271,269,267,265,263,261,259];var shg_table=[9,11,12,13,13,14,14,15,15,15,15,16,16,16,16,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24];function stackBlurCanvasRGB(id,top_x,top_y,width,height,radius){if(isNaN(radius)||radius<1)return;radius|=0;var canvas=document.getElementById(id);var context=canvas.getContext("2d");var imageData;try{try{imageData=context.getImageData(top_x,top_y,width,height)}catch(e){try{netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");imageData=context.getImageData(top_x,top_y,width,height)}catch(e){alert("Cannot access local image");throw new Error("unable to access local image data: "+e);return}}}catch(e){alert("Cannot access image");throw new Error("unable to access image data: "+e);}var pixels=imageData.data;var x,y,i,p,yp,yi,yw,r_sum,g_sum,b_sum,r_out_sum,g_out_sum,b_out_sum,r_in_sum,g_in_sum,b_in_sum,pr,pg,pb,rbs;var div=radius+radius+1;var w4=width<<2;var widthMinus1=width-1;var heightMinus1=height-1;var radiusPlus1=radius+1;var sumFactor=radiusPlus1*(radiusPlus1+1)/2;var stackStart=new BlurStack();var stack=stackStart;for(i=1;i<div;i++){stack=stack.next=new BlurStack();if(i==radiusPlus1)var stackEnd=stack}stack.next=stackStart;var stackIn=null;var stackOut=null;yw=yi=0;var mul_sum=mul_table[radius];var shg_sum=shg_table[radius];for(y=0;y<height;y++){r_in_sum=g_in_sum=b_in_sum=r_sum=g_sum=b_sum=0;r_out_sum=radiusPlus1*(pr=pixels[yi]);g_out_sum=radiusPlus1*(pg=pixels[yi+1]);b_out_sum=radiusPlus1*(pb=pixels[yi+2]);r_sum+=sumFactor*pr;g_sum+=sumFactor*pg;b_sum+=sumFactor*pb;stack=stackStart;for(i=0;i<radiusPlus1;i++){stack.r=pr;stack.g=pg;stack.b=pb;stack=stack.next}for(i=1;i<radiusPlus1;i++){p=yi+((widthMinus1<i?widthMinus1:i)<<2);r_sum+=(stack.r=(pr=pixels[p]))*(rbs=radiusPlus1-i);g_sum+=(stack.g=(pg=pixels[p+1]))*rbs;b_sum+=(stack.b=(pb=pixels[p+2]))*rbs;r_in_sum+=pr;g_in_sum+=pg;b_in_sum+=pb;stack=stack.next}stackIn=stackStart;stackOut=stackEnd;for(x=0;x<width;x++){pixels[yi]=(r_sum*mul_sum)>>shg_sum;pixels[yi+1]=(g_sum*mul_sum)>>shg_sum;pixels[yi+2]=(b_sum*mul_sum)>>shg_sum;r_sum-=r_out_sum;g_sum-=g_out_sum;b_sum-=b_out_sum;r_out_sum-=stackIn.r;g_out_sum-=stackIn.g;b_out_sum-=stackIn.b;p=(yw+((p=x+radius+1)<widthMinus1?p:widthMinus1))<<2;r_in_sum+=(stackIn.r=pixels[p]);g_in_sum+=(stackIn.g=pixels[p+1]);b_in_sum+=(stackIn.b=pixels[p+2]);r_sum+=r_in_sum;g_sum+=g_in_sum;b_sum+=b_in_sum;stackIn=stackIn.next;r_out_sum+=(pr=stackOut.r);g_out_sum+=(pg=stackOut.g);b_out_sum+=(pb=stackOut.b);r_in_sum-=pr;g_in_sum-=pg;b_in_sum-=pb;stackOut=stackOut.next;yi+=4}yw+=width}for(x=0;x<width;x++){g_in_sum=b_in_sum=r_in_sum=g_sum=b_sum=r_sum=0;yi=x<<2;r_out_sum=radiusPlus1*(pr=pixels[yi]);g_out_sum=radiusPlus1*(pg=pixels[yi+1]);b_out_sum=radiusPlus1*(pb=pixels[yi+2]);r_sum+=sumFactor*pr;g_sum+=sumFactor*pg;b_sum+=sumFactor*pb;stack=stackStart;for(i=0;i<radiusPlus1;i++){stack.r=pr;stack.g=pg;stack.b=pb;stack=stack.next}yp=width;for(i=1;i<=radius;i++){yi=(yp+x)<<2;r_sum+=(stack.r=(pr=pixels[yi]))*(rbs=radiusPlus1-i);g_sum+=(stack.g=(pg=pixels[yi+1]))*rbs;b_sum+=(stack.b=(pb=pixels[yi+2]))*rbs;r_in_sum+=pr;g_in_sum+=pg;b_in_sum+=pb;stack=stack.next;if(i<heightMinus1){yp+=width}}yi=x;stackIn=stackStart;stackOut=stackEnd;for(y=0;y<height;y++){p=yi<<2;pixels[p]=(r_sum*mul_sum)>>shg_sum;pixels[p+1]=(g_sum*mul_sum)>>shg_sum;pixels[p+2]=(b_sum*mul_sum)>>shg_sum;r_sum-=r_out_sum;g_sum-=g_out_sum;b_sum-=b_out_sum;r_out_sum-=stackIn.r;g_out_sum-=stackIn.g;b_out_sum-=stackIn.b;p=(x+(((p=y+radiusPlus1)<heightMinus1?p:heightMinus1)*width))<<2;r_sum+=(r_in_sum+=(stackIn.r=pixels[p]));g_sum+=(g_in_sum+=(stackIn.g=pixels[p+1]));b_sum+=(b_in_sum+=(stackIn.b=pixels[p+2]));stackIn=stackIn.next;r_out_sum+=(pr=stackOut.r);g_out_sum+=(pg=stackOut.g);b_out_sum+=(pb=stackOut.b);r_in_sum-=pr;g_in_sum-=pg;b_in_sum-=pb;stackOut=stackOut.next;yi+=width}}context.putImageData(imageData,top_x,top_y)}function BlurStack(){this.r=0;this.g=0;this.b=0;this.a=0;this.next=null}
215+
// https://gist.github.com/mjackson/5311256
216+
217+
function rgbToHsl(r, g, b){
218+
r /= 255, g /= 255, b /= 255;
219+
var max = Math.max(r, g, b), min = Math.min(r, g, b);
220+
var h, s, l = (max + min) / 2;
221+
222+
if(max == min){
223+
h = s = 0; // achromatic
224+
}else{
225+
var d = max - min;
226+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
227+
switch(max){
228+
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
229+
case g: h = (b - r) / d + 2; break;
230+
case b: h = (r - g) / d + 4; break;
231+
}
232+
h /= 6;
233+
}
234+
235+
return [h, s, l];
236+
}
237+
238+
function hslToRgb(h, s, l){
239+
var r, g, b;
240+
241+
if(s == 0){
242+
r = g = b = l; // achromatic
243+
}else{
244+
var hue2rgb = function hue2rgb(p, q, t){
245+
if(t < 0) t += 1;
246+
if(t > 1) t -= 1;
247+
if(t < 1/6) return p + (q - p) * 6 * t;
248+
if(t < 1/2) return q;
249+
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
250+
return p;
251+
}
252+
253+
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
254+
var p = 2 * l - q;
255+
r = hue2rgb(p, q, h + 1/3);
256+
g = hue2rgb(p, q, h);
257+
b = hue2rgb(p, q, h - 1/3);
258+
}
259+
260+
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
261+
}
262+
263+
function lightBlur(hsl) {
264+
265+
// Adjust the luminance.
266+
let lumCalc = 0.35 + (0.3 / hsl[2]);
267+
if (lumCalc < 1) { lumCalc = 1; }
268+
else if (lumCalc > 3.3) { lumCalc = 3.3; }
269+
const l = hsl[2] * lumCalc;
270+
271+
// Adjust the saturation.
272+
const colorful = 2 * hsl[1] * l;
273+
const s = hsl[1] * colorful * 1.5;
274+
275+
return [hsl[0],s,l];
276+
277+
}
278+
279+
function darkBlur(hsl) {
280+
281+
// Adjust the saturation.
282+
const colorful = 2 * hsl[1] * hsl[2];
283+
const s = hsl[1] * (1 - hsl[2]) * 3;
284+
285+
return [hsl[0],s,hsl[2]];
286+
287+
}
288+
289+
// Set up the canvas.
290+
const img = document.getElementById("blurImg");
291+
const canvas = document.getElementById("mainCanvas");
292+
293+
const w = img.naturalWidth;
294+
const h = img.naturalHeight;
295+
296+
canvas.style.width = w + "px";
297+
canvas.style.height = h + "px";
298+
canvas.width = w;
299+
canvas.height = h;
300+
301+
const context = canvas.getContext("2d");
302+
context.clearRect( 0, 0, w, h );
303+
context.drawImage( img, 0, 0 );
304+
305+
// Get the image data from the context.
306+
var imageData = context.getImageData(0,0,w,h);
307+
var pix = imageData.data;
308+
309+
var isDark = "${style}" == "dark";
310+
var imageFunc = isDark ? darkBlur : lightBlur;
311+
312+
for (let i=0; i < pix.length; i+=4) {
313+
314+
// Convert to HSL.
315+
let hsl = rgbToHsl(pix[i],pix[i+1],pix[i+2]);
316+
317+
// Apply the image function.
318+
hsl = imageFunc(hsl);
319+
320+
// Convert back to RGB.
321+
const rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
322+
323+
// Put the values back into the data.
324+
pix[i] = rgb[0];
325+
pix[i+1] = rgb[1];
326+
pix[i+2] = rgb[2];
327+
328+
}
329+
330+
// Draw over the old image.
331+
context.putImageData(imageData,0,0);
332+
333+
// Blur the image.
334+
stackBlurCanvasRGB("mainCanvas", 0, 0, w, h, ${blur});
335+
336+
// Perform the additional processing for dark images.
337+
if (isDark) {
338+
339+
// Draw the hard light box over it.
340+
context.globalCompositeOperation = "hard-light";
341+
context.fillStyle = "rgba(55,55,55,0.2)";
342+
context.fillRect(0, 0, w, h);
343+
344+
// Draw the soft light box over it.
345+
context.globalCompositeOperation = "soft-light";
346+
context.fillStyle = "rgba(55,55,55,1)";
347+
context.fillRect(0, 0, w, h);
348+
349+
// Draw the regular box over it.
350+
context.globalCompositeOperation = "source-over";
351+
context.fillStyle = "rgba(55,55,55,0.4)";
352+
context.fillRect(0, 0, w, h);
353+
354+
// Otherwise process light images.
355+
} else {
356+
context.fillStyle = "rgba(255,255,255,0.4)";
357+
context.fillRect(0, 0, w, h);
358+
}
359+
360+
// Return a base64 representation.
361+
canvas.toDataURL();
362+
`
363+
364+
// Convert the images and create the HTML.
365+
let blurImgData = Data.fromPNG(img).toBase64String()
366+
let html = `
367+
<img id="blurImg" src="data:image/png;base64,${blurImgData}" />
368+
<canvas id="mainCanvas" />
369+
`
370+
371+
// Make the web view and get its return value.
372+
let view = new WebView()
373+
await view.loadHTML(html)
374+
let returnValue = await view.evaluateJavaScript(js)
375+
376+
// Remove the data type from the string and convert to data.
377+
let imageDataString = returnValue.slice(22)
378+
let imageData = Data.fromBase64String(imageDataString)
379+
380+
// Convert to image and crop before returning.
381+
let imageFromData = Image.fromData(imageData)
382+
// return cropImage(imageFromData)
383+
return imageFromData
384+
}
385+
386+
211387
// Pixel sizes and positions for widgets on all supported phones.
212388
function phoneSizes() {
213389
let phones = {
@@ -387,9 +563,19 @@ class Base {
387563
crop.y = position ? phone.middle : phone.top
388564
}
389565

566+
// 透明/模糊选项
567+
message = "需要给背景图片加什么显示效果?"
568+
let blurOptions = ["透明", "白色 模糊", "黑色 模糊"]
569+
let blurred = await generateAlert(message, blurOptions)
570+
390571
// Crop image and finalize the widget.
572+
if (blurred) {
573+
const style = (blurred === 1) ? 'light' : 'dark'
574+
img = await blurImage(img, style)
575+
}
391576
let imgCrop = cropImage(img, new Rect(crop.x,crop.y,crop.w,crop.h))
392577

578+
393579
return imgCrop
394580

395581
}
@@ -512,6 +698,55 @@ class Base {
512698

513699
}
514700
// @base.end
701+
// 运行环境
702+
// @running.start
703+
const Running = async (Widget, default_args = "") => {
704+
let M = null
705+
// 判断hash是否和当前设备匹配
706+
if (config.runsInWidget) {
707+
M = new Widget(args.widgetParameter || '')
708+
const W = await M.render()
709+
Script.setWidget(W)
710+
Script.complete()
711+
} else {
712+
let { act, data, __arg, __size } = args.queryParameters
713+
M = new Widget(__arg || default_args || '')
714+
if (__size) M.init(__size)
715+
if (!act || !M['_actions']) {
716+
// 弹出选择菜单
717+
const actions = M['_actions']
718+
const _actions = [
719+
async () => {
720+
Safari.openInApp("https://support.qq.com/products/287371", false)
721+
}
722+
]
723+
const alert = new Alert()
724+
alert.title = M.name
725+
alert.message = M.desc
726+
alert.addAction("反馈交流")
727+
for (let _ in actions) {
728+
alert.addAction(_)
729+
_actions.push(actions[_])
730+
}
731+
alert.addCancelAction("取消操作")
732+
const idx = await alert.presentSheet()
733+
if (_actions[idx]) {
734+
const func = _actions[idx]
735+
await func()
736+
}
737+
return
738+
}
739+
let _tmp = act.split('-').map(_ => _[0].toUpperCase() + _.substr(1)).join('')
740+
let _act = `action${_tmp}`
741+
if (M[_act] && typeof M[_act] === 'function') {
742+
const func = M[_act].bind(M)
743+
await func(data)
744+
}
745+
}
746+
}
747+
// @running.end
748+
749+
// 测试环境
515750
const Testing = async (Widget, default_args = "") => {
516751
let M = null
517752
// 判断hash是否和当前设备匹配
@@ -731,7 +966,8 @@ const Testing = async (Widget, default_args = "") => {
731966

732967
module.exports = {
733968
Base,
734-
Testing
969+
Testing,
970+
Running,
735971
}
736972

737973
// 自更新

encode.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// 加密压缩打包后的小组件代码
2+
// 方便隐藏敏感信息,减少组件体积和保护小组件不被随意修改
3+
4+
// 用法:
5+
// node encode.js Dist/「小件件」你的小组件.js
6+
7+
8+
const process = require('process')
9+
const os = require('os')
10+
const fs = require('fs')
11+
const path = require('path')
12+
13+
var JB = require('javascript-obfuscator');
14+
15+
if (process.argv.length !== 3) {
16+
console.log('[!] 用法:node encode.js Dist/「小件件」xxx.js')
17+
process.exit(0)
18+
}
19+
20+
const file_name = process.argv[2]
21+
const out_name = file_name.replace(".js", ".enc.js")
22+
23+
// 读取源文件
24+
const widget_file = fs.readFileSync(path.join(__dirname, file_name))
25+
26+
let widget_code = widget_file.toString("utf-8")
27+
widget_code = widget_code.split("await Running(Widget)")[0];
28+
29+
30+
var result = JB.obfuscate(widget_code.toString("utf-8"), {
31+
"rotateStringArray": true,
32+
"selfDefending": true,
33+
"stringArray": true,
34+
splitStringsChunkLength: 100,
35+
"stringArrayEncoding": ["rc4", "base64"]
36+
}).getObfuscatedCode()
37+
38+
let result_header = widget_code.split("// icon-color:")[0]
39+
result_header += "// icon-color:"
40+
result_header += widget_code.split("// icon-color:")[1].split("\n")[0]
41+
result_header += "\n// " + file_name
42+
result_header += "\n// https://github.com/im3x/Scriptables"
43+
44+
let result_code = `${result_header}\n${result};await Running(Widget);`
45+
46+
fs.writeFileSync(path.join(__dirname, out_name), result_code);
47+
48+
console.log("[*] 文件已压缩混淆至:", out_name)

0 commit comments

Comments
 (0)