• I wrote this post more than 2 years ago.
• That's enough time for things to change.
• Possibly, I may not endorse the content anymore.

## Sending Notifications on Chrome Extension

counting...

The goal is to...

1. Send notifications on Installation and Updates of a given Chrome Extension (with different content, of course)

var extensionPage =  'https://chosunghyun.com/youtube-comment-language-filter'var updateLogPage =  'https://chosunghyun.com/youtube-comment-language-filter/updates'chrome.runtime.onInstalled.addListener(function (object) {  if (object.reason === 'install') {    chrome.notifications.create(extensionPage, {      title: 'YCLF is now installed 😎',      message:        'Click here to learn more about the extension!',      iconUrl: './images/min-icon128.png',      type: 'basic',    })  } else if (object.reason === 'update') {    chrome.notifications.create(updateLogPage, {      title:        'YCLF updated to v' +        chrome.runtime.getManifest().version +        ' 🚀',      message: "Click here to check out what's new!",      iconUrl: './images/min-icon128.png',      type: 'basic',    })  }})

Also available on GitHub

• Note that iconUrl should be the path from manifest.json to the image file, not from the background script.
• You can use chrome.runtime.getManifest().version it to get the version of the extension.
• If you want to send notifications from anywhere else than the background script, you must have a communication module between the notification sender and the background script to pass the notification details. Create a notification at background.js with that given detail. Sending notifications directly from content.js seems restricted. Check this post for more information.

Generally, you would need an event listener for each notification. However, there is a neat way to reduce duplicate codes.

chrome.notifications.onClicked.addListener(function (notificationId) {  chrome.tabs.create({ url: notificationId });});

The trick is to store the link in notificationId field and attach an event listener to the notifications. This way, you can only use one event listener to open multiple types of links.

### Note: Added June 19, 2020​

It doesn't seem that this is the ultimate answer. While the notification opens up the intended page when the user clicks the notification right after it pops up, the notification does not open up the page on click if the notification is sent to the notification center. This post will be updated if I find a better solution.

• I wrote this post more than 2 years ago.
• That's enough time for things to change.
• Possibly, I may not endorse the content anymore.

counting...
💬Work in Progress

I wrote this post in another language. I did not translate it to other languages yet. If you speak different languages, look for this post in that language.

• I wrote this post more than 2 years ago.
• That's enough time for things to change.
• Possibly, I may not endorse the content anymore.

## Displaying exact datetimes on Ghost

counting...

If your Ghost CMS blog using Handlebars theme shows published dates in relative time (like Published 11 months ago), you will find a handlebars code like this in your theme file.

<time datetime='{{date format='YYYY-MM-DD'}}'>  {{date published_at timeago='true'}}</time>

## Show exact date​

The date published_at timeago="true" is responsible for the relative time. Change it to this.

<time datetime='{{date format='YYYY-MM-DD'}}'>  {{date published_at format='MMMM DD, YYYY'}}</time>

This will give something like September 7, 2000.

## Show exact time​

