Scriptable那些令人惊艳的脚本汇总集锦

已收录   阅读次数: 3,201
2021-10-1616:22:28 发表评论
摘要

前几天,伯衡君推荐用Scriptable撰写并运行Javascript脚本,部署在iPhone和iPad桌面上,及时获取各种资讯以提高生活品质,具体可以参看下面的前情提要。本篇文章,则是汇总一些伯衡君在使用过程中觉得十分惊艳的脚本,本篇会陆续更新的,敬请关注……

分享至:
Scriptable那些令人惊艳的脚本汇总集锦

开篇寄语

前几天,伯衡君推荐用Scriptable撰写并运行Javascript脚本,部署在iPhone和iPad桌面上,及时获取各种资讯以提高生活品质,具体可以参看下面的前情提要。本篇文章,则是汇总一些伯衡君在使用过程中觉得十分惊艳的脚本,本篇会陆续更新的,敬请关注。

前情提要

收录列表

百度热搜北京一周尾号限行豆瓣电影一周口碑榜
订阅或日期进度条汇率展示微博热搜Top10
知乎热榜Top10Nasa美图随机菜谱
随机电影台词随机古诗随机英文名句

温馨提示

文中会涉及到的透明脚本效果,请参看下方两张图,手机壁纸尽量挑一些颜色不太复杂的,这样效果会非常好,有那种浑然一体的效果:

Scriptable那些令人惊艳的脚本汇总集锦

内容详情

  • 百度热搜
  • 取了前10新闻,以在最小的小组件显示,可根据需求自行修改,百度热搜出现的数据有20个
const { transparent } = importModule('no-background')
const w = new ListWidget()
w.backgroundImage = await transparent(Script.name())
const req = new Request("https://www.baidu.com/");
req.method = "GET";
req.headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.55"
};
const res = await req.loadString();
    // console.log(res)
const tmp = res.split(`<textarea id="hotsearch_data" style="display:none;">`)[1].split(`</textarea>`)[0]
const data = JSON.parse(tmp).hotsearch;
for(let i of data.slice(0,10)){
  const stack = w.addStack()
  stack.centerAlignContent()
  const text = stack.addText(i.pure_title)
  text.textColor = Color.white()
  text.font = Font.semiboldSystemFont(9)
}

if(Device.isPad()){
   w.presentExtraLarge()
}else if(Device.isPhone()){
   w.presentLarge()
}

Script.setWidget(w)
Script.complete()
  • 获取中国北京(或者其他地方则需要到各省的政务网站去查看了)一周尾号限行
  • 这里引入了一个名为no-background的脚本,需要提前先写好放置在Scriptable中,先运行该透明背景脚本,将手机桌面截屏的图片保存好,运行脚本后将该图片设为背景,之后就可以运行实现Scriptable小组件的透明化布置了,no-background脚本请参考该网址:https://github.com/supermamon/scriptable-no-background,当然,你也可以自己设置背景
const { transparent } = importModule('no-background') //自己设置时该行去掉
const w = new ListWidget()
w.backgroundImage = await transparent(Script.name()) //await transparent(Script.name())替换为new Color("#ff0000")等

let url = "http://yw.jtgl.beijing.gov.cn/jgjxx/services/getRuleWithWeek"
let req = new Request(url)
let result = await req.loadJSON()
const stack = w.addStack();
stack.centerAlignContent();
const title = stack.addText("北京一周尾号限行")
title.textColor = Color.white()
title.font = Font.semiboldSystemFont(12)
if(result.state="success"){
  //获取数据成功,进行筛选
  let tmp = result.result;
  for(let i = 0; i<tmp.length; i++){
   const stack = w.addStack();
   stack.centerAlignContent();
   const days = stack.addText(tmp[i].limitedWeek)
   days.textColor = Color.white()
   days.font = Font.semiboldSystemFont(12)
   stack.addSpacer(20)
   const text = stack.addText(tmp[i].limitedNumber)
   text.textColor = Color.white()
   text.font = Font.semiboldSystemFont(12)
   stack.addSpacer(20)
  
 }
}else{
  //获取数据失败
}
if(Device.isPad()){
  w.presentExtraLarge()
}else if(Device.isPhone()){
  w.presentLarge()
}

Script.setWidget(w)
Script.complete()
  • 获取豆瓣电影一周口碑榜
  • 这里说一下,需要先以WebView.loadURL打开豆瓣官网,切换到电脑模式后再返回就可以获取了,代码中有一段注释“//”去掉就可以了,当切换到电脑端界面时返回再注释上就可以了
