Convert MP3 to m3u8 for streaming

Check the video resolution

ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 video1.mp4

CONVERT TO M3u8

ffmpeg -i video1.mp4 -profile:v baseline -level 3.0 -s 712x480 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls index.m3u84

STREAM WITH jwplayer

<div id="player">Loading the player...</div>
<script>
// Setup the player
const player = jwplayer('player').setup({
  file: 'HLS/test/index.m3u8',
  image: 'HLS/test/index.png'
});

// Call the API
const bumpIt = () => {
  const vol = player.getVolume();
  player.setVolume(vol + 10);
}
bumpIt();
</script>

5 JavaScript features to know

JavaScript brings tons of new features and it is hard to track of everything. I would like to share 5 features that incredibly useful.

1. Nullish Coalescing : Check undefined or null using ??

function calculatePrice(price, taxes, description) {
  taxes = taxes ?? 0.05
  description = description ?? "Default item"
  const total = price * (1 + taxes)
  console.log(`${description} with tax: CAD${total}`)
}



calculatePrice(100, 0.05, "First item") /* First item with tax: CAD105 */
calculatePrice(100, 0, "Second item") /* Second item with tax CAD100 */
calculatePrice(100, undefined, undefined)/* Default item with tax CAD105 */

2. Styling Console Log: add styles using %c

console.log(`%c${description} with tax: %cCAD${total}`, "font-weight: bold; color: green;", "color: red")

3. Optional Chaining: using ?

class Person {
  contructor(name, address, hobbies) {
    this.name = name
    this.address = address
    this.hobbies = hobbies

  }

  print() {
    console.log(this)
  }
}


function printPersonStreet(person) {
  /* check whether person is defined, then person.address is defined and person.address.street is defined */
  console.log(person?.address?.street)
}

const sugith = new Person("Sugith", {street: "1234 Edmonton St", city: "Edmonton"}, ["Cricket", "Badminton"])

sugith.print?.() /* print function will execute if it is available */

console.log(sugith.hobbies?.[0]) /*this will console log only if there is a hobbies array and the array has values*/

console.log(sugith.hobbies?.[0].toLowerCase())

printPersonStreet(sugith)

4. Object Shorthand: If you want to use the same key as the value variable.

const name = "Sugith"
const favouriteFood = "Rice"

const sugith = {
  name, favouriteFood
}

console.log(sugith)

5. Defer/Async Loading: add defer to your script tag and you can place it in the head instead of the end of the body

<script src="script.js" defer></script>
This will run the script after the page renders

Laravel 8 with auth

laravel new laravel-vue

cd laravel-vue

--update the .env file with the database connection info 
-- update below settings to make sure the session is saving on a database.

CACHE_DRIVER=database
SESSION_DRIVER=database

php artisan migrate

composer require laravel/breeze --dev

php artisan breeze:install

npm install

npm run dev

php artisan session:table

php artisan cache:table 

php artisan migrate

php artisan serve






TURN ON debugger bar

composer require barryvdh/laravel-debugbar --dev


.env file

APP_DEBUG=true




php artisan make:model Company -m

Nodejs deployment with PM2, NGINX and Let’s Encrypt

Install pm2

npm install -g pm2
#start the service with pm2
pm2 start [FILE_NAME]
#check the status 
pm2 status
#restart the service using pm2
pm2 restart [FILE_NAME]
#check your logs
pm2 logs
#flush/clear the logs
pm2 flush
#start the app when the server restarts
pm2 startup ubuntu

Before using NGINX

Turn on the firewall

:~# ufw status
Status inactive

#enable the firewall
ufw enable
ufw allow ssh

#Every port will be closed now. Because we activated the firewall
#We are going to turn on port 80 and 443

ufw allow http
ufw allow https

#Check the firewall status
ufw status

#WE COMPLETED THE BASIC FIREWALL
#Setup NGINX

#install NGINX
sudo apt install nginx

#configure
sudo nano /etc/nginx/sites-availble/default

Add the following to the location part of the server block

server_name yourdomain.com www.yourdomain.com;

location / {
  proxy_pass http://localhost:5000;
  proxy_http_version 1.1;
  proxy_set_header Upgrade #http_upgrade;
  proxy_set_header Connection 'upgrade';
  proxy_set_header Host $host;
  proxy_cache_bypass $http_upgrade;
}

#Check NGINX config
sudo nginx -t

# Restart NGINX
sudo service nginx restart

Add domain in Digital Ocean

In digital ocean, go to networking and add a domain

Add an A record for @ and for www your droplet

Register and/or setup domain from registrar

Go to your preferred domain registrar

Choose “custom namservers” and add these 3

ns1.digitalocean.com
ns2.digitalocean.com
ns3.digitalocean.com

Add SSL with LetsEncrypt

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

#Only valid for 90 days, test the renewal process with
certbot renew --dry-run

#Renew automatically- LetsEncrypt recommends that subscribers renew every sixty days.

#Add line into crontab -e
@monthly certbot renew

.Net Core MVC identity with PostgresSQL

Create the MVC project with authentication using visual studio.

Install these two libraries using NuGet

  • Npgsql.EntityFrameworkCore.PostgreSQL
  • Npgsql.EntityFrameworkCore.PostgreSQL.Design

Change the Providers in Startup.cs file

options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));

Change the connection string in appsettings.json

"DefaultConnection":"Server=localhost;Port=5432;Database=example;Username=postgres;Password=postgres;Pooling=true"

