Write a Chrome plug-in from scratch

Plug-in function

  • Usually the most time-consuming thing for me is brushing "know-it", but I can't stop being cheap. Chrome has one installed on it. StayFocusd 10 minutes later, the zhihu domain name is blocked. But sometimes you really need to know to check something. Every time you turn it off, you will "forget" to open it.
  • I hope someone can remind me every five minutes that you brushed for five minutes today, you brushed for 10 minutes today, and you brushed for 15 minutes today... To be honest, I think this kind of reminder is both mild and effective, of course, it can also become very mild, such as sending reminders directly to the boss.
  • The code for this article is already on github: dingding_robort/chrome_extension.

file structure

  • manifest.json (plug-in registration metadata)
  • bg.js (main program)
  • jquery-3.2.1.min.js (for sending ajax requests)

manifest.json

{
  "name": "block zhihu",
  "version": "0.1",
  "description": "Notify dingding every 5 minuntes for browsing zhihu",
  "permissions": [
    "tabs",
    "storage",
    "alarms",
    "idle",
    "https://oapi.dingtalk.com/"
  ],
  "background": {
    "scripts": ["jquery-3.2.1.min.js","bg.js"]
  },
  "manifest_version": 2
}
  • manifest.json: It's a necessary documentation for the chrome plug-in, and the name doesn't have to be changed.
  • name, version, description, these can be written freely.
  • "manifest_version": 2 This is the manifest file format version of chrome.
  • Permissions: To call the chrome interface, the chrome plug-in needs to declare permissions here. tabs, alarms, idle are all chrome API s. Storage is a local storage. The pin address below is to request permissions across domains.
  • Background: The scripts in this list run in the background. To know that the script running in the background and the script of the web page itself are not in the same process, so you can't see the script by opening the web page review directly. If you want to debug the plug-in program, go to extension - inspect views to find it. If you need to interact with the web script itself, you need to add content_scripts.