const w = new ListWidget()
w.backgroundColor = new Color("#42a056")
const wv = new WebView(); 
const url = 'https://movie.douban.com/'; 
await wv.loadURL(url)
var getData = `
    function getData(){
         a = []
         x = document.querySelectorAll(".billboard-bd .title a")
         for(s of x){
           a.push(s.innerHTML)
         }
         return a
     } 
        getData()
   `
let response = await wv.evaluateJavaScript(getData,false)
for(let r in response){
  const stack = w.addStack()
  stack.centerAlignContent()
  const text = stack.addText(response[r])
  text.textColor = Color.white()
  stack.addSpacer(10)
}
if(Device.isPad()){
   w.presentExtraLarge()
}else if(Device.isPhone()){
   w.presentLarge()
}
// WebView.loadURL(url)
Script.setWidget(w)
Script.complete()
  • 订阅或者重要日期进程条
  • 设置一个重要日期或者服务的到期时间,与今天时间对比,距离截止小于60天进度条变成红色以提醒
const width=125
const h=5
const w = new ListWidget()
w.backgroundColor=new Color("#222222")

//设置截止列表
const arr = {
  'Bandwagonhost': '2021-12-08',
  'GoDaddy': '2022-06-15',
  'Textnow': '2022-04-09',
  'Name': '2029-10-11'
}

const oneDay = 24 * 60 * 60 * 1000;

for(let i of Object.keys(arr)){
const firstDate = new Date(`${arr[i]}`);
const secondDate = new Date();
const diffDays = Math.round(Math.abs((firstDate - secondDate) / oneDay));
  if(diffDays<=60){
    getwidget(diffDays + 30, 31, i, "#ff0000")
  }else{
    getwidget(diffDays + 30, 31, i, "#ffd60a")
  }
}
Script.setWidget(w)
Script.complete()
w.presentSmall()

function getwidget(ends, haveGone, str, color) {
  const titlew = w.addText(str)
  titlew.textColor = new Color("#e587ce")
  titlew.font = Font.boldSystemFont(13)
  w.addSpacer(6)
  const imgw = w.addImage(creatProgress(ends, haveGone, color))
  imgw.imageSize=new Size(width, h)
  w.addSpacer(6)
}

function creatProgress(ends, havegone, color){
const context =new DrawContext()
context.size=new Size(width, h)
context.opaque=false
context.respectScreenScale=true
context.setFillColor(new Color("#48484b"))
const path = new Path()
path.addRoundedRect(new Rect(0, 0, width, h), 3, 2)
context.addPath(path)
context.fillPath()
context.setFillColor(new Color(color))
const path1 = new Path()
path1.addRoundedRect(new Rect(0, 0, width*havegone/ends, h), 3, 2)
context.addPath(path1)
context.fillPath()
return context.getImage()
}
  • 汇率展示
  • 这个需要到一个网址申请api,app.exchangerate-api.com,每月有1500次请求限制而已,将代码中的url换上自己的即可
const w = new ListWidget()
w.backgroundColor = new Color("#222222")

const resp= await get({url:"https://v6.exchangerate-api.com/v6/your token/latest/USD"})

const arr = Object.keys(resp["conversion_rates"]).filter(x=>x=="USD" || x=="CNY" || x=="JPY")

for(let rate of arr){
  const stack =w.addStack()
  stack.centerAlignContent()
  const img= await loadImage("https://www.ecb.europa.eu/shared/img/flags/"+rate+".gif")
  const imgw =stack.addImage(img)
  imgw.imageSize=new Size(20, 20)
  stack.addSpacer(20)
  const textw = stack.addText(resp["conversion_rates"][rate].toFixed(2))
  textw.textColor = Color.white()
  stack.addSpacer(20)
}

Script.setWidget(w)
Script.complete()
w.presentLarge()
async function get(opts) {
      const request = new Request(opts.url)
      request.headers = {
        ...opts.headers,
        ...this.defaultHeaders
      }
      var result=await request.loadJSON()
      return result
    
}

 async function  loadImage(imgUrl) {
  let req = new Request(imgUrl)
  let image = await req.loadImage()
  return image
}
  • 微博热搜Top10
  • 伯衡君这里设置了两种模式,一种是网页打开模式,一种是小组件模式,可以自由选择,如果选择网页打开模式,那么建议把.slice(0,10)去掉,然后将// WebView.loadHTML(title)前面的“//”去掉
