// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: red; icon-glyph: user-astronaut;
/**
* Author:LSP
* Date:2022-12-10
*/
// -------------------------------------------------------
// 是否是开发环境,配合手机端调试使用,正式发布设置为false
const isDev = false;
console.log(`开发环境 👉👉👉👉👉 ${isDev ? 'DEV' : 'RELEASE'}`);
console.log(`----------------------------------------`);
const remoteRoot = 'https://gitcode.net/enoyee/scriptable/-/raw/master/';
// 依赖包目录
const fm = FileManager.local();
const rootDir = fm.documentsDirectory();
const cacheDir = fm.joinPath(rootDir, 'LSP');
const dependencyFileName = isDev ? "_LSP.js" : `${cacheDir}/_LSP.js`;
// 下载依赖包
await downloadLSPDependency();
// -------------------------------------------------------
if (typeof require === 'undefined') require = importModule
// 引入相关方法
const { BaseWidget } = require(dependencyFileName);
// @定义小组件
class Widget extends BaseWidget {
defaultPreference = {
domain: 'https://tophub.today',
hotban: { title: '微博 · 热搜榜', url: 'https://tophub.today/n/KqndgxeLl9' },
// 网络请求头
phoneHeaders: {
"user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1",
},
computerHeader: {
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36",
},
};
getHotban = () => JSON.parse(this.base64Decode(this.getSettingValueByKey('hotban', this.base64Encode(JSON.stringify(this.defaultPreference.hotban)))));
constructor(scriptName) {
super(scriptName);
}
async renderSearchResultView(response) {
const { coverArr = [], linkArr = [], titleArr = [], tipArr = [] } = response;
// =========================================================
const style = `
.list__body {
margin-top: 10px;
background: var(--card-background);
border-radius: var(--card-radius);
overflow: hidden;
}
.form-label {
display: flex;
align-items: center;
}
.form-item {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 4em;
padding: 0.5em 18px;
position: relative;
}
.form-item--link .icon-arrow-right {
color: #86868b;
}
.form-item-cover {
width: 40px;
height: 40px;
border-radius: 6px;
border: 0;
}
.form-item-tite {
margin: 0px 12px;
font-size: 14px;
font-weight: 700;
}
.form-item-desc {
color: #999;
margin: 0px 12px;
font-size: 13px;
}
`;
// =========================================================
const js = `
(() => {
// const settingItems = JSON.parse('${JSON.stringify(settingItems)}')
// window.invoke = (title, url) => {
// window.dispatchEvent(
// new CustomEvent(
// 'JBridge',
// { detail: { title, url } }
// )
// )
// }
// const fragment = document.createDocumentFragment()
// for (const item of settingItems) {
// }
// document.getElementById('form').appendChild(fragment)
})()`;
// =========================================================
const html = `
`;
// 预览web
const previewWebView = new WebView();
await previewWebView.loadHTML(html, 'https://tophub.today');
const injectListener = async () => {
const event = await previewWebView.evaluateJavaScript(
`(() => {
try {
const controller = new AbortController()
const listener = (e) => {
completion(e.detail)
controller.abort()
}
window.addEventListener(
'JBridge',
listener,
{ signal: controller.signal }
)
} catch (e) {
alert("搜索界面出错:" + e);
throw new Error("搜索界面处理出错: " + e);
return;
}
})()`, true).catch((err) => {
console.error(err);
this.ERRS.push(err);
if (!config.runsInApp) {
this.notify('APP主界面', `🚫 ${err}`);
} else {
throw err
}
});
////////////////////////////////////
const { code, data } = event;
}
injectListener().catch((e) => {
console.error(e);
});
previewWebView.present();
}
async getAppViewOptions() {
return {
widgetProvider: {
small: false, // 是否提供小号组件
medium: true, // 是否提供中号组件
large: true, // 是否提供大号组件
},
// 预览界面的组件设置item
settingItems: [
{
name: 'hotban',
label: '热搜榜搜索',
type: 'cell',
icon: { name: 'flame', color: '#EB3323', },
needLoading: true,
default: this.getHotban().title,
},
],
// cell类型的item点击回调
onItemClick: async (item) => {
let widgetSetting = this.readWidgetSetting();
let insertDesc;
switch (item.name) {
case 'hotban':
await this.generateInputAlert({
title: '热榜搜索',
options: [{ hint: '请输入关键字', value: '' }]
}, async (inputArr) => {
const keyword = inputArr[0].value;
let response = undefined;
try {
//////
const html = await this.httpGet(`${this.defaultPreference.domain}/search?q=${encodeURIComponent(keyword)}`, { jsonFromat: false, headers: this.defaultPreference.phoneHeaders });
let webview = new WebView();
await webview.loadHTML(html);
// 通过dom操作把HTML里面的热榜内容提取出来
const getData = `
function getData() {
// 图片封面
coverArr = []
// 链接
linkArr = []
// 标题
titleArr = []
// 描述
tipArr = []
// 图片封面
let allItemNodeList = document.getElementsByClassName('weui-media-box__thumb radius');
for(let node of allItemNodeList) {
coverArr.push(node.src)
}
// 链接
allItemNodeList = document.getElementsByClassName('weui-media-box weui-media-box_appmsg weui-cell');
for(let node of allItemNodeList) {
linkArr.push(node.href)
}
// 标题
allItemNodeList = document.getElementsByClassName('weui-media-box__title');
for(let node of allItemNodeList) {
titleArr.push(node.innerText)
}
// 订阅人数
allItemNodeList = document.getElementsByClassName('weui-media-box__desc');
for(let node of allItemNodeList) {
tipArr.push(node.innerText)
}
return { coverArr, linkArr, titleArr, tipArr };
}
getData()
`
// 热榜数据
response = await webview.evaluateJavaScript(getData, false);
const { linkArr = [] } = response;
if (linkArr.length === 0) {
await this.generateAlert('热榜搜索', '搜索结果为空', ['确定']);
} else {
await this.renderSearchResultView(response);
}
//////
} catch (error) {
console.error(`🚫 热榜搜索出错===>${error}`);
await this.generateAlert('热榜搜索', '🚫热榜搜索出错了', ['确定']);
};
});
break;
}
// 写入更新配置
this.writeWidgetSetting(widgetSetting);
return {
desc: { value: insertDesc },
};
},
};
}
async render({ widgetSetting, family }) {
let widget = new ListWidget();
widget.setPadding(0, 0, 0, 0);
let image = await this.drawSFIcon2();
let imgSpan = widget.addImage(image);
// let textSpan = widget.addText('HTML5 Canvas Shadow')
// textSpan.font = Font.systemFont(30)
// textSpan.textColor = Color.white()
console.log(`>>>>>>>>>${image.size.width}, ${image.size.height}`);
// Photos.save(image)
// let scale = Device.screenScale();
// imgSpan.imageSize = new Size(image.size.width / scale, image.size.height / scale);
return widget;
}
drawSFIcon2 = async (
) => {
try {
const { width, height } = this.getWidgetSize('中号')
console.log(`---------${width}`);
const html = `
`
const js = `
var canvas = document.getElementById("mainCanvas");
var context = canvas.getContext("2d");
context.textBaseline= "hanging";
let width = canvas.width, height = canvas.height;
if (window.devicePixelRatio) {
canvas.style.width = width + "px";
canvas.style.height = height + "px";
canvas.height = height * window.devicePixelRatio;
canvas.width = width * window.devicePixelRatio;
context.scale(window.devicePixelRatio, window.devicePixelRatio);
}
// context.shadowOffsetX = 10;
// context.shadowOffsetY = 10;
// context.shadowBlur = 4;
// context.shadowColor = "#666666";//或使用rgb(红色,绿色,蓝色)
context.fillStyle = "#FFFFFF";
context.font = "normal 30px Arial";
context.textBaseline= "hanging";
context.fillText("HTML5 Canvas Shadow", 0, 20);
var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
context.putImageData(imgData, 0, 0);
silhouetteImg.src = canvas.toDataURL();
output = canvas.toDataURL()
`
let wv = new WebView();
await wv.loadHTML(html);
const base64Image = await wv.evaluateJavaScript(js);
const iconImage = await new Request(base64Image).loadImage();
return iconImage;
} catch (error) {
console.error(error);
this.ERRS.push(error);
if (!config.runsInApp) {
await this.notify('icon绘制', `🚫 ${error}`);
} else {
throw error
}
}
}
// --------------------------NET START--------------------------
// --------------------------NET END--------------------------
}
await new Widget(Script.name()).run();
// =================================================================================
// =================================================================================
async function downloadLSPDependency() {
let fm = FileManager.local();
const dependencyURL = `${remoteRoot}_LSP.js`;
if (isDev) {
const iCloudPath = FileManager.iCloud().documentsDirectory();
const localIcloudDependencyExit = fm.isFileStoredIniCloud(`${iCloudPath}/_LSP.js`);
const localDependencyExit = fm.fileExists(`${rootDir}/_LSP.js`);
const fileExist = localIcloudDependencyExit || localDependencyExit;
console.log(`🚀 DEV开发依赖文件${fileExist ? '已存在 ✅' : '不存在 🚫'}`);
if (!fileExist) {
console.log(`🤖 DEV 开始下载依赖~`);
await downloadFile2Scriptable('_LSP', dependencyURL);
}
return
}
//////////////////////////////////////////////////////////
console.log(`----------------------------------------`);
const remoteDependencyExit = fm.fileExists(`${cacheDir}/_LSP.js`);
console.log(`🚀 RELEASE依赖文件${remoteDependencyExit ? '已存在 ✅' : '不存在 🚫'}`);
console.log(`----------------------------------------`);
// ------------------------------
if (!remoteDependencyExit) { // 下载依赖
// 创建根目录
if (!fm.fileExists(cacheDir)) {
fm.createDirectory(cacheDir, true);
}
// 下载
console.log('🤖 RELEASE开始下载依赖~');
console.log(`----------------------------------------`);
const req = new Request(dependencyURL);
const moduleJs = await req.load();
if (moduleJs) {
fm.write(fm.joinPath(cacheDir, '/_LSP.js'), moduleJs);
console.log('✅ LSP远程依赖环境下载成功!');
console.log(`----------------------------------------`);
} else {
console.error('🚫 获取依赖环境脚本失败,请重试!');
console.log(`----------------------------------------`);
}
}
}
/**
* 获取保存的文件名
* @param {*} fileName
* @returns
*/
function getSaveFileName(fileName) {
const hasSuffix = fileName.lastIndexOf(".") + 1;
return !hasSuffix ? `${fileName}.js` : fileName;
};
/**
* 保存文件到Scriptable软件目录,app可看到
* @param {*} fileName
* @param {*} content
* @returns
*/
function saveFile2Scriptable(fileName, content) {
try {
const fm = FileManager.iCloud();
let fileSimpleName = getSaveFileName(fileName);
const filePath = fm.joinPath(fm.documentsDirectory(), fileSimpleName);
fm.writeString(filePath, content);
return true;
} catch (error) {
return false;
}
};
/**
* 下载js文件到Scriptable软件目录
* @param {*} moduleName 名称
* @param {*} url 在线地址
* @returns
*/
async function downloadFile2Scriptable(moduleName, url) {
const req = new Request(url);
const content = await req.loadString();
return saveFile2Scriptable(`${moduleName}`, content);
};
// =================================================================================
// =================================================================================