Stop Motion Videos...in Slack? Spice Up Your Profile Picture with Cron Jobs & Github Actions!

Over the past year, many of us have been working from home with most of our communication happening on Slack. We can use our status to update our current situation whether it is in a heads down coding mode (do not disturb), out at lunch, at a doctors appointment, on vacation, not feeling well, or whatever emoji and text you are feeling.

The idea for this came from a simple question "what if people could know your status just by viewing your profile picture?"

The Idea

Update my profile picture in Slack throughout the day based on the time without being too disruptive.

A key part of this plan is that some people use other people's profile picture as a quick "who am I talking to" reference. Instead of reading names in the sidebar or the chat, they have become accustomed to one's profile picture. The images needed to update often enough to change "state" but not be too dramatic of changes to interrupt coworker's "flow."

Slack Stop Motion was born.

Slack Stop Motion

Implementation

From my initial idea and my requirements, I started brainstorming how to implement the idea. What I landed on was pretty simple:

Images

I've taken so many images with my webcam to try and figure this part out. I have a Logitech C920 that I thought would work but kept on running into small but frustrating issues. I used a terminal command to take pictures every 1 second to slowly move out of the camera, but the images there were quite grainy and low resolution. I tried using my Bluetooth mouse to click "capture" once I was in place, but those images ended up not being cohesive enough.

The last thing I did was put my iPhone on this $10 Amazon selfie stick that contains a Bluetooth button to trigger the capture. This solution worked out best in terms of quality and ease of use.

Cron Job

A cron job was the simplest solution and the one that immediately came to mind. I wanted to have the photos update on a fairly defined cadence and on certain days of the week (I am excluding weekends). Cron can do all that for you - and more!

Slack API

Integrating the Slack API took some messing around with but their documentation is easy to follow and click through to get what you need. The only things you need to get the Slack API working are:

From there, it's just like calling an API!

Github Actions

I thought about looking into more defined solutions from Google, AWS, and Microsoft, but at the end of the day, remember this is just a simple cron job. I didn't want to over architect a cron job. I learned that Github Actions can do a simple cron that can run whenever you define it - perfect!

Tutorial

Below is the step-by-step guide of how to set up your instance. I also have a public Github repository of what I'm using now if you'd like to visit that as well.

Gather Images

The first thing to do is to grab all your photos and map out when you want to update your profile and to what picture. This can be a fairly intensive task as it depends on the number of photos you have, your work hours, how often you want to update, etc.

:::note

I am not including this in part of the tutorial. Take your own photos! It's fun to do and you can spice it up to however you like.

:::

:::tip

:::

I created a folder on my Desktop, I named it images, and I added my images in there.

Images folder desktop

Here are all my images in gif form to help get an understanding of how I flowed them:

Slack Stop Motion

Create a Slack App

In this tutorial, we are only creating a one-off Slack app. If you want to look into how to create one that other people can sign in with, capture their tokens, be secure, and market, be my guest.

  1. Visit your Slack workspace, click on the workspace name in the top left and then go to Settings & Administation -> Manage apps

    Manage App

  2. From there, in the top right, click on "Build"

    Build

  3. Click "Create New App", give it a name, and add it to your Slack Workspace

    Create App Name App

  4. From here, on the left-hand side under "Features" click on "OAuth & Permissions"

    Oauth and Permissions

  5. Scroll down to "Scopes" and find "User Token Scopes"

  6. Click "Add an Oauth Scope" and search for users.profile:write Scopes

  7. Now scroll back up to the top and under the "Oath Tokens & Redirect URLs" click on "Install to Workspace"

    Scopes

  8. Allow the app to be installed on your workspace Install

  9. After installation, you will see the title "User Oauth Token" - this is very important - this is how we access the Slack API. Copy and save this to a safe location for now. Important Token