const wv = new WebView()

const w = new ListWidget()

w.backgroundColor = new Color("#E6162D")

const url = "https://m.weibo.cn/api/container/getIndex?containerid=106003type%3D25%26t%3D3%26disable_hot%3D1%26filter_type%3Drealtimehot"
const req = new Request(url)
const result = await req.loadJSON()
const check = result.ok

var title = `
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body{
            background-color:#E6162D;
        }
        .weibohot{
            color:#000000;
        }
        ul li{
            list-style:none;
        }
    </style>
    <div calss="weibohot">
        <ul>
`

if (check != 1) {
    return
} else {
    for (let i of result.data.cards[0].card_group.slice(0,10)) {
  const stack = w.addStack()
  stack.centerAlignContent()
  const text = stack.addText(i.desc)
  text.textColor = Color.white()
  text.font = Font.semiboldSystemFont(9)
        title += `<li>${i.desc}</li>`;
    }
    title += "</ul></div>"
}

// WebView.loadHTML(title)

if(Device.isPad()){
   w.presentExtraLarge()
}else if(Device.isPhone()){
   w.presentLarge()
}

Script.setWidget(w)
Script.complete()
  • 实时上证和深成指数
const w = new ListWidget()
w.backgroundColor = new Color("#4169E1")
const array = ["上证指数", "深圳成指"]

let url = "https://cors.luckydesigner.workers.dev/?http://hq.sinajs.cn/list=sh000001,sz399001"
let req = new Request(url)
let result = await req.loadString()
let sz = result.split(";")

for(let i = 0; i<sz.length - 1; i++){
  const stack = w.addStack()
  stack.centerAlignContent()
  const text = stack.addText(array[i])
  text.textColor = Color.white()
  stack.addSpacer(20)
  const ratew = stack.addText(sz[i].split(",")[3])
  ratew.textColor = Color.white()
  stack.addSpacer(20)
}

if(Device.isPad()){
  w.presentExtraLarge()
}else if(Device.isPhone()){
  w.presentLarge()
}

Script.setWidget(w)
Script.complete()
  • 知乎热榜Top10
const w = new ListWidget()
w.backgroundColor = new Color("#4169E1")


let url = "https://api.zhihu.com/topstory/hot-lists/total?limit=10&reverse_order=0"
let req = new Request(url)
let result = await req.loadJSON()

for(let i = 0; i<result.data.length; i++){
  if(i<10){
    const stack = w.addStack()
    stack.centerAlignContent()
    const text = stack.addText(`${i + 1}.${result.data[i].target.title}`)
    text.textColor = Color.white()
    text.font = Font.semiboldSystemFont(9)
  }
}

if(Device.isPad()){
  w.presentExtraLarge()
}else if(Device.isPhone()){
  w.presentLarge()
}

Script.setWidget(w)
Script.complete()
  • Nasa美图
  • 先前往https://api.nasa.gov/申请一个key,之后替换脚本中的Api key为自己的就可以了
let apiURL = "https://api.nasa.gov/planetary/apod";
let apiKey = "Api Key";
if ( Keychain.contains('Api Key') ) {
  apiKey = Keychain.get('Api Key');
}

let apodNavURL = "https://apod.nasa.gov";

function createWidget() {
  let widget = new ListWidget();
  widget.spacing = 0;
  let now = Date.now();
  let delay = 6 * 60 * 60 * 1000;
  let nextUpdate = new Date(now + delay);
  widget.refreshAfterDate = nextUpdate;
  return widget;
}

async function loadPhoto(widget) {
  let requestURI = `${apiURL}?api_key=${apiKey}`;
  
  let request = new Request(requestURI);
  let json = await request.loadJSON();
  
  if ( json && json.url ) {
    if ( json.media_type == 'image' ) {
      let imgRequest = new Request(json.url);
      let img = await imgRequest.loadImage();
  
      widget.backgroundImage = img;
    }
    else if ( json.media_type == 'video' && json.url.match(/^https?:\/\/(www.)?youtube.com/) ) {
      let ytID = json.url.match(/\/embed\/([^)]+)\?.*/, "/vi/$1/0.jpg")
      let imgURL = `https://img.youtube.com/vi/${ ytID[1] }/0.jpg`;
      let imgRequest = new Request(imgURL);
      let img = await imgRequest.loadImage();
  
      widget.backgroundImage = img;
      
      let font = Font.blackRoundedSystemFont(10);
      let text = widget.addText("Video");
      text.rightAlignText();
      text.font = font;
      text.textColor = Color.white();
      
      widget.addSpacer(null);
    }
    else {
      let font = Font.blackRoundedSystemFont(22);
      let text = widget.addText("今天没有天文图像 "+json.media_type);
      text.centerAlignText();
      text.font = font;
      text.textColor = Color.white();
      
      let bg = new LinearGradient();
      bg.colors = [
        new Color("#6666ff", 1.0),
        new Color("#000033", 1.0)
      ];
      bg.locations = [0, 1];
      widget.backgroundGradient = bg;
    }
    
    widget.url = apodNavURL;
  } else if ( json && json.error && json.error.message ) {
    widget.addText(json.error.message);
  } else {
    widget.addText("Error, no message")
  }
}

