STEEM编程练习记录 三

in STEEM CN/中文last year

今天早晨,正在我因为是星期五发懒,不知道想做什么事的时候,收到了村长@ericet圈给我的一条回复。在[Life]likeCoin 为什么不制作一个chrome 扩展程序?里,@jun0621提出了一个非常有趣的想法。就是制作一个like Coin的Chrome扩展程序。用一个Chrome Extension,在所有的STEEM的结点上添加“啪啪啪”的小手。
一个挺好玩的程序。于是我打算做一个试试。

设计思路

要想制作这么一个能够在所有和STEEMIT有关的结点拍手的扩展程序,必须要让这个程序知道自己在1)STEEM的节点上;2)正在浏览的文章是一个有注册LikeCoin的用户。

  1. 第一项非常简单,因为在Chrome扩展程序的manifest.json里面可以规定程序在哪些网站上运行。

  2. 第二项稍微复杂一点。需要用一种方法搜取文章的作者,查询作者是不是已经注册了Matters
    文章的作者可以从网址中截取。举一个例子:@huaren.news的文章武汉肺炎多国蔓延,该指责还是该合作?世界欠中国/武汉一份感谢!在不同的节点上的网址是:

    1. https://staging.busy.org/@huaren.news/48spug
    2. https://steem.buzz/hive-180932/@huaren.news/48spug
    3. https://steempeak.com/@huaren.news/48spug
    4. https://steemit.com/hive-180932/@huaren.news/48spug


    仔细观察的话,不难发现,每个网址后半段都是@huaren.news/48spug。如果程序在/之间切开整条网址的话,倒数第二段便是@huaren.news。如果我们观察非发表的文章的网址,比如说SteemCN社区(https://steemit.com/trending/hive-180932),这个网址中,没有@用户。我们可以利用这一特点从网址中筛选当前的网页是否是一片STEEM上的文章,并且得到作者的用户ID。

  3. 我们还要找出所有已经申请Matters的用户。



    上面一张截图中是我问村长SteemCN是怎么记录Matters用户的对话。看来只要我把@cn-likers关注的名单调出来就知道所有Matters用户了。我在STEEM编程练习记录 二介绍过如何利用SteemJs的API搜索follower和following名单。在回复中村长@erice还贴了他原来写过的follower的程序。由于他的代码比我的更加完整。我借用了他的代码,并改成搜索following的名单。

  4. 第四步是寻找当前文章用户的LikerId。我在写程序的时候,忽略了这一点。正巧我借用来测试的@windowglass【职场碎碎念】辞职@windowglassLikerIdSteemId是相同的。所以我在push我的commit到github上,再测试cn-fund的时候才发现找不到正确的LikerId



    我在STEEM编程练习记录 一介绍过如果搜索STEEM用户信息。在第二步通过网址截取用户ID之后,可以先用用户ID搜索用户信息,从中获得用户Location里面LikerId:xxx的数值。

  5. 第五步也是在push commit之后发现的。就是更换网址之后,Chrome扩展程序里面的网址和用户LikerId并没有更改。我需要在更换网址的时候,触发扩展程序里面的存储的数值的更新。
    本来想利用Chrome Extension里面的content.jsbackground.js利用Chrome自己的API做触发。但是由于想在半天内写出一个Beta版本供大家啪啪啪,所以我选择了一条更简单粗暴的方法:就是设置一个无限循环的程序环,每个200毫秒自动检查一下当前的网址是否和上一次检查时是不同的网址,如果有变化,则从新更新一遍数据。

编写程序

manifest.json是Chrome扩展程序的清单文件。里面记载着扩展程序的版本,导入的其它JavaScript库,注入的配置文件等等。

{
  "manifest_version": 2,
  "name": "Liker Clap Extension",
  "description": "This extension will add a Matters Likr Clap Button",
  "version": "0.1",
  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  },
  "content_scripts": [
    {
      "matches": [
        "*://*.busy.org/*",
        "*://*.steem.buzz/*",
        "*://*.steemit.com/*",
        "*://*.steempeak.com/*"
      ],
      "js": [
        "steem.js",
        "liker.js"
      ]
    }
  ],
  "permissions": [
    "tabs"
  ]
}


上段代码就是本程序的manifest.json。其中content_scripts里面规定了,在哪些网站上,这个扩展程序可以运行(matches)和运行哪些JavaScript的library(steem.jsliker.js)。
由于Chrome扩展程序不能调用CDN上面的程序库,我想STEEM API下载下来,放到了程序本地的目录下(steem.js)。
必须要主意程序库的排列顺序。liker.js里面要调取steem.js里面的变量steem,所以steem.js必须在liker.js的前面。

var url = window.location.href;
const button = document.createElement("div");
const css = document.createElement("style");
var href = url.split("/");
var steemId = href[href.length-2];
//steem.api.setOptions({ url: "https://anyx.io" });