Creating the Script

  1. Now that we have our images and our Slack API key, we can go ahead and create our script locally to test it out. The script is really, really basic. Here's a brief overview:

    • Get's the current hour
    • Get's the current minute
    • A lot of switch and if statements.

    Super basic, I know.

  2. To create our script, let's create a file called slack-stop-motion.sh

  3. Open up the file in your favorite code editor and add we are going to add our code to get the current hour and the current minute:

    #!/bin/bash
    
    hour=$(TZ=":America/New_York" date +%H)
    minute=$(TZ=":America/New_York" date +%M)
    
  4. With those two values, we can do our math/configuration of "at what time we want certain photos to display:.

  5. I have 30 images and I want them to change every 20 minutes. So I did some sweet calculations, determined what image I wanted when and made those if statements work. All I'm doing is checking the hour and then checking what minute it currently is to determine if it is the 0th, 20th, or 40th minute. 🙃

    :::note

    Your images and timing will be different than mine! Probably very different. Unless you have the same image name and timing structure, this won't work. I also use America/New_York as my timezone.

    :::

    :::note

    I set my "default" image to be when I am "away".

    :::

    #!/bin/bash
    
    hour=$(TZ=":America/New_York" date +%H)
    minute=$(TZ=":America/New_York" date +%M)
    
    img="1740.jpg"
    
    case $hour in
    7)
    if (($minute < 20)); then
       img="0700.jpg"
    elif (($minute < 40)): then
       img="0720.jpg"
    else
       img="0740.jpg"
    fi
    ;;
    8)
    if (($minute < 20)); then
       img="0800.jpg"
    elif (($minute < 40)): then
       img="0820.jpg"
    else
       img="0840.jpg"
    fi
    ;;
    9)
    if (($minute < 20)); then
       img="0900.jpg"
    elif (($minute < 40)): then
       img="0920.jpg"
    else
       img="0940.jpg"
    fi
    ;;
    10)
    if (($minute < 20)); then
       img="1000.jpg"
    elif (($minute < 40)): then
       img="1020.jpg"
    else
       img="1040.jpg"
    fi
    ;;
    11)
    if (($minute < 20)); then
       img="1100.jpg"
    elif (($minute < 40)): then
       img="1120.jpg"
    else
       img="1140.jpg"
    fi
    ;;
    12)
    if (($minute < 20)); then
       img="1200.jpg"
    elif (($minute < 40)): then
       img="1220.jpg"
    else
       img="1240.jpg"
    fi
    ;;
    13)
    if (($minute < 20)); then
       img="1300.jpg"
    elif (($minute < 40)): then
       img="1320.jpg"
    else
       img="1340.jpg"
    fi
    ;;
    14)
    if (($minute < 20)); then
       img="1400.jpg"
    elif (($minute < 40)): then
       img="1420.jpg"
    else
       img="1440.jpg"
    fi
    ;;
    15)
    if (($minute < 20)); then
       img="1500.jpg"
    elif (($minute < 40)): then
       img="1520.jpg"
    else
       img="1540.jpg"
    fi
    ;;
    16)
    if (($minute < 20)); then
       img="1600.jpg"
    elif (($minute < 40)): then
       img="1620.jpg"
    else
       img="1640.jpg"
    fi
    ;;
    17)
    if (($minute < 20)); then
       img="1700.jpg"
    elif (($minute < 40)): then
       img="1720.jpg"
    else
       img="1740.jpg"
    fi
    ;;
    esac
    
  6. Could this be more efficient? Oh you betcha. But that's for another time.

  7. Let's make sure we set the current image path based on our folder structure:

    <!-- ...previous code -->
    
    img="./images/${img}"
    
  8. Finally, we can now send our request to Slack! We will be making a simple curl POST request.

    <!-- ...previous code -->
    
    img="./images/${img}"
    
    curl --location --request POST 'https://slack.com/api/users.setPhoto' --form "token=xoxp-XYZ" --form "image=@${img}"
    

    :::note

    Be sure to replace xoxp-XYZ with your actual Slack API token from before!

    :::

  9. Return to your terminal and we can now safely run the script:

    sh ./slack-stop-motion.sh
    
  10. Hopefully there is a successful response like below. If not, tweet at me and I will try and help you out!

    {
      "ok": true,
      "profile": {
        "image_24": "https://avatars.slack-edge.com/2021-03-24/1919928028576_d0f5e53078c3e08fbcd3_24.jpg",
        "image_32": "https://avatars.slack-edge.com/2021-03-24/1919928028576_d0f5e53078c3e08fbcd3_32.jpg",
        "image_48": "https://avatars.slack-edge.com/2021-03-24/1919928028576_d0f5e53078c3e08fbcd3_48.jpg",
        "image_72": "https://avatars.slack-edge.com/2021-03-24/1919928028576_d0f5e53078c3e08fbcd3_72.jpg",
        "image_192": "https://avatars.slack-edge.com/2021-03-24/1919928028576_d0f5e53078c3e08fbcd3_192.jpg",
        "image_512": "https://avatars.slack-edge.com/2021-03-24/1919928028576_d0f5e53078c3e08fbcd3_512.jpg",
        "image_1024": "https://avatars.slack-edge.com/2021-03-24/1919928028576_d0f5e53078c3e08fbcd3_1024.jpg",
        "image_original": "https://avatars.slack-edge.com/2021-03-24/1919928028576_d0f5e53078c3e08fbcd3_original.jpg",
        "avatar_hash": "d0f5e53078c3"
      }
    }
    

    :::note

    Depending on the time of day, the image that shows up may not be what you "expect". Be sure to double-check!

    :::

  11. Here's our full script that we will then use later on:

    #!/bin/bash
    
    hour=$(TZ=":America/New_York" date +%H)
    minute=$(TZ=":America/New_York" date +%M)
    
    img="1740.jpg"
    
    case $hour in
    7)
    if (($minute < 20)); then
       img="0700.jpg"
    elif (($minute < 40)): then
       img="0720.jpg"
    else
       img="0740.jpg"
    fi
    ;;
    8)
    if (($minute < 20)); then
       img="0800.jpg"
    elif (($minute < 40)): then
       img="0820.jpg"
    else
       img="0840.jpg"
    fi
    ;;
    9)
    if (($minute < 20)); then
       img="0900.jpg"
    elif (($minute < 40)): then
       img="0920.jpg"
    else
       img="0940.jpg"
    fi
    ;;
    10)
    if (($minute < 20)); then
       img="1000.jpg"
    elif (($minute < 40)): then
       img="1020.jpg"
    else
       img="1040.jpg"
    fi
    ;;
    11)
    if (($minute < 20)); then
       img="1100.jpg"
    elif (($minute < 40)): then
       img="1120.jpg"
    else
       img="1140.jpg"
    fi
    ;;
    12)
    if (($minute < 20)); then
       img="1200.jpg"
    elif (($minute < 40)): then
       img="1220.jpg"
    else
       img="1240.jpg"
    fi
    ;;
    13)
    if (($minute < 20)); then
       img="1300.jpg"
    elif (($minute < 40)): then
       img="1320.jpg"
    else
       img="1340.jpg"
    fi
    ;;
    14)
    if (($minute < 20)); then
       img="1400.jpg"
    elif (($minute < 40)): then
       img="1420.jpg"
    else
       img="1440.jpg"
    fi
    ;;
    15)
    if (($minute < 20)); then
       img="1500.jpg"
    elif (($minute < 40)): then
       img="1520.jpg"
    else
       img="1540.jpg"
    fi
    ;;
    16)
    if (($minute < 20)); then
       img="1600.jpg"
    elif (($minute < 40)): then
       img="1620.jpg"
    else
       img="1640.jpg"
    fi
    ;;
    17)
    if (($minute < 20)); then
       img="1700.jpg"
    elif (($minute < 40)): then
       img="1720.jpg"
    else
       img="1740.jpg"
    fi
    ;;
    esac
    img="./images/${img}"
    
    curl --location --request POST 'https://slack.com/api/users.setPhoto' --form "token=xoxp-XYZ" --form "image=@${img}"
    

