JavaScript

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.

How you set the homepage and new tab default page varies by browser.  In Brave try hamburger->appearance->show home button->select option->paste the location of the homepage.html file, e.g. file://home/gessel/homepage.html.

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

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <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;
    }

    #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="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 = '.images/';
      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');
      const formattedDateTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
      dateTimeElement.textContent = formattedDateTime;
    }

    // Function to fetch and display the weather information
    // The delay is set for 10 seconds to avoid hitting the wttr.in server if you're just 
    // opening a tab to enter a web address.  Hopefully one-line forcasts will be implemented
    // soon - check https://github.com/chubin/wttr.in/issues/447 for progress
    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);

    // Update the weather information every 100 minutes
    updateWeather();
    setInterval(updateWeather, 6000000);

    // thanks to claude.ai for helping with the scripts.
  </script>
</body>
</html>

 

Posted at 05:48:19 GMT-0700

Category: CodeHowToLinuxTechnologyWeather

Testing Privacy Tools

Saturday, December 4, 2010 

I was curious after posting some hints about how to protect your privacy to see how they worked.

Using EFF’s convenient panopticlick browser fingerprinting site. Panopticlick doesn’t use all the tricks available, such as measuring the time delta between your machine and a reference time, but it does a pretty good job. Most of my machines test as “completely unique,” which I find complementary but isn’t really all that good for not being tracked.

Personally I’m not too wound up about targeted marketing style uses of information. If I’m going to see ads I’d rather they be closer to my interests than not. But there are bad actors using the same information for more nefarious purposes and I’d rather see mistargeted ads than give the wrong person useful information.

Panopticlik noscript.jpg

Testing Panopticlick with scripts blocked (note TACO doesn’t help with browser fingerprinting, just cookie control) I cut my fingerprint to 12.32 bits from 20.29 bits, the additional data comes from fonts and plugins.

Note that EFF reports that 1:4.1 browsers have javascript disabled. Visitors to EFF are, I would assume, more likely to disable javascript than teh norm on teh interwebz, but that implies that javascript-based analytics packages like Google analytics miss about 25% of visitors.

Panopticlick_1291458952178.jpg

It is also interesting to note that fingerprint scanners (fingerprints as on the ends of fingers) have false reject rates of about 0.5% and false acceptance rates of about 0.001%. Obviously they’re tuned that way to be 50x more likely to reject a legitimate user than to accept the wrong person and the algorithms are intrinsically fallible in both directions, so this is a necessary trade-off. Actual entropy measures in fingerprints are the subject of much debate. An estimate based on Pankanti‘s analysis computes a 5.5×10^59 chance of a collision or 193 bits of entropy but manufacturer published false acceptance rates of 0.001% are equivalent to 16.6 bits, less accurate than browser fingerprinting.

Posted at 06:44:41 GMT-0700

Category: PoliticsTechnology