From 9137d3af7016be42d736c5e5d19608db21351280 Mon Sep 17 00:00:00 2001 From: dompling <374779789@qq.com> Date: Mon, 21 Aug 2023 15:50:07 +0800 Subject: [PATCH 01/42] Spotify --- Scripts/DmYY.js | 754 ++++++++++++++++++++------------------------- Scripts/Spotify.js | 672 ++++++++++++++++++++++++++++++++++++++++ install.json | 21 ++ 3 files changed, 1029 insertions(+), 418 deletions(-) create mode 100644 Scripts/Spotify.js diff --git a/Scripts/DmYY.js b/Scripts/DmYY.js index eb2acde..ea51fb4 100644 --- a/Scripts/DmYY.js +++ b/Scripts/DmYY.js @@ -11,35 +11,36 @@ class DmYY { constructor(arg, defaultSettings) { this.arg = arg; this.defaultSettings = defaultSettings || {}; + this.SETTING_KEY = this.md5(Script.name()); this._init(); this.isNight = Device.isUsingDarkAppearance(); } - BaseCacheKey = 'DmYY'; + BaseCacheKey = "DmYY"; _actions = []; _menuActions = []; widgetColor; backGroundColor; isNight; - userConfigKey = ['avatar', 'nickname', 'homePageDesc']; + userConfigKey = ["avatar", "nickname", "homePageDesc"]; // 获取 Request 对象 - getRequest = (url = '') => { + getRequest = (url = "") => { return new Request(url); }; // 发起请求 http = async ( - options = { headers: {}, url: '' }, - type = 'JSON', + options = { headers: {}, url: "" }, + type = "JSON", onError = () => { - return SFSymbol.named('photo').image; + return SFSymbol.named("photo").image; } ) => { let request; try { - if (type === 'IMG') { + if (type === "IMG") { const fileName = `${this.cacheImage}/${this.md5(options.url)}`; request = this.getRequest(options.url); let response; @@ -60,50 +61,50 @@ class DmYY { }); request.headers = { ...this.defaultHeaders, ...options.headers }; - if (type === 'JSON') { + if (type === "JSON") { return await request.loadJSON(); } - if (type === 'STRING') { + if (type === "STRING") { return await request.loadString(); } return await request.loadJSON(); } catch (e) { - console.log('error:' + e); - if (type === 'IMG') return onError?.(); + console.log("error:" + e); + if (type === "IMG") return onError?.(); } }; //request 接口请求 $request = { - get: (url = '', options = {}, type = 'JSON') => { - let params = { ...options, method: 'GET' }; - if (typeof url === 'object') { + get: (url = "", options = {}, type = "JSON") => { + let params = { ...options, method: "GET" }; + if (typeof url === "object") { params = { ...params, ...url }; } else { params.url = url; } let _type = type; - if (typeof options === 'string') _type = options; + if (typeof options === "string") _type = options; return this.http(params, _type); }, - post: (url = '', options = {}, type = 'JSON') => { - let params = { ...options, method: 'POST' }; - if (typeof url === 'object') { + post: (url = "", options = {}, type = "JSON") => { + let params = { ...options, method: "POST" }; + if (typeof url === "object") { params = { ...params, ...url }; } else { params.url = url; } let _type = type; - if (typeof options === 'string') _type = options; + if (typeof options === "string") _type = options; return this.http(params, _type); }, }; // 获取 boxJS 缓存 - getCache = async (key = '', notify = true) => { + getCache = async (key = "", notify = true) => { try { - let url = 'http://' + this.prefix + '/query/boxdata'; - if (key) url = 'http://' + this.prefix + '/query/data/' + key; + let url = "http://" + this.prefix + "/query/boxdata"; + if (key) url = "http://" + this.prefix + "/query/data/" + key; const boxdata = await this.$request.get( url, key ? { timeoutInterval: 1 } : {} @@ -125,15 +126,15 @@ class DmYY { if (notify) await this.notify( `${this.name} - BoxJS 数据读取失败`, - '请检查 BoxJS 域名是否为代理复写的域名,如(boxjs.net 或 boxjs.com)。\n若没有配置 BoxJS 相关模块,请点击通知查看教程', - 'https://chavyleung.gitbook.io/boxjs/awesome/videos' + "请检查 BoxJS 域名是否为代理复写的域名,如(boxjs.net 或 boxjs.com)。\n若没有配置 BoxJS 相关模块,请点击通知查看教程", + "https://chavyleung.gitbook.io/boxjs/awesome/videos" ); return false; } }; transforJSON = (str) => { - if (typeof str == 'string') { + if (typeof str == "string") { try { return JSON.parse(str); } catch (e) { @@ -141,13 +142,13 @@ class DmYY { return str; } } - console.log('It is not a string!'); + console.log("It is not a string!"); }; // 选择图片并缓存 chooseImg = async (verify = false) => { const response = await Photos.fromLibrary().catch((err) => { - console.log('图片选择异常:' + err); + console.log("图片选择异常:" + err); }); if (verify) { const bool = await this.verifyImage(response); @@ -166,7 +167,7 @@ class DmYY { : Number(this.settings.lightOpacity); widget.backgroundImage = await this.shadowImage( backgroundImage, - '#000', + "#000", opacity ); return true; @@ -188,21 +189,21 @@ class DmYY { const { width, height } = img.size; const direct = true; if (width > 1000) { - const options = ['取消', '打开图像处理']; + const options = ["取消", "打开图像处理"]; const message = - '您的图片像素为' + + "您的图片像素为" + width + - ' x ' + + " x " + height + - '\n' + - '请将图片' + - (direct ? '宽度' : '高度') + - '调整到 1000 以下\n' + - (!direct ? '宽度' : '高度') + - '自动适应'; + "\n" + + "请将图片" + + (direct ? "宽度" : "高度") + + "调整到 1000 以下\n" + + (!direct ? "宽度" : "高度") + + "自动适应"; const index = await this.generateAlert(message, options); if (index === 1) - Safari.openInApp('https://www.sojson.com/image/change.html', false); + Safari.openInApp("https://www.sojson.com/image/change.html", false); return false; } return true; @@ -364,8 +365,8 @@ class DmYY { } let message = - title || '开始之前,请先前往桌面,截取空白界面的截图。然后回来继续'; - let exitOptions = ['我已截图', '前去截图 >']; + title || "开始之前,请先前往桌面,截取空白界面的截图。然后回来继续"; + let exitOptions = ["我已截图", "前去截图 >"]; let shouldExit = await this.generateAlert(message, exitOptions); if (shouldExit) return; @@ -374,15 +375,15 @@ class DmYY { let height = img.size.height; let phone = phoneSizes()[height]; if (!phone) { - message = '好像您选择的照片不是正确的截图,请先前往桌面'; - await this.generateAlert(message, ['我已知晓']); + message = "好像您选择的照片不是正确的截图,请先前往桌面"; + await this.generateAlert(message, ["我已知晓"]); return; } // Extra setup needed for 2436-sized phones. if (height === 2436) { const files = this.FILE_MGR_LOCAL; - let cacheName = 'mz-phone-type'; + let cacheName = "mz-phone-type"; let cachePath = files.joinPath(files.libraryDirectory(), cacheName); // If we already cached the phone size, load it. @@ -391,70 +392,70 @@ class DmYY { phone = phone[typeString]; // Otherwise, prompt the user. } else { - message = '您的📱型号是?'; - let types = ['iPhone 12 mini', 'iPhone 11 Pro, XS, or X']; + message = "您的📱型号是?"; + let types = ["iPhone 12 mini", "iPhone 11 Pro, XS, or X"]; let typeIndex = await this.generateAlert(message, types); - let type = typeIndex === 0 ? 'mini' : 'x'; + let type = typeIndex === 0 ? "mini" : "x"; phone = phone[type]; files.writeString(cachePath, type); } } // Prompt for widget size and position. - message = '截图中要设置透明背景组件的尺寸类型是?'; - let sizes = ['小尺寸', '中尺寸', '大尺寸']; + message = "截图中要设置透明背景组件的尺寸类型是?"; + let sizes = ["小尺寸", "中尺寸", "大尺寸"]; let size = await this.generateAlert(message, sizes); let widgetSize = sizes[size]; - message = '要设置透明背景的小组件在哪个位置?'; + message = "要设置透明背景的小组件在哪个位置?"; message += height === 1136 - ? ' (备注:当前设备只支持两行小组件,所以下边选项中的「中间」和「底部」的选项是一致的)' - : ''; + ? " (备注:当前设备只支持两行小组件,所以下边选项中的「中间」和「底部」的选项是一致的)" + : ""; // Determine image crop based on phone size. - let crop = { w: '', h: '', x: '', y: '' }; - if (widgetSize === '小尺寸') { + let crop = { w: "", h: "", x: "", y: "" }; + if (widgetSize === "小尺寸") { crop.w = phone.small; crop.h = phone.small; let positions = [ - '左上角', - '右上角', - '中间左', - '中间右', - '左下角', - '右下角', + "左上角", + "右上角", + "中间左", + "中间右", + "左下角", + "右下角", ]; let _posotions = [ - 'Top left', - 'Top right', - 'Middle left', - 'Middle right', - 'Bottom left', - 'Bottom right', + "Top left", + "Top right", + "Middle left", + "Middle right", + "Bottom left", + "Bottom right", ]; let position = await this.generateAlert(message, positions); // Convert the two words into two keys for the phone size dictionary. - let keys = _posotions[position].toLowerCase().split(' '); + let keys = _posotions[position].toLowerCase().split(" "); crop.y = phone[keys[0]]; crop.x = phone[keys[1]]; - } else if (widgetSize === '中尺寸') { + } else if (widgetSize === "中尺寸") { crop.w = phone.medium; crop.h = phone.small; // Medium and large widgets have a fixed x-value. crop.x = phone.left; - let positions = ['顶部', '中间', '底部']; - let _positions = ['Top', 'Middle', 'Bottom']; + let positions = ["顶部", "中间", "底部"]; + let _positions = ["Top", "Middle", "Bottom"]; let position = await this.generateAlert(message, positions); let key = _positions[position].toLowerCase(); crop.y = phone[key]; - } else if (widgetSize === '大尺寸') { + } else if (widgetSize === "大尺寸") { crop.w = phone.medium; crop.h = phone.large; crop.x = phone.left; - let positions = ['顶部', '底部']; + let positions = ["顶部", "底部"]; let position = await this.generateAlert(message, positions); // Large widgets at the bottom have the "middle" y-value. @@ -465,17 +466,17 @@ class DmYY { return cropImage(img, new Rect(crop.x, crop.y, crop.w, crop.h)); } - setLightAndDark = async (title, desc, val, placeholder = '') => { + setLightAndDark = async (title, desc, val, placeholder = "") => { try { const a = new Alert(); a.title = title; a.message = desc; - a.addTextField(placeholder, `${this.settings[val] || ''}`); - a.addAction('确定'); - a.addCancelAction('取消'); + a.addTextField(placeholder, `${this.settings[val] || ""}`); + a.addAction("确定"); + a.addCancelAction("取消"); const id = await a.presentAlert(); if (id === -1) return false; - this.settings[val] = a.textFieldValue(0) || ''; + this.settings[val] = a.textFieldValue(0) || ""; this.saveSettings(); return true; } catch (e) { @@ -493,17 +494,17 @@ class DmYY { setAlertInput = async (title, desc, opt = {}, isSave = true) => { const a = new Alert(); a.title = title; - a.message = !desc ? '' : desc; + a.message = !desc ? "" : desc; Object.keys(opt).forEach((key) => { a.addTextField(opt[key], this.settings[key]); }); - a.addAction('确定'); - a.addCancelAction('取消'); + a.addAction("确定"); + a.addCancelAction("取消"); const id = await a.presentAlert(); if (id === -1) return; const data = {}; Object.keys(opt).forEach((key, index) => { - data[key] = a.textFieldValue(index) || ''; + data[key] = a.textFieldValue(index) || ""; }); // 保存到本地 if (isSave) { @@ -516,17 +517,17 @@ class DmYY { setBaseAlertInput = async (title, desc, opt = {}, isSave = true) => { const a = new Alert(); a.title = title; - a.message = !desc ? '' : desc; + a.message = !desc ? "" : desc; Object.keys(opt).forEach((key) => { - a.addTextField(opt[key], this.baseSettings[key] || ''); + a.addTextField(opt[key], this.baseSettings[key] || ""); }); - a.addAction('确定'); - a.addCancelAction('取消'); + a.addAction("确定"); + a.addCancelAction("取消"); const id = await a.presentAlert(); if (id === -1) return; const data = {}; Object.keys(opt).forEach((key, index) => { - data[key] = a.textFieldValue(index) || ''; + data[key] = a.textFieldValue(index) || ""; }); // 保存到本地 if (isSave) return this.saveBaseSettings(data); @@ -539,14 +540,14 @@ class DmYY { * @returns {Promise} */ setCacheBoxJSData = async (opt = {}) => { - const options = ['取消', '确定']; - const message = '代理缓存仅支持 BoxJS 相关的代理!'; + const options = ["取消", "确定"]; + const message = "代理缓存仅支持 BoxJS 相关的代理!"; const index = await this.generateAlert(message, options); if (index === 0) return; try { const boxJSData = await this.getCache(); Object.keys(opt).forEach((key) => { - this.settings[key] = boxJSData[opt[key]] || ''; + this.settings[key] = boxJSData[opt[key]] || ""; }); // 保存到本地 this.saveSettings(); @@ -554,8 +555,8 @@ class DmYY { console.log(e); this.notify( this.name, - 'BoxJS 缓存读取失败!点击查看相关教程', - 'https://chavyleung.gitbook.io/boxjs/awesome/videos' + "BoxJS 缓存读取失败!点击查看相关教程", + "https://chavyleung.gitbook.io/boxjs/awesome/videos" ); } }; @@ -567,72 +568,72 @@ class DmYY { setWidgetConfig = async () => { const basic = [ { - icon: { name: 'arrow.clockwise', color: '#1890ff' }, - type: 'input', - title: '刷新时间', - desc: '刷新时间仅供参考,具体刷新时间由系统判断,单位:分钟', - val: 'refreshAfterDate', + icon: { name: "arrow.clockwise", color: "#1890ff" }, + type: "input", + title: "刷新时间", + desc: "刷新时间仅供参考,具体刷新时间由系统判断,单位:分钟", + val: "refreshAfterDate", }, { - icon: { name: 'sun.max.fill', color: '#d48806' }, - type: 'color', - title: '白天字体颜色', - desc: '请自行去网站上搜寻颜色(Hex 颜色)', - val: 'lightColor', + icon: { name: "sun.max.fill", color: "#d48806" }, + type: "color", + title: "白天字体颜色", + desc: "请自行去网站上搜寻颜色(Hex 颜色)", + val: "lightColor", }, { - icon: { name: 'moon.stars.fill', color: '#d4b106' }, - type: 'color', - title: '晚上字体颜色', - desc: '请自行去网站上搜寻颜色(Hex 颜色)', - val: 'darkColor', + icon: { name: "moon.stars.fill", color: "#d4b106" }, + type: "color", + title: "晚上字体颜色", + desc: "请自行去网站上搜寻颜色(Hex 颜色)", + val: "darkColor", }, ]; return this.renderAppView([ - { title: '基础设置', menu: basic }, + { title: "基础设置", menu: basic }, { - title: '背景设置', + title: "背景设置", menu: [ { - icon: { name: 'photo', color: '#13c2c2' }, - type: 'color', - title: '白天背景颜色', - desc: '请自行去网站上搜寻颜色(Hex 颜色)\n支持渐变色,各颜色之间以英文逗号分隔', - val: 'lightBgColor', + icon: { name: "photo", color: "#13c2c2" }, + type: "color", + title: "白天背景颜色", + desc: "请自行去网站上搜寻颜色(Hex 颜色)\n支持渐变色,各颜色之间以英文逗号分隔", + val: "lightBgColor", }, { - icon: { name: 'photo.fill', color: '#52c41a' }, - type: 'color', - title: '晚上背景颜色', - desc: '请自行去网站上搜寻颜色(Hex 颜色)\n支持渐变色,各颜色之间以英文逗号分隔', - val: 'darkBgColor', + icon: { name: "photo.fill", color: "#52c41a" }, + type: "color", + title: "晚上背景颜色", + desc: "请自行去网站上搜寻颜色(Hex 颜色)\n支持渐变色,各颜色之间以英文逗号分隔", + val: "darkBgColor", }, ], }, { menu: [ { - icon: { name: 'photo.on.rectangle', color: '#fa8c16' }, - name: 'dayBg', - type: 'img', - title: '日间背景', + icon: { name: "photo.on.rectangle", color: "#fa8c16" }, + name: "dayBg", + type: "img", + title: "日间背景", val: this.cacheImage, verify: true, }, { - icon: { name: 'photo.fill.on.rectangle.fill', color: '#fa541c' }, - name: 'nightBg', - type: 'img', - title: '夜间背景', + icon: { name: "photo.fill.on.rectangle.fill", color: "#fa541c" }, + name: "nightBg", + type: "img", + title: "夜间背景", val: this.cacheImage, verify: true, }, { - icon: { name: 'text.below.photo', color: '#faad14' }, - type: 'img', - name: 'transparentBg', - title: '透明背景', + icon: { name: "text.below.photo", color: "#faad14" }, + type: "img", + name: "transparentBg", + title: "透明背景", val: this.cacheImage, onClick: async (item, __, previewWebView) => { const backImage = await this.getWidgetScreenShot(); @@ -649,38 +650,38 @@ class DmYY { { menu: [ { - icon: { name: 'record.circle', color: '#722ed1' }, - type: 'input', - title: '日间蒙层', - desc: '完全透明请设置为0', - val: 'lightOpacity', + icon: { name: "record.circle", color: "#722ed1" }, + type: "input", + title: "日间蒙层", + desc: "完全透明请设置为0", + val: "lightOpacity", }, { - icon: { name: 'record.circle.fill', color: '#eb2f96' }, - type: 'input', - title: '夜间蒙层', - desc: '完全透明请设置为0', - val: 'darkOpacity', + icon: { name: "record.circle.fill", color: "#eb2f96" }, + type: "input", + title: "夜间蒙层", + desc: "完全透明请设置为0", + val: "darkOpacity", }, ], }, { menu: [ { - icon: { name: 'clear', color: '#f5222d' }, - name: 'removeBackground', - title: '清空背景图片', + icon: { name: "clear", color: "#f5222d" }, + name: "removeBackground", + title: "清空背景图片", val: `${this.cacheImage}/`, onClick: async (_, __, previewWebView) => { - const ids = ['dayBg', 'nightBg', 'transparentBg']; + const ids = ["dayBg", "nightBg", "transparentBg"]; const options = [ - '清空日间', - '清空夜间', - '清空透明', + "清空日间", + "清空夜间", + "清空透明", `清空全部`, - '取消', + "取消", ]; - const message = '该操作不可逆,会清空背景图片!'; + const message = "该操作不可逆,会清空背景图片!"; const index = await this.generateAlert(message, options); if (index === 4) return; switch (index) { @@ -703,17 +704,34 @@ class DmYY { }, ], }, + { + title:"重置组件", + menu:[ + { + icon: { name: "trash", color: "#D85888" }, + title: "重置", + desc: "重置当前组件配置", + name:"reset", + val: "reset", + onClick:()=>{ + this.settings = {} + this.saveSettings(); + this.reopenScript(); + } + }, + ] + } ]).catch((e) => { console.log(e); }); }; drawTableIcon = async ( - icon = 'square.grid.2x2', - color = '#504ED5', + icon = "square.grid.2x2", + color = "#504ED5", cornerWidth = 42 ) => { - let sfi = SFSymbol.named('square.grid.2x2'); + let sfi = SFSymbol.named("square.grid.2x2"); try { sfi = SFSymbol.named(icon); sfi.applyFont(Font.mediumSystemFont(30)); @@ -790,8 +808,8 @@ class DmYY { }; loadSF2B64 = async ( - icon = 'square.grid.2x2', - color = '#56A8D6', + icon = "square.grid.2x2", + color = "#56A8D6", cornerWidth = 42 ) => { const sfImg = await this.drawTableIcon(icon, color, cornerWidth); @@ -809,25 +827,25 @@ class DmYY { return this.renderAppView([ { - title: '个性设置', + title: "个性设置", menu: [ { - icon: { name: 'person', color: '#fa541c' }, + icon: { name: "person", color: "#fa541c" }, name: this.userConfigKey[0], - title: '首页头像', - type: 'img', + title: "首页头像", + type: "img", val: this.baseImage, onClick: async (_, __, previewWebView) => { - const options = ['相册选择', '在线链接', '取消']; - const message = '设置个性化头像'; + const options = ["相册选择", "在线链接", "取消"]; + const message = "设置个性化头像"; const index = await this.generateAlert(message, options); if (index === 2) return; const cachePath = `${_.val}/${_.name}`; switch (index) { case 0: - const albumOptions = ['选择图片', '清空图片', '取消']; + const albumOptions = ["选择图片", "清空图片", "取消"]; - const albumIndex = await this.generateAlert('', albumOptions); + const albumIndex = await this.generateAlert("", albumOptions); if (albumIndex === 2) return; if (albumIndex === 1) { await this.htmlChangeImage(false, cachePath, { @@ -848,18 +866,18 @@ class DmYY { break; case 1: const data = await this.setBaseAlertInput( - '在线链接', - '首页头像在线链接', + "在线链接", + "首页头像在线链接", { - avatar: '🔗请输入 URL 图片链接', + avatar: "🔗请输入 URL 图片链接", } ); if (!data) return; - if (data[_.name] !== '') { + if (data[_.name] !== "") { const backImage = await this.$request.get( data[_.name], - 'IMG' + "IMG" ); await this.htmlChangeImage(backImage, cachePath, { previewWebView, @@ -879,22 +897,22 @@ class DmYY { }, }, { - icon: { name: 'pencil', color: '#fa8c16' }, - type: 'input', - title: '首页昵称', - desc: '个性化首页昵称', - placeholder: '👤请输入头像昵称', + icon: { name: "pencil", color: "#fa8c16" }, + type: "input", + title: "首页昵称", + desc: "个性化首页昵称", + placeholder: "👤请输入头像昵称", val: this.userConfigKey[1], name: this.userConfigKey[1], defaultValue: this.baseSettings.nickname, onClick: baseOnClick, }, { - icon: { name: 'lineweight', color: '#a0d911' }, - type: 'input', - title: '首页昵称描述', - desc: '个性化首页昵称描述', - placeholder: '请输入描述', + icon: { name: "lineweight", color: "#a0d911" }, + type: "input", + title: "首页昵称描述", + desc: "个性化首页昵称描述", + placeholder: "请输入描述", val: this.userConfigKey[2], name: this.userConfigKey[2], defaultValue: this.baseSettings.homePageDesc, @@ -905,23 +923,23 @@ class DmYY { { menu: [ { - icon: { name: 'shippingbox', color: '#f7bb10' }, - type: 'input', - title: 'BoxJS 域名', - desc: '设置BoxJS访问域名,如:boxjs.net 或 boxjs.com', - val: 'boxjsDomain', - name: 'boxjsDomain', - placeholder: 'boxjs.net', + icon: { name: "shippingbox", color: "#f7bb10" }, + type: "input", + title: "BoxJS 域名", + desc: "设置BoxJS访问域名,如:boxjs.net 或 boxjs.com", + val: "boxjsDomain", + name: "boxjsDomain", + placeholder: "boxjs.net", defaultValue: this.baseSettings.boxjsDomain, onClick: baseOnClick, }, { - icon: { name: 'clear', color: '#f5222d' }, - title: '恢复默认设置', - name: 'reset', + icon: { name: "clear", color: "#f5222d" }, + title: "恢复默认设置", + name: "reset", onClick: async () => { - const options = ['取消', '确定']; - const message = '确定要恢复当前所有配置吗?'; + const options = ["取消", "确定"]; + const message = "确定要恢复当前所有配置吗?"; const index = await this.generateAlert(message, options); if (index === 1) { this.settings = {}; @@ -936,8 +954,8 @@ class DmYY { this.saveSettings(false); this.saveBaseSettings(); await this.notify( - '重置成功', - '请关闭窗口之后,重新运行当前脚本' + "重置成功", + "请关闭窗口之后,重新运行当前脚本" ); this.reopenScript(); } @@ -954,7 +972,7 @@ class DmYY { this.insertTextByElementId( previewWebView, id, - base64Img ? `` : '' + base64Img ? `` : "" ); }; @@ -1236,7 +1254,7 @@ class DmYY { actionsConfig = [...item.menu, ...actionsConfig]; configList += `
-
${item.title || ''}
+
${item.title || ""}
`; @@ -1245,7 +1263,7 @@ class DmYY { if (menuItem.children) { menuItem.onClick = () => { return this.renderAppView( - typeof menuItem.children === 'function' + typeof menuItem.children === "function" ? menuItem.children() : menuItem.children ); @@ -1254,13 +1272,13 @@ class DmYY { if (menuItem.url) { const imageIcon = await this.http( { url: menuItem.url }, - 'IMG', + "IMG", () => { - return this.drawTableIcon('gear'); + return this.drawTableIcon("gear"); } ); - if (menuItem.url.indexOf('png') !== -1) { + if (menuItem.url.indexOf("png") !== -1) { iconBase64 = `data:image/png;base64,${Data.fromPNG( imageIcon ).toBase64String()}`; @@ -1277,11 +1295,11 @@ class DmYY { let defaultHtml = ``; if (idName !== undefined && !menuItem.defaultValue) - menuItem.defaultValue = this.settings[idName] || ''; + menuItem.defaultValue = this.settings[idName] || ""; - if (menuItem.type === 'input') { - defaultHtml = menuItem.defaultValue || ''; - } else if (menuItem.type === 'img') { + if (menuItem.type === "input") { + defaultHtml = menuItem.defaultValue || ""; + } else if (menuItem.type === "img") { const cachePath = `${menuItem.val}/${menuItem.name}`; if (await this.FILE_MGR.fileExistsExtra(cachePath)) { const imageSrc = `data:image/png;base64,${Data.fromFile( @@ -1289,25 +1307,25 @@ class DmYY { ).toBase64String()}`; defaultHtml = ``; } - } else if (menuItem.type === 'select') { - let selectOptions = ''; + } else if (menuItem.type === "select") { + let selectOptions = ""; menuItem.options.forEach((option) => { let selected = `selected="selected"`; selectOptions += ``; }); defaultHtml = ``; - } else if (menuItem.type === 'switch') { + } else if (menuItem.type === "switch") { const checked = - menuItem.defaultValue === 'true' ? `checked="checked"` : ''; + menuItem.defaultValue === "true" ? `checked="checked"` : ""; defaultHtml += ``; } else if (menuItem.type) { defaultHtml = ``; + }" enterkeyhint="done" value="${menuItem.defaultValue || ""}">`; } configList += ` @@ -1326,15 +1344,15 @@ class DmYY { configList += `
`; } - let avatarHtml = ''; + let avatarHtml = ""; if (renderAvatar) { const cachePath = `${this.baseImage}/${this.userConfigKey[0]}`; const avatarConfig = { avatar: `https://avatars.githubusercontent.com/u/23498579?v=4`, - nickname: this.baseSettings[this.userConfigKey[1]] || 'Dompling', + nickname: this.baseSettings[this.userConfigKey[1]] || "Dompling", homPageDesc: this.baseSettings[this.userConfigKey[2]] || - '18岁,来自九仙山的设计师', + "18岁,来自九仙山的设计师", }; if (await this.FILE_MGR.fileExistsExtra(cachePath)) { @@ -1409,30 +1427,30 @@ class DmYY { (item) => (item.name || item.val) === code ); - if (code === 'userInfo') await this.setUserInfo(); + if (code === "userInfo") await this.setUserInfo(); if (actionItem) { const idName = actionItem?.name || actionItem?.val; if (actionItem?.onClick) { await actionItem?.onClick?.(actionItem, data, previewWebView); - } else if (actionItem.type == 'input') { + } else if (actionItem.type == "input") { if ( await this.setLightAndDark( - actionItem['title'], - actionItem['desc'], + actionItem["title"], + actionItem["desc"], idName, - actionItem['placeholder'] + actionItem["placeholder"] ) ) this.insertTextByElementId( previewWebView, idName, - this.settings[idName] || '' + this.settings[idName] || "" ); - } else if (actionItem.type === 'img') { + } else if (actionItem.type === "img") { const cachePath = `${actionItem.val}/${actionItem.name}`; - const options = ['相册选择', '清空图片', '取消']; - const message = '相册图片选择,请选择合适图片大小'; + const options = ["相册选择", "清空图片", "取消"]; + const message = "相册图片选择,请选择合适图片大小"; const index = await this.generateAlert(message, options); switch (index) { case 0: @@ -1462,7 +1480,7 @@ class DmYY { } } } catch (error) { - console.log('异常操作:' + error); + console.log("异常操作:" + error); } this.dismissLoading(previewWebView); injectListener(); @@ -1472,7 +1490,7 @@ class DmYY { console.error(e); this.dismissLoading(previewWebView); if (!config.runsInApp) { - this.notify('主界面', `🚫 ${e}`); + this.notify("主界面", `🚫 ${e}`); } }); @@ -1482,14 +1500,13 @@ class DmYY { _init(widgetFamily = config.widgetFamily) { // 组件大小:small,medium,large this.widgetFamily = widgetFamily; - this.SETTING_KEY = this.md5(Script.name()); //用于配置所有的组件相关设置 // 文件管理器 // 提示:缓存数据不要用这个操作,这个是操作源码目录的,缓存建议存放在local temp目录中 this.FILE_MGR = FileManager[ - module.filename.includes('Documents/iCloud~') ? 'iCloud' : 'local' + module.filename.includes("Documents/iCloud~") ? "iCloud" : "local" ](); this.FILE_MGR.fileExistsExtra = async (filePath) => { @@ -1528,14 +1545,14 @@ class DmYY { this.settings = { ...this.defaultSettings, ...this.settings }; - this.settings.lightColor = this.settings.lightColor || '#000000'; - this.settings.darkColor = this.settings.darkColor || '#ffffff'; - this.settings.lightBgColor = this.settings.lightBgColor || '#ffffff'; - this.settings.darkBgColor = this.settings.darkBgColor || '#000000'; - this.settings.boxjsDomain = this.baseSettings.boxjsDomain || 'boxjs.net'; - this.settings.refreshAfterDate = this.settings.refreshAfterDate || '30'; - this.settings.lightOpacity = this.settings.lightOpacity || '0.4'; - this.settings.darkOpacity = this.settings.darkOpacity || '0.7'; + this.settings.lightColor = this.settings.lightColor || "#000000"; + this.settings.darkColor = this.settings.darkColor || "#ffffff"; + this.settings.lightBgColor = this.settings.lightBgColor || "#ffffff"; + this.settings.darkBgColor = this.settings.darkBgColor || "#000000"; + this.settings.boxjsDomain = this.baseSettings.boxjsDomain || "boxjs.net"; + this.settings.refreshAfterDate = this.settings.refreshAfterDate || "30"; + this.settings.lightOpacity = this.settings.lightOpacity || "0.4"; + this.settings.darkOpacity = this.settings.darkOpacity || "0.7"; this.prefix = this.settings.boxjsDomain; @@ -1565,8 +1582,8 @@ class DmYY { ); } - getColors = (color = '') => { - const colors = typeof color === 'string' ? color.split(',') : color; + getColors = (color = "") => { + const colors = typeof color === "string" ? color.split(",") : color; return colors; }; @@ -1587,9 +1604,9 @@ class DmYY { * @param {string} name 操作函数名 * @param {func} func 点击后执行的函数 */ - registerAction(name, func, icon = { name: 'gear', color: '#096dd9' }, type) { - if (typeof name === 'object' && !name.menu) return this._actions.push(name); - if (typeof name === 'object' && name.menu) + registerAction(name, func, icon = { name: "gear", color: "#096dd9" }, type) { + if (typeof name === "object" && !name.menu) return this._actions.push(name); + if (typeof name === "object" && name.menu) return this._menuActions.push(name); const action = { @@ -1599,7 +1616,7 @@ class DmYY { onClick: func.bind(this), }; - if (typeof icon === 'string') { + if (typeof icon === "string") { action.url = icon; } else { action.icon = icon; @@ -1631,150 +1648,7 @@ class DmYY { * @param {string} str 要加密成md5的数据 */ // prettier-ignore - md5(str) { - function d(n, t) { - var r = (65535 & n) + (65535 & t); - return (((n >> 16) + (t >> 16) + (r >> 16)) << 16) | (65535 & r); - } - - function f(n, t, r, e, o, u) { - return d(((c = d(d(t, n), d(e, u))) << (f = o)) | (c >>> (32 - f)), r); - var c, f; - } - - function l(n, t, r, e, o, u, c) { - return f( - (t & r) | (~t & e), n, t, o, u, c); - } - - function v(n, t, r, e, o, u, c) { - return f( - (t & e) | (r & ~e), n, t, o, u, c); - } - - function g(n, t, r, e, o, u, c) {return f(t ^ r ^ e, n, t, o, u, c);} - - function m(n, t, r, e, o, u, c) {return f(r ^ (t | ~e), n, t, o, u, c);} - - function i(n, t) { - var r, e, o, u; - (n[t >> 5] |= 128 << t % 32), (n[14 + (((t + 64) >>> 9) << 4)] = t); - for (var c = 1732584193, f = -271733879, i = -1732584194, a = 271733878, h = 0; h < - n.length; h += 16) (c = l( - (r = c), (e = f), (o = i), (u = a), n[h], 7, -680876936)), (a = l( - a, c, f, i, n[h + 1], 12, -389564586)), (i = l( - i, a, c, f, n[h + 2], 17, 606105819)), (f = l( - f, i, a, c, n[h + 3], 22, -1044525330)), (c = l( - c, f, i, a, n[h + 4], 7, -176418897)), (a = l( - a, c, f, i, n[h + 5], 12, 1200080426)), (i = l( - i, a, c, f, n[h + 6], 17, -1473231341)), (f = l( - f, i, a, c, n[h + 7], 22, -45705983)), (c = l( - c, f, i, a, n[h + 8], 7, 1770035416)), (a = l( - a, c, f, i, n[h + 9], 12, -1958414417)), (i = l( - i, a, c, f, n[h + 10], 17, -42063)), (f = l( - f, i, a, c, n[h + 11], 22, -1990404162)), (c = l( - c, f, i, a, n[h + 12], 7, 1804603682)), (a = l( - a, c, f, i, n[h + 13], 12, -40341101)), (i = l( - i, a, c, f, n[h + 14], 17, -1502002290)), (c = v( - c, (f = l(f, i, a, c, n[h + 15], 22, 1236535329)), i, a, n[h + 1], 5, - -165796510, - )), (a = v(a, c, f, i, n[h + 6], 9, -1069501632)), (i = v( - i, a, c, f, n[h + 11], 14, 643717713)), (f = v( - f, i, a, c, n[h], 20, -373897302)), (c = v( - c, f, i, a, n[h + 5], 5, -701558691)), (a = v( - a, c, f, i, n[h + 10], 9, 38016083)), (i = v( - i, a, c, f, n[h + 15], 14, -660478335)), (f = v( - f, i, a, c, n[h + 4], 20, -405537848)), (c = v( - c, f, i, a, n[h + 9], 5, 568446438)), (a = v( - a, c, f, i, n[h + 14], 9, -1019803690)), (i = v( - i, a, c, f, n[h + 3], 14, -187363961)), (f = v( - f, i, a, c, n[h + 8], 20, 1163531501)), (c = v( - c, f, i, a, n[h + 13], 5, -1444681467)), (a = v( - a, c, f, i, n[h + 2], 9, -51403784)), (i = v( - i, a, c, f, n[h + 7], 14, 1735328473)), (c = g( - c, (f = v(f, i, a, c, n[h + 12], 20, -1926607734)), i, a, n[h + 5], 4, - -378558, - )), (a = g(a, c, f, i, n[h + 8], 11, -2022574463)), (i = g( - i, a, c, f, n[h + 11], 16, 1839030562)), (f = g( - f, i, a, c, n[h + 14], 23, -35309556)), (c = g( - c, f, i, a, n[h + 1], 4, -1530992060)), (a = g( - a, c, f, i, n[h + 4], 11, 1272893353)), (i = g( - i, a, c, f, n[h + 7], 16, -155497632)), (f = g( - f, i, a, c, n[h + 10], 23, -1094730640)), (c = g( - c, f, i, a, n[h + 13], 4, 681279174)), (a = g( - a, c, f, i, n[h], 11, -358537222)), (i = g( - i, a, c, f, n[h + 3], 16, -722521979)), (f = g( - f, i, a, c, n[h + 6], 23, 76029189)), (c = g( - c, f, i, a, n[h + 9], 4, -640364487)), (a = g( - a, c, f, i, n[h + 12], 11, -421815835)), (i = g( - i, a, c, f, n[h + 15], 16, 530742520)), (c = m( - c, (f = g(f, i, a, c, n[h + 2], 23, -995338651)), i, a, n[h], 6, - -198630844, - )), (a = m(a, c, f, i, n[h + 7], 10, 1126891415)), (i = m( - i, a, c, f, n[h + 14], 15, -1416354905)), (f = m( - f, i, a, c, n[h + 5], 21, -57434055)), (c = m( - c, f, i, a, n[h + 12], 6, 1700485571)), (a = m( - a, c, f, i, n[h + 3], 10, -1894986606)), (i = m( - i, a, c, f, n[h + 10], 15, -1051523)), (f = m( - f, i, a, c, n[h + 1], 21, -2054922799)), (c = m( - c, f, i, a, n[h + 8], 6, 1873313359)), (a = m( - a, c, f, i, n[h + 15], 10, -30611744)), (i = m( - i, a, c, f, n[h + 6], 15, -1560198380)), (f = m( - f, i, a, c, n[h + 13], 21, 1309151649)), (c = m( - c, f, i, a, n[h + 4], 6, -145523070)), (a = m( - a, c, f, i, n[h + 11], 10, -1120210379)), (i = m( - i, a, c, f, n[h + 2], 15, 718787259)), (f = m( - f, i, a, c, n[h + 9], 21, -343485551)), (c = d(c, r)), (f = d( - f, e)), (i = d(i, o)), (a = d(a, u)); - return [c, f, i, a]; - } - - function a(n) { - for (var t = '', r = 32 * n.length, e = 0; e < - r; e += 8) t += String.fromCharCode((n[e >> 5] >>> e % 32) & 255); - return t; - } - - function h(n) { - var t = []; - for (t[(n.length >> 2) - 1] = void 0, e = 0; e < - t.length; e += 1) t[e] = 0; - for (var r = 8 * n.length, e = 0; e < r; e += 8) t[e >> 5] |= (255 & - n.charCodeAt(e / 8)) << e % 32; - return t; - } - - function e(n) { - for (var t, r = '0123456789abcdef', e = '', o = 0; o < - n.length; o += 1) (t = n.charCodeAt(o)), (e += r.charAt((t >>> 4) & 15) + - r.charAt(15 & t)); - return e; - } - - function r(n) {return unescape(encodeURIComponent(n));} - - function o(n) { - return a(i(h((t = r(n))), 8 * t.length)); - var t; - } - - function u(n, t) { - return (function(n, t) { - var r, e, o = h(n), u = [], c = []; - for (u[15] = c[15] = void 0, 16 < o.length && - (o = i(o, 8 * n.length)), r = 0; r < 16; r += 1) (u[r] = 909522486 ^ - o[r]), (c[r] = 1549556828 ^ o[r]); - return ((e = i(u.concat(h(t)), 512 + 8 * t.length)), a( - i(c.concat(e), 640))); - })(r(n), r(t)); - } - - function t(n, t, r) { - return t ? (r ? u(t, n) : e(u(t, n))) : r ? o(n) : e(o(n)); - } - - return t(str); - } + md5(str){function d(n,t){var r=(65535&n)+(65535&t);return(((n>>16)+(t>>16)+(r>>16))<<16)|(65535&r)}function f(n,t,r,e,o,u){return d(((c=d(d(t,n),d(e,u)))<<(f=o))|(c>>>(32-f)),r);var c,f}function l(n,t,r,e,o,u,c){return f((t&r)|(~t&e),n,t,o,u,c)}function v(n,t,r,e,o,u,c){return f((t&e)|(r&~e),n,t,o,u,c)}function g(n,t,r,e,o,u,c){return f(t^r^e,n,t,o,u,c)}function m(n,t,r,e,o,u,c){return f(r^(t|~e),n,t,o,u,c)}function i(n,t){var r,e,o,u;(n[t>>5]|=128<>>9)<<4)]=t);for(var c=1732584193,f=-271733879,i=-1732584194,a=271733878,h=0;h>5]>>>e%32)&255);return t}function h(n){var t=[];for(t[(n.length>>2)-1]=void 0,e=0;e>5]|=(255&n.charCodeAt(e/8))<>>4)&15)+r.charAt(15&t));return e}function r(n){return unescape(encodeURIComponent(n))}function o(n){return a(i(h((t=r(n))),8*t.length));var t}function u(n,t){return(function(n,t){var r,e,o=h(n),u=[],c=[];for(u[15]=c[15]=void 0,16 { @@ -2023,7 +1897,7 @@ class DmYY { provideText = (string, container, format) => { format = { - font: 'light', + font: "light", size: 14, color: this.widgetColor, opacity: 1, @@ -2044,11 +1918,11 @@ class DmYY { } // @base.end -const Runing = async (Widget, default_args = '', isDebug = true, extra) => { +const Runing = async (Widget, default_args = "", isDebug = true, extra) => { let M = null; // 判断hash是否和当前设备匹配 if (config.runsInWidget) { - M = new Widget(args.widgetParameter || ''); + M = new Widget(args.widgetParameter || ""); if (extra) { Object.keys(extra).forEach((key) => { @@ -2071,22 +1945,22 @@ const Runing = async (Widget, default_args = '', isDebug = true, extra) => { } } else { let { act, __arg, __size } = args.queryParameters; - M = new Widget(__arg || default_args || ''); + M = new Widget(__arg || default_args || ""); if (extra) { Object.keys(extra).forEach((key) => { M[key] = extra[key]; }); } if (__size) M._init(__size); - if (!act || !M['_actions']) { + if (!act || !M["_actions"]) { // 弹出选择菜单 - const actions = M['_actions']; + const actions = M["_actions"]; const onClick = async (item) => { M.widgetFamily = item.val; try { M._init(item.val); } catch (error) { - console.log('初始化异常:' + error); + console.log("初始化异常:" + error); } w = await M.render(); const fnc = item.val @@ -2095,13 +1969,14 @@ const Runing = async (Widget, default_args = '', isDebug = true, extra) => { if (w) return w[`present${fnc}`](); }; - const preview = []; + const preview = [], + lockView = []; if (M.renderSmall) { preview.push({ url: `https://raw.githubusercontent.com/dompling/Scriptable/master/images/small.png`, - title: '小尺寸', - val: 'small', - name: 'small', + title: "小尺寸", + val: "small", + name: "small", dismissOnSelect: true, onClick, }); @@ -2110,9 +1985,9 @@ const Runing = async (Widget, default_args = '', isDebug = true, extra) => { if (M.renderMedium) { preview.push({ url: `https://raw.githubusercontent.com/dompling/Scriptable/master/images/medium.png`, - title: '中尺寸', - val: 'medium', - name: 'medium', + title: "中尺寸", + val: "medium", + name: "medium", dismissOnSelect: true, onClick, }); @@ -2121,18 +1996,61 @@ const Runing = async (Widget, default_args = '', isDebug = true, extra) => { if (M.renderLarge) { preview.push({ url: `https://raw.githubusercontent.com/dompling/Scriptable/master/images/large.png`, - title: '大尺寸', - val: 'large', - name: 'large', + title: "大尺寸", + val: "large", + name: "large", + dismissOnSelect: true, + onClick, + }); + } + + if (M.renderAccessoryInline) { + lockView.push({ + icon: { + color: "#4676EE", + name: "list.triangle", + }, + title: "锁屏列表", + val: "accessoryInline", + name: "accessoryInline", + dismissOnSelect: true, + onClick, + }); + } + + if (M.renderAccessoryRectangular) { + lockView.push({ + icon: { + color: "#4676EE", + name: "arrow.rectanglepath", + }, + title: "锁屏 2x", + val: "accessoryRectangular", + name: "accessoryRectangular", + dismissOnSelect: true, + onClick, + }); + } + + if (M.renderAccessoryCircular) { + lockView.push({ + icon: { + color: "#4676EE", + name: "circle.circle", + }, + title: "锁屏 1x", + val: "accessoryCircular", + name: "accessoryCircular", dismissOnSelect: true, onClick, }); } const menuConfig = [ - { title: '预览组件', menu: preview }, - { title: '组件配置', menu: actions }, - ...M['_menuActions'], + ...(preview ? [{ title: "预览组件", menu: preview }] : []), + ...(lockView.length ? [{ title: "锁屏组件", menu: lockView }] : []), + { title: "组件配置", menu: actions }, + ...M["_menuActions"], ]; await M.renderAppView(menuConfig, true); } diff --git a/Scripts/Spotify.js b/Scripts/Spotify.js new file mode 100644 index 0000000..f1446b8 --- /dev/null +++ b/Scripts/Spotify.js @@ -0,0 +1,672 @@ +// Variables used by Scriptable. +// These must be at the very top of the file. Do not edit. +// icon-color: deep-blue; icon-glyph: dollar; + +// 添加require,是为了vscode中可以正确引入包,以获得自动补全等功能 +if (typeof require === "undefined") require = importModule; +const { DmYY, Runing } = require("./DmYY"); + +const logo = `https://open.spotifycdn.com/cdn/images/favicon.0f31d2ea.ico`; +const fontFamily = "AmericanTypewriter-Bold"; + +const api = { + me: `https://api.spotify.com/v1/me`, + accounts: `https://accounts.spotify.com/api/token`, + currentlyPlayingTrack: `https://api.spotify.com/v1/me/player/currently-playing`, + getTrack: `https://api.spotify.com/v1/tracks/11dFghVXANMlKmJXsNCbNl`, + palyState: `https://api.spotify.com/v1/me/player`, + playlists: `https://api.spotify.com/v1/me/playlists`, + following: `https://api.spotify.com/v1/me/following?type=artist`, +}; + +const scope = [ + "ugc-image-upload", + "playlist-read-collaborative", + "playlist-modify-private", + "playlist-modify-public", + "playlist-read-private", + "user-read-playback-position", + "user-read-recently-played", + "user-top-read", + "user-modify-playback-state", + "user-read-currently-playing", + "user-read-playback-state", + "user-read-private", + "user-read-email", + "user-library-modify", + "user-library-read", + "user-follow-modify", + "user-follow-read", + "streaming", + "app-remote-control", +]; + +const webUri = `https://accounts.spotify.com/zh-CN/login?continue=${encodeURIComponent( + "https://developer.spotify.com/documentation/web-api/reference/get-current-users-profile" +)}`; + +function generateRandomString(length) { + let text = ""; + let possible = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + for (let i = 0; i < length; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; +} + +function convertMillisecondsToHMS(milliseconds) { + // 计算总共有多少秒 + let totalSeconds = Math.floor(milliseconds / 1000); + + // 计算分钟数 + let minutes = Math.floor(totalSeconds / 60); + + // 剩余的秒数 + let seconds = totalSeconds - minutes * 60; + + if (minutes < 10) { + minutes = "0" + minutes; + } + if (seconds < 10) { + seconds = "0" + seconds; + } + + // 组合时分秒 + return minutes + ":" + seconds; +} + +// @组件代码开始 +class Widget extends DmYY { + constructor(arg) { + super(arg); + this.en = "Spotify"; + this.name = "声田音乐"; + this.SETTING_KEY = this.md5(this.en); + this._init(); + this.auth2 = args.queryParameters.code + ? args.queryParameters + : this.settings.auth2; + + this.settings.auth2 = this.auth2; + this.saveSettings(false); + + if (config.runsInApp) { + this.registerAction({ + icon: { + name: "airplayaudio.circle.fill", + color: "#65D46E", + }, + title: "登录", + val: "login", + name: "login", + dismissOnSelect: true, + onClick: () => { + return this.getWebToken(); + }, + }); + + this.registerAction({ + icon: { + name: "music.note", + color: "#65D46E", + }, + title: "客户端 ID", + val: "clientId", + name: "clientId", + type: "input", + dismissOnSelect: true, + }); + + this.registerAction("基础设置", this.setWidgetConfig); + } + } + + baseUri = ""; + accessToken = ""; + dataSource = { + currentlyPlayingTrack: {}, + playlists: {}, + me: {}, + following: {}, + }; + + init = async () => { + await this.getAccessToken(); + if (!this.settings.accessToken) return this.notify(this.name, "请登录!!"); + this.accessToken = `${this.settings.accessToken.token_type} ${this.settings.accessToken.access_token}`; + this.dataSource.playlists = await this.getApiRes(api.playlists); + this.dataSource.following = await this.getApiRes(api.following); + this.dataSource.me = await this.getApiRes(api.me); + this.dataSource.currentlyPlayingTrack = await this.getApiRes( + api.currentlyPlayingTrack + ); + }; + + getAccessToken = async () => { + const { accessToken } = this.settings; + if (accessToken) { + const diffTime = (new Date().getTime() - accessToken.time) / 1000; + if (diffTime > accessToken.expires_in) { + return this.refreshToken(); + } + } else if (this.auth2) { + if (!this.auth2.code) + return this.notify( + this.name, + "请登录!!!", + "https://developer.spotify.com" + ); + const { clientId, codeVerifier } = this.settings; + + const options = { + code: this.auth2.code, + client_id: clientId, + code_verifier: codeVerifier, + grant_type: "authorization_code", + redirect_uri: "scriptable:///run/Spotify?openEditor=true", + }; + + const body = Object.entries(options) + .map((item) => `${item[0]}=${item[1]}`) + .join("&"); + + const response = await this.$request.post(api.accounts, { + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: body, + }); + + console.log(response); + + if (!response.error) { + this.auth2 = null; + this.settings.auth2 = null; + this.settings.accessToken = { + ...this.settings.accessToken, + ...response, + time: new Date().getTime(), + }; + console.log( + `获取 Token 成功,有效期 ${response.expires_in / (60 * 10)} 分钟` + ); + this.saveSettings(); + } + } + }; + + refreshToken = async () => { + const { accessToken, clientId } = this.settings; + + const options = { + client_id: clientId, + grant_type: "refresh_token", + refresh_token: accessToken.refresh_token, + }; + + const body = Object.entries(options) + .map((item) => `${item[0]}=${item[1]}`) + .join("&"); + const response = await this.$request.post(api.accounts, { + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Authorization: this.accessToken, + }, + body: body, + }); + console.log("token 过期,更新"); + console.log(response); + if (!response.error) { + this.auth2 = null; + this.settings.auth2 = null; + this.settings.accessToken = { + ...this.settings.accessToken, + ...response, + time: new Date().getTime(), + }; + console.log( + `刷新 Token 成功,有效期 ${response.expires_in / (60 * 10)} 分钟` + ); + this.saveSettings(false); + } + }; + + getWebToken = async () => { + const clientId = this.settings.clientId; + if (!clientId) + this.notify( + this.name, + "请到 Spotify 官网申请开发者账号创建 APP", + "https://developer.spotify.com" + ); + + this.settings.codeVerifier = generateRandomString(128); + this.saveSettings(false); + + return WebView.loadURL( + `https://dompling.github.io/Spotify?clientId=${clientId}&codeVerifier=${ + this.settings.codeVerifier + }&scope=${encodeURIComponent(scope.join(" "))}` + ); + }; + + getApiRes = async (uri) => { + try { + const response = await this.$request.get(uri, { + headers: { Authorization: this.accessToken }, + }); + if (!response || response.error) + throw new Error(JSON.stringify(response)); + return response; + } catch (error) { + console.log(error); + return {}; + } + }; + + renderLarge = async (widget) => { + const { currentlyPlayingTrack, playlists, me, following } = this.dataSource; + if (currentlyPlayingTrack.is_playing) { + } else { + const containerStack = widget.addStack(); + containerStack.layoutVertically(); + const logoStack = containerStack.addStack(); + + logoStack.centerAlignContent(); + logoStack.addSpacer(); + const logoImage = await this.$request.get(logo, "IMG"); + const logoImageWidget = logoStack.addImage(logoImage); + logoImageWidget.imageSize = new Size(20, 20); + logoImageWidget.centerAlignImage(); + + const meStack = containerStack.addStack(); + meStack.centerAlignContent(); + + const avatarImage = await this.$request.get( + me.images[1]?.url || me.images[0]?.url, + "IMG" + ); + + const avatarStack = meStack.addImage(avatarImage); + avatarStack.imageSize = new Size(64, 64); + avatarStack.cornerRadius = avatarStack.imageSize.height / 2; + + meStack.addSpacer(20); + + const infoStack = meStack.addStack(); + infoStack.layoutVertically(); + this.provideText(me.display_name, infoStack, { + size: 16, + font: fontFamily, + }); + infoStack.addSpacer(20); + + this.provideText(me.email, infoStack, { + size: 12, + font: fontFamily, + }); + + containerStack.addSpacer(20); + + const followStack = containerStack.addStack(); + followStack.centerAlignContent(); + this.provideText(`Following`, followStack, { + size: 16, + font: fontFamily, + }); + + followStack.addSpacer(); + + this.provideText(`${following.artists.total || 0}`, followStack, { + size: 16, + font: fontFamily, + }); + + containerStack.addSpacer(10); + + const followingItemStack = containerStack.addStack(); + followingItemStack.addSpacer(); + const itemSize = new Size(48, 48); + for (let index = 0; index < following.artists.items.length; index++) { + if (index === 4) break; + + const item = following.artists.items[index]; + const itemImage = await this.$request.get(item.images[0].url, "IMG"); + const itemImgStack = followingItemStack.addImage(itemImage); + itemImgStack.imageSize = itemSize; + itemImgStack.cornerRadius = itemSize.height / 2; + followingItemStack.addSpacer(); + } + + containerStack.addSpacer(); + + const playListStack = containerStack.addStack(); + + const listItems = playlists.items.reverse(); + const bottomItems = [ + listItems[0], + listItems[1], + listItems[2], + listItems[3], + ].filter((item) => !!item); + + playListStack.addSpacer(); + + for (const index in bottomItems) { + const item = bottomItems[index]; + const itemImage = await this.$request.get(item.images[0].url, "IMG"); + const itemImageStack = playListStack.addImage(itemImage); + itemImageStack.cornerRadius = 6; + itemImageStack.imageSize = new Size(68, 68); + playListStack.addSpacer(); + } + + containerStack.addSpacer(); + } + return widget; + }; + + renderMedium = async (widget) => { + const { currentlyPlayingTrack, playlists } = this.dataSource; + if (currentlyPlayingTrack.is_playing) { + const containerStack = widget.addStack(); + const leftStack = containerStack.addStack(); + leftStack.centerAlignContent(); + + const thumbImage = await this.$request.get( + currentlyPlayingTrack.item.album.images[0].url, + "IMG" + ); + leftStack.addSpacer(); + leftStack.size = new Size(140, 140); + const thumbImgStack = leftStack.addImage(thumbImage); + thumbImgStack.imageSize = leftStack.size; + thumbImgStack.cornerRadius = 12; + leftStack.addSpacer(); + + containerStack.addSpacer(20); + + const rightStack = containerStack.addStack(); + rightStack.layoutVertically(); + rightStack.addSpacer(); + + const logoStack = rightStack.addStack(); + + logoStack.centerAlignContent(); + logoStack.addSpacer(); + const logoImage = await this.$request.get(logo, "IMG"); + const logoImageWidget = logoStack.addImage(logoImage); + logoImageWidget.imageSize = new Size(20, 20); + logoImageWidget.centerAlignImage(); + + rightStack.addSpacer(); + + const nameStack = this.provideText( + currentlyPlayingTrack.item.name, + rightStack, + { size: 16, font: fontFamily } + ); + + nameStack.lineLimit = 1; + nameStack.minimumScaleFactor = 0.5; + + rightStack.addSpacer(); + + const athorStack = this.provideText( + currentlyPlayingTrack.item.artists[0].name, + rightStack, + { size: 12, font: fontFamily } + ); + + athorStack.lineLimit = 1; + athorStack.minimumScaleFactor = 0.5; + + rightStack.addSpacer(); + + const actionsStack = rightStack.addStack(); + + const preImage = SFSymbol.named("backward.end.fill").image; + const playImage = SFSymbol.named("pause.fill").image; + const nextImage = SFSymbol.named("forward.end.fill").image; + + const iconSize = new Size(20, 20); + const preStack = actionsStack.addImage(preImage); + preStack.tintColor = this.widgetColor; + preStack.imageSize = iconSize; + + actionsStack.addSpacer(); + + const playStack = actionsStack.addImage(playImage); + playStack.tintColor = this.widgetColor; + playStack.imageSize = iconSize; + + actionsStack.addSpacer(); + + const nextStack = actionsStack.addImage(nextImage); + nextStack.tintColor = this.widgetColor; + nextStack.imageSize = iconSize; + + rightStack.addSpacer(); + + containerStack.addSpacer(); + } else { + const listItems = playlists.items.reverse(); + const topItem = listItems[0]; + const containerStack = widget.addStack(); + containerStack.layoutVertically(); + const topStack = containerStack.addStack(); + topStack.centerAlignContent(); + + const topImg = await this.$request.get(topItem.images[0].url, "IMG"); + const topImageStack = topStack.addImage(topImg); + topImageStack.cornerRadius = 6; + topImageStack.imageSize = new Size(50, 50); + + topStack.addSpacer(20); + + this.provideText(topItem.name, topStack, { font: fontFamily, size: 16 }); + + topStack.addSpacer(); + + const logoImage = await this.$request.get(logo, "IMG"); + const logoImageWidget = topStack.addImage(logoImage); + logoImageWidget.imageSize = new Size(20, 20); + + containerStack.addSpacer(); + + const bottomStack = containerStack.addStack(); + + const bottomItems = [ + listItems[1], + listItems[2], + listItems[3], + listItems[4], + ].filter((item) => !!item); + for (const index in bottomItems) { + const item = bottomItems[index]; + const itemImage = await this.$request.get(item.images[0].url, "IMG"); + const itemImageStack = bottomStack.addImage(itemImage); + itemImageStack.cornerRadius = 6; + itemImageStack.imageSize = new Size(65, 65); + if (index !== bottomItems.length - 1) bottomStack.addSpacer(); + } + } + + return widget; + }; + + renderSmall = async (widget) => { + widget.setPadding(0, 0, 0, 0); + const { currentlyPlayingTrack, playlists } = this.dataSource; + + if (currentlyPlayingTrack.is_playing) { + const iconSize = new Size(20, 20); + + const containerStack = widget.addStack(); + containerStack.setPadding(12, 12, 12, 12); + containerStack.layoutVertically(); + + const thumbImage = await this.$request.get( + currentlyPlayingTrack.item.album.images[0].url, + "IMG" + ); + const opacityImg = await this.shadowImage(thumbImage, "#000", 0.3); + containerStack.backgroundImage = opacityImg; + + const topStack = containerStack.addStack(); + topStack.centerAlignContent(); + + const music = SFSymbol.named("timer.circle.fill").image; + const musicStack = topStack.addImage(music); + musicStack.tintColor = Color.white(); + musicStack.imageSize = new Size(14, 14); + + topStack.addSpacer(10); + + this.provideText( + convertMillisecondsToHMS(currentlyPlayingTrack.item.duration_ms), + topStack, + { size: 12, font: fontFamily, color: Color.white() } + ); + + topStack.addSpacer(); + const logoStack = topStack.addStack(); + logoStack.centerAlignContent(); + + logoStack.addSpacer(); + const logoImage = await this.$request.get(logo, "IMG"); + const logoImageWidget = logoStack.addImage(logoImage); + logoImageWidget.imageSize = new Size(20, 20); + logoImageWidget.centerAlignImage(); + + containerStack.addSpacer(); + + const nameStack = this.provideText( + currentlyPlayingTrack.item.name, + containerStack, + { size: 16, font: fontFamily, color: Color.white() } + ); + + nameStack.lineLimit = 2; + containerStack.addSpacer(); + + const athorStack = this.provideText( + currentlyPlayingTrack.item.artists[0].name, + containerStack, + { size: 12, font: fontFamily, color: Color.white() } + ); + + athorStack.lineLimit = 1; + athorStack.minimumScaleFactor = 0.5; + + containerStack.addSpacer(); + + const actionsStack = containerStack.addStack(); + + const preImage = SFSymbol.named("backward.end.fill").image; + const playImage = SFSymbol.named("pause.fill").image; + const nextImage = SFSymbol.named("forward.end.fill").image; + + const preStack = actionsStack.addImage(preImage); + preStack.tintColor = Color.white(); + preStack.imageSize = iconSize; + + actionsStack.addSpacer(); + + const playStack = actionsStack.addImage(playImage); + playStack.tintColor = Color.white(); + playStack.imageSize = iconSize; + + actionsStack.addSpacer(); + + const nextStack = actionsStack.addImage(nextImage); + nextStack.tintColor = Color.white(); + nextStack.imageSize = iconSize; + } else { + const listItems = playlists.items.reverse(); + const topItem = listItems[0]; + + const containerStack = widget.addStack(); + containerStack.setPadding(12, 12, 12, 12); + containerStack.layoutVertically(); + + const thumbImage = await this.$request.get(topItem.images[0].url, "IMG"); + const opacityImg = await this.shadowImage(thumbImage, "#000", 0.3); + containerStack.backgroundImage = opacityImg; + + const topStack = containerStack.addStack(); + topStack.addSpacer(); + const logoImage = await this.$request.get(logo, "IMG"); + const logoImageWidget = topStack.addImage(logoImage); + logoImageWidget.imageSize = new Size(20, 20); + + containerStack.addSpacer(); + + this.provideText(topItem.name, containerStack, { + font: fontFamily, + size: 16, + color: Color.white(), + }); + + containerStack.addSpacer(); + + const descStack = this.provideText(topItem.description, containerStack, { + font: fontFamily, + size: 12, + color: Color.white(), + }); + + descStack.lineLimit = 2; + descStack.minimumScaleFactor = 0.5; + + containerStack.addSpacer(); + + const actionsStack = containerStack.addStack(); + actionsStack.addSpacer(); + actionsStack.centerAlignContent(); + + const heartImage = SFSymbol.named("heart.circle.fill").image; + const heartStack = actionsStack.addImage(heartImage); + heartStack.tintColor = Color.white(); + heartStack.imageSize = new Size(20, 20); + + actionsStack.addSpacer(5); + + this.provideText(`${topItem.tracks.total}`, actionsStack, { + size: 14, + font: fontFamily, + color: Color.white(), + }); + } + + return widget; + }; + + renderAccessoryInline = async (widget) => { + return widget; + }; + + /** + * 渲染函数,函数名固定 + * 可以根据 this.widgetFamily 来判断小组件尺寸,以返回不同大小的内容 + */ + async render() { + await this.init(); + const widget = new ListWidget(); + widget.useDefaultPadding(); + + await this.getWidgetBackgroundImage(widget); + if (this.widgetFamily === "small") await this.renderSmall(widget); + if (this.widgetFamily === "medium") await this.renderMedium(widget); + if (this.widgetFamily === "large") await this.renderLarge(widget); + if (this.widgetFamily == "accessoryInline") + await this.renderAccessoryInline(widget); + + return widget; + } +} + +// @组件代码结束 +await Runing(Widget, "", false); //远程开发环境 diff --git a/install.json b/install.json index 20b105a..8a6e539 100644 --- a/install.json +++ b/install.json @@ -507,6 +507,27 @@ "scriptURL": "https://raw.githubusercontent.com/dompling/Scriptable/master/Scripts/DmYY.js" } ] + }, + { + "version": "1.0.0", + "description": "Spotify", + "scriptURL": "https://raw.githubusercontent.com/dompling/Scriptable/master/Scripts/Spotify.js", + "thumb": "https://open.spotifycdn.com/cdn/images/favicon.0f31d2ea.ico", + "name": "Spotify", + "title": "声田音乐", + "html": [ + "

Spotify

", + "
  • 1.打开网站Developer Spotify
  • ", + "
  • 2.Create App 创建 app
  • ", + "
  • 3.其他随意回调地址填写 scriptable:///run/Spotify?openEditor=true
  • ", + "
  • 4.在创建好的 App 设置复制客户端Id (Client ID)
  • " + ], + "depend": [ + { + "name": "DmYY", + "scriptURL": "https://raw.githubusercontent.com/dompling/Scriptable/master/Scripts/DmYY.js" + } + ] } ] } From d5bdf2d8f482ad67a054147f815c593c9c0ac71b Mon Sep 17 00:00:00 2001 From: dompling <374779789@qq.com> Date: Thu, 19 Oct 2023 11:58:06 +0800 Subject: [PATCH 02/42] feat: chinaTelecom.js add input cookie --- Scripts/ChinaTelecom.js | 186 +++++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 88 deletions(-) diff --git a/Scripts/ChinaTelecom.js b/Scripts/ChinaTelecom.js index 10a99ed..03fa63f 100644 --- a/Scripts/ChinaTelecom.js +++ b/Scripts/ChinaTelecom.js @@ -3,30 +3,30 @@ // icon-color: pink; icon-glyph: paper-plane; // 添加require,是为了vscode中可以正确引入包,以获得自动补全等功能 -if (typeof require === 'undefined') require = importModule; -const {DmYY, Runing} = require('./DmYY'); +if (typeof require === "undefined") require = importModule; +const { DmYY, Runing } = require("./DmYY"); // @组件代码开始 class Widget extends DmYY { constructor(arg) { super(arg); - this.name = '中国电信'; - this.en = 'ChinaTelecom'; + this.name = "中国电信"; + this.en = "ChinaTelecom"; this.Run(); } - cookie = ''; - authToken = ''; - fgCircleColor = Color.dynamic(new Color('#dddef3'), new Color('#fff')); + cookie = ""; + authToken = ""; + fgCircleColor = Color.dynamic(new Color("#dddef3"), new Color("#fff")); percentColor = this.widgetColor; - textColor1 = Color.dynamic(new Color('#333'), new Color('#fff')); + textColor1 = Color.dynamic(new Color("#333"), new Color("#fff")); textColor2 = this.widgetColor; - circleColor1 = new Color('#ffbb73'); - circleColor2 = new Color('#ff0029'); - circleColor3 = new Color('#00b800'); - circleColor4 = new Color('#8376f9'); - iconColor = new Color('#827af1'); + circleColor1 = new Color("#ffbb73"); + circleColor2 = new Color("#ff0029"); + circleColor3 = new Color("#00b800"); + circleColor4 = new Color("#8376f9"); + iconColor = new Color("#827af1"); format = (str) => { return parseInt(str) >= 10 ? str : `0${str}`; @@ -43,37 +43,37 @@ class Widget extends DmYY { // percent 的计算方式,剩余/总量 * 100 = 百分比| 百分比 * 3.6 ,为显示进度。 phoneBill = { percent: 0, - label: '话费剩余', + label: "话费剩余", count: 0, - unit: '元', - icon: 'yensign.circle', + unit: "元", + icon: "yensign.circle", circleColor: this.circleColor1, }; flow = { percent: 0, - label: '流量剩余', + label: "流量剩余", count: 0, - unit: 'M', - icon: 'waveform.path.badge.minus', + unit: "M", + icon: "waveform.path.badge.minus", circleColor: this.circleColor2, }; voice = { percent: 0, - label: '语音剩余', + label: "语音剩余", count: 0, - unit: '分钟', - icon: 'mic', + unit: "分钟", + icon: "mic", circleColor: this.circleColor3, }; updateTime = { percent: 0, - label: '电信更新', + label: "电信更新", count: `${this.arrUpdateTime[2]}:${this.arrUpdateTime[3]}`, - unit: '', - urlIcon: 'https://raw.githubusercontent.com/Orz-3/mini/master/10000.png', + unit: "", + urlIcon: "https://raw.githubusercontent.com/Orz-3/mini/master/10000.png", circleColor: this.circleColor4, }; @@ -89,12 +89,12 @@ class Widget extends DmYY { // "User-Agent": "TYUserCenter/2.8 (iPhone; iOS 14.0; Scale/3.00)", }, // body: "t=tysuit", - method: 'POST', + method: "POST", }; fetchUri = { - detail: 'https://e.189.cn/store/user/package_detail.do', - balance: 'https://e.189.cn/store/user/balance_new.do', + detail: "https://e.189.cn/store/user/package_detail.do", + balance: "https://e.189.cn/store/user/balance_new.do", }; init = async () => { @@ -112,9 +112,9 @@ class Widget extends DmYY { formatFlow(number) { const n = number / 1024; if (n < 1024) { - return {count: n.toFixed(2), unit: 'M'}; + return { count: n.toFixed(2), unit: "M" }; } - return {count: (n / 1024).toFixed(2), unit: 'G'}; + return { count: (n / 1024).toFixed(2), unit: "G" }; } getData = async () => { @@ -131,7 +131,7 @@ class Widget extends DmYY { if (detail.result === 0) { // 套餐分钟数 this.voice.percent = Math.floor( - (parseInt(detail.voiceBalance) / parseInt(detail.voiceAmount)) * 100, + (parseInt(detail.voiceBalance) / parseInt(detail.voiceAmount)) * 100 ); this.voice.count = detail.voiceBalance; console.log(detail.items); @@ -139,10 +139,10 @@ class Widget extends DmYY { detail.items.forEach((data) => { if (data.offerType !== 19) { data.items.forEach((item) => { - if (item.unitTypeId === '3') { - if (item.usageAmount !== '0' && item.balanceAmount !== '0') { + if (item.unitTypeId === "3") { + if (item.usageAmount !== "0" && item.balanceAmount !== "0") { this.flow.percent = Math.floor( - (item.balanceAmount / (item.ratableAmount || 1)) * 100, + (item.balanceAmount / (item.ratableAmount || 1)) * 100 ); const flow = this.formatFlow(item.balanceAmount); this.flow.count = flow.count; @@ -155,19 +155,19 @@ class Widget extends DmYY { }); } else { this.flow.percent = Math.floor( - (detail.balance / (detail.total || 1)) * 100, + (detail.balance / (detail.total || 1)) * 100 ); const flow = this.formatFlow(detail.balance); this.flow.count = flow.count; this.flow.unit = flow.unit; this.flow.max = detail.total; } - } if (balance.result === 0) { // 余额 this.phoneBill.count = parseFloat( - parseInt(balance.totalBalanceAvailable) / 100).toFixed(2) + parseInt(balance.totalBalanceAvailable) / 100 + ).toFixed(2); } this.phoneBill.percent = Math.floor((this.phoneBill.count / 100) * 100); }; @@ -194,13 +194,13 @@ class Widget extends DmYY { canvas.setFillColor(color); for (let t = 0; t < degree; t++) { const rect_x = - ctr.x + - (this.canvRadius - radiusOffset) * this.sinDeg(t) - - this.canvWidth / 2; + ctr.x + + (this.canvRadius - radiusOffset) * this.sinDeg(t) - + this.canvWidth / 2; const rect_y = - ctr.y - - (this.canvRadius - radiusOffset) * this.cosDeg(t) - - this.canvWidth / 2; + ctr.y - + (this.canvRadius - radiusOffset) * this.cosDeg(t) - + this.canvWidth / 2; const rect_r = new Rect(rect_x, rect_y, this.canvWidth, this.canvWidth); canvas.fillEllipse(rect_r); } @@ -208,10 +208,10 @@ class Widget extends DmYY { drawText(txt, canvas, txtOffset, fontSize) { const txtRect = new Rect( - this.canvTextSize / 2 - 20, - txtOffset - this.canvTextSize / 2, - this.canvSize, - this.canvTextSize, + this.canvTextSize / 2 - 20, + txtOffset - this.canvTextSize / 2, + this.canvSize, + this.canvTextSize ); canvas.setTextColor(this.percentColor); canvas.setFont(Font.boldSystemFont(fontSize)); @@ -238,10 +238,10 @@ class Widget extends DmYY { const canvas = this.makeCanvas(); stackCircle.size = new Size(70, 70); this.makeCircle( - canvas, - this.dayRadiusOffset, - data.percent * 3.6, - data.circleColor, + canvas, + this.dayRadiusOffset, + data.percent * 3.6, + data.circleColor ); this.drawText(data.percent, canvas, 75, 18); @@ -251,8 +251,8 @@ class Widget extends DmYY { stackCircle.setPadding(20, 0, 0, 0); stackCircle.addSpacer(); const icon = data.urlIcon - ? {image: data.icon} - : SFSymbol.named(data.icon); + ? { image: data.icon } + : SFSymbol.named(data.icon); const imageIcon = stackCircle.addImage(icon.image); imageIcon.tintColor = this.iconColor; imageIcon.imageSize = new Size(15, 15); @@ -293,11 +293,11 @@ class Widget extends DmYY { const stackFooter = stackBody.addStack(); stackFooter.addSpacer(); const text = this.textFormat.defaultText; - text.color = new Color('#aaa'); + text.color = new Color("#aaa"); this.provideText( - `电信更新:${this.arrUpdateTime[2]}:${this.arrUpdateTime[3]}`, - stackFooter, - text, + `电信更新:${this.arrUpdateTime[2]}:${this.arrUpdateTime[3]}`, + stackFooter, + text ); stackFooter.addSpacer(); return w; @@ -312,8 +312,8 @@ class Widget extends DmYY { const stackBottom = stackBody.addStack(); this.setCircleText(stackBottom, this.voice); this.updateTime.icon = await this.$request.get( - this.updateTime.urlIcon, - 'IMG', + this.updateTime.urlIcon, + "IMG" ); this.setCircleText(stackBottom, this.updateTime); return w; @@ -325,18 +325,18 @@ class Widget extends DmYY { renderWebView = async () => { const webView = new WebView(); - const url = 'https://e.189.cn/index.do'; + const url = "https://e.189.cn/index.do"; await webView.loadURL(url); await webView.present(false); const request = new Request(this.fetchUri.detail); - request.method = 'POST'; + request.method = "POST"; const response = await request.loadJSON(); console.log(response); if (response.result === -10001) { - const index = await this.generateAlert('未获取到用户信息', [ - '取消', - '重试', + const index = await this.generateAlert("未获取到用户信息", [ + "取消", + "重试", ]); if (index === 0) return; await this.renderWebView(); @@ -344,7 +344,7 @@ class Widget extends DmYY { const cookies = request.response.cookies; let cookie = []; cookie = cookies.map((item) => `${item.name}=${item.value}`); - cookie = cookie.join('; '); + cookie = cookie.join("; "); this.settings.cookie = cookie; this.saveSettings(); } @@ -352,35 +352,45 @@ class Widget extends DmYY { Run() { if (config.runsInApp) { - const widgetInitConfig = {cookie: 'china_telecom_cookie'}; - this.registerAction('颜色配置', async () => { + const widgetInitConfig = { cookie: "china_telecom_cookie" }; + this.registerAction("颜色配置", async () => { await this.setAlertInput( - `${this.name}颜色配置`, - '进度条颜色|底圈颜色\n图标颜色|比值颜色|值颜色', - { - step1: '进度颜色 1', - step2: '进度颜色 2', - step3: '进度颜色 3', - step4: '进度颜色 4', - inner: '底圈颜色', - icon: '图标颜色', - percent: '比值颜色', - value: '值颜色', - }, + `${this.name}颜色配置`, + "进度条颜色|底圈颜色\n图标颜色|比值颜色|值颜色", + { + step1: "进度颜色 1", + step2: "进度颜色 2", + step3: "进度颜色 3", + step4: "进度颜色 4", + inner: "底圈颜色", + icon: "图标颜色", + percent: "比值颜色", + value: "值颜色", + } ); }); - this.registerAction('账号设置', async () => { - const index = await this.generateAlert('设置账号信息', [ - '取消', - '网站登录', + this.registerAction("账号设置", async () => { + const index = await this.generateAlert("设置账号信息", [ + "取消", + "手动输入", + "网站登录", ]); if (index === 0) return; - await this.renderWebView(); + + if (index === 1) + return this.setAlertInput( + `${this.name}账号设置`, + "手动输入电信 COOKIE", + { + cookie: "电信 cookie", + } + ); + return this.renderWebView(); }); - this.registerAction('代理缓存', async () => { + this.registerAction("代理缓存", async () => { await this.setCacheBoxJSData(widgetInitConfig); }); - this.registerAction('基础设置', this.setWidgetConfig); + this.registerAction("基础设置", this.setWidgetConfig); } const { step1, @@ -419,9 +429,9 @@ class Widget extends DmYY { const widget = new ListWidget(); widget.setPadding(0, 0, 0, 0); await this.getWidgetBackgroundImage(widget); - if (this.widgetFamily === 'medium') { + if (this.widgetFamily === "medium") { return await this.renderMedium(widget); - } else if (this.widgetFamily === 'large') { + } else if (this.widgetFamily === "large") { return await this.renderLarge(widget); } else { return await this.renderSmall(widget); From 26779dea445d04e55b9b0bbd9da9d3b9af8f22fd Mon Sep 17 00:00:00 2001 From: Dream <47107706+2578893153@users.noreply.github.com> Date: Fri, 27 Oct 2023 11:53:38 +0800 Subject: [PATCH 03/42] Update DmYY.js --- Scripts/DmYY.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Scripts/DmYY.js b/Scripts/DmYY.js index ea51fb4..4407e4a 100644 --- a/Scripts/DmYY.js +++ b/Scripts/DmYY.js @@ -1056,6 +1056,9 @@ class DmYY { padding: 0.5em 18px; position: relative; } + label > * { + pointer-events: none; + } .form-label { display: flex; align-items: center; From d262f649d44ad851f934e53b4c7d19067a1a071c Mon Sep 17 00:00:00 2001 From: Dream <47107706+2578893153@users.noreply.github.com> Date: Sat, 28 Oct 2023 14:37:25 +0800 Subject: [PATCH 04/42] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B1=8F=E8=94=BDLable?= =?UTF-8?q?=E5=86=85=E5=85=83=E7=B4=A0=E7=9A=84=E7=84=A6=E7=82=B9=EF=BC=8C?= =?UTF-8?q?=E8=80=8C=E5=AF=BC=E8=87=B4=E7=9A=84switch=E5=8F=8Acheckbox?= =?UTF-8?q?=E4=B8=8D=E5=8F=AF=E6=94=B9=E5=80=BC=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Scripts/DmYY.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Scripts/DmYY.js b/Scripts/DmYY.js index 4407e4a..a93e9dd 100644 --- a/Scripts/DmYY.js +++ b/Scripts/DmYY.js @@ -1046,14 +1046,14 @@ class DmYY { border-radius:50%; border: 1px solid #F6D377; } - .form-item { + .form-item, .form-item-Switch { display: flex; align-items: center; justify-content: space-between; font-size: ${settingItemFontSize}px; font-weight: 400; min-height: 2.2em; - padding: 0.5em 18px; + padding: 0.5em 10px; position: relative; } label > * { @@ -1095,14 +1095,18 @@ class DmYY { border-radius:3px; } - .form-item + .form-item::before { + .form-item + .form-item::before, + .form-item-switch + .form-item::before, + .form-item + .form-item-switch::before + { content: ""; position: absolute; top: 0; - left: 20px; + left: 0; right: 0; border-top: 0.5px solid var(--divider-color); } + .form-item input[type="checkbox"] { width: 2em; height: 2em; @@ -1330,9 +1334,16 @@ class DmYY { menuItem.type }" enterkeyhint="done" value="${menuItem.defaultValue || ""}">`; } - + + let addLable = ""; + if(menuItem.type === "switch" || menuItem.type === "checkbox") { + addLable = `