It’s Been a Long Way

It feels like I’ve been posting these kinds of website update posts every few months (or years). I still remember the day I got the first version of my website working in middle school. It’s been about 6 years since that day (wow). And the domain DeemOcean.com has been in use for 5 years. One good thing about keeping a website alive for so long and actively maintaining its SEO is achieving a high rank in search engines, even with my lazy update rate of more than a month.

Traffic for 1 Month (CloudFlare)

Traffic for 1 Month (CloudFlare)

So I tried putting Google Ads on the website to see how much passive income I can get:
Ads Earning for 1 Month (Google Adsense)

Ads Earning for 1 Month (Google Adsense)

It is really not bad, was peaked at $200 per month even with 0 posts for a long time.

Why the Switch

Wordpress is really not bad for a new website builder with almost zero experience. But it’s the kind of thing you’ll enjoy if your use cases are just within its design range. The moment you want something specific, it just gets annoying to use. And I don’t even need most of the functionalities in its package. This results in a messy, slow website that is hard to customize.

Also, it has security risks. Two months ago, my website got hacked and there were like 200 pages of Casino Ads. Part of that is my problem, since I basically never visited the website to check for too long.

But, I always wanted something more elegant, with nice version control features, and fast. Thus, I made the decision to switch to the Hugo Framework.

The Setup

I am a huge fan of CloudFlare and have been using it for 5 years - I absolutely love it. It has a feature called Pages, which is somewhat similar to GitHub Pages, but with the CloudFlare network. Since it’s free, I’m also saving on server fees. (For anyone who wants to do the same, it provides a free X.pages.dev domain.)

In this way, I created a private GitHub repo for my website, and every time I push to the repo, CloudFlare automatically builds my website and then publishes it onto its global networks.

Modifications

Hugo gives you so much freedom to do things, so I have added many features to it.

A Hugo Shortcodes is a simple snippet inside a content file that Hugo will render using a predefined template.

One of these is the figure shortcode for inserting images with my desired functionalities:

<figure {{ with .Get "pos" }}class="{{.}}"{{ end }}>
    {{- if .Get "link" -}}
        <a href="{{ .Get "link" }}" {{ with .Get "target" }} target="{{ . }}" {{ end }}{{ with .Get "rel" }} rel="{{ . }}" {{ end }}>
    {{- end }}
    <img src="{{ .Get "src" }}"
        class="{{ .Get "pos" }}"
        {{- if or (.Get "alt" ) (.Get "caption" ) }}
        alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "caption" | markdownify| plainify }}{{ end }}"
        {{- end -}}
        {{- with .Get "width" }} width="{{ . }}"{{ end -}}
        {{- with .Get "height" }} height="{{ . }}"{{ end -}}
        style="{{- with .Get "style" }} {{ . | safeCSS }};{{ end -}}
        {{- with .Get "round" }}border-radius: {{ . | safeCSS }}px;{{ end -}}
        {{- with .Get "rotate" }}transform: rotate({{ . | safeCSS }}deg);{{ end }}"
    /> 
</figure>

Which gives the options like link pos src alt caption width height style round rotate

Image Optimization

I have a lot of images on this website, to have a good performance, I wrote a python script to backup the original files into a folder with the same relative paths, and replace the images with a optimizaed .webp file without metadata.

# THIS FILE ASSUMES PROJ ROOT DIR
import os
import re
import shutil
from PIL import Image, ImageSequence
from tqdm import tqdm

# the folders to be optimized
path = ['static/','content/DeemoGraphy/']
# backup the files to a new folder
orig_path = ['ORIG/static_ORIG/', 'ORIG/gallery_ORIG/']

for i in range(len(path)):

    # Get the list of files and folders in the source directory tree
    source_items = list(os.walk(path[i]))

    # all common imgs
    img_pattern = re.compile(r'\.(jpg|png|jpeg)$', re.IGNORECASE)
    gif_pattern = re.compile(r'\.gif$', re.IGNORECASE)
    # optimize 
    progress_bar = tqdm(source_items, desc="Optimizing", unit="file")
    for rootDir, subdirs, filenames in progress_bar:
        
        # Create the corresponding directories in the destination folder
        for dir_name in subdirs:
            source_dir_path = os.path.join(rootDir, dir_name)
            destination_dir_path = source_dir_path.replace(path[i], orig_path[i], 1)
            os.makedirs(destination_dir_path, exist_ok=True)
    
        for filename in filenames:
            file_path = os.path.join(rootDir, filename)
            bkup_file_path = file_path.replace(path[i], orig_path[i], 1)
            try:
                if img_pattern.search(filename):
                    #BACK UP
                    shutil.copy(file_path, bkup_file_path)
                    progress_bar.write(f"Backing up: {file_path}")
                    #########
                    img = Image.open(file_path)
                    #REMOVE metadata
                    img.info.pop('exif', None)
                    progress_bar.write(f"Removing EXIF(METADATA): {file_path}")
                    #OPTIMIZATION
                    img.save(os.path.splitext(file_path)[0]+'.webp', optimize=True, quality=85,format="webp")
                    os.remove(file_path)
                    progress_bar.write(f"Optimizting: {file_path}")

            except OSError:
                print("Error while saving file")

print("Back-Up & EXIF(METADATA) Removal & Optimization DONE")
Running Image Opt script

Running Image Opt script

Shell Shortcuts

Obviously I need a quick way to maintain all my custom functionalities, so I wrote a shell .alias script to take over the boring part of using the terminal:

WORKSPACE_PATH=$HOME/Desktop/workspace
BLOG_PATH=$WORKSPACE_PATH/DeemOcean

# Use double quotes around variables and remove spaces around the equal sign
alias gowk="cd $WORKSPACE_PATH"
alias goblog="cd $BLOG_PATH"

function blog() {
    goblog
    case $1 in
        "new")
            hugo new posts/$2.md
        ;;
        "server")
            hugo server --noHTTPCache;;
        "opt")
            python opt.py;;
        "commit")
            echo "------------------------"
            echo "committing custom theme..."
            cd themes/terminal
            git add .
            git commit -m $2
            cd ../..
            echo "------------------------"
            echo "committing blog..."    
            git add .
            git commit -m $2;;
	    "push")
            echo "------------------------"
            echo "pushing custom theme..."
            cd themes/terminal
            git push
            echo "------------------------"
            echo "pushing blog..."
            cd ../..    
	        git push;;
	    "")
	        echo "landing at blog dir";;
        *)
            echo "invalid blog option";;
    esac
}

Domains

You might noticed that the main domain for this website now is dmo.page, but I have added the URL page redirect rules. Meaning the old DeemOcean.com/somesection/somepage indexed by Search Engines will be redirect to dmo.page/somesection/somepage It is a painless transition :D