let widget = createWidget();
await loadPhoto(widget);

if (config.runsInWidget) {
  Script.setWidget(widget);
} else {
  widget.presentLarge();
}

Script.complete();
  • 随机菜谱
  • 随机展示一道菜,点击插件后跳转到Youtube观看制作方法
const {meals} = await new Request("https://www.themealdb.com/api/json/v1/1/random.php").loadJSON()

const {
  strMeal: title,
  strMealThumb: imgUrl,
  strYoutube: videoUrl,
  strSource: articleUrl
} = meals[0]

const w = new ListWidget()
w.url = videoUrl || articleUrl
w.backgroundColor = new Color("#222222")
w.backgroundImage = await new Request(imgUrl).loadImage()

const t = w.addText(title)
t.textColor = Color.white()
t.font = new Font("Avenir-Heavy", 28)
t.shadowRadius = 3
t.shadowColor = Color.black()
t.centerAlignText()
 
if(Device.isPad()){
  w.presentExtraLarge()
}else if(Device.isPhone()){
  w.presentLarge()
}

Script.setWidget(w)
Script.complete()
  • 随机电影台词
  • 随机一句经典电影台词
Scriptable那些令人惊艳的脚本汇总集锦
const isLarge = config.widgetFamily === 'large'

async function getData() {
    const target = 'https://howdz.deno.dev/movieLines'
    const { img1, img2, img3, img4, link, name, quotes } = await (new Request(target)).loadJSON()
    const randomImgArr = [img1, img1, img2, img3, img4].filter(Boolean)
    const randomImgIdx = ~~(Math.random() * randomImgArr.length)
    const randomImg = randomImgArr[randomImgIdx]
    const wallpaperImg = randomImg.replace('original', 'w1280')
    const img = await (new Request(wallpaperImg)).loadImage()
    const greyImg = await getGreyImg(img)
    return { name, link, quotes, img: greyImg }
}

async function getGreyImg(img) {
    let ctx = new DrawContext()
    ctx.size = img.size
    ctx.drawImageInRect(img, new Rect(0, 0, img.size['width'], img.size['height']))
    ctx.setFillColor(new Color("#000000", 0.7))
    ctx.fillRect(new Rect(0, 0, img.size['width'], img.size['height']))
    let res = await ctx.getImage()
    return res
}
  
const widget = new ListWidget()
const { name: movieName, link, quotes, img } = await getData()
widget.backgroundImage = img
widget.url = link

const content = widget.addStack()
content.setPadding(0, 0, 10, 0)
const quotesText = content.addText(quotes)
quotesText.lineLimit = isLarge ? 5: 3
quotesText.textColor = Color.white()
quotesText.font = Font.boldSystemFont(isLarge ? 24: 18)
quotesText.shadowRadius = 2
quotesText.shadowOffset = new Point(1, 1)


const footer = widget.addStack()
footer.setPadding(isLarge ? 32 : 16, 0, 0, 0)
footer.addSpacer()
const footerText = footer.addText(`——『 ${movieName} 』`)
footerText.lineLimit = 1
footerText.shadowRadius = 2
footerText.shadowOffset = new Point(1, 1)
footerText.textColor = Color.white()
footerText.rightAlignText()

if (config.runsInWidget) {
    Script.setWidget(widget)
} else {
    widget.presentMedium()
}
Script.complete()
  • 随机古诗
  • 随机生成一段古诗
Scriptable那些令人惊艳的脚本汇总集锦
const fontSizeMap = {
  small: 16,
  medium: 24,
  large: 32
}
const fontSize = fontSizeMap[config.widgetFamily || 'medium']