Setting up Github Repository

  1. Be sure you have a Github Account;
  2. Next, create a new repository. I named mine slack-stop-motion but you can name yours whatever you like. Click the green "Create" button at the bottom of the page.

Create New Repository

  1. On the next page, there will be a bunch of information about adding files to your Github repository. Under the "Quick Setup" headline, there is a link that says "uploading an existing file". This is how we will add our images.

Upload Existing File

  1. It will probably be easier to drag and drop your whole folder in on this UI to add your images to the repository.

Add Files

  1. Make sure to scroll to the bottom to commit your changes!

Commit Images

  1. Once they are finished uploading, you should be taken back to your repository homepage with your images folder.

Repository Homepage

  1. The last thing we are going to do is to add our slack-stop-motion.sh script to the repository as well.

:::warning

Edit your slack-stop-motion.sh file and remove your key from the file and replace it with ${TOKEN}. The curl command should look like the following:

curl --location --request POST 'https://slack.com/api/users.setPhoto' --form "token=${TOKEN}" --form "image=@${img}"

:::

  1. Next, go through the same process of uploading your file like you did with the images.

Upload Individual File Repo with Script

Adding Your Slack Key

  1. In order to safely and securely use the Slack API, we need to add our Slack API key to our repository. Thankfully, Github has thought of this problem and solved it for us!

  2. Click on "Settings" and then click on "Secrets" in the sidebar.