You can use [moment.js](https://momentjs.com/) syntax for fine-tuning the details.

<!-- 2000 September 07 9:00:00 PM --><time datetime='{{date format='YYYY-MM-DD hh:mm:ss A'}}'>  {{date published_at format='YYYY MMMM DD hh:mm:ss A'}}</time><!-- 2000 09 07 9:00 PM --><time datetime='{{date format='YYYY-MM-DD hh:mm A'}}'>  {{date published_at format='YYYY MM DD hh:mm A'}}</time><!-- 2000 09 07 21:00 --><time datetime='{{date format='YYYY-MM-DD hh:mm'}}'>  {{date published_at format='YYYY MM DD hh:mm'}}</time>

For months, use MM for short notations (like 09) and MMMM for more extended notations (like September.) The basic syntax is for hours, minutes, seconds, and AM/PM if you want to display time. For example, I am using the following.

<time datetime='{{date format='YYYY-MM-DD h:mm A'}}'>  {{date published_at format='YYYY/MM/DD h:mm A'}}</time>

• I wrote this post more than 2 years ago.
• That's enough time for things to change.
• Possibly, I may not endorse the content anymore.

counting...
💬Work in Progress

I wrote this post in another language. I did not translate it to other languages yet. If you speak different languages, look for this post in that language.

• I wrote this post more than 2 years ago.
• That's enough time for things to change.
• Possibly, I may not endorse the content anymore.

## Finding the size of the directory in Python

counting...
import osimport mathdef getFileSize(path, kilo=1024, readable=False, shortRead=False):    size = 0    sizeArr = []    units = ["B", "KB", "MB", "GB", "TB", "PB", "EB"]    if os.path.isdir(path):        for dirpath, dirnames, filenames in os.walk(path):            for i in filenames:                size += os.path.getsize(os.path.join(dirpath, i))    elif os.path.isfile(path):        size += os.path.getsize(path)    unit = math.floor(math.log(size, kilo))    for k in range(0, unit + 1):        sizeArr.append(            math.floor((size % kilo ** (k + 1)) / kilo ** k)        )    if readable:        sizeString = ""        if not shortRead:            for x in range(unit, -1, -1):                sizeString += str(sizeArr[x]) + units[x] + " "            return sizeString[:-1]        else:            return (                str(sizeArr[-1])                + "."                + str(math.floor(sizeArr[-2] / 1.024))                + units[len(sizeArr) - 1]            )    else:        return sizeArr

## Examples​

### Reference​

• C:\Users\anacl\OneDrive\Documents (Folder): 3.13GB (3,366,343,239 Bytes)
• C:\Users\anacl\OneDrive\Pictures (Folder): 83.4MB (87,468,781 Bytes)
• C:\Users\anacl\OneDrive\Pictures\screenshot.png (File): 139KB (143,262 Bytes)

### Default​

print(getFileSize("C:\\Users\\anacl\\OneDrive\\Documents"))print(getFileSize("C:\\Users\\anacl\\OneDrive\\Pictures"))print(    getFileSize(        "C:\\Users\\anacl\\OneDrive\\Pictures\\screenshot.png"    ))# Expected Output# [583, 404, 138, 3]# [749, 426, 83]# [926, 139]

Each element in the returned list is the value of [B, KB, MB, GB, ...] of the file size.

print(    getFileSize(        "C:\\Users\\anacl\\OneDrive\\Documents", readable=True    ))print(    getFileSize("C:\\Users\\anacl\\OneDrive\\Pictures", readable=True))print(    getFileSize(        "C:\\Users\\anacl\\OneDrive\\Pictures\\screenshot.png",        readable=True,    ))# Expected Output# 3GB 138MB 404KB 583B# 83MB 426KB 749B# 139KB 926B

print(    getFileSize(        "C:\\Users\\anacl\\OneDrive\\Documents",        readable=True,        shortRead=True,    ))print(    getFileSize(        "C:\\Users\\anacl\\OneDrive\\Pictures",        readable=True,        shortRead=True,    ))print(    getFileSize(        "C:\\Users\\anacl\\OneDrive\\Pictures\\screenshot.png",        readable=True,        shortRead=True,    ))# Expected Output# 3.134GB# 83.416MB# 139.904KB
• I wrote this post more than 2 years ago.
• That's enough time for things to change.
• Possibly, I may not endorse the content anymore.

## Apple Newsroom Font Styles

counting...
💬Work in Progress

I wrote this post in another language. I did not translate it to other languages yet. If you speak different languages, look for this post in that language.

• I wrote this post more than 2 years ago.
• That's enough time for things to change.
• Possibly, I may not endorse the content anymore.

## Porting a Chrome Extension to Firefox Add-on

counting...

While Chrome and Firefox are two very different browsers, Chrome Extension and Firefox Add-on are now more similar than ever. Therefore, it is possible to transplant a Chrome extension to a Firefox Add-on and publish it to the Mozilla store with minor changes. This post is how I transplanted my YouTube Comment Language Filter to Firefox.

## Checking the Chrome incompatibilities​

First of all, Firefox can run commands with chrome namespace, such as chrome.tabs.onUpdated. However, there are still a few codes that Firefox cannot run. Firefox offers a handy website to check the chrome incompatibilities.

1. On your Chrome browser (or on any equivalent Chromium browsers,) visit chrome://extensions.
2. Enable Developer Mode and Press Pack Extension.
3. Select your extension directory and pack your extension. That will create a .crx file.
4. Visit the Firefox Extension Test website and upload your .crx file.
5. If it says there is no problem, then you are fine.

If there is any problem, I advise you to visit the MDN docs and see what code caused the problem. I didn't have any problem, so I cannot share any experience here.

Firefox also requires an ID inside the manifest.json file. It is like the following.

"browser_specific_settings": {  "gecko": {    "id": "addon@example.com",    "strict_min_version": "42.0"  }},

As you can see, you can also add a strict_min_version here. See original MDN docs.

This was a minor hassle since Chrome could not recognize the above code block. So you need to keep two manifest.json, one with the above code block (for Firefox) and one without it (for Chrome). If I find a more straightforward way, I will add it here.

3. Visit Firefox Submit a New Add-on page.
4. Follow the guidelines on the screen.

One little tip: make sure you don't include any unnecessary files .DS_Store or anything like that. Using macOS's default Finder compressor will sometimes have these files. I recommend using Keka.

## Update​

• It seems that you don't necessarily need a Firefox manifest ID. Therefore – submit the Chrome version, and 99% will work (If you didn't get any warning on the Firefox Extension Test website).
• I wrote this post more than 2 years ago.
• That's enough time for things to change.
• Possibly, I may not endorse the content anymore.

## Building a Raspberry Pi Smart Audio System

counting...
💬Work in Progress

I wrote this post in another language. I did not translate it to other languages yet. If you speak different languages, look for this post in that language.

• I wrote this post more than 2 years ago.
• That's enough time for things to change.
• Possibly, I may not endorse the content anymore.

## Apple's Easter Egg

counting...

I recently found this:

This is just a thought. But it might be nice to have some sortof easter egg message in here for the hard core Apple fans thatwill stop the video.01010011 01101111 00100000 01111001 01101111 0111010100100000 01110100 01101111 01101111 01101011 0010000001110100 01101000 01100101 00100000 01110100 0110100101101101 01100101 00100000 01110100 01101111 0010000001110100 01110010 01100001 01101110 01110011 0110110001100001 01110100 01100101 00100000 01110100 0110100001101001 01110011 00111111 0010000001010111 01100101 00100000 01101100 01101111 0111011001100101 00100000 01111001 01101111 01110101 00101110

So I made a short script.

egg = '''01010011 01101111 00100000 01111001 01101111 0111010100100000 01110100 01101111 01101111 01101011 0010000001110100 01101000 01100101 00100000 01110100 0110100101101101 01100101 00100000 01110100 01101111 0010000001110100 01110010 01100001 01101110 01110011 0110110001100001 01110100 01100101 00100000 01110100 0110100001101001 01110011 00111111 0010000001010111 01100101 00100000 01101100 01101111 0111011001100101 00100000 01111001 01101111 01110101 00101110'''.split()for e in egg:    print(chr(int(e,2)), end="")print()

It said...

So you took the time to translate this? We love you.