<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Omar Ahmed</title>
    <description>The latest articles on Forem by Omar Ahmed (@mrgeek).</description>
    <link>https://forem.com/mrgeek</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F107151%2F0b7d642a-17b3-4d07-bb53-194796ac8efa.jpg</url>
      <title>Forem: Omar Ahmed</title>
      <link>https://forem.com/mrgeek</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mrgeek"/>
    <language>en</language>
    <item>
      <title>[Side Project] Post automated Youtube videos from Reddit</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Wed, 05 Oct 2022 18:49:14 +0000</pubDate>
      <link>https://forem.com/mrgeek/side-project-post-automated-youtube-videos-from-reddit-42ga</link>
      <guid>https://forem.com/mrgeek/side-project-post-automated-youtube-videos-from-reddit-42ga</guid>
      <description>&lt;h2&gt;
  
  
  Long introduction
&lt;/h2&gt;

&lt;p&gt;I've always been curious about some videos that I come across on Facebook and YouTube that look a little strange. Like they were just generated by a robot. Think of a video playing with a little box of a guy reacting to it while their reaction is incredibly strange and appears utterly unrelated. They always feature stuff that either doesn't fit the caption or the content itself is unusual.&lt;/p&gt;

&lt;p&gt;I finally understand why. These videos are all automated and performed by scripts. It also appears that "Youtube/Facebook automation" is popular right now.&lt;/p&gt;

&lt;p&gt;I first became curious about "Youtube automation" after running across the word. I didn't know that some people were building scripts to scrape stuff from websites (like Facebook and Reddit, but largely Reddit, to be honest), process it, and then produce a video from it to put online.&lt;/p&gt;

&lt;p&gt;Imagine this thing running, and having a cron-job to run and post a new video every day. Consider your potential earnings and the consistency of this. You simply need to worry about funding your server and maybe improving how the material is processed while being scraped.&lt;/p&gt;

&lt;p&gt;There is a lot to say about this, but I'm here to explain how I used Golang to get several Tiktok videos from a subreddit, combine them, and post a video of the "Top 10 funny/cringiest Tiktok videos" on YouTube without knowing what the video's content was.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR&lt;/p&gt;

&lt;p&gt;Social media is really weird. Authentic content is becoming harder to find, and BTW! I managed to code a Golang script to scrape Tiktok videos from a Subreddit, combine them into a single video, and upload it to Youtube all automatically.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  So how though?
&lt;/h2&gt;

&lt;p&gt;So for starters, the initial idea is to split the big thing into smaller things and blah blah you know the boring engineering stuff. But I seriously wanted to make it to scale. So it made sense to have 3 Golang packages/modules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reddit Aggregator:

&lt;ul&gt;
&lt;li&gt;This would be responsible for scraping a subreddit and extracting Tiktok videos out of it.&lt;/li&gt;
&lt;li&gt;Will save the results into a MongoDB collection - because schema is overrated -&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Video Processor:

&lt;ul&gt;
&lt;li&gt;This would grab unpublished results from MongoDB collection:

&lt;ul&gt;
&lt;li&gt;Downloads all videos on the server&lt;/li&gt;
&lt;li&gt;Process each single video&lt;/li&gt;
&lt;li&gt;Combine all videos into a single video&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Now obviously this seems a bit too much for a single service, but ... meh&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Uploader:

&lt;ul&gt;
&lt;li&gt;This will upload the final video to Youtube&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR&lt;/p&gt;

&lt;p&gt;This is a side project, and I wanted it to be complex enough that Youtube would actually use it. However, spoiler alert: they won't. That is why I divided the code into three Golang packages to run them as microservices serverless functions. Spoiler alert again: they are not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Reddit Aggregator
&lt;/h2&gt;

&lt;p&gt;The aggregator is straightforward; all it does is use the Reddit API to obtain posts from a subreddit and store them in a MongoDB collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://www.reddit.com/r/&amp;lt;SUBREDDIT&amp;gt;/&amp;lt;POSTS_TYPE&amp;gt;.json?limit&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;LIMIT&amp;gt;
https://www.reddit.com/r/linux/hot.json?limit&lt;span class="o"&gt;=&lt;/span&gt;10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now not to keep it too simple, every single thing between &lt;code&gt;&amp;lt; &amp;gt;&lt;/code&gt; is a variable, that can be provided before the run to make it more robust.&lt;/p&gt;