Settings & Secret

  1. Click "New Repository Secret"

New Repository Secret

  1. Create a secret with the name: "TOKEN" and paste in your Slack API Key from above. (Hint, it should start with xoxp if you followed the steps correctly.)

Slack API Token

Creating Your Github Action

  1. Our Github Action will be the foundation of our project. To get started, click on "Actions". (Don't see Github Actions? Visit the Documentation to learn more about how to get started.)

Github Actions

  1. Click "set up a workflow yourself"

Set up a workflow yourself

  1. Now we are onto some coding! This is where some of your custom configuration may come in; I run my cron job every 20 minutes between the hours of 7AM and 5PM. Here is the start of what my workflow looks like:

    name: Slack Stop Motion
    on:
      schedule:
        - cron: "*/20 11-21 * * mon-fri"
    

    :::note

    Cron can do some marvelous things. Visit https://crontab.guru to schedule to your heart's desire!

    Also note - check the timezone for cron on Github! It isn't Eastern 😬 that's why the cron is from 11-21 to account for the time difference.

    :::

  2. The next part of our workflow is calling the script we made earlier. There are a couple steps here that we want to make sure to hit:

    • Make sure the system has permissions to run the script (chmod)
    • Make sure our TOKEN from our environment secrets is defined in the environment
    • Call our script with the token.

    :::note

    Make sure the slack-stop-motion.sh script doesn't contain your actual Slack key but instead is replaced with ${TOKEN}. Revisit the previous steps if you're confused.

    Slack will turn off the key if you do accidentally make it public. If that happens, reinstall your app in your workspace.

    :::

  3. We can add those steps to our workflow with the following:

    name: Slack Stop Motion
    on:
    schedule:
      - cron: "*/20 11-21 * * mon-fri"
    jobs:
      cron:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v2
          - run: |
              chmod +x "${GITHUB_WORKSPACE}/slack-stop-motion.sh"
              export TOKEN=${{ secrets.SLACK_TOKEN }}
              "${GITHUB_WORKSPACE}/slack-stop-motion.sh"
    
  4. Our workflow is complete! Make sure you commit your file by clicking "Start Commit" on the right side.

With any luck, we've made it through this tutorial with a running cron job in Github Actions. You can leave your Action alone and it will all work for you. If you check the Actions tab you will see it running every 20 minutes between 7:00AM and 5:00PM.

Final Workflow

🎉🎉🎉 You did it! 🎉🎉🎉

With your Slack API Key, your images, and your Github actions, you can now enjoy your very own Slack Stop Motion!

Slack Stop Motion

Feedback and Questions

You can find me on Twitter @kevinguebert and I am open to all questions! You can also find the Github repo where I have my images and code available for reference.

Tweet at me

Visit Github

Twitch Livestream

:::note

The livestream on Twitch was done at the start of the project while I was still learning. Don't follow this word-for-word as things have changed!

:::




export default function NextraPage (props) {
    return withSSG(withLayout({
      filename: "slack-stop-motion.mdx",
      route: "/posts/slack-stop-motion",
      meta: {"title":"Stop Motion Videos...in Slack? Spice Up Your Profile Picture with Cron Jobs & Github Actions!","slug":"stop-motion-videos-in-slack","date":"2021-03-15T20:30:13.000Z","date_updated":"2021-03-15T20:30:35.000Z","tags":"tutorial","description":"Slack motion videos...in slack? Update your profile throughout the day.","feature_image":"/images/slack-stop-motion-cover.png"},
      pageMap: [{"name":"_app","route":"/_app"},{"name":"_document","route":"/_document"},{"name":"harvy-ios","route":"/harvy-ios","frontMatter":{"title":"Harvy (iOS)","type":"page","slug":"harvy-ios","date":"2020-09-28T13:14:22.000Z","date_updated":"2020-09-29T19:29:50.000Z","description":"Harvy analyzes the route ahead, the elevation profile, and the difficulty of the path and then queues music to match. By providing seed songs, Harvy uses the Spotify recommendation engine alongside Harvy's difficulty algorithm to create the best experience for runners.","author":"You"}},{"name":"harvy","route":"/harvy","frontMatter":{"title":"Harvy","type":"page","slug":"harvy","date":"2020-09-28T13:14:22.000Z","date_updated":"2020-09-29T19:29:50.000Z","description":"By analyzing the elevation changes along a route to create a difficulty rating for specific segments, Harvy correlates music tempo and beats per minute to this difficulty rating. Have a big hill coming up in the next mile? Harvy picks a song to help you push through.","author":"You"}},{"name":"index","route":"/","frontMatter":{"type":"page","title":"About","date":"2021-03-19T00:00:00.000Z"}},{"name":"posts","children":[{"name":"behat-and-js-go-casperjs","route":"/posts/behat-and-js-go-casperjs","frontMatter":{"title":"Behat and JS? Go CasperJS","slug":"behat-and-js-go-casperjs","date":"2018-01-02T05:00:00.000Z","tag":"tutorials","description":"However the problem is that the ads do not populate on first page load. They have to send a request to get the ads and populate them. So, this means for Behat, it is not waiting for those ads to load","author":"You"}},{"name":"build-your-first-alexa-app","route":"/posts/build-your-first-alexa-app","frontMatter":{"title":"Build Your First Alexa App","slug":"build-your-first-alexa-app","date":"2017-04-03T04:00:00.000Z","date_updated":"2020-09-25T19:48:51.000Z","tags":"tutorials","description":"In today's tutorial we are going to set up a very basic Amazon Alexa Skill that uses Python, specifically a package called Flask-Ask.","feature_image":"/images/5f05c1190149b0eac97e0572_0_-i6SHpZL8cxTO5_Q--1--1.png"}},{"name":"coding-after-hours-episode-1-recap","route":"/posts/coding-after-hours-episode-1-recap","frontMatter":{"title":"Coding After Hours - Episode 1 Recap","slug":"coding-after-hours-episode-1-recap","date":"2021-03-03T20:19:29.000Z","date_updated":"2021-03-03T20:20:01.000Z","tags":"videos","description":"The first installation of Coding After Hours is complete with some mild success. This week we tackled a problem from our friend @thederril to build out a weather app."}},{"name":"coding-mnemonically","route":"/posts/coding-mnemonically","frontMatter":{"title":"Coding Mnemonically","slug":"coding-mnemonically","date":"2018-03-24T04:00:00.000Z","date_updated":"2020-09-25T19:53:57.000Z","tags":"coding","description":"Mnemonic: a device such as a pattern of letters, ideas, or associations that assists in remembering something."}},{"name":"dont-think-design-is-a-priority-look-at-this","route":"/posts/dont-think-design-is-a-priority-look-at-this","frontMatter":{"title":"Don't think design is a priority? Look at this.","slug":"dont-think-design-is-a-priority-look-at-this","date":"2018-09-29T04:00:00.000Z","date_updated":"2020-09-25T20:02:01.000Z","tags":"harvy","description":"Let me preface this by saying I am not a designer, I am a developer at heart. My \"design process\" is usually taking Bootstrap or Foundation and applying it to my latest project to get a pretty basic design.","feature_image":"/images/5f05c487f0081ef56c8ff7a1_rJin049-1.png"}},{"name":"explore-exploit-algorithm-in-decisions-regret","route":"/posts/explore-exploit-algorithm-in-decisions-regret","frontMatter":{"title":"Explore/Exploit Algorithm in Decisions & Regret","slug":"explore-exploit-algorithm-in-decisions-regret","date":"2018-01-09T05:00:00.000Z","date_updated":"2020-09-25T19:49:29.000Z","tags":"productivity","description":"Explore/Exploit: In the explore phase, we gather all the information, and the exploit phase is using that information you have to make the best decision."}},{"name":"fac-si-facis","route":"/posts/fac-si-facis","frontMatter":{"title":"Fac, si facis","slug":"fac-si-facis","date":"2018-03-01T05:00:00.000Z","date_updated":"2020-09-25T17:25:40.000Z","tags":"productivity","description":"What is the difference between working for a company and owning a company with employees? What is the difference between a snowboarding going to the Olympics and an amateur riding in the terrain park?"}},{"name":"find-your-why","route":"/posts/find-your-why","frontMatter":{"title":"Find Your Why","slug":"find-your-why","date":"2018-07-10T04:00:00.000Z","date_updated":"2020-09-25T19:59:51.000Z","tags":"productivity","description":"When you are deep into a workout, whether it is your final half mile of a run, last repetition of your squat, or last minute of your AMRAP, what pushes you to finish? What is it that you dig into to keep you going?"}},{"name":"getting-started-with-mysql","route":"/posts/getting-started-with-mysql","frontMatter":{"title":"Getting started with MySQL","slug":"getting-started-with-mysql","date":"2018-01-16T05:00:00.000Z","date_updated":"2020-09-25T19:51:19.000Z","tags":"tutorials","description":"Want to learn how to use MySQL? This post will share how to get started with the basics!"}},{"name":"have-to-stretch-and-be-smart","route":"/posts/have-to-stretch-and-be-smart","frontMatter":{"title":"How to Stretch and Be SMART","slug":"have-to-stretch-and-be-smart","date":"2018-02-28T05:00:00.000Z","date_updated":"2020-09-29T13:44:30.000Z","tags":"productivity","description":"We've all heard of SMART Goals - Specific Measureable Achievable Realistic and Timeline. I think I recall first hearing about them when I was in school."}},{"name":"how-react-saved-harvy","route":"/posts/how-react-saved-harvy","frontMatter":{"title":"How React Saved Harvy","slug":"how-react-saved-harvy","date":"2018-08-23T20:00:00.000Z","date_updated":"2020-09-28T17:05:57.000Z","tags":"harvy","description":"A couple months ago, Harvy launched to the world after spending a couple weeks as a prototype and a very simple minimal viable product. After the launch, there was a little fanfare with some small bursts in traffic that helped validate the idea enough for me to continue working on development.","feature_image":"/images/5f0726c3d304273233b4a763_5f05c4878bb4b9d8b4526c1a_U3okKSh.png"}},{"name":"index","route":"/posts","frontMatter":{"type":"posts","title":"Posts","date":"2021-03-18T00:00:00.000Z"}},{"name":"launching-harvy-bpm-explorer","route":"/posts/launching-harvy-bpm-explorer","frontMatter":{"title":"Launching Harvy BPM Explorer","slug":"launching-harvy-bpm-explorer","date":"2018-04-02T04:00:00.000Z","date_updated":"2020-09-25T20:04:57.000Z","tags":"harvy"}},{"name":"look-then-leap-rule-explained","route":"/posts/look-then-leap-rule-explained","frontMatter":{"title":"Look-Then-Leap Rule - Explained","slug":"look-then-leap-rule-explained","date":"2018-01-08T05:00:00.000Z","date_updated":"2020-09-25T18:01:30.000Z","tags":"productivity","description":"You set a predetermined amount of time for 'looking' - that is, exploring your options, gathering data - in which you categorically don't choose anyone, no matter how impressive. After that point, you enter the 'leap' phase..."}},{"name":"meet-harvy-beta","route":"/posts/meet-harvy-beta","frontMatter":{"title":"Meet Harvy (Beta)","slug":"meet-harvy-beta","date":"2018-05-01T04:00:00.000Z","date_updated":"2020-09-25T19:55:50.000Z","tags":"harvy","description":"For the past 2 years, I've been struggling with a fairly simple problem..."}},{"name":"migrating-back-to-ghost","route":"/posts/migrating-back-to-ghost","frontMatter":{"title":"Migrating (back to) Ghost","slug":"migrating-back-to-ghost","date":"2020-09-28T17:35:34.000Z","date_updated":"2020-09-28T17:38:20.000Z","description":"At this point, I've lost track of the number of different iterations of my personal websites I've created."}},{"name":"offloading-work-to-spotify","route":"/posts/offloading-work-to-spotify","frontMatter":{"title":"Offloading Work to Spotify","slug":"offloading-work-to-spotify","date":"2018-06-04T04:00:00.000Z","date_updated":"2020-09-25T19:56:39.000Z","tags":"harvy","description":"Hopefully by now you've had the chance to Meet Harvy. In its very starter and simple phase, Harvy uses your songs in your playlists to determine the playlist for you. There are some pros and cons to this approach:","feature_image":"/images/5f072709b853bce18d28fd4c_1b3a5b00-ae72-4ad6-a30a-fd492a2bb9c0.jpeg"}},{"name":"product-hunt-makers-festival-no-code-maker-in-chief","route":"/posts/product-hunt-makers-festival-no-code-maker-in-chief","frontMatter":{"title":"Product Hunt Maker's Festival No-Code Maker in Chief!","slug":"product-hunt-makers-festival-no-code-maker-in-chief","date":"2019-06-06T04:00:00.000Z","date_updated":"2020-09-25T20:02:42.000Z","tags":"coding","description":"The Product Hunt Maker's Festival 2019 No-Code edition was a blast to work on a a great challenge to all makers.","feature_image":"/images/5f0725e3d8a42e41db319cd3_5f05c4c6fd4f252cfd130ca8_Screen-Shot-2019-06-07-at-2.52.06-PM.png"}},{"name":"responsibilities-of-a-software-architect","route":"/posts/responsibilities-of-a-software-architect","frontMatter":{"title":"Responsibilities of a Software Architect","slug":"responsibilities-of-a-software-architect","date":"2018-03-26T04:00:00.000Z","date_updated":"2020-09-25T19:54:22.000Z","description":"Post inspired from: Design It! From Programmer to Software Architect by Michael Keeling."}},{"name":"simple-object-oriented-programming-with-javascript","route":"/posts/simple-object-oriented-programming-with-javascript","frontMatter":{"title":"Simple Object Oriented Programming with Javascript","slug":"simple-object-oriented-programming-with-javascript","date":"2018-07-05T04:00:00.000Z","date_updated":"2020-09-25T19:59:17.000Z","tags":"tutorials","description":"With the introduction of ES6, creating classes in Javascript has improved. Even though the new syntax boils down to the same as it was previously done, coming from other OOP languages makes it easier to understand."}},{"name":"slack-stop-motion","route":"/posts/slack-stop-motion","frontMatter":{"title":"Stop Motion Videos...in Slack? Spice Up Your Profile Picture with Cron Jobs & Github Actions!","slug":"stop-motion-videos-in-slack","date":"2021-03-15T20:30:13.000Z","date_updated":"2021-03-15T20:30:35.000Z","tags":"tutorial","description":"Slack motion videos...in slack? Update your profile throughout the day.","feature_image":"/images/slack-stop-motion-cover.png"}},{"name":"the-myth-of-unlimited-vacation-days","route":"/posts/the-myth-of-unlimited-vacation-days","frontMatter":{"title":"The Myth of Unlimited Vacation Days","slug":"the-myth-of-unlimited-vacation-days","date":"2018-01-19T05:00:00.000Z","date_updated":"2020-09-25T19:52:12.000Z","tags":"productivity","description":"Is that not something all of us want to see when applying for jobs? Unlimited Vacation Days - it sure does sound perfect. But what if I told you that oftentimes that in the companies that implement the unlimited vacation day policy, employees actually take less vacation time."}},{"name":"things-i-wish-i-knew-coding-edition","route":"/posts/things-i-wish-i-knew-coding-edition","frontMatter":{"title":"Things I Wish I Knew (Coding Edition)","slug":"things-i-wish-i-knew-coding-edition","date":"2018-03-20T04:00:00.000Z","date_updated":"2020-09-25T19:53:23.000Z","tags":"productivity","description":"My list of \"things I need to learn\" in the world of programming is growing every day. Most recently, while working on a side project, I have fallen into the hole of poor application architecture and design. Why did this happen?"}},{"name":"twitch-building-a-portfolio-nextjs-mdx","route":"/posts/twitch-building-a-portfolio-nextjs-mdx","frontMatter":{"title":"[Twitch] Building a portfolio with nextjs and mdx","slug":"building-portfolio-nextjs-mdx","date":"2021-03-18T13:06:46.000Z","date_updated":"2021-03-18T13:07:22.000Z","tags":"videos","description":"You may have noticed a new look for my potfolio. Well in this Twitch stream I share my thoughts about the current state, why I decided to change it up, and work in progress along the way"}},{"name":"twitch-implementing-skeleton-loaders-in-react","route":"/posts/twitch-implementing-skeleton-loaders-in-react","frontMatter":{"title":"[Twitch] Implementing Skeleton Loaders 💀 in React","slug":"twitch-implementing-skeleton-loaders-in-react","date":"2021-02-26T13:06:46.000Z","date_updated":"2021-02-26T13:07:22.000Z","tags":"videos","description":"Skeleton loaders have always been a beautiful way to showcase to a user that 'something is happening'. Turns out it isn't as hard to implement as I thought!"}},{"name":"twitch-revisiting-harvy","route":"/posts/twitch-revisiting-harvy","frontMatter":{"title":"[Twitch] Coding After Hours - Let's check in on our running app built with #react","slug":"check-in-on-our-running-app","date":"2021-03-23T13:06:46.000Z","date_updated":"2021-03-23T13:07:22.000Z","tags":"videos","description":"It has been a hot minute since we took a look at Harvy, the running app I built with React and Swift. Let's check it out in this week's installment of Coding After Hours."}},{"name":"understanding-logical-operators-with-non-boolean-objects-in-javascript","route":"/posts/understanding-logical-operators-with-non-boolean-objects-in-javascript","frontMatter":{"title":"Understanding Logical Operators with Non-boolean Objects in Javascript","slug":"understanding-logical-operators-with-non-boolean-objects-in-javascript","date":"2018-06-06T04:00:00.000Z","date_updated":"2020-09-25T19:57:56.000Z","tags":"tutorials","description":"A quick dive into logical operators - they can sometimes be confusing and have some \"gotchas\" in Javascript."}},{"name":"updating-multi-reference-fields-with-zapier-webflow","route":"/posts/updating-multi-reference-fields-with-zapier-webflow","frontMatter":{"title":"Updating Multi-reference Fields with Zapier & Webflow","slug":"updating-multi-reference-fields-with-zapier-webflow","date":"2020-02-20T05:00:00.000Z","date_updated":"2020-09-25T20:04:01.000Z","tags":"tutorials","description":"This past week while integrating Zapier and Webflow, I became surprised to learn that updating reference and multi-reference fields did not work right out of the box."}},{"name":"want-to-learn-how-to-code-start-here","route":"/posts/want-to-learn-how-to-code-start-here","frontMatter":{"title":"Want to Learn How to Code? Start Here","slug":"want-to-learn-how-to-code-start-here","date":"2018-04-21T04:00:00.000Z","date_updated":"2020-09-25T19:55:08.000Z","tags":"tutorials","description":"Well, I am proud to say that I have officially completed the Python for Everybody course this past weekend, and, if you want to learn how to program, I would highly recommend taking this class."}}],"route":"/posts"},{"name":"tags","children":[{"name":"[tag]","route":"/tags/[tag]","frontMatter":{"type":"tag","title":"Tagged Posts"}}],"route":"/tags"},{"name":"what-song-when","route":"/what-song-when","frontMatter":{"title":"What Song When","type":"page","slug":"what-song-when","date":"2021-3-31T13:14:22.000Z","date_updated":"2021-03-31T19:29:50.000Z","author":"You"}}]
    }, layoutConfig))(props)
}