const getFollowing = (start = 0, limit = 1000, following = []) => {
  return new Promise((resolve, reject) => {
    steem.api.getFollowing("cn-likers", start, 'blog', limit, async function (err, result) {
      if (result.length > 1) {
        let newResult = [];
        result.forEach(following => {
            if (following.follower != start) {
                newResult.push(following.following);
            }
        });
        following = [...following, ...newResult];
        let followingList = [];
        for (let i in newResult) {
            followingList.push(newResult[i].following);
        }
        getFollowing(result[result.length - 1].following, limit, following)
        .then(resolve)
        .catch(reject);
      } else {
        resolve(following);
      }
    });
  });
}

const getLikerId = (profile) => {
  const location = profile.location;
  console.log(location)
  if(typeof location !=="undefined" && location !== "") {
    const loc = location.split(":");
    if( loc[0] === "likerid" ) { return loc[1]; }
    else { return false; }
  }
  else { return false; }
}

const isLiker = (steemId, following) => {
  let flag = false;
  if(steemId.startsWith("@")) {
    const id = steemId.substr(1);
    for(let i = 0; i < following.length; i++) {
      if(id === following[i]) {
        flag = true;
        break;
      }
    }
    if(flag) { return id; }
    else { return false; }
  }
  else{ return false; }
}

async function createLikerButton(url, steemId) {
  let following = await getFollowing();
  //url = encodeURIComponent(url);
  steemId = isLiker(steemId, following);
  console.log(url);
  console.log(steemId);
  if(steemId) {
    steem.api.getAccounts([steemId], function(err, result) {
      if(err === null) {
        const data = result[0];
        const profile = JSON.parse(data.json_metadata);
        const likerId = getLikerId(profile.profile);
        if(likerId) {
          const src = `https://button.like.co/in/embed/${likerId}/button?referrer=${url}`;
          //console.log(src);
          const iframe = document.createElement("iframe");
          iframe.setAttribute("src", src);
          iframe.setAttribute("frameborder", 0);
          iframe.setAttribute("scrolling", 0);
          iframe.setAttribute("target", "_top");
          button.appendChild(iframe);
        }
      }
      else{
        console.log(err);
      }
    });
  }
  else{
    console.log("Not a registered Liker");
  }
}

css.innerHTML = `
.likecoin-button {
  bottom: 20px;
  position: fixed;
  right: 20px;
  height: 240px;
  width: 500px;
  overflow: hidden;
  z-index: 2000
}
.likecoin-button > div {
  padding-top: 49.48454%;
}
.likecoin-button > iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  -ms-zoom: 0.75;
        -moz-transform: scale(0.75);
        -moz-transform-origin: 0 0;
        -o-transform: scale(0.75);
        -o-transform-origin: 0 0;
        -webkit-transform: scale(0.75);
        -webkit-transform-origin: 0 0;
}
`;
document.body.appendChild(css);
button.className = "likecoin-embed likecoin-button";
document.body.appendChild(button);


createLikerButton(url, steemId);
window.setInterval(function() {
  let tempurl = window.location.href;
  if(tempurl !== url) {
    button.textContent = "";
    url = tempurl;
    href = url.split("/");
    steemId = href[href.length-2];
    createLikerButton(url, steemId);
  }
}, 1000);

liker.js是本程序的主心骨。程序一开始先记录当前的网址,生成啪啪啪按键的iFrame。搜取用户的SteemId

我在测试中,可能是调用API太频繁了,惹得https://anyx.io生气把我给block掉了。对于我来说,用steem默认得结点没有任何问题。但是对于墙内的朋友,估计还得使用https://anyx.io这样的结点支持。使用的方法是uncommon第六行(去掉//

  1. getFollowing方程在原来的文章里面讲过,是用来搜索所有@cn-likers关注的名单。
  2. getLikerId的用处是搜索当前文章的作者是否在自己的Location里面填写了自己的LikerId
  3. isLiker是用来过滤非发表的文章的网页。上面介绍多,所有文章的网址里面都用@用户,只要我们将网址切开,倒数第二段里面是以@开头的网址,就都是文章。
  4. createLikerButton则是将所有前面的方程都连接起来。先收录所有@cn-likers关注的用户的名单;再搜索当前网页是否是一篇文章,如果是的话,则截取文章的作者;搜索作者的用户资料并检查是否记录了LikerId。如果拥有LikerId的话,则在网页上加上一个啪啪啪按键。上面提到的@huaren.news就没有注册Matters,所以文章上就没有出现LikeCoin的按键。

扩展程序使用效果


https://steemit.com


https://steempeak.com/


https://staging.busy.org

Screenshot_20200228_135153_com.oice.jpg
啪啪啪之后,在Liker Land*上可以看到Busy,Steemit的啪啪啪。


以后还可以做什么

