<?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: Azimjon Pulatov</title>
    <description>The latest articles on Forem by Azimjon Pulatov (@azimjohn).</description>
    <link>https://forem.com/azimjohn</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%2F427606%2Fafbff2b3-962f-4379-a7e4-efcac3f08614.jpeg</url>
      <title>Forem: Azimjon Pulatov</title>
      <link>https://forem.com/azimjohn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/azimjohn"/>
    <language>en</language>
    <item>
      <title>How I Built Spotify Alternative for Google Home</title>
      <dc:creator>Azimjon Pulatov</dc:creator>
      <pubDate>Sun, 02 May 2021 12:49:11 +0000</pubDate>
      <link>https://forem.com/azimjohn/how-i-built-spotify-alternative-for-google-home-2ilf</link>
      <guid>https://forem.com/azimjohn/how-i-built-spotify-alternative-for-google-home-2ilf</guid>
      <description>&lt;p&gt;It was Sunday night. Hackathon results were about to be announced and when I heard my team's name, I jumped out of my chair, I was thrilled. To add more excitement, I asked my Google Home to play &lt;em&gt;"We Are The Champions"&lt;/em&gt; and to my surprise, it played totally different song. I could be disappointed but instead, I was inspired to know what I was building next.&lt;/p&gt;

&lt;p&gt;Why did it play a different song? Because choosing songs is only available to Spotify Premium subscribers. Instead of subscribing, I decided to build an alternative myself.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1328395582252183553-70" src="https://platform.twitter.com/embed/Tweet.html?id=1328395582252183553"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1328395582252183553-70');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1328395582252183553&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;From the day I got my Google Home, I was wondering how to program it to do things I want. The first and easiest option was &lt;a href="https://ifttt.com" rel="noopener noreferrer"&gt;IFTTT&lt;/a&gt;. After connecting my Google Account, I was able to make simple applets that allowed to make Google Assistant say things back when certain questions were asked and bind it to actions like making a web request.&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%2F2dqn4fly5bdkldgshuhf.png" 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%2F2dqn4fly5bdkldgshuhf.png" alt="IFTTT Simple Phrase Applet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;IFTTT wasn't quite what I was looking for, because it couldn't perform tasks like playing audio or programmatically generate a response. Then I discovered &lt;a href="http://actions.google.com/" rel="noopener noreferrer"&gt;Google Actions&lt;/a&gt;. When I saw its capabilities, I realized - this is the way. &lt;/p&gt;

&lt;p&gt;The first thing I needed to set up for the application was a webhook. So whenever the application gets invoked, Google Action makes a request to the webhook. One way to provide a publicly available URL for the webhook would be to deploy the application somewhere. Instead, for the development, I used JPRQ, a Ngrok Alternative for exposing a local webserver. You can read about how I built it. &lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/azimjohn" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F427606%2Fafbff2b3-962f-4379-a7e4-efcac3f08614.jpeg" alt="azimjohn"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/azimjohn/how-i-built-ngrok-alternative-3n0g" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How I built Ngrok Alternative&lt;/h2&gt;
      &lt;h3&gt;Azimjon Pulatov ・ Jul 9 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#python&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#go&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#sideprojects&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&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%2Fxa3mfocxvbo7cux61pad.png" 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%2Fxa3mfocxvbo7cux61pad.png" alt="Setting Up WebHook in Google Actions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After setting up the webhook, my local server was receiving anything I say to Google Assistant after the application was invoked. I could easily send a media response - a playable URL, and the assistant would play it. Great!&lt;/p&gt;

&lt;p&gt;The best tutorial I could find on Google Actions is &lt;a href="https://www.youtube.com/watch?v=Z1hxvniJ18s" rel="noopener noreferrer"&gt;Behind the Actions&lt;/a&gt;, it helped me to understand basic building blocks like &lt;em&gt;Scenes, Types, and Intents&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;The next part is searching for songs. I first looked into available APIs provided by Deezer, Sound Cloud, and Apple Music. But none of them provided the full song, only the partial content. Then I decided to write a simple crawler to search songs from z1.fm. I thought about copyright issues, so I decided to keep MusicSpider to myself and not publish it for others.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/6fVuZLaj9WI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Source code for MusicSpider is available on &lt;a href="https://github.com/azimjohn/musicspider" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, both the web application built using Flask and the crawler for searching for songs.&lt;/p&gt;