const loadImage = async (url) => (await new Request(url)).loadImage()

const getGreyImg = async (img, light = 0.4) => {
  const ctx = new DrawContext()
  ctx.size = img.size
  ctx.drawImageInRect(img, new Rect(0, 0, img.size['width'], img.size['height']))
  ctx.setFillColor(new Color("#000000", light))
  ctx.fillRect(new Rect(0, 0, img.size['width'], img.size['height']))
  return await ctx.getImage()
}

const loadRandomBg = async () => {
  const randomImgURL = 'https://howdz.deno.dev/unsplash/random?w=768&keyword=Nature'
  const randomImg = await loadImage(randomImgURL)
  const greyImg = await getGreyImg(randomImg)
  return greyImg
}

const loadVerse = async () => (await new Request('https://v1.jinrishici.com/all.json')).loadJSON()

const { content: randomVerse, origin: title }= await loadVerse()
const widget = new ListWidget()
const randomImg = await loadRandomBg()
widget.setPadding(0, fontSize / 2, 0, fontSize / 2)
widget.backgroundImage = randomImg
widget.url = 'https://hanyu.baidu.com/s?wd=' + encodeURIComponent(title)+ '&from=poem'

const textEl = widget.addText(randomVerse)
textEl.textColor = Color.white()
textEl.font = Font.boldSystemFont(fontSize)
textEl.shadowRadius = 2
textEl.shadowOffset = new Point(1, 1)
textEl.centerAlignText()

if (config.widget !== 'small') {
  const footer = widget.addStack()
  footer.setPadding(fontSize, 0, 0, 0)
  footer.addSpacer()
  const footerText = footer.addText(`——『 ${title} 』`)
  footer.font = Font.boldSystemFont(16)
  footerText.lineLimit = 1
  footerText.shadowRadius = 2
  footerText.shadowOffset = new Point(1, 1)
  footerText.textColor = Color.white()
  footerText.rightAlignText()
}


if (config.runsInWidget) {
  Script.setWidget(widget)
} else {
  widget.presentMedium()
}
Script.complete()
  • 随机英文名居
  • 随机生成一段英文
Scriptable那些令人惊艳的脚本汇总集锦
const fontSizeMap = {
  small: 18,
  medium: 24,
  large: 32
}
const fontSize = fontSizeMap[config.widgetFamily || 'medium']

const loadImage = async (url) => (await new Request(url)).loadImage()

const getGreyImg = async (img, light = 0.4) => {
  const ctx = new DrawContext()
  ctx.size = img.size
  ctx.drawImageInRect(img, new Rect(0, 0, img.size['width'], img.size['height']))
  ctx.setFillColor(new Color("#000000", light))
  ctx.fillRect(new Rect(0, 0, img.size['width'], img.size['height']))
  return await ctx.getImage()
}

const loadRandomBg = async () => {
  const randomImgURL = 'https://howdz.deno.dev/unsplash/random?w=768&keyword=Nature'
  const randomImg = await loadImage(randomImgURL)
  const greyImg = await getGreyImg(randomImg)
  return greyImg
}

const loadSentence = async () => (await new Request('https://favqs.com/api/qotd')).loadJSON()

const { quote } = await loadSentence()
const { body: text, author } = quote
const widget = new ListWidget()
const randomImg = await loadRandomBg()
widget.setPadding(0, fontSize / 2, 0, fontSize / 2)
widget.backgroundImage = randomImg

const textEl = widget.addText(text.replaceAll('\\r', '').replaceAll('<br>', ''))
textEl.textColor = Color.white()
textEl.font = Font.boldSystemFont(fontSize)
textEl.shadowRadius = 2
textEl.shadowOffset = new Point(1, 1)
textEl.centerAlignText()

if (config.widgetFamily !== 'small') {
  const footer = widget.addStack()
  footer.setPadding(fontSize, 0, 0, 0)
  footer.addSpacer()
  const footerText = footer.addText(`—— ${author}`)
  footer.font = Font.boldSystemFont(16)
  footerText.lineLimit = 1
  footerText.shadowRadius = 2
  footerText.shadowOffset = new Point(1, 1)
  footerText.textColor = Color.white()
  footerText.rightAlignText()
}


if (config.runsInWidget) {
  Script.setWidget(widget)
} else {
  widget.presentMedium()
}
Script.complete()
  • 我的微信
  • 微信扫一扫加好友
  • weinxin
  • 我的微信公众号
  • 扫描关注公众号
  • weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: