A one page home/new tab page with random pictures, time, and weather

Thursday, April 11, 2024 

Are you annoyed by a trend in browsers to default to an annoying advertising page with new tabs? I sure am. And they don’t make it easy to change that. I thought, rather than a blank new tab page, why not load something cute and local. I enlisted claude.ai to help expedite the code and got something I like.

homepage.html is a very simple default page that loads a random image from a folder as a background, overlays the current local time in the one correct time format with seconds, live update, and throws up the local weather from wttr.in after a delay (to avoid hitting the server unnecessarily if you’re not going to keep the tab blank long enough to see the weather).

Images have to be in a local folder and in a predictable naming structure, as written “image_001.webp” to “image_999.webp.” If the random enumerator chooses an image name that doesn’t exist, you get a blank page.

Browsers don’t auto-rotate by exif (or webp) metadata, so orient all images in the folder as you’d like them to appear.

The weather information is only “current” which isn’t all that useful to me, I’d like tomorrows weather, but that’s not quite possible with the one-liner format yet.

Update, I added some code to display today and tomorrow’s events from your Thunderbird calendar, if you have it. If not, just don’t cron the bash script and no diff. I also changed the mechanism of updating the weather to a 30 minute refresh of the page itself, this way you get more pix AND the calendar data updates every 30 minutes.  Web browsers and javascript are pretty isolated from the host device, you can’t even read a local file in most (let alone write one).  All good security, but a problem if you want data from your host computer in a web page without running a local server to deliver it.

My work around was to write the data into the file itself with a script.  Since the data being written is multi-line, I opted to tag the span for insert with non-breaking spaces, a weird character and the script sanatizes the input from calendar events extracted from the sqlite database in case some event title includes them.   The current config is by default:

~/.myHomePage/myHomePage.html
~/.myHomePage/getEvents.sh
~/.myHomePage/myHomeImages/image_001.webp
~/.myHomePage/myHomeImages/image_002.webp
etc.

The code for the executables, myHomePage.html and getEvents.sh, is below. The images you have to supply yourself.

How you set the homepage and new tab default page varies by browser.  In Brave try hamburger→settings→appearance→show home button→select option→paste the location of the homepage.html file, e.g. file:///home/(username)/.myHomePage/myHomePage.html

The pictures are up to you, but here’s the code:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name='author' content='David Gessel, dg@brt.llc'>
  <meta name='summary' content='This is a nice homepage/new tab that shows some useful info and pix'>
  <meta name='url' content='https://gessel.blackrosetech.com'>
  <meta name='date' content='2024-05-16'>
  <title>New Tab</title>
  <style>
    body {
      margin: 0;
      padding: 0;
      height: 100vh;
      display: flex;
      justify-content: center;
      align-items: flex-start;
      overflow: hidden;
    }

    #background-image {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-size: cover;
      background-position: center;
      z-index: -1;
    }

    #time-date {
      position: absolute;
      top: 20px;
      right: 20px;
      font-size: 48px;
      color: white;
      text-shadow: 3px 3px 8px rgba(0, 0, 0, 1);
      font-family: sans-serif;
      font-weight: bold;
    }

    #events {
      position: absolute;
      top: 80px;
      right: 20px;
      font-size: 24px;
      color: white;
      text-shadow: 3px 3px 8px rgba(0, 0, 0, 1);
      font-family: sans-serif;
      text-align: right;
    }

    #weather {
      position: absolute;
      bottom: 20px;
      left: 20px;
      font-size: 24px;
      color: white;
      text-shadow: 3px 3px 8px rgba(0, 0, 0, 1);
      font-family: sans-serif;
    }
  </style>
