Even More Nerdiness

Last week, I wrote about a simple Windows app I built to automatically set my Windows 10 wallpaper to a random photo from 75CentralPhotography.Com. This week, I ran into another issue/want/need that required me to once again dust off my Windows development skills to solve.

I thought it would be nice if all my Chromecast-connected TVs and my Google Home Hub would display my photos as part of their screensaver feature. However, to do this, I’d need to have a folder in Google Photos of all my published photos. Building this collection of photos is actually a bit harder than it sounds, believe it or not! Why not just export all of the photos from your Photoblog collection in Lightroom?, you ask. Well, the problem there is that that collection actually contains about 600 other photos that have either not been published or were mistakenly tagged as a photoblog item, so any export would have a lot of cruft. So, I needed a way to get all of the photos. Downloading from the backend of 75CentralPhotography.Com was also an option, except that there’d be a lot of extraneous files there as well for a couple of reasons: 1) since the site runs on WordPress, any time an image is uploaded, WordPress helpfully generates a few versions of the file in addition to the original for thumbnail and featured images and, 2), there are leftover files from revisions to posts, so for any photo I’ve ever re-edited and republished, there’s the old version lurking about. Also, a few years ago, we painstakingly re-edited each post to upsize the photos to more-pleasing, easier-to-appreciate dimensions, so the previous versions are out there as well.

To solve this, I decided that I could reuse a lot of the code I’d written for the previous wallpaper project and build a couple of items:

  1. A new RESTful API that would return the photo from a particular date presented to it.
  2. A Windows application to iterate through every day since we started publishing photos (August 12, 2007) until the present day, calling the aforementioned webservice and downloading the photo that was returned by the service.

To accomplish the first step, I made a copy of the code from the webservice built for my previous project and modified it expect a date query string parameter, so calling the service looks something like this:

{base URL}/photodate/?date=12/14/2018

The webservice parses the date element into three strings for month, day and year and adds them to an argument array for WordPress’ WP_Query() function:

$datep=  $_GET['date'];
$pieces = explode("/", $datep);

  $args = array(
      'date_query' => array(
          array(
              'year' => $pieces[2],
              'month' => $pieces[0],
              'day' => $pieces[1]

          )
      )
  );
$your_query = new WP_Query( $args );

WordPress automatically performs the query, and if results are returned, assigns the results to variables:

if($your_query->have_posts()){
  while ($your_query->have_posts()) :
    $your_query->the_post();
    $imageurl= catch_that_image();
    $permlink = get_post_permalink();

  endwhile;
}

We use the catch_that_image() function again to get the URL to the first (and, in our case, only) image in the post. We then serialize this into a JSON string and return the results:

{"Image":"http://www.75centralphotography.com/wp-content/uploads/2018/12/las-vegas-bliss-dance-sculpture-hand.jpg","permalink":"http://www.75centralphotography.com/?post_type=post&p=38007"}

Moving on to the Windows app part of the solution, I built a simple UI that would let me choose a start date, choose a folder to save the images to, and a button to actual start the process:

On the backend, clicking the Process button calls this bit of code:

 Dim startdate As Date = Me.DateTimePicker1.Value.Date()
        Dim today As Date = Date.Now()
        Dim i As Integer
        Dim wo As New WebOps
        Dim rP As Bitmap
        Dim currUrl As String
        While startdate <= today
            currUrl = wo.getURL(startdate)
            rP = tempPB(currUrl)
            rP.Save(Me.FolderBrowserDialog1.SelectedPath & "\" & i & ".jpg", Imaging.ImageFormat.Jpeg)
            i = i + 1
            startdate = startdate.AddDays(1)
            Application.DoEvents()
        End While

First, we declare our variables and objects:

  • today is obviously today’s date and sets the upper bound of possible days that images have been published
  • i is the counter for how many times we’ve looped through the download process (we also use that to build our filenames so that our output is a nicely-ordered list of published photos in order of published date
  • wo instantiates a copy of a class I built called WebOps, which does the heavy-lifting of calling the webservice and returning the results
  • rp is a Bitmap object, basic a blob of data that represents our image file that we’ve downloaded
  • currlURL represents the URL we’re calling, in this case, the base URL for the service with the date parameter appended

Next, we start the actual processing:

  • We wrap everything in a while loop. This loop starts at the date chosen in the datepicker control on the user interface and iterates through each day until today by adding a day to startdate on each pass through the loop.
  • We first set the value of currUrl by calling the getURL function in the WebOps class:
        Dim format As String = "MM/dd/yyyy"
        Dim fdate As String = getdate.ToString(format)
        Dim url As String = baseURL & "?date=" & fdate
        Dim wc As New WebClient
        Dim jRes As String
        wc = New WebClient
        Dim retry = True
        While retry
            Try
                jRes = wc.DownloadString(url)
                retry = False

            Catch
                retry = True
            End Try
        End While
        Dim tempPost = New With {Key .Image = ""}
        Dim post = JsonConvert.DeserializeAnonymousType(jRes, tempPost)
        Dim com As String = post.Image
        Dim tempURL = New With {Key .permalink = ""}
        Dim pURL = JsonConvert.DeserializeAnonymousType(jRes, tempURL)
        Dim plink As String = pURL.permalink
        Dim u As New utilities
        wc = Nothing
        Return com

This returns the URL of the photo posted on the specific date passed into the webservice (you’ll notice that we also get the permalink, but we don’t use it…this is simply because I reused this code from the wallpaper app).

  • We pass the currUrl into the tempPB function, which does the work of downloading the image and setting its data to the rp bitmap object
Private Function tempPB(url As String) As Bitmap 
        Dim tClient As WebClient = New WebClient
        Dim tImage As Bitmap = Bitmap.FromStream(New 
           MemoryStream(tClient.DownloadData(url)))
        Return tImage
End Function
  • Then we save rp to disk as a .jpg file, targeting the folder chosen in the user interface and using the value if i as the filename.
  • We then increment our startdate value and i‘s value
  • Finally, we through in a call to Application.DoEvents(), which is a simple, though not-necessarily-the-best, way to ensure that the application’s interface doesn’t freeze while in a loop.

When the application runs, it iterates from the chosen date to today and saves the files locally. When it finishes running, which is in the case of starting on August 12, 2007 and ending today, we end up with a folder of of over 4200 ordered .jpg files of every published photo on 75CentralPhotography.Com:

To get these into Google Photos for casting to Chromecast devices, we create a folder in Google Photos and upload:

Finally, we hop into the Google Home app and set the album as the source of images for the Chromecast’s Ambient Mode:

  • February 12, 2019