Run DB Migration

PM>Update-Database

When trying to run the migration, cause you an error like

System.NullReferenceException: Object reference not set to an instance of an object. System.InvalidOperationException: No mapping to a relational type can be found for property ‘Microsoft.AspNetCore.Identity.IdentityUser.TwoFactorEnabled’ with the CLR type ‘bool’.

Delete the entire migration directory & regenerate a new initial migration

PM>Add-Migration Initial

This will create the migration table in your database. Then run

PM>Update-Database

Learn Docker in 7 easy steps

Three things you need to know

  • Dockerfile – Blueprint for building a docker image
  • Image – Template for running docker container
  • Container – Running process
  • Kubernetes & Swarm can scale containers to the infinite workload.

If you are on Mac or Windows, download the Docker Desktop. Once you install, then you should get access to the docker from the command line.

First Command you should memorize : gives you all the containers running on your system.

  • docker ps

Install docker extension for VSCode.: gives you the language support.

The Dockerfile

Dockerfile:

Dockerfile

FROM node:12

WORKDIR /app

COPY package*.json

RUN npm install

COPY . . 

ENV PORT=8080

EXPOSE 8080

CMD ["npm", "start"]
.dockerignore

node_modules

The Image

How do we build the docker image

Go to your project and execute it. -t to tag the project with a useful name. Build a username on Docker Hub. Use that username followed by whatever you want to call this image. You can add a version number separated by a colon. Then add the path to your docker file

docker build -t sugith/demoapp:1.0 .

After it finishes, will give you a message “Successfully build [imageid]”

You can use this image as a base image to create other images or can use to run containers.

In real life to use this image, push the image to a container registry somewhere : dockerhub or your favourite cloud provider. The command you use to do that

docker push

Developer from somewhere can use docker pull to pull that image back down.

docker pull

The container

You can use the image id or the tag name

docker run b909406d737x

port forwarding to our local machine

docker run -p 5000:8080 b909406d737x

Go to localhost:5000 to see your app.

Docker container can still be running even after you close your terminal window. Go to the docker dashboard and stop the container.

When you stop the container any state or the data you created inside of it will be lost. But there can be a situation where you want to share data across between multiple containers. The preferred way to do this is with volumes.

Volumes

Volume; is a dedicated folder on the host machine. A container can create files that can remounted in to future containers or multiple containers at the same time.

docker volume create shared-stuff
docker run \
> --mount source=shared-stuff,target=/stuff

The files will stick around even after all the containers are shut down.

Debugging

Docker desktop can be handy in this situation

Click on the running containers, you can see all the logs and search through them. You can do this with the commandline with

docker exact

It will take you the root of the file system of the container. To keep your containers healthy, always write simple maintainable microservices

TIP

  • Keep 1 process per container

For multiple processes use multiple containers. Docker has a tool called docker-compose for that. It runs multiple Docker containers at the same time.

docker-compose

docker-compose.yml

version: '3'
services:
  web:
    build: .
    ports:
      - "8080:8080"
  db: 
    image: "mysql"
    environment:
      MYSQL_ROOT_PASSWORD: password
    volumes:
      - db-data:/foo

volumes:
  db-data:
docker-compose up

Find this file and run all the containers together. To shutdown the containers

docker-compose down

Go Lang

Install on Ubuntu

  • Download go .tar.gz file
tar -xvf go1.14.6.linux-amd64.tar.gz
sudo mv go /usr/local/
sudo vim ~/.profile and add this line
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
source ~/.profile
go version

Real-time data passing, Node.js, Express.js, postgres

Building a small app which gives the total count of people in a room and the flow of people enter and leave.

  1. Postgres DB and a table
  2. Postgres trigger on upsert or insert

CREATE TABLE realtime(
id SERIAL NOT NULL PRIMARY KEY,
title character varying(128)
);

CREATE FUNCTION notify_realtime() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
PERFORM pg_notify('addedrecord', NEW.title);
RETURN NULL;
END;
$$;

CREATE TRIGGER updated_realtime_trigger AFTER INSERT ON realtime
FOR EACH ROW EXECUTE PROCEDURE notify_realtime();

Setup a node project with express

mkdir testRealTime
cd testRealTime

npm init -y
npm install express pg socket.io --save

Node Server Code – index.js

const express = require("express");
const app = express();
const server = require("http").createServer(app);
const io = require("socket.io").listen(server);
const pg = require ('pg');

let db = {
  user: 'postgres',
  host: 'localhost',
  database: 'realtime',
  password: 'postgres',
  port: 5432
}

let pg_client = new pg.Client(db);

pg_client.connect();

let query = pg_client.query('LISTEN addedrecord');

io.sockets.on('connection', function (socket) {
  socket.emit('connected', { connected: true });

  socket.on('ready for data', function (data) {
    pg_client.on('notification', function(title) {
      socket.emit('update', { message: title });
    });
  });
});

app.get("/", function(req, res) {
  res.sendFile(__dirname + "/index.html");
});

server.listen(9001, function() {
  console.log("listening on *:9001");
});

Client side code – index.html

<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
Hello
<script src="http://localhost:9001/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>

<script>
$(function () {
  let socket = io.connect('http://localhost:9001');
  socket.on('connected', function (data) {
    socket.emit('ready for data', {});
  });

  socket.on('update', function (data) {
    console.log(data.message.payload);
  });
});
</script>
</body>
</html>