bg.js

  • To write this program, you first need to master some concepts:

    • JavaScript: The chrome plug-in is written by JavaScript.
    • tabs behavior: Here we use two behaviors of chrome tab: on Update and on Activated. That is to refresh the page in tab and click on a tab.
    • windows Behavior: This program uses the onFocus Changed behavior of windows. That's when I switch programs, such as cutting chrome to the background and Wechat to the front desk.
    • Idle behavior: This program uses idle's onStateChanged behavior, computer dormancy and other states.
    • alarms: triggers a task on a regular basis.
    • ajax request: send get, post and other requests, here is to send messages to the nail robot.
    • localStorge: The local storage of chrome can be seen as a dictionary with key-value pairs, with only string values.
  • Program logic structure:

    1. Judge if I'm going to brush: When a tab page refreshes the zhihu.com domain name (tab.onUpdate), or I click on the tab with zhihu.com (tab.onActivated), it means I'm starting to brush, and the timing starts.
    2. Interpret how long I brushed: When I left the zhihu.com domain name to another domain name (tab.onUpdate), or when I went to another tab (tab.onActivated), or simply my focus was not on chrome (windows.onFocusChanged) or even idle.onStateChanged) counted as a time-out.
    3. Send a nail request: If the brush exceeds a certain time, let the nail robot nail you directly. Or you can simply use alert to bounce windows over chrome.
  • Code implementation: global constants and initialization of local storage

    // In fact, more domain names can be added here, such as youtube.com, weibo.com and so on. After all, it is not only unknown that they can be brushed.
    var track_sites = ["zhihu.com"]
    
    // Time is calculated according to the time of East Eighth District, mainly for clearing data at zero every day.
    var GMT = +8
    var MINUTE_PER_DAY = 1440
    
    // Give a reminder every few minutes. Here is a reminder every five minutes.
    var TIMEPACE = 5 * 60
    
    //Links for sending nail robots
    var NOTIFY_URL = "https://oapi.dingtalk.com/robot/send?access_token="
        + "c6d5a2936381dfc29394f3c336bea5fad962d90ffd31809e92d95xxxxxxx"
    var MOBILE_NUMBER = "176xxxxx619"
    
    initLocalStorage();
    
    function initLocalStorage(){
        //Initialize localStorage
        localStorage.clear();
        localStorage["is_idle"] = "false";
        localStorage["last_site"] = "null";
        localStorage["last_time"] = timeNow();
        localStorage["total_elapsed_time"] = 0;
        localStorage["next_alarm_time"] = TIMEPACE;
        //How long does each domain name with each domain name as the key access time
        //Although this dictionary is logically unnecessary, it can be extended to a specific website for a specific length of visits per day or per week in the future.
        for (var i in track_sites){
            localStorage[track_sites[i]] = JSON.stringify({"elapsed_time": 0});
        }
    }
    
    function timeNow(){
        // Returns the current timestamp
        return Math.round(Date.now()/1000) + GMT * 3600;
    }
    
    • Trace_sites: You can actually add more domain names here, such as youtube.com, weibo.com and so on. After all, you can brush more than you know.
    • GMT: Time is calculated according to the time of East Eighth District, mainly for clearing data at zero every day.
    • MINUTE_PER_DAY: 1440 minutes a day, no explanation.
    • TIMEPACE: Give a reminder every few minutes, here is a reminder every five minutes.
    • NOTIFY_URL, MOBILE_NUMBER: Send links to nail robots. Why nail robots? http://www.jianshu.com/p/418e4ffbb4e3
    • Obsessive-compulsive disorder (OCD) asks why track_sites are lowercase and the rest are capitalized. Because (forgot to change, scratch out) this later to do an interface in the foreground to manually add domain names, it will be a variable.
    • initLocalStorage(): Clear the local storage and add variables such as whether the is_idle computer is dormant, how much time total_elapsed_time wastes on a site visited on last_site, and when next_alarm_time brushes to this point, it reminds you how much time each domain name has visited, although logically not. You need to use this dictionary, but in the future it can be extended to specific websites with specific visits per day or per week.
    • timeNow(): Gets the current timestamp.
  • Code implementation: event listening

    function classifyDomin(domain){
        // Check if the domain name is on the blacklist?
        var in_list = false;
        for (var i in track_sites){
            if(domain.match(track_sites[i])){
                addTimeDelta(track_sites[i]);
                in_list = true;
                break
            }
        }
        // Domain names not on the blacklist are treated as null
        if(in_list == false){
            addTimeDelta("null");
        }
    }
    
    function getCurrentTabDomin(){
        // Get the domain name of the currently active tab
        chrome.tabs.query({active: true, lastFocusedWindow: true}, function(tabs){
            if (tabs.length == 1){
                var url = new URL(tabs[0].url);
                var domain = url.hostname;
                classifyDomin(domain);
            } else if (tabs.length == 0){
                addTimeDelta("null");
            } else {
                console.log("Strange to find more than one tabs active?");
                console.log(tabs);
            }
        })
    }
    
    chrome.tabs.onUpdated.addListener(getCurrentTabDomin)
    chrome.tabs.onActivated.addListener(getCurrentTabDomin)
    chrome.windows.onFocusChanged.addListener(getCurrentTabDomin)
    chrome.idle.onStateChanged.addListener(function(idleState){
        if (idleState == "active"){
            // The is_idle status record is for the following minute-by-minute periodic check events. If idle is gone, check no more.
            localStorage["is_idle"] = false;
            getCurrentTabDomin();
        }else{
            localStorage["is_idle"] = true;
            addTimeDelta("null");
        }
    })
    
    • Check CurrentTab (), get the domain name of the currently active tab, then go to updateDomin() to confirm that the domain name is in the blacklist, and then go to addTimeDelta() "Update the browsing time". Note: addTimeDelta() in the code will be implemented below.
    • tab Update, Activated, and windows focus Changed bind the checkCurrentTab() function to these three events.
    • When idle.onStateChanged wakes up and recovers from computer hibernation, record idle status, and if it is from hibernation to activity, it is equivalent to windows focus Changed event.
  • Code implementation: update browsing time

    function updateLocalStorageTime(){
        // Update access time in localStorage
        var domain = localStorage["last_site"];
        var site_log = JSON.parse(localStorage[domain]);
        timedelta = timeNow() - parseInt(localStorage["last_time"]);
        site_log["elapsed_time"] = parseInt(site_log["elapsed_time"]) + timedelta;
        console.log(domain, "elapsed_time: ", site_log["elapsed_time"]);
        localStorage[domain] = JSON.stringify(site_log);
        localStorage["total_elapsed_time"] = parseInt(localStorage["total_elapsed_time"]) + timedelta;
        if(parseInt(localStorage["total_elapsed_time"]) > parseInt(localStorage["next_alarm_time"])){
            fireNotification();
        }
        localStorage["last_time"] = timeNow();
    }
    
    function isElapsedTime(domain){
        // Is it a good idea to judge the past time?
        if(localStorage["last_site"] == "null" && domain != "null"){
            localStorage["last_site"] = domain;
            localStorage["last_time"] = timeNow();
        }else if(localStorage["last_site"] != "null"){
            updateLocalStorageTime();
            localStorage["last_site"] = domain;
        }
    }
    
    • Is ElapsedTime () based on the domain name of the site being visited at the time of the last event, to determine whether the last period of time was being notified?
    • updateLocalStorageTime() Update the visiting time of each site of the localStorage.
  • Code implementation: timing program

    function minLeftMidnight(){
        // How many minutes are left before 0 o'clock? It's necessary to empty the timed task init every day.
        return MINUTE_PER_DAY - Math.round(timeNow()/60) % MINUTE_PER_DAY
    }
    
    chrome.alarms.create("mignight_clear",
            {delayInMinutes: minLeftMidnight(), periodInMinutes: MINUTE_PER_DAY});
    // Clean up the local Storage at zero every day
    chrome.alarms.create("minute_check", {periodInMinutes: 1})
    // Check the website you are browsing every minute and send a reminder in time
    chrome.alarms.onAlarm.addListener(function(alarm){
        if (alarm.name == "mignight_clear"){
            console.log("clear localStorage");
            initLocalStorage();
        }else if (alarm.name == "minute_check"){
            if(localStorage["is_idle"] == true){
                console.log("minute_check");
                getCurrentTabDomin();
            }
        }
    })
    
    • Triggering Clear localStorage Program at Zero Point Every Day
    • In addition to the fact that a specific event occurs that triggers the check of the current tab domin, it also triggers once a minute.
  • Code implementation: sending reminders

    function notifyDingding(msg){
        // Send msg to nail reminder
        $.ajax({
            type: "POST",
            beforeSend: function(request) {
                request.setRequestHeader("Content-Type",
                    "application/json; charset=utf-8");
            },
            url: NOTIFY_URL,
            data: JSON.stringify({
                "msgtype": "text",
                "text": {
                    "content": msg
                },
                "at": {
                    "atMobiles": [MOBILE_NUMBER]
                }
            }),
            success: function(return_msg){
                console.log(return_msg);
            }
        });
    }
    
    function fireNotification(){
        // Stitching msg, bouncing windows and requesting nails
        let elapsed_time = parseInt(localStorage["next_alarm_time"]) / 60
        msg = "You have brushed it today." + elapsed_time + "Minutes tell." 
        console.log(msg);
        alert(msg);
        notifyDingding(msg);
        localStorage["next_alarm_time"] = parseInt(localStorage["next_alarm_time"]) + TIMEPACE;
    }
    
    • The nail module is similar to python, but it's sent in ajax.
    • fireNotification will pop up a window alert directly on the browser and receive it without nails.
  • All the code can be seen in github:

  • To see the effect, I specially brushed my face for half an hour.


WX20170823-151825.png

Keywords: JSON Windows github JQuery

Added by isign4jc on Fri, 31 May 2019 21:40:19 +0300