我曾经听过一句形容完成程序开发的话:“没有完成开发的程序,只有不想再继续做下去的程序。”那么,这个我们还能再在这个程序上添加些什么呢?

  1. 可以建设访问@cn-likers关注名单的次数。前面提到了https://anyx.io暂时性限制了我访问他们API的权限。我们在第一次搜索@cn-likers关注名单之后,将名单存储下来,在规定的时间内不再访问Steem API结点。
  2. 提供Steem API的结点服务器很多,可以适当轮换当前使用的结点,这样可以减少过多使用同一个结点的频率。
  3. 加一个on/off开关。在不想使用Chrome Extension的时候,将其关掉。

安装Chrome扩展程序

我已经把扩展程序存在Github和码云上面。

  1. Github: https://github.com/xiangstan/likecoin-extension
  2. 码云: https://gitee.com/xiangstan/likecoin-extension

登陆不了Github的可以去码云下载。

代码资料库里面有介绍如何将扩展程序安装到自己的浏览器上(如图)。


感谢

  1. 设计啪啪啪按键得到了https://github.com/likecoin/likecoin-button-sdk的启发。其中CSS Style也是根据likecoin-button-sdk里面JavaScript的代码改编的。
  2. 村长@ericet的getFollowers代码
  3. 特别感谢,压轴的重头戏。扩展程序在浏览器里面的图标是女友当年练习Illustrator的时候设计的。别人都可以不感谢,这个必须感谢……
Sort:  

拍拍拍,可以放 Chrome webstore 让大家方便安装

 last year 

哇塞,这个操作太厉害了(可惜,我是程序白痴,有看没懂 XD)

幸苦啦,kuma兄,给你大力拍手!!!

谢谢哈

为最后一句啪啪啪😂

🤣 🤣

看到文章题目我就纳闷你@我干嘛……
原来是拿我来做试验……哈哈哈……
拍拍拍……
!shop

因为当时,你那篇是拍手公民里面的第一篇,所以拿来各种试验🤣 🤣
👏 👏 回敬

小白鼠是很为伟大的
!shop

你好鸭,糖糖!
@cloudblade赠送1枚SHOP币给你!

目前你总共有: 113枚SHOP币

查看或者交易 SHOP币 请到 steem-engine.com.

无聊吗?跟我猜拳吧! **石头,剪刀,布~**


You win!!!! 你赢了!我这新手村猜拳小能手的名号让给你了! 给你1枚SHOP币!

你好鸭,lnakuma!
@windowglass赠送1枚SHOP币给你!

目前你总共有: 24枚SHOP币

查看或者交易 SHOP币 请到 steem-engine.com.

无聊吗?跟我猜拳吧! **石头,剪刀,布~**

石头


You lose! 你输了!愿赌服输,请给我点赞~

不错,谢谢提醒,这就去注册liker:)

👍 👍

太厉害了
啪啪啪啪
!shop

你好鸭,lnakuma!
@cloudblade赠送1枚SHOP币给你!

目前你总共有: 26枚SHOP币

查看或者交易 SHOP币 请到 steem-engine.com.

无聊吗?跟我猜拳吧! **石头,剪刀,布~**

哇~~ 这么快就搞定了?
我必须试试,哈哈哈
多谢多谢

(帖子里我的名字写错了😀😁,我都没有收到提醒,才发现这个文章,哈哈)

Sorry,我总是丢三落四的,今天名字都写错了。😱 😱

我用插件给你拍拍手,真好~ 哈哈

😄 😄
用着好用就是我最高兴的事情👏 👏

你好鸭,lnakuma!
@annepink赠送1枚SHOP币给你!

目前你总共有: 23枚SHOP币

查看或者交易 SHOP币 请到 steem-engine.com.

无聊吗?跟我猜拳吧! **石头,剪刀,布~**

石头


You lose! 你输了!愿赌服输,请给我点赞~

西利!

這樣大家都可快快啪啪啪了!

為最後一個啪!

谢谢

最后一句是整篇post的重点😄



This post has been voted on by the SteemSTEM curation team and voting trail. It is elligible for support from @curie and @minnowbooster.

If you appreciate the work we are doing, then consider supporting our witness @stem.witness. Additional witness support to the curie witness would be appreciated as well.

For additional information please join us on the SteemSTEM discord and to get to know the rest of the community!

Please consider using the steemstem.io app and/or including @steemstem in the list of beneficiaries of this post. This could yield a stronger support from SteemSTEM.

Thanks for using eSteem!
Your post has been voted as a part of eSteem encouragement program. Keep up the good work!
Dear reader, Install Android, iOS Mobile app or Windows, Mac, Linux Surfer app, if you haven't already!
Learn more: https://esteem.app
Join our discord: https://discord.me/esteem

我在steemit.com拍你

在Busy里回拍(发现busy里面无法上传贴图。跑到esteem.app里面回复🤣)

bflpry.jpg

最后一个怕啥?🤣
👏 👏

@tipu curate
!shop

Posted using Partiko Android

Upvoted 👌 (Mana: 10/15 - need recharge?)

我是用插件幫您拍手

不過,不知為何,在插件上顯示為 0

偶遇帖子补拍5⃣👏

Brelent