// 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); }; // ================================================================================= // =================================================================================