Skip to main content

One afternoon, one script: college Python utilities I wrote for myself

Share:XLinkedInHN
Cover for One afternoon, one script: college Python utilities I wrote for myself

The captive portal

The first one was the hostel WiFi. PSG Tech, third-year hostel room, laptop on a plastic chair because the desk was covered in slide packs. Every time the machine woke from sleep, or every time I moved between the lab and the room, or every time the router hiccuped, the browser would redirect me to a captive portal at 172.17.0.1 on some port I did not want to memorise. The page had a frame, a terms-of-service checkbox that you could not click straight because the div swallowed the click, a username field, and a password field. I would type my roll number twice a day, sometimes ten times a day if I was on a video call and the session dropped.

I wrote a Python script to do it for me. It was called WiFi-Login-Automation. It used Selenium in headless Chrome, walked into the frame, pressed Tab twice, hit Space to toggle the checkbox because clicking it normally sent the event to the wrong element, typed my roll number and password, and clicked submit. May 2022. About a hundred lines. Committed in a flurry over a few days, then ran daily for the rest of the year.

That was the first script I wrote where the ratio flipped: the thing took me an afternoon to write and it saved me an afternoon of small annoyances over the semester. I remember the moment because I remember what I did after. I closed the laptop, walked to the mess, ate rice, and came back to a WiFi session that was already live. Small win. Very small win. But the shape of the win was different from anything I had built before.

The three scripts

Before I go further, the three scripts, briefly:

WiFi-Login-Automation (May 2022). Selenium, headless Chrome, one function called login(usr_name, pwd). It found the frame, tabbed to the checkbox, typed the credentials, hit submit. Also a connect() wrapper that checked whether we were on PSG WiFi by shelling out to netsh, and pinged google to confirm the session was up. The README even had a "how to use" that told you to open the file in IDLE and edit line 107.

JET-PDF (February 2022). PyPDF2, tqdm for the progress bar, a nested loop that compared every page against every other page using extractText, and a delete_duplicate function that wrote out a new PDF minus the flagged pages. I built it because I had downloaded a slide pack from somewhere, a course pack I think, and the same fifteen slides appeared four times in the file. The web tools that promised to fix it either wanted money or wanted me to install something sketchy. I wrote it in an evening.

Youtube-heatmap (June to July 2022, three related repos). This one had layers. The core script was thirty lines: fetch the YouTube page HTML with urllib, find the substring that starts with {"heatMarkerRenderer":, walk to the end marker, do a few string replaces to turn YouTube's undocumented JSON blob into a parseable structure of (start_ms, duration_ms, intensity) triples. The follow-up scripts, Youtube-heatmap-video and Youtube-heatmap-analysis, used Selenium and svgpathtools to open the most-replayed segment of a lecture video in a new tab. I was watching a lot of lectures at 2x that summer and I wanted to skip to the part everyone else rewound to.

Same shape, three times. One file. One user. One exact annoyance.

What the code actually looked like

The YouTube heatmap script is the cleanest of the three because there was nothing to it. No browser automation, no PDF byte fiddling, just a string scan and a few replaces. Here is the core:

import requests
from urllib.request import urlopen
 
def get_heatmap(url):
    '''
    parameter -> url :str
    returns a json response with
    {start_time in ms, end_time in ms, re-wind relative}
    re-wind relative = 1 --> most replayed part of the video
    '''
    html = str(urlopen(url).read())
    str_ind = html.index('{"heatMarkerRenderer":')
    end_ind = html.index('heatMarkersDecorations')
    text_html = '{' + html[str_ind + 22:end_ind - 3]
    text_html = text_html.replace('"timeRangeStartMillis":', '')
    text_html = text_html.replace('"markerDurationMillis":', '')
    text_html = text_html.replace('"heatMarkerIntensityScoreNormalized":', '')
    text_html = text_html.replace('{"heatMarkerRenderer":', '')
    text_html = text_html.replace('},', ',\n')
    return text_html

Look at that. No JSON parser. No regex. Just index and replace. If YouTube changed the field name I would have to fix it, and the response is not even valid JSON when you get done with it. Nobody would ship this to production. Nobody was shipping it to production. It was for me, running on my laptop, on a video I already had the URL of. If it broke, I would spend ten minutes fixing the substring index and move on.

The JET-PDF loop had the same character. Compare every page to every other page in a double loop. On a hundred-page slide pack that is five thousand comparisons and each comparison calls extractText on a full page object. Slow. Wildly slow. But I ran it three times in a semester, and it saved me the alternative of paying for smallpdf or clicking around Adobe Acrobat's page thumbnails and deleting duplicates by hand. The tqdm bar meant I could tab away, drink a coffee, and come back to a clean PDF.

The WiFi script had the same sin. It launched a full Chrome instance in headless mode just to press four keys and click a button. There was almost certainly a way to POST the login form directly and skip Chrome entirely. But the login page was inside a frame and I did not want to reverse-engineer what the checkbox toggle actually sent. So I paid the cost of launching Chromium every time the session dropped. It ran in about eight seconds. Fine.

The ratio

The lesson these three scripts taught me, and it is a lesson I still think about, is that the value of a personal utility is not the elegance of its code. The value is the ratio of time saved over time spent, over the lifetime of the tool. And the lifetime is the thing you underestimate.

I would have guessed, when I wrote the WiFi script, that I would run it maybe fifty times. In practice I ran it hundreds of times, because it ran silently every time my laptop woke up, and my laptop woke up several times a day for a year and a half. Each run saved me maybe fifteen seconds of typing and thirty seconds of mental context switch. Multiply that out. The script paid for itself in the first two weeks and every run after that was pure profit.

JET-PDF was the opposite curve. I ran it maybe six times total. Each run saved me twenty minutes of clicking. Different math, same conclusion. The script paid for its afternoon.

The heatmap script paid off in a different currency: I was watching lectures for exams that summer, and skipping to the most-replayed segment let me sample a professor's whole hour in about six minutes to decide whether it was worth watching in full. I probably watched thirty lectures that summer with it. Time saved, hard to quantify, definitely positive.

What that taught me

The habit those three scripts installed is the habit I still use. When something annoying happens twice, I do not automate it. When it happens a third time, I notice. When it happens a fourth time, I open a file called something.py, import the two libraries I need, and write the smallest thing that turns the four-time annoyance into zero-time annoyance. No tests. No CLI. No config file. Hardcoded paths, hardcoded credentials, one function, one entry point.

Almost everything I have written since, at work and outside it, is a bigger version of this. The command palette on this site started as one script that grepped my content directory. The CipherStack vault started as one script that rotated a Gemini API key. The pattern is the same: one exact annoyance, one file, one afternoon, and then years of quiet payoff because the annoyance never comes back.

The three college scripts are still on my GitHub, unedited since 2022. WiFi-Login-Automation has a comment on line 49 that says "Hard coded for clicking Terms and conditions checkbox as all the contents were placed in a single div so clicking it normally would cause the click to be interpreted by other elements". I would not change the comment. It is the sound of a twenty-year-old figuring out that the real world's UIs are held together with duct tape, and that the correct response is to bring your own duct tape.

See also

Cite as: Saravanan, K. (2026). One afternoon, one script: college Python utilities I wrote for myself. Kaushik Saravanan. https://www.kaushik.cv/blog/college-python-utility-scripts