</head>
<body>
  <div id="background-image"></div>
  <div id="time-date"></div>
  <div id="events"></div>
  <div id="weather"></div>

  <script>
    // Function to get a random image from the 'image_001.webp' to 'image_230.webp' range
    // Edit image folder to match the folder you want to store the images in
    // edit the min and max image index range to match the images 
    // set the imageName extension to suit (e.g. .jpg, .webp, .png)
    // white screen usually means the images or folder can't be found
    function getRandomImage() {
      const imageFolder = 'myHomeImages/';
      const minImageIndex = 1;
      const maxImageIndex = 230;
      const randomIndex = Math.floor(Math.random() * (maxImageIndex - minImageIndex + 1)) + minImageIndex;
      const imageName = `image_${randomIndex.toString().padStart(3, '0')}.webp`;
      return `${imageFolder}${imageName}`;
    }

    // Function to update the time and date display
    // Updates every second, uses the only technically correct* date and time format
    // * The best kind of correct.
    function updateTimeDate() {
      const dateTimeElement = document.getElementById('time-date');
      const currentDate = new Date();
      const year = currentDate.getFullYear();
      const month = String(currentDate.getMonth() + 1).padStart(2, '0');
      const day = String(currentDate.getDate()).padStart(2, '0');
      const hours = String(currentDate.getHours()).padStart(2, '0');
      const minutes = String(currentDate.getMinutes()).padStart(2, '0');
      const seconds = String(currentDate.getSeconds()).padStart(2, '0');
      // Get the day of the week in short form
      const daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
      const dayOfWeek = daysOfWeek[currentDate.getDay()];
      const formattedDateTime = `${dayOfWeek}, ${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
      dateTimeElement.textContent = formattedDateTime;
    }

    // Function to display the events data
    function displayEvents() {
      const eventsElement = document.getElementById('events');
      const eventsData = `​   ​`;
      eventsElement.innerHTML = eventsData.replace(/\n/g, '<br>');
    }

    // Function to fetch and display the weather information
    async function updateWeather() {
      const weatherElement = document.getElementById('weather');
      try {
        await new Promise(resolve => setTimeout(resolve, 10000)); // 10-second delay
        const response = await fetch('https://wttr.in/?m&format=%l%20%c+%C+%t%20+%h%20+%w\n');
        const weatherData = await response.text();
        weatherElement.textContent = weatherData;
      } catch (error) {
        console.error('Error fetching weather information:', error);
        weatherElement.textContent = 'Error fetching weather information.';
      }
    }

    // Set the random background image
    const backgroundImage = document.getElementById('background-image');
    backgroundImage.style.backgroundImage = `url('${getRandomImage()}')`;

    // Update the time and date every second
    setInterval(updateTimeDate, 1000);

    // Display the events data
    displayEvents();

    // Update the weather information
    updateWeather();

    // Refresh the page every 30 minutes
    setInterval(() => {
      location.reload();
    }, 1800000);

    // thanks to claude.ai for helping with the scripts.
  </script>
</body>
</html>
#!/bin/bash
# this should extract today and tomorrow's events from your
# Thunderbird calendar-data/&lt;prefix&gt;.sqlite file and then write them
# into the events section of corresponding myHomePage.html file, which
# will display them. Probably.
# I use a remote calendar, so my local calendar file is cache.sqlite
# but if you keep your events local, it should be local.sqlite.
# Set the path to the Thunderbird local.sqlite database file
# you need to replace the &lt;provile&gt; with yours like 432v2c4.username

DB_PATH="$HOME/.thunderbird/&lt;profile&gt;/calendar-data/cache.sqlite"

# Set the temporary database file path
TEMP_DB_PATH="/tmp/local_temp.sqlite"

# Set the output file path
OUTPUT_FILE="$HOME/.myHomePage/myHomePage.html"

# Set the temporary output file path
TEMP_OUTPUT_FILE="/tmp/myHomePage_temp.html"

# Get the current date and the date for tomorrow in the format used by Thunderbird, considering the local timezone
TODAY=$(date -d "today 00:00:00" +%s)000000
TOMORROW=$(date -d "tomorrow 00:00:00" +%s)000000

# Create a temporary copy of the database
cp "$DB_PATH" "$TEMP_DB_PATH"

# Query the temporary database for today's events
TODAY_EVENTS=$(sqlite3 -separator '|' "$TEMP_DB_PATH" "SELECT title, time(event_start/1000000, 'unixepoch', 'localtime') AS start FROM cal_events WHERE event_start >= $TODAY AND event_start < $TOMORROW")

# Query the temporary database for tomorrow's events
TOMORROW_EVENTS=$(sqlite3 -separator '|' "$TEMP_DB_PATH" "SELECT title, time(event_start/1000000, 'unixepoch', 'localtime') AS start FROM cal_events WHERE event_start >= $TOMORROW AND event_start < $TOMORROW + 86400000000")

# Function to replace the last occurrence of "|" with "starts: " in each line
replace_last_pipe() {
  while IFS= read -r line; do
    echo "${line%|*} starts: ${line##*|}"
  done
}

# Create the events data variable
EVENTS_DATA=""

# Check if there are today's events
if [ -n "$TODAY_EVENTS" ]; then
  EVENTS_DATA+="Today's Events:\n$(echo "$TODAY_EVENTS" | replace_last_pipe)\n\n"
fi

# Check if there are tomorrow's events
if [ -n "$TOMORROW_EVENTS" ]; then
  EVENTS_DATA+="Tomorrow's Events:\n$(echo "$TOMORROW_EVENTS" | replace_last_pipe)\n\n"
fi

# Remove any existing zero-width spaces from the events data
EVENTS_DATA=$(echo "$EVENTS_DATA" | perl -pe 's/\xe2\x80\x8b//g')

# Prefix and postfix the events data with zero-width spaces
EVENTS_DATA=$(echo -e "\xe2\x80\x8b$EVENTS_DATA\xe2\x80\x8b")

# Escape special characters in the events data
EVENTS_DATA=$(echo "$EVENTS_DATA" | perl -pe 's/`/\\`/g; s/\//\\\//g')

# Read the myHomePage.html file
HTML_CONTENT=$(cat "$OUTPUT_FILE")

# Replace the events data between the zero-width space delimiters with the updated events data
HTML_CONTENT=$(echo "$HTML_CONTENT" | perl -0777 -pe 's/\xe2\x80\x8b.*?\xe2\x80\x8b/'"$EVENTS_DATA"'/s')

# Check if the replacement was successful
if [ $? -eq 0 ]; then
  # Write the updated HTML content to the temporary output file
  echo "$HTML_CONTENT" > "$TEMP_OUTPUT_FILE"
  
  # Move the temporary output file to the original output file
  mv "$TEMP_OUTPUT_FILE" "$OUTPUT_FILE"
else
  echo "Error: Failed to update the events data in the HTML file."
fi

# Remove the temporary database file
rm "$TEMP_DB_PATH"

 

And to collect the latest events and insert them in the above code, this bash script should work:

Then just set a cron script like <code>*/30 * * * * /home/<username>/.myHomePage/getEvents.sh</code> for regular updates.

Posted at 05:48:19 GMT-0700

Category : CodeHowToLinuxTechnologyWeather

Tags :

Leave a Reply

95 Views