&lt;p&gt;The aggregator will save each post on a DB collection that will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ObjectId(&lt;/span&gt;&lt;span class="s2"&gt;"633c37a1740ff26f2433f99c"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hash"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"78a0428f87a9adf7d692e5435466bc5b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;POST_TITLE&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"video"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;VIDEO_LINK&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ISODate(&lt;/span&gt;&lt;span class="s2"&gt;"2022-10-04T15:39:45.808+02:00"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"updated_at"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ISODate(&lt;/span&gt;&lt;span class="s2"&gt;"2022-10-04T15:39:45.808+02:00"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"published"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What are the &lt;code&gt;hash&lt;/code&gt; and &lt;code&gt;published&lt;/code&gt; fields for you wonder?&lt;/p&gt;

&lt;p&gt;Well, &lt;code&gt;hash&lt;/code&gt; is a simple MD5 hash of the video link, and on DB this field has a unique index so that we're sure that the aggregator never inserts duplicates. While &lt;code&gt;published&lt;/code&gt; is for determining to not return a post/video that was already published to our Youtube channel, this way it will not slip into the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video processor
&lt;/h2&gt;

&lt;p&gt;So, this package will begin by getting a list of unpublished posts from the database, downloading them all to a specific directory, and then starting the processor to process them all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Downloader
&lt;/h3&gt;

&lt;p&gt;Downloader is using &lt;code&gt;youtube-dl&lt;/code&gt; behind the scenes to download every single video, now why not just a simple HTTP GET request and write the file?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;youtube-dl&lt;/code&gt; provide great support for downloading videos, from various sources.&lt;/li&gt;
&lt;li&gt;The goal is to be scalable and to be able to even have multiple aggregators ( facebook aggregator, youtube aggregator, Vimeo... etc )&lt;/li&gt;
&lt;li&gt;I already had a wrapper to run a CLI command safely that I did (&lt;a href="https://github.com/omarahm3/turtle/blob/master/pkg/sniffer/sniff.go#L118"&gt;sniff.go#L118&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Goroutines were required since downloading 10 videos one at a time seemed incredibly slow. I had to run 10 goroutines and wait for them to complete before going on to the next step.&lt;/p&gt;

&lt;p&gt;With Goroutines in place, there comes a challenge, more on that will be on here&lt;/p&gt;

&lt;p&gt;So to download a single video is just that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;ydl_command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"youtube-dl %s -q -o %s.%%(ext)s"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;dest&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"downloads"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cmdString&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ydl_command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmdString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;helpers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunCmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Processor
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ffmpeg is pure evil&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The processor is identical to the downloader; it will run through each video and, given that all Tiktok videos are vertical and have a black background on the left and right sides, its sole function will be to create blurry background for the video.&lt;/p&gt;

&lt;p&gt;So to achieve that goal, you will have to use &lt;code&gt;ffmpeg&lt;/code&gt; which seems more evil than Regex.&lt;/p&gt;

&lt;p&gt;Anyway for processing a single video this is the function to do it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ffmpeg_quality&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1080k"&lt;/span&gt;
    &lt;span class="n"&gt;ffmpeg_command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;`ffmpeg -i %s -lavfi %s -vb %s -c:v libx264 -crf 20 %s.mp4 -n`&lt;/span&gt;
    &lt;span class="n"&gt;ffmpeg_filters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;`[0:v]scale=ih*16/9:-1,boxblur=luma_radius=min(h\,w)/20:luma_power=1:chroma_radius=min(cw\,ch)/20:chroma_power=1[bg];[bg][0:v]overlay=(W-w)/2:(H-h)/2,crop=h=iw*9/16`&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;video&lt;/span&gt; &lt;span class="n"&gt;downloader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;dest&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"blurry"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cmdString&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ffmpeg_command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ffmpeg_filters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ffmpeg_quality&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmdString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;helpers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunCmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"already exists. Exiting"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the record, it took me ~1hr to fix an issue running &lt;code&gt;ffmpeg&lt;/code&gt; command to learn that I had to change this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="s"&gt;`ffmpeg -i %s -lavfi '%s' -vb %s -c:v libx264 -crf 20 %s.mp4 -n`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="s"&gt;`ffmpeg -i %s -lavfi %s -vb %s -c:v libx264 -crf 20 %s.mp4 -n`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now of course since the script will be processing 10 videos, this needs to be done using Goroutines to benefit the concurrency. As with the downloader, this will be later explained in the concurrency challenge section&lt;/p&gt;

&lt;h3&gt;
  
  
  Merger
&lt;/h3&gt;

&lt;p&gt;The merger is the processor's last step, where after adding the blurry background to all of the videos, it will merge them all into a single video. But it does that in steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a text file that has all of the videos paths in this format
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;file /some/path/blurry-file1.mp4
file /some/path/blurry-file2.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Then pass that file to &lt;code&gt;ffmpeg&lt;/code&gt; so that it combines all videos
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-f&lt;/span&gt; concat &lt;span class="nt"&gt;-safe&lt;/span&gt; 0 &lt;span class="nt"&gt;-i&lt;/span&gt; all_videos.txt final.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Then remove the temporary &lt;code&gt;all_videos.txt&lt;/code&gt; file
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;MergeAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;videos&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;ProcessedVideo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;createVideosFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;videos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;runMerge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error running command, output: %q"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Uploader
&lt;/h2&gt;

&lt;p&gt;This is the last piece of the puzzle where the final video gets uploaded to youtube, but to avoid having the same title always, there is an option to have a random title deduced from the posts we already have on the database.&lt;/p&gt;

&lt;p&gt;Since the goal is to be able to publish a video every single day, you can just get all posts of today and get a single random post, and then make it the video's title.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;VideoInfoType&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;VideoTitle&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;VideoDescription&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DatabaseURI&lt;/span&gt;      &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetTitle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VideoInfoType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;VideoTypeManual&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VideoTitle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;VideoTypeRandom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getDbClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FindRandomOfToday&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Top 10 best/cringiest Tiktoks today: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unknown video type %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VideoInfoType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Besides that script of course will need &lt;code&gt;client_credentials&lt;/code&gt; and API token to be able to use youtube API to upload the video.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;upload&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;youtube&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Snippet&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;youtube&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VideoSnippet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;youtube&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VideoStatus&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;PrivacyStatus&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PrivacyStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Videos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"snippet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OutputFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Media&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Concurrency challenge
&lt;/h2&gt;

&lt;p&gt;The main challenge for me was to be able to just concurrently run tasks I want to run, of which i have 2:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Downloading videos&lt;/li&gt;
&lt;li&gt;Processing videos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the most expensive tasks I have in terms of time because if they run one by one it will take so much time obviously.&lt;/p&gt;

&lt;p&gt;So I wanted to have a way of running a tasks pool, where I pass the number of needed threads, and the pool will just split the tasks across these threads. So I ended up implementing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ThreadElement&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Element&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Threadify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numOfThreads&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;ThreadElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;numOfThreads&lt;/span&gt;
    &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numOfThreads&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numOfThreads&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;numOfThreads&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
            &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty basic right? and for sure there is a better way to do it, but hey it actually worked, and now I can download videos by calling it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;videos&lt;/span&gt;   &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Video&lt;/span&gt;
  &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;helpers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThreadElement&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ThreadElement&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Element&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Threadify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"calling download %q"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;downloadedPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error downloading video: %q of this post: %q::: %q&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;command output: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Downloaded video: %q with hash %q on %q&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;downloadedPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;videos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;videos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReplaceAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;downloadedPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"%(ext)s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"mp4"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Videos downloaded"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;videos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I loved how generic this function is, and that is I just can use it for anything I want to concurrently run, and the way you can pass elements to it, by just kind of mapping it into &lt;code&gt;ThreadElement&lt;/code&gt; so that it understands what it will later pass to the callback function.&lt;/p&gt;

&lt;p&gt;But still, that looked hard to maintain, and I asked myself there has to be a better way to do this, just out of curiosity i googled and came across &lt;a href="https://github.com/panjf2000/ants"&gt;ants&lt;/a&gt; which seemed exactly right for this kind of functionality I wanted, so I converted the same function to use ants, and it became this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Threadify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numOfThreads&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;ThreadElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}))&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewPoolWithFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numOfThreads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it even looks cleaner, and I just don't care anymore about how it works as long as it works, and the most beautiful thing is that the function signature is still the same, which means I could still use it in the same way I did and have it generic just as I wanted initially.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons learned
&lt;/h2&gt;

&lt;p&gt;Finally now after the project is complete, here are the top lessons I learned from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I shouldn't be surprised to know about "Youtube automation", literally everything is possible nowadays.&lt;/li&gt;
&lt;li&gt;Golang is just super easy, Goroutines are easy when you just think of them logically, but also they're easy to produce bugs.&lt;/li&gt;
&lt;li&gt;Don't use any &lt;code&gt;dotenv&lt;/code&gt; package in Golang, IDK why I did!! it just makes no sense at least in this kind of project.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;I got the idea from this &lt;a href="https://www.reddit.com/r/linux/comments/l5awi1/automating_an_entire_youtube_channel_with/"&gt;Reddit post&lt;/a&gt; huge kudos to the OP, he made it simply in bash, but I just had to be a nerd to do it in Golang :/&lt;/p&gt;

&lt;p&gt;There is huge room for improvement indeed, but I'm happy with the results, mission is achieved now to the new side project.&lt;/p&gt;

</description>
      <category>go</category>
      <category>showdev</category>
      <category>productivity</category>
      <category>performance</category>
    </item>
    <item>
      <title>MongoDB aggregations are easy</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Sun, 01 Aug 2021 06:01:15 +0000</pubDate>
      <link>https://forem.com/mrgeek/mongodb-aggregations-are-easy-1coo</link>
      <guid>https://forem.com/mrgeek/mongodb-aggregations-are-easy-1coo</guid>
      <description>&lt;p&gt;Building aggregation pipelines sometimes just seems so hard, especially when you're working with NoSQL database such as MongoDB, since there is no defined schema, and there are just so many nested fields&lt;/p&gt;

&lt;p&gt;Well in this article i'm not going to go deep into what aggregation query is, since i think  &lt;a href="https://docs.mongodb.com/manual/core/aggregation-pipeline/" rel="noopener noreferrer"&gt;MongoDB Docs&lt;/a&gt;  explained this perfectly, but instead i will go through a kind of seeming-complex aggregation query, which is you probably going to face if you're currently with MongoDB and i will use this example here to just show you how aggregation pipelines are just logically easy, and it's always depends on how you think while building it&lt;/p&gt;

&lt;h2&gt;
  
  
  The example
&lt;/h2&gt;

&lt;p&gt;Well for the sake of our example, let's consider that you have this silly &lt;code&gt;products&lt;/code&gt; collection which has these 2 documents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "_id": {
    "$oid": "55c30ff62cfa09af198b465a"
  },
  "name": "Awesome Tshirt",
  "currency": "usd",
  "one_size": "xl",
  "variants": [
    {
      "type": "color",
      "base_sku": 132145,
      "items": [
        {
          "color": "Grey Melange",
          "price": 80,
          "sku": 1243252369
        },
        {
          "color": "Bottle Green",
          "price": 90,
          "sku": 1243252368
        },
        {
          "color": "Deep Charcoal Grey",
          "price": 80,
          "sku": 1243252376
        },
        {
          "color": "White",
          "price": 80,
          "sku": 1243252363
        },
        {
          "color": "Black",
          "price": 80,
          "sku": 1243252362
        }
      ]
    }
  ]
},
{
  "_id": {
    "$oid": "55c30ff62cfa09af198b465c"
  },
  "name": "Hacker Tshirt",
  "currency": "usd",
  "one_size": false,
  "variants": [
    {
      "type": "color",
      "base_sku": 132155,
      "items": [
        {
          "color": "Black",
          "price": 100,
          "sku": 87987963
        }
      ]
    },
    {
      "type": "size",
      "base_sku": 342434,
      "items": [
        {
          "size": "sm",
          "price": 100,
          "sku": 97896796
        },
        {
          "size": "xl",
          "price": 100,
          "sku": 43534534
        },
        {
          "size": "xxl",
          "price": 100,
          "sku": 76576532
        }
      ]
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and now our goal is to get the price of all grey T-shirts, so since as you can see that each product has it's price vary based on the variant itself, so we have to get both from variants items &lt;code&gt;item&lt;/code&gt; object. Yes in this collection its so silly that somehow you have to choose of either having black T-shirt or XXl tshirt, but not both :D&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage #1
&lt;/h2&gt;

&lt;p&gt;The very first step when you create a pipeline is to always &lt;code&gt;match&lt;/code&gt; your query, this to narrow down querying the whole collection to just a limited number of documents that match your criteria&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You always want to narrow down the number of documents you're searching within at the very beginning of the aggregation pipeline, this will lead to faster queries&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So let's do this, first we want to use only the documents that has &lt;code&gt;color&lt;/code&gt; variant, and it has also grey color inside it's variant items. So this is how we're translating this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    {
        '$match': {
            'variants': {
                '$elemMatch': {
                    'type': 'color', 
                    'items': {
                        '$elemMatch': {
                            'color': /grey/i
                        }
                    }
                }
            }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://docs.mongodb.com/manual/reference/operator/query/elemMatch/" rel="noopener noreferrer"&gt;$elemMatch&lt;/a&gt; operator matches documents that contain an array field with at least one element that matches all the specified query criteria.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We're using $elemMatch here to find a variant of &lt;code&gt;type&lt;/code&gt; &lt;strong&gt;color&lt;/strong&gt; first, and then we're using it again to find an element of color that contains &lt;strong&gt;grey&lt;/strong&gt; and its case insensitive - notice the regex &lt;code&gt;/grey/i&lt;/code&gt; - &lt;/p&gt;

&lt;p&gt;So this was our first step, notice that only 1 item will be returned in this case that has ID &lt;code&gt;55c30ff62cfa09af198b465a&lt;/code&gt;, since it is the only one with variants of type color that has grey color&lt;/p&gt;

&lt;p&gt;Document &lt;code&gt;55c30ff62cfa09af198b465c&lt;/code&gt; it has variants of type color, but it has only black color&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage #2
&lt;/h2&gt;

&lt;p&gt;Now we still need to query a nested object that is inside variants &lt;em&gt;(array)&lt;/em&gt; and also inside items &lt;em&gt;(array)&lt;/em&gt;, so its more like this &lt;code&gt;variants -&amp;gt; items -&amp;gt; {color, price}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This seems complicated, and since we're dealing with array of objects here, what could make it easier? .. to just deal with this array as an object instead, so we can just leverage the dot notation syntax in Mongo&lt;/p&gt;

&lt;p&gt;Well we can do that by just unwinding the array! simple as that, just flatten this array into objects by using &lt;code&gt;$unwind&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/" rel="noopener noreferrer"&gt;$unwind&lt;/a&gt; Deconstructs an array field from the input documents to output a document for each element&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;$unwind is so simple that the only required parameter to pass is &lt;code&gt;path&lt;/code&gt; which is the path of the array you want to flatten&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  {
    '$unwind': {
      'path': '$variants'
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the dollar sign before &lt;code&gt;variants&lt;/code&gt;, we have to prefix the field name with it so Mongo can interpret it, it just tells Mongo to inject the actual value of &lt;code&gt;variants&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now by then we will have also 1 document still, since &lt;code&gt;variants&lt;/code&gt; array has only 1 element&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsi9okmw3je79gsi6f0z.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsi9okmw3je79gsi6f0z.jpeg" alt="Stage #2 output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that &lt;code&gt;variants&lt;/code&gt; is now object instead of array&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage #3
&lt;/h2&gt;

&lt;p&gt;Now what? we still need to query &lt;code&gt;variants.items&lt;/code&gt; elements which is the same case as variants before we unwind it. So i guess we will have to flatten &lt;code&gt;variants.items&lt;/code&gt; too, so next stage will be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  {
    '$unwind': {
      'path': '$variants.items'
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice now that we can easily access &lt;code&gt;items&lt;/code&gt; with dot notation, since &lt;code&gt;variants&lt;/code&gt; is an object and not an array anymore, now these are the the new documents returned after this stage&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0o7lngz0t9p7plbeg55c.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0o7lngz0t9p7plbeg55c.jpeg" alt="Stage #3 output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;items&lt;/code&gt; is an object now with 1 document per &lt;code&gt;items&lt;/code&gt; element which is exactly what we need, but did you notice something strange?&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage #4
&lt;/h2&gt;

&lt;p&gt;Now we have documents with &lt;code&gt;items.color&lt;/code&gt; value that does not contains &lt;code&gt;grey&lt;/code&gt; we have Black, White, and Bottle Green as well, why is that?&lt;/p&gt;

&lt;p&gt;Well that would be because our first &lt;code&gt;$match&lt;/code&gt; stage was  only getting the documents that have items with grey color, having this does not necessary means that it will magically just filter other colors from &lt;code&gt;items&lt;/code&gt;, this our job to do now&lt;/p&gt;

&lt;p&gt;So now we will need to get only the documents that has &lt;code&gt;variants.items.color&lt;/code&gt; with greyish color, looks like another &lt;code&gt;$match&lt;/code&gt; query, right?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  {
    '$match': {
    'variants.type': 'color', 
    'variants.items.color': /grey/i
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is so simple now, here we're just saying, out of the result of stage 3 we just want the documents which has variants of type &lt;code&gt;color&lt;/code&gt; and any item that has &lt;code&gt;grey&lt;/code&gt; with case insensitive, that will return us these documents:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbbf1xrqfihu8f1ic5vxv.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbbf1xrqfihu8f1ic5vxv.jpeg" alt="Stage #4 output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage #5
&lt;/h2&gt;

&lt;p&gt;Now we have the documents, but we don't really care about all of these properties right? We only care about the color and the price&lt;/p&gt;

&lt;p&gt;So since we're having a couple levels of nesting here &lt;code&gt;variants -&amp;gt; items&lt;/code&gt; and we only care about &lt;code&gt;price&lt;/code&gt; and &lt;code&gt;color&lt;/code&gt; properties, then we need to focus/project these properties only and ignore any other stuff we don't need&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://docs.mongodb.com/manual/reference/operator/aggregation/project/" rel="noopener noreferrer"&gt;$project&lt;/a&gt; Passes along the documents with the requested fields to the next stage in the pipeline.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;$project is so simple also, you'll probably just need to know that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It takes field name as a key and 1 or 0 as value (1 to show, 0 to hide)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_id&lt;/code&gt; is shown by default, unless you specify to hide it&lt;/li&gt;
&lt;li&gt;You have to specify at least 1 output field&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So our stage implementation will be simple as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  {
    '_id': 0,
    'color': '$variants.items.color',
    'price': '$variants.items.price'
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we passed &lt;code&gt;'_id': 0&lt;/code&gt; because we don't really care about the document ID - at least not in this example, normally you'll need it though - so we just hid it&lt;/p&gt;

&lt;p&gt;So now this will be the final result&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eb5jdo9bae39xaio4xg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eb5jdo9bae39xaio4xg.jpeg" alt="Stage #5 output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The aggregation query
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.getCollection('products').aggregate([
  {
    '$match': {
      'variants': {
        '$elemMatch': {
          'type': 'color', 
          'items': {
            '$elemMatch': {
              'color': new RegExp('grey', 'i')
            }
          }
        }
      }
    }
  },
  {
    '$unwind': {
      'path': '$variants'
    }
  },
  {
    '$unwind': {
      'path': '$variants.items'
    }
  },
  {
    '$match': {
      'variants.type': 'color', 
      'variants.items.color': new RegExp('grey', 'i')
    }
  },
  {
    $project:  {
      '_id': 0,
      'color': '$variants.items.color',
      'price': '$variants.items.price'
    }
  }
])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;As you can see it's pretty straight forward, and it's quite easy and seems quite logical too, building aggregation pipelines stages is just like actually talking to rubber duck while coding, instead this time you're just talking to Mongo shell &lt;/p&gt;

&lt;p&gt;This post was originally published on my blog &lt;a href="https://blog.mrg.sh/mongodb-aggregations-are-easy" rel="noopener noreferrer"&gt;blog.mrg.sh&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>node</category>
      <category>javascript</category>
      <category>database</category>
    </item>
    <item>
      <title>I Don’t Know!</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Wed, 28 Jul 2021 23:56:13 +0000</pubDate>
      <link>https://forem.com/mrgeek/i-don-t-know-2mb2</link>
      <guid>https://forem.com/mrgeek/i-don-t-know-2mb2</guid>
      <description>&lt;p&gt;Just finished my working day and wow today was just filled up that it made me wonder, how long I’m gonna last working like this, and most importantly, do I even want this to end? Or do I like it? I don’t know.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Meetings are indeed time-consuming but only if they were with the wrong people, or if they were just useless, thank god that is not my case.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The day started with an ~1hr long meeting, discussing some challenges that are facing us related to our upcoming features, and oh these challenges are indeed complex and a brand new type for me probably I can write about them whenever I get the chance.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Having challenges are quite good training and experience booster, but do you like having constant challenges? Do I like that?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then my day went on to exploring some emails, checking snd reviewing some PRs, till I was interrupted with some issue, that I kinda didn’t have the time to check it and it was quite important. I checked the card, did some quick investigation (~1hr) and hey, it was not replicating! Smooth eh? Typical bug, the support team will say it exists but you can’t replicate it, no surprise there.&lt;/p&gt;

&lt;p&gt;I checked again, went deep this time by checking some corner cases, read the code again tried to be at least sure before pulling out my big gun, but it was in vain. So I had to do it... I called one of our support guys, the one reported it, we hoped in a meeting, that lasted for ~1hr and we come up with this besides exchanging some laughs&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Issue is not an issue, and it was something wrong with the client configuration.&lt;/li&gt;
&lt;li&gt;There is another different type of issue happening (nice trade eh?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;so that was it, now I had to eat something and get some fresh air, but oh wait... it’s hot outside, so just eat something while watching some YouTube videos.&lt;/p&gt;

&lt;p&gt;I finished and went back to a task that I planned on doing, we have an issue and we need to check for a memory leak. So ideas were thrown at my first meeting to try flame graphs, and heap dumps, so here I go trying.&lt;/p&gt;

&lt;p&gt;I tried to use &lt;code&gt;perf&lt;/code&gt; command to monitor a Nodejs running server, got nothing, just weird ASCII characters on the output, tried parsing them, but it just didn’t look right, so now I just have to try heap… oh message from DevOps what they want? They’re asking about something related to the database, I have to give them a query now, and it’s a kinda complex one. Okay, let’s first start the Vagrant machine, hop into Robo3t to access my local database, and start building a 5 stages aggregation pipeline to return a field value from a nested array of objects.&lt;/p&gt;

&lt;p&gt;Now where we’re we? Oh, heap dump, yeah let’s try to use &lt;code&gt;heapdump&lt;/code&gt; package to generate a heap dump for my running Nodejs server, as usual pasting some code from the documentation, tweaking it a bit, and now .. a message from scrum master? I need to review these 2 PRs ASAP that belong to another team but they’re touching our team functionality so we can do the release. Ding it, I didn’t notice these PRs so I gotta check them.&lt;/p&gt;

&lt;p&gt;Now, what is this variable for? Let me open the repository, look for it, I get it now.. wait.. no I  let’s understand the code, oh what’s that? Let me call the developer he knows better, I message him we hop into a meeting and he explains the issue perfectly and we find that this code has a problem and it wouldn’t properly work with a specific corner case. Okay great now I just jest changes on the PR, type a comment summarizing our meeting discussion, and back to where I was.&lt;/p&gt;

&lt;p&gt;Now what? Where? Oh, heap dump I left the server running, so I just have to hit a specific endpoint and the heap snapshot will be written to the disk for me to analyze it, let’s do that. Endpoint called, no errors, but the server is restarting … hmmm is this expected? Does this package somehow affect the runtime? IDK but hey doesn’t matter now, let me just see the heap dump.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat ./heaptest.heapsnapshot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s empty! Hmm weird, let me do it again. After 4 times repeating the file is still empty now I’m pissed off it should work, right? Okay, let just google that, I found tutorials, articles, and StackOverflow questions but they’re all the same, maybe I’m missing something.&lt;/p&gt;

&lt;p&gt;In the meanwhile, I’m replying to messages and answering questions, but what got me mentally blocked is another PR, but this time a comment I made a while ago and the developer is asking about it. The comment was about some clean code stuff and how it’s better not to pollute a function with custom conditions and instead think of another way of doing it. We discussed and he suggested a perfect approach, so now it was time to continue.&lt;/p&gt;

&lt;p&gt;But I lost it already, I’m not as focused as before, so I just did a couple of other tries, and called it day at 6 pm already.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now what?
&lt;/h2&gt;

&lt;p&gt;This was indeed a busy day, but I’m kinda used to it by now, but Is this okay? I do let know.&lt;/p&gt;

&lt;p&gt;This is definitely not bad to make you practice multitasking and make you available at all times, but it comes with a cost on your concentration. I’m not here to propose a solution though, I’m just here to share and for the hope that I will find the solution by just writing this kind of a daily routine.&lt;/p&gt;

&lt;p&gt;Do I like being busy? Yeah, it makes my mind spin and thinks, and mostly shifting from thinking on a certain problem to another one, helps me find a solution for the first problem. I got a weird mind IKR?&lt;/p&gt;

&lt;p&gt;This article was originally published to my blog &lt;a href="https://blog.mrg.sh/i-dont-know"&gt;blog.mrg.sh&lt;/a&gt;&lt;/p&gt;

</description>
      <category>writing</category>
      <category>codereview</category>
      <category>computerscience</category>
      <category>mentalhealth</category>
    </item>
    <item>
      <title>Why you should start your wargames journey?</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Wed, 28 Jul 2021 15:30:14 +0000</pubDate>
      <link>https://forem.com/mrgeek/why-you-should-start-your-wargames-journey-3ai8</link>
      <guid>https://forem.com/mrgeek/why-you-should-start-your-wargames-journey-3ai8</guid>
      <description>&lt;p&gt;Lately i been exploring some hacking and offensive security content, so basically it involved me just turning off my room lights, me wearing a hacker hoodie, and watching &lt;br&gt;
 &lt;a href="https://www.youtube.com/c/JohnHammond010"&gt;John Hammond videos&lt;/a&gt;  and nodding my head, gasping and a little bit actually trying to mimic what he does on my machine&lt;/p&gt;

&lt;p&gt;So wargames bandit was something that John Hammond actually recommended to get familiar with Linux for anyone that wanted to start hacking and become a hacker. I thought oh what is this wargames and started googling&lt;/p&gt;

&lt;p&gt;I found it,  &lt;a href="https://overthewire.org/wargames/bandit/"&gt;wargames bandit&lt;/a&gt; and i read it and thought, well this is going to be easy, i know Linux i been working on it for about 6 years now, managing and deploying servers and use it everyday since then for my daily life, i even play games on it for god sake&lt;/p&gt;

&lt;h2&gt;
  
  
  What is wargames bandit?
&lt;/h2&gt;

&lt;p&gt;Well this game is simple, its consists of levels, you start at level 0 and make your way through by finishing the level, basically finishing a level means that you get the password for the next level, and so on&lt;/p&gt;

&lt;p&gt;Bandit is made for absolute wargames beginners and it aims to get players familiar with Linux and the wargames style&lt;/p&gt;

&lt;h2&gt;
  
  
  Why wargames?
&lt;/h2&gt;

&lt;p&gt;Well first because it's fun, and i mean it, it is actually fun, and no matter how you're using Linux, mostly you'll learn a lot by playing it&lt;/p&gt;

&lt;p&gt;You will know more about some commands that you might be using everyday like &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;ssh&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, or &lt;code&gt;find&lt;/code&gt;. And even new commands (at least for me) like &lt;code&gt;strings&lt;/code&gt;, &lt;code&gt;uniq&lt;/code&gt;, &lt;code&gt;bzip2&lt;/code&gt;, &lt;code&gt;s_client&lt;/code&gt;, and &lt;code&gt;xxd&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You will write a simple bash scripts, which is super fun especially if you're like me, someone that loves to automate some tedious work by writing scripts&lt;/p&gt;

&lt;p&gt;You will understand some Unix concepts and even interact with text editors like &lt;code&gt;vi&lt;/code&gt; for example, and even know how to deal with different shells&lt;/p&gt;

&lt;p&gt;Also you will interact with git and running some git commands so you can look for some secret credentials in git branches, commits, or tags&lt;/p&gt;

&lt;p&gt;And of course you will know some hacking concepts, and how to protect your server by avoiding some silly mistakes, that we all may be doing&lt;/p&gt;

&lt;p&gt;As a developer you'll find this also important, especially if you're interacting with servers on any environment, you'll learn essential security concepts and it will open your eyes to a whole new world&lt;/p&gt;

&lt;h2&gt;
  
  
  The gist
&lt;/h2&gt;

&lt;p&gt;You should  &lt;a href="https://overthewire.org/wargames/bandit/"&gt;give a try&lt;/a&gt; , i started it on a weekend and i found myself finishing the 33 levels in 1 day that's how entertaining this is, and i will probably check other  &lt;a href="https://overthewire.org/wargames/"&gt;wargame&lt;/a&gt;  as well maybe natas? who knows!&lt;/p&gt;

&lt;p&gt;This article was originally published on my personal blog &lt;a href="https://blog.mrg.sh/why-you-should-start-your-wargames-journey"&gt;blog.mrg.sh&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hacking</category>
      <category>bash</category>
      <category>linux</category>
      <category>security</category>
    </item>
    <item>
      <title>Introducing and installing API Platform on your machine</title>
      <dc:creator>Omar Ahmed</dc:creator>
      <pubDate>Wed, 10 Oct 2018 14:16:18 +0000</pubDate>
      <link>https://forem.com/mrgeek/introducing-and-installing-api-platform-on-your-machine-1i3k</link>
      <guid>https://forem.com/mrgeek/introducing-and-installing-api-platform-on-your-machine-1i3k</guid>
      <description>&lt;p&gt;I’m a full stack web developer, who takes API seriously. Its been 2 years now and i’m still doing the same steps to create every API i implemented, sure i was automating some stuff using some frameworks who makes things easy, organised and simple starting with &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt; and &lt;a href="https://sailsjs.com/" rel="noopener noreferrer"&gt;Sails&lt;/a&gt;, to using &lt;a href="https://symfony.com/" rel="noopener noreferrer"&gt;Symfony&lt;/a&gt; and finally &lt;a href="https://api-platform.com/" rel="noopener noreferrer"&gt;API Platform&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Two months ago -give or take I’ve a bad memory- I was thinking that i hope one day i’ll automate the API design and implementation to be much faster, maybe running a couple of PHP commands to create a whole entities with its relationships and API routes, and expose them, with a well auto-generated docs for entities based on annotations -maybe- .. well that till a friend of mine told me about this awesome framework which he stumbled upon and “we need to check it out, this 100% gonna be awesome” — he said. And he was right, they did the same thing i wanted to do AND MORE.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fs5ku4wmmm336gcg29p5x.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fs5ku4wmmm336gcg29p5x.gif" alt="pffff"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;pffff!&lt;/center&gt;

&lt;p&gt;Enough nonsense, i’m not a good writer anyway. Lets get into installation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;First of all you need to have docker &amp;amp; &lt;a href="https://docs.docker.com/compose" rel="noopener noreferrer"&gt;docker-compose&lt;/a&gt; installed on your machine you, you can install it by following the official docker documentation &lt;a href="https://docs.docker.com/install" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;You need to clone API Platform repo, by running this command &lt;code&gt;git clone git@github.com:api-platform/api-platform.git&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then while you’re standing on the main root of the repo. run the following command to actually run the platform containers &lt;code&gt;docker-compose up -d&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If you’ve ran into this error or similar&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;code&gt;ERROR: for client Cannot start service client: driver failed programming external connectivity on endpoint api-platform_client_1 (7d82cb397e0a882f7474f227541ca43eb804316ece68c8a7dc5ac9af91972202): Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;that actually self explanatory it means that port 80 is in use in your current OS, so check which service is using it and kill it or better change its port. In my case this service was apache so a simple sudo service apache2 stop was enough to do the trick.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Everything should be working now, &lt;code&gt;docker-compose up -d&lt;/code&gt; should be full with green done statements indicating everything is working. You should be able to head to &lt;code&gt;http://localhost&lt;/code&gt; first then navigating to &lt;code&gt;https://localhost&lt;/code&gt; and see the cool API Platform PWA client.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fz5wcl64ea1fnbujt5iu5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fz5wcl64ea1fnbujt5iu5.gif" alt="pffff"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;But what if its not!&lt;/strong&gt;&lt;br&gt;
You may run into this &lt;a href="https://github.com/api-platform/api-platform/issues/730" rel="noopener noreferrer"&gt;issue here&lt;/a&gt;, Its okay i ran into it and &lt;a href="https://github.com/api-platform/api-platform/issues/730#issuecomment-399941316" rel="noopener noreferrer"&gt;jcarrier-vp solution&lt;/a&gt; did it for me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You’re now ready to create your API and consider following &lt;a href="https://api-platform.com/docs/distribution" rel="noopener noreferrer"&gt;API Platform awesome documentation&lt;/a&gt; its really helpful and they have a cool walk through that will help you get to know it more.&lt;/p&gt;

</description>
      <category>node</category>
      <category>php</category>
      <category>react</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
