Pankaj Tanwar
Published on

I turned my 10 year old tablet into a digital photo frame, displaying google photos album. 🌴

––– views

Last weekend, I built a digital photo frame, from my a-decade-old tablet. It cycles through photos from a shared Google Photos album, switching up the display every hour.

End Result

Mango Relaxing

Here's my cat Mango, just casually relaxing.

How I did it?

On another lazy Saturday afternoon, nostalgia led me to sift through a mid-sized carton box filled with my college day treasures: random electronics, old photos, the script from my first stand-up performance, a diary, keyrings, and even gifts I carried all the way to Bangalore.

I stumbled upon a forgotten tablet, though I doubted it would still work. Undeterred, I looked through my carton box and miraculously found a compatible charging cable. With little optimism, I plugged it in.

No luck.

I was convinced it wouldn't work, but decided to give it one last shot. I held down the power button for a full minute, and suddenly, the screen lit up. However, it promptly went back to sleep again.

After two more hours of experimenting, I eventually succeeded in powering it on, but it was terribly slow. Each click took a frustrating 2-3 seconds to respond. Fortunately, it managed to connect to WiFi.

Upon checking the model details, I found it was a decade-old device running Android 4.4.4 KitKat, with only 512MB RAM and 2GB of storage. Clearly, in 2024, it had become obsolete and would serve little practical purpose.

My Tablet

Digital Frame?

Out of the blue, an idea popped into my folly brain - why not repurpose it as a digital photo frame?

Mindful of security concerns & storage constraints, I opted not to transfer my personal photos. Instead, I devised a simple plan: using Google Photos to display images from a shared album, switching every hour. Unsure if it would actually work, I decided to give it a try.

Challenge #1

No way I'm logging into Gmail on this ancient thing! I'm brainstorming ways of snagging photos from a Google Photos album shared with my family and friends. They can add pics, and voila! Instant digital frame upgrade.

But, alas! the tablet's antiquated browser couldn't handle today's websites. Faced with this hiccup, I set off on a mission to find a workaround, only to discover it couldn't even display a basic site with half-decent JavaScript.

Thanks to my internet stranger friend Terence Eden's beautiful post, I came across an ancient open source light weight app Electric Sign. This gem lets you input any website URL and automagically refreshes it at your chosen interval. Yay! Sorted.

But here's the kicker - it turned out "Electric Sign" wasn't exactly a fan of SSL or those flashy modern websites. When I tried to load up something fancy, the screen just threw in the towel and went blank!

Challenge #2

I attempted to set up a simple HTML page on platforms like Netlify, GitHub Pages, and Vercel to host my website, but all I got was a dazzling white screen!

To overcome it, I had to setup a custom nginx server and a static website to use http instead of https. The security-conscious side of me wasn't thrilled about this workaround, but hey, desperate times call for desperate measures!

Finally, my website was live. Next up, I planned to integrate some Google Photos APIs to fetch and display a random image—but of course, nothing is ever that simple!

Challenge #3

After wasting another two hours, I discovered there's no public Google Photos API (thanks, Google!).

Wait, "Why not build something myself?"

I created a Google Photos album and generated a public link. Opening it in an incognito tab, I sifted through the HTML. Damn! Every image in my album appeared with URLs like https://lh3.googleusercontent.com/<something>

My master plan: read the HTML of my public link using fetch, use regex to extract all URLs, filter out duplicates, randomly select an image, and display it on my website.

Here's what the JavaScript code in my HTML file looked like:

function setRandomImage() {
fetch('https://photos.app.goo.gl/<album_id>')
.then(response => response.text())
.then(data => {
const regex = '"(https:\/\/lh3\.googleusercontent\.com\/pw\/[a-zA-Z0-9\-_]*)"';
const imageUrls = [];
while ((match = regex.exec(data)) !== null) {
imageUrls.push(match[1]);
if (imageUrls.length > 0) {
const randomIndex = Math.floor(Math.random() * imageUrls.length);
const img = document.createElement('img');
img.src = imageUrls[randomIndex];
document.body.appendChild(img);
}
}
})
.catch(error => console.error('Error fetching URLs:', error));
}

Please bear with my ugly code.

Challenge #4

I soon realised, fetch was not supported in my dinosaur-era browser. So, I reluctantly switched gears to XMLHttpRequest, only to have Google slam the door on me with some pesky CORS issues.

My minimalist brain refused to entertain the idea of setting up a server for such a small task. Instead, I opted to hack my way through using just HTML and JavaScript.

However, I quickly realized it would be too much for a simple web page to handle—fetching content, filtering unique URLs, and displaying one of them would slow down the reload significantly. Plus, the sluggish tablet was practically begging me not to overload it with work.

A bash script

My old time good friend, bash script came to the rescue. I crafted a tiny script that curls to fetch the content of the album URL, performs some regex magic to scoop up unique URLs, randomly picks one, and updates index.html.

#!/bin/bash
url="https://photos.app.goo.gl/<here_goes_my_album_id>"
# Fetch HTML content
html_content=$(curl -sSL "$url")
# Regex pattern to match URLs
regex='"(https:\/\/lh3\.googleusercontent\.com\/pw\/[a-zA-Z0-9\-_]*)"'
# Use grep with -oP (perl-compatible) to extract all matches
urls=$(echo "$html_content" | grep -oP "$regex" | sort -u)
# Function to add '=w1100-h600-s-no-gm' to each URL
add_params_to_url() {
cleaned_url=$(echo "$1" | sed 's/^"//;s/"$//') # Remove surrounding quotes if present
echo "$cleaned_url=w1100-h600-s-no-gm"
}
# Array to store modified URLs
modified_urls=()
# Loop through each URL, add parameters, and store in array
while IFS= read -r url; do
modified_urls+=( "$(add_params_to_url "$url")" )
done <<< "$urls"
# Select a random URL from the modified list
random_url=$(shuf -e "${modified_urls[@]}" -n 1)
# Generate HTML file with the random modified URL as background image
cat > index.html << EOF
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pankaj Tanwar : My Digital Photo Frame</title>
<style>
body {
margin: 0;
padding: 0;
background-image: url('$random_url');
background-size: cover;
background-position: center;
height: 100vh;
}
</style>
</head>
<body>
<!-- Content goes here -->
</body>
</html>
EOF
echo "Generated index.html with random background image: $random_url"

I called upon my trusty buddy crontab to run the script every hour like clockwork.

So, at this point, index.html always had a single image link ready to go—just open the webpage. It all worked like a charm! Who needs fancy setups when you've got bash scripts and a sprinkle of creativity?

Here's a neat trick: I added w1100-h600-s-no-gm to the Google Photos URL to resize images perfectly for my tablet's display.

Gluing everything together.

I set up the tablet on the desk next to my favorite bike miniature, set it to never sleep, scheduled it to refresh every hour, connected it to WiFi, and plugged it in with a charging cable. Now, it's all systems go! My little tech creation is ready to roll.

By then, my other two cats, Cherry and Litchi, were really miffed because I hadn't included their photos. To appease them, I promptly added our group picture to the album and promised not to forget them next time. They let me off with a warning not to mess up again!

Next up on the agenda: I'll snag a wooden frame to give it that extra touch of aesthetic appeal!