&lt;p&gt;To share my learnings, I gave a talk about "&lt;em&gt;Programmable Google Assistant&lt;/em&gt;" where I also shared some of my other applications I built for Google Assistant.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/G1EigCSIsIs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Happy building,&lt;/p&gt;

&lt;p&gt;Cheers&lt;/p&gt;

</description>
      <category>python</category>
      <category>node</category>
      <category>webdev</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>How I built Ngrok Alternative</title>
      <dc:creator>Azimjon Pulatov</dc:creator>
      <pubDate>Thu, 09 Jul 2020 23:12:32 +0000</pubDate>
      <link>https://forem.com/azimjohn/how-i-built-ngrok-alternative-3n0g</link>
      <guid>https://forem.com/azimjohn/how-i-built-ngrok-alternative-3n0g</guid>
      <description>&lt;p&gt;&lt;b&gt;Here's a quick intro of what I built&lt;b&gt;&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/BXuB3cK8R0g"&gt;
&lt;/iframe&gt;
&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://ngrok.io" rel="noopener noreferrer"&gt;Ngrok&lt;/a&gt; is a fantastic tool that helps developers to expose their localhost to the Internet with minimal effort. One day I was going to share a local project with a client without deploying it somewhere.  But this time I needed to expose &lt;b&gt;2 ports&lt;/b&gt;: one running frontend and the other backend of the project, I found out that the ngrok's free plan only allows one tunnel at a time. Later that day, I also found out that there's a &lt;b&gt;40-requests/minute limit&lt;/b&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Bam! An idea.&lt;/b&gt;&lt;br&gt;
What if I build an alternative instead of paying $5/mo.? &lt;br&gt;
That's what developers do, right? I also had the idea of making it open-source.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;It's time to plan.&lt;/b&gt;&lt;br&gt;
There are obviously 3 parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a developer with a command-line tool (cli)&lt;/li&gt;
&lt;li&gt;a proxy server&lt;/li&gt;
&lt;li&gt;a client with a browser. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was sure there had to be at least those steps to make it work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a developer connects to the server via a cli with a port number: &lt;code&gt;jprq 8000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the server responds with an assigned domain. &lt;code&gt;amazing-coder.jprq.live&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a client opens the domain in a browser: &lt;code&gt;https://amazing-coder.jprq.live&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the server receives the request and sends it to the cli.&lt;/li&gt;
&lt;li&gt;the cli makes the request to localhost at the given port and sends the response to the server.&lt;/li&gt;
&lt;li&gt;the server responds back to the client with the response it received from the cli.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a chart to help you picture those steps.&lt;br&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%2Fi%2Fldpnnlez5fnv0g4r2ty3.jpg" 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%2Fi%2Fldpnnlez5fnv0g4r2ty3.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The cli and the server needs to make back and forth communication. A carefully managed TCP Sockets would do a great job but would take a long time to implement. &lt;br&gt;
I decided to use and used the WebSocket Protocol. As you might know, WebSocket is a hop-by-hop protocol and sadly, my ngrok alternative now can't support Polling and HTTP streaming (because they never end or last too long).  &lt;/p&gt;

&lt;p&gt;The command-line tool is written in Python and published to PyPy. Currently implementing the command-line in javascript to publish in npm just for fun. And the server-side is in Golang. I think it was the best decision to choose golang because of its easy data sharing between goroutines and learned about leaking goroutines the hard way. I now have a good understanding of memory leaks because of this project.&lt;/p&gt;

&lt;p&gt;Another small but impactful mistake I made during implementing the client-server communication was using JSON. I realized it only after adding a feature for handling files. With JSON one can only serialize strings. To turn file contents, bytes into a string, I needed to Base64 them. It turns out to be CPU intensive process. It's better to use BSON, I believe.&lt;/p&gt;

&lt;p&gt;The project is open-source and waiting for your contribution. Take some time to visit the GitHub repo at &lt;a href="https://github.com/azimjohn/jprq" rel="noopener noreferrer"&gt;github.com/azimjohn/jprq&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keep building,&lt;br&gt;
Cheers.&lt;/p&gt;

</description>
      <category>python</category>
      <category>go</category>
      <category>sideprojects</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
