From 401a1d3630bf544a486867a26723604a39c5cc2a Mon Sep 17 00:00:00 2001
From: Nyah Check <nyah.check@anchorlabs.com>
Date: Wed, 22 Dec 2021 20:55:05 +0000
Subject: [PATCH 1/9] Update ci workflow

---
 .github/workflows/ci.yml | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index abd4329..dc425fe 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,4 +1,4 @@
-name: Build
+name: CI
 
 on: [push, pull_request]
 
@@ -8,15 +8,17 @@ jobs:
     name: Setup, Build, Test
     strategy:
       matrix:
-        go-version: [1.13.x]
-        platform: [macos-latest]
-    runs-on: ${{ matrix.platform }}
+        go-version: [1.16.x, 1.17.x, 1.18.x]
+        platform: [macos-latest, ubuntu-latest, windows-latest]
+    runs-on: ${{ matrix.os }}
     steps:
-    - name: Setup Go
-      uses: actions/setup-go@v1
+    - name: Install go
+      uses: actions/setup-go@v2
       with:
         go-version: ${{ matrix.go-version }}
     - name: Checkout code
-      uses: actions/checkout@v1
+      uses: actions/checkout@v2
+    - name: Test
+      run: go test -v -coverage ./...
     - name: Build
-      run: brew install ffmpeg && make build && make vet
\ No newline at end of file
+      run: make all

From c9a7bb206ab54da50bf28c808aed0461a41c865c Mon Sep 17 00:00:00 2001
From: Nyah Check <nyah.check@anchorlabs.com>
Date: Wed, 22 Dec 2021 20:59:05 +0000
Subject: [PATCH 2/9] Updates to gitignore

---
 .gitignore | 51 ++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 38 insertions(+), 13 deletions(-)

diff --git a/.gitignore b/.gitignore
index e22a576..983895f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,7 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
+# MacOS DS_Store files
+.DS_Store
 
-# Ignore all downloaded video and audio files
+# Binaries for programs and plugins
 *.mp3
 *.flv
 *.webm
@@ -11,22 +9,49 @@
 *.mp4
 *.3gpp
 *.ogg
+*.exe
+*.exe~
+*.dll
+*.o
+*.a
+*.so
+*.dylib
 
-# Compiled binaries
+## Compiled binaries
 ytd
 youtube-dl
 
-*.exe
+
+# Test binary, built with `go test -c`
 *.test
 *.prof
 
-# OSX
-.DS_Store
-
-# CODE coverage results
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+coverage.html
 coverage.txt
 profile.out
 
-# ENV files
+# Dependency directories (remove the comment below to include it)
+vendor/
+
+# Output of GoReleaser
+dist/
+
+# Visual Studio Code files
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+# GoLand and IntelliJ IDEA files
+.idea/
+
+# env files that usually contain secrets or local config
+.env
 .envrc
-.idea
\ No newline at end of file

From 5eac880289f0315edf09aea7d4c154878bd62b48 Mon Sep 17 00:00:00 2001
From: Nyah Check <nyah.check@anchorlabs.com>
Date: Wed, 22 Dec 2021 20:59:50 +0000
Subject: [PATCH 3/9] Add dependabot configs workflow

---
 .github/workflows/dependabot.yml | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 .github/workflows/dependabot.yml

diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml
new file mode 100644
index 0000000..49a3b5a
--- /dev/null
+++ b/.github/workflows/dependabot.yml
@@ -0,0 +1,19 @@
+
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+  # Maintain dependencies for Go
+  - package-ecosystem: "gomod"
+    directory: "/"
+    schedule:
+      interval: "weekly"
+
+  # Maintain dependencies for build tools
+  - package-ecosystem: "gomod"
+    directory: "/tools"
+    schedule:
+      interval: "weekly"

From b71ae3cd9f13d10f93396b4356b995376810b085 Mon Sep 17 00:00:00 2001
From: Nyah Check <nyah.check@anchorlabs.com>
Date: Wed, 22 Dec 2021 21:26:06 +0000
Subject: [PATCH 4/9] Update github repo configs

---
 .github/CODEOWNERS                         |  1 -
 CONTRIBUTING.md => .github/CONTRIBUTING.md |  0
 .github/ISSUE_TEMPLATE.md                  | 14 ++++++++++++++
 .github/PULL_REQUEST_TEMPLATE.md           | 15 +++++++++++++++
 .github/issue_template.md                  |  7 -------
 5 files changed, 29 insertions(+), 8 deletions(-)
 rename CONTRIBUTING.md => .github/CONTRIBUTING.md (100%)
 create mode 100644 .github/ISSUE_TEMPLATE.md
 create mode 100644 .github/PULL_REQUEST_TEMPLATE.md
 delete mode 100644 .github/issue_template.md

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index fc81ca9..52cb09a 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,2 +1 @@
 * @ch3ck
-
diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md
similarity index 100%
rename from CONTRIBUTING.md
rename to .github/CONTRIBUTING.md
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..553ec76
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,14 @@
+---
+name: Bug Report
+about: If something isn't working as its supposed to
+labels: bug, feature request, needs triage, won't fix
+assignees: ch3ck
+---
+
+Please provide more details:
+
+* What are you trying to do
+* What happened
+* What was the expected behaviour
+
+Please share relevent code sample or [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example).
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..3cd82d0
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,15 @@
+## Proposed changes
+Describe the *big picture* reason for your PR.
+
+## Checklist
+
+Please review the following checklist before submitting a PR:
+
+- [ ] **CONSIDER** adding a unit test to demonstrate your PR resolves an issue
+- [ ] **DO** keep PRs small for easy review
+- [ ] **DO** make sure unit tests pass
+- [ ] **DO** ensure no compiler warnings are triggered
+- [ ] **AVOID** breaking the CI builds
+
+## Other comments
+Any other comments you might have.
diff --git a/.github/issue_template.md b/.github/issue_template.md
deleted file mode 100644
index 8b31d81..0000000
--- a/.github/issue_template.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: Tracking issue
-about: Use this template for tracking new features.
-title: "[DATE]: [FEATURE NAME]"
-labels: bug, feature request, needs triage, won't fix
-assignees: ch3ck
----
\ No newline at end of file

From 10671ae782ce636de11e1c620242601c8f2eeecc Mon Sep 17 00:00:00 2001
From: Nyah Check <nyah.check@anchorlabs.com>
Date: Wed, 22 Dec 2021 21:56:57 +0000
Subject: [PATCH 5/9] refactor module

---
 build.sh                                      | 10 -----
 main.go => cmd/main.go                        | 21 +++++------
 go.mod                                        | 17 +++------
 go.sum                                        | 37 ++++++-------------
 download.go => pkg/downloader/download.go     | 10 ++---
 .../downloader/download_test.go               |  6 +--
 6 files changed, 35 insertions(+), 66 deletions(-)
 delete mode 100644 build.sh
 rename main.go => cmd/main.go (85%)
 rename download.go => pkg/downloader/download.go (86%)
 rename download_test.go => pkg/downloader/download_test.go (86%)

diff --git a/build.sh b/build.sh
deleted file mode 100644
index c8c8b8d..0000000
--- a/build.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#Script builds the program
-#!/usr/bin/env bash
-
-p=`pwd`
-for d in $(ls ./); do
-  echo "building main/$d"
-  cd $p/cm$d
-  env GOOS=linux GOARCH=386 go build
-done
-cd $p
diff --git a/main.go b/cmd/main.go
similarity index 85%
rename from main.go
rename to cmd/main.go
index 463d7f1..d49b80e 100644
--- a/main.go
+++ b/cmd/main.go
@@ -11,6 +11,8 @@ import (
 	"strings"
 	"sync"
 
+	"youtube-dl/pkg/downloader"
+
 	"github.com/sirupsen/logrus"
 )
 
@@ -87,21 +89,18 @@ func parseUrls(urls string) []string {
 	}
 }
 
-func beginDownload(urls []string) {
-	if len(urls) < 2 {
-		if err := decodeVideoStream(urls[0], format); err != nil {
-			logrus.Errorf("Unable to beginDownload: %v", err)
-		}
-	} else {
-		if err := concurrentDownload(MAXDOWNLOADS, format, urls); err != nil {
-			logrus.Errorf("Unable to concurrently download videos: %v with errors => %v", urls, err)
-		}
+// beginDownload of videos from specified url(s)
+// and returns error if it fails
+func beginDownload(urls []string) <-chan error {
+	if err := concurrentDownload(MAXDOWNLOADS, format, urls); err != nil {
+		logrus.Errorf("Unable to download video(s): %v with errors => %v", urls, err)
+		return err
 	}
+	return nil
 }
 
 //DownloadStreams download a batch of elements asynchronously
 func concurrentDownload(maxOperations int, format string, urls []string) <-chan error {
-
 	var wg sync.WaitGroup
 	wg.Add(len(urls))
 
@@ -109,7 +108,7 @@ func concurrentDownload(maxOperations int, format string, urls []string) <-chan
 	for _, url := range urls {
 		go func(url string) {
 			defer wg.Done()
-			ch <- decodeVideoStream(url, format)
+			ch <- downloader.DecodeVideoStream(url, format)
 		}(url)
 	}
 
diff --git a/go.mod b/go.mod
index 8ebf5bb..7b580ec 100644
--- a/go.mod
+++ b/go.mod
@@ -1,15 +1,10 @@
-module github.com/ch3ck/youtube-dl
+module youtube-dl
 
-go 1.12
+go 1.17
 
 require (
-	github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
-	github.com/sirupsen/logrus v1.5.0
-	github.com/stretchr/objx v0.2.0 // indirect
-	github.com/stretchr/testify v1.4.0 // indirect
-	github.com/wader/goutubedl v0.0.0-20200327095909-c841a70bbbad
-	github.com/wader/osleaktest v0.0.0-20191111175233-f643b0fed071 // indirect
-	golang.org/x/sys v0.0.0-20200408040146-ea54a3c99b9b // indirect
-	gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
-	gopkg.in/yaml.v2 v2.2.7 // indirect
+	github.com/sirupsen/logrus v1.8.1
+	github.com/wader/goutubedl v0.0.0-20211221155015-039073da1ac8
 )
+
+require golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
diff --git a/go.sum b/go.sum
index 2f5e223..9477086 100644
--- a/go.sum
+++ b/go.sum
@@ -1,31 +1,16 @@
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
-github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/wader/goutubedl v0.0.0-20200115162246-9eae90476a5d h1:+noQWJMxTu1ruNLG1KcA7tz0kHR7QYUBu+88Y2+w930=
-github.com/wader/goutubedl v0.0.0-20200115162246-9eae90476a5d/go.mod h1:TEOvzRw4YvTeOdSvGyoZD9KbKK4xbx0EJoSqj4v6yAs=
-github.com/wader/goutubedl v0.0.0-20200327095909-c841a70bbbad h1:16IhHxbHNcIjuAXABVcKczJlHRO7sRwLPCnSmogRPCA=
-github.com/wader/goutubedl v0.0.0-20200327095909-c841a70bbbad/go.mod h1:TEOvzRw4YvTeOdSvGyoZD9KbKK4xbx0EJoSqj4v6yAs=
-github.com/wader/osleaktest v0.0.0-20190723190525-c53af4cfc4a3/go.mod h1:XD6emOFPHVzb0+qQpiNOdPL2XZ0SRUM0N5JHuq6OmXo=
+github.com/wader/goutubedl v0.0.0-20211221155015-039073da1ac8 h1:sAGy4o7qRHWJ8kM8fr69VWVdANx4BC8Q4BAU/eTqfvE=
+github.com/wader/goutubedl v0.0.0-20211221155015-039073da1ac8/go.mod h1:5KXd5tImdbmz4JoVhePtbIokCwAfEhUVVx3WLHmjYuw=
+github.com/wader/osleaktest v0.0.0-20191111175233-f643b0fed071 h1:QkrG4Zr5OVFuC9aaMPmFI0ibfhBZlAgtzDYWfu7tqQk=
 github.com/wader/osleaktest v0.0.0-20191111175233-f643b0fed071/go.mod h1:XD6emOFPHVzb0+qQpiNOdPL2XZ0SRUM0N5JHuq6OmXo=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200117145432-59e60aa80a0c h1:gUYreENmqtjZb2brVfUas1sC6UivSY8XwKwPo8tloLs=
-golang.org/x/sys v0.0.0-20200117145432-59e60aa80a0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200408040146-ea54a3c99b9b h1:h03Ur1RlPrGTjua4koYdpGl8W0eYo8p1uI9w7RPlkdk=
-golang.org/x/sys v0.0.0-20200408040146-ea54a3c99b9b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/download.go b/pkg/downloader/download.go
similarity index 86%
rename from download.go
rename to pkg/downloader/download.go
index 6440768..6eae3bc 100644
--- a/download.go
+++ b/pkg/downloader/download.go
@@ -1,4 +1,4 @@
-package main
+package downloader
 
 import (
 	"context"
@@ -34,10 +34,10 @@ func fixExtension(str string) string {
 	return str
 }
 
-// decodeVideoStream processes downloaded video stream and
-// decodeVideoStream calls helper functions and writes the
+// DecodeVideoStream processes downloaded video stream and
+// DecodeVideoStream calls helper functions and writes the
 // output in the required format
-func decodeVideoStream(videoUrl, format string) error {
+func DecodeVideoStream(videoUrl, format string) error {
 
 	// Get video data
 	res, err := goutubedl.New(context.Background(), videoUrl, goutubedl.Options{})
@@ -65,4 +65,4 @@ func decodeVideoStream(videoUrl, format string) error {
 	io.Copy(fp, videoStream)
 
 	return nil
-}
\ No newline at end of file
+}
diff --git a/download_test.go b/pkg/downloader/download_test.go
similarity index 86%
rename from download_test.go
rename to pkg/downloader/download_test.go
index de83282..937ea6f 100644
--- a/download_test.go
+++ b/pkg/downloader/download_test.go
@@ -1,4 +1,4 @@
-package main
+package downloader
 
 import (
 	"testing"
@@ -22,7 +22,7 @@ func TestApi(t *testing.T) {
 
 	// path := "test"
 	for i, table := range tables {
-		err := decodeVideoStream(table.url, "mp3")
+		err := DecodeVideoStream(table.url, "mp3")
 		if err != nil {
 			t.Errorf("videoId(%d): expected %q, actual %q", i, table.id, err)
 		}
@@ -31,7 +31,7 @@ func TestApi(t *testing.T) {
 
 func BenchmarkVideoId(b *testing.B) {
 	for n := 0; n < b.N; n++ {
-		if err := decodeVideoStream(tables[0].url, "mp3"); err != nil {
+		if err := DecodeVideoStream(tables[0].url, "mp3"); err != nil {
 			b.Errorf("Error downloading video: %v", err)
 		}
 	}

From 4122d5a1fdcf8017e8aa857dc68e82b4ff5507f0 Mon Sep 17 00:00:00 2001
From: Nyah Check <nyah.check@anchorlabs.com>
Date: Thu, 23 Dec 2021 01:34:07 +0000
Subject: [PATCH 6/9] Add ci workflow for rust jobs

---
 .github/workflows/ci.yml | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dc425fe..903cc65 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,8 +4,34 @@ on: [push, pull_request]
 
 
 jobs:
+  build-and-test-rust-lib:
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        os: [ubuntu-latest, windows-latest, macOS-latest]
+        rust: [nightly]
+    steps:
+    - uses: actions/checkout@v2
+      with:
+        rust-version: ${{ matrix.rust }}
+    - name: Build
+      run: cargo +nightly build --tests --verbose
+    - name: Run tests
+      run: cargo +nightly test --verbose
+  publish-crate-on-new-release:
+    name: "Publish crate on Release"
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+            toolchain: stable
+            override: true
+      - uses: katyo/publish-crates@v1
+        with:
+            registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
   setup-build-test:
-    name: Setup, Build, Test
+    name: Setup, Build, Test go source
     strategy:
       matrix:
         go-version: [1.16.x, 1.17.x, 1.18.x]

From f4755b3921925c04e9af86199a34e6aa75e7568c Mon Sep 17 00:00:00 2001
From: Nyah Check <nyah.check@anchorlabs.com>
Date: Thu, 23 Dec 2021 01:35:40 +0000
Subject: [PATCH 7/9] rename youtube-dl to ydl

---
 .gitignore |  2 +-
 Dockerfile |  6 +++---
 LICENSE    |  2 +-
 README.md  | 29 ++++++++++++++---------------
 4 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/.gitignore b/.gitignore
index 983895f..00efb8e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,7 +19,7 @@
 
 ## Compiled binaries
 ytd
-youtube-dl
+ydl
 
 
 # Test binary, built with `go test -c`
diff --git a/Dockerfile b/Dockerfile
index 2a25d3f..0feca45 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,10 +10,10 @@ ENV GO111MODULE=on
 WORKDIR /app
 RUN echo "Build container"
 COPY . .
-RUN CGO_ENABLED=0 GOOS=linux go build -o /youtube-dl .
+RUN CGO_ENABLED=0 GOOS=linux go build -o /ydl .
 
 
 # Runtime container
 FROM scratch
-COPY --from=go-base /youtube-dl /youtube-dl
-ENTRYPOINT ["/youtube-dl"]
+COPY --from=go-base /ydl /ydl
+ENTRYPOINT ["/ydl"]
diff --git a/LICENSE b/LICENSE
index de90ebd..d769fd0 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2020 youtube-dl
+Copyright (c) 2020 ydl
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index c2375e2..dfb558a 100644
--- a/README.md
+++ b/README.md
@@ -1,37 +1,36 @@
-# youtube-dl
+# ydl
 
-[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/ch3ck/youtube-dl/Build?style=for-the-badge)](https://github.com/ch3ck/youtube-dl/actions)
-[![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4.svg?style=for-the-badge)](https://godoc.org/github.com/ch3ck/youtube-dl)
-[![GitHub license](https://img.shields.io/github/license/ch3ck/youtube-dl?style=for-the-badge)](https://github.com/ch3ck/youtube-dl/blob/master/LICENSE)
+[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/ch3ck/ydl/Build?style=for-the-badge)](https://github.com/ch3ck/ydl/actions)
+[![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4.svg?style=for-the-badge)](https://godoc.org/github.com/ch3ck/ydl)
+[![GitHub license](https://img.shields.io/github/license/ch3ck/ydl?style=for-the-badge)](https://github.com/ch3ck/ydl/blob/master/LICENSE)
 
-`youtube-dl` is a simple youtube video downloader and can also download multiple videos concurrently.
-Downloaded videos could be converted to `flv` or `mp3` formats.
+`ydl` is a simple youtube video downloader.
 
 
 ## Build
 
 ```bash
-$ git clone https://github.com/Ch3ck/youtube-dl
-$ cd youtube-dl
+$ git clone https://github.com/Ch3ck/ydl
+$ cd ydl
 $ make
 ```
 
 
 ## Usage
 
-To install youtube-dl
+To install ydl
 
 ```console
-$ go get github.com/Ch3ck/youtube-dl
+$ go get github.com/ch3ck/ydl
 ```
 
 To run download:
 
 ```console
-youtube-dl -h
-youtube-dl - Simple youtube video/audio downloader
+ydl -h
+ydl - Simple youtube video/audio downloader
 
-Usage: youtube-dl [OPTIONS] [ARGS]
+Usage: ydl [OPTIONS] [ARGS]
 
 Flags:
   -bitrate        Audio Bitrate (default 123)
@@ -45,7 +44,7 @@ Flags:
 ### Example
 
 ```bash
-$ ./youtube-dl -format mp3 -id lWEbEtr_Vng
+$ ./ydl -format mp3 -id lWEbEtr_Vng
 ```
 
 ## Roadmap
@@ -62,7 +61,7 @@ Follow the basic instruction in the [CONTRIBUTING](CONTRIBUTING.md) file.
 
 ## Licence
 
-`youtube-dl` is licensed under [The MIT Licence](LICENSE.md).
+`ydl` is licensed under [The MIT Licence](LICENSE.md).
 
 
 ## Support

From 23146e14d00cde2bb7f45ee361446124f904b11c Mon Sep 17 00:00:00 2001
From: Nyah Check <nyah.check@anchorlabs.com>
Date: Thu, 23 Dec 2021 03:17:24 +0000
Subject: [PATCH 8/9] Add download package

---
 .github/workflows/ci.yml         | 40 +++++++------------
 .github/workflows/dependabot.yml |  1 -
 .github/workflows/release.yml    | 51 ++++++++++++++++++++++++
 .github/workflows/security.yml   | 18 +++++++++
 pkg/download.h                   | 13 ++++++
 pkg/download/.gitignore          | 12 ++++++
 pkg/download/.rustfmt.toml       |  5 +++
 pkg/download/Cargo.toml          | 29 ++++++++++++++
 pkg/download/src/lib.rs          | 42 ++++++++++++++++++++
 pkg/downloader/download.go       | 68 --------------------------------
 pkg/downloader/download_test.go  | 38 ------------------
 11 files changed, 185 insertions(+), 132 deletions(-)
 create mode 100644 .github/workflows/release.yml
 create mode 100644 .github/workflows/security.yml
 create mode 100644 pkg/download.h
 create mode 100644 pkg/download/.gitignore
 create mode 100644 pkg/download/.rustfmt.toml
 create mode 100644 pkg/download/Cargo.toml
 create mode 100644 pkg/download/src/lib.rs
 delete mode 100644 pkg/downloader/download.go
 delete mode 100644 pkg/downloader/download_test.go

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 903cc65..e74a40a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,34 +4,24 @@ on: [push, pull_request]
 
 
 jobs:
-  build-and-test-rust-lib:
-    runs-on: ${{ matrix.os }}
-    strategy:
-      matrix:
-        os: [ubuntu-latest, windows-latest, macOS-latest]
-        rust: [nightly]
-    steps:
-    - uses: actions/checkout@v2
-      with:
-        rust-version: ${{ matrix.rust }}
-    - name: Build
-      run: cargo +nightly build --tests --verbose
-    - name: Run tests
-      run: cargo +nightly test --verbose
-  publish-crate-on-new-release:
-    name: "Publish crate on Release"
+  build-and-test-rust-library:
+    name: Build and test rust library
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
-      - uses: actions-rs/toolchain@v1
-        with:
-            toolchain: stable
-            override: true
-      - uses: katyo/publish-crates@v1
+      - name: checkout source
+        uses: actions/checkout@v2
+      - name: install latest nightly
+        uses: actions-rs/toolchain@v1
         with:
-            registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
-  setup-build-test:
-    name: Setup, Build, Test go source
+          toolchain: nightly
+          override: true
+          components: rustfmt, clippy
+      - name: build and test
+        working-directory: ./pkg/download
+        run: |
+          cargo build --tests --verbose && cargo test --verbose
+  build-and-test-go-module:
+    name: Build and test go source
     strategy:
       matrix:
         go-version: [1.16.x, 1.17.x, 1.18.x]
diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml
index 49a3b5a..edeb6cc 100644
--- a/.github/workflows/dependabot.yml
+++ b/.github/workflows/dependabot.yml
@@ -1,4 +1,3 @@
-
 # To get started with Dependabot version updates, you'll need to specify which
 # package ecosystems to update and where the package manifests are located.
 # Please see the documentation for all configuration options:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..72ace2d
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,51 @@
+name: release new binaries
+
+on:
+  workflow_dispatch:
+    inputs:
+      reason:
+        description: new release message
+        required: true
+  push:
+    tags:
+      - "*"
+
+permissions:
+  contents: write
+
+
+jobs:
+  publish-crate-on-new-release:
+    name: "Publish crate on Release"
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+            toolchain: stable
+            override: true
+      - uses: katyo/publish-crates@v1
+        with:
+            registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
+  publish-go-package-on-release:
+    name: Release go binaries
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+      - name: Setup Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: 1.17
+      - name: Run GoReleaser
+        uses: goreleaser/goreleaser-action@v2
+        with:
+          distribution: goreleaser
+          version: latest
+          args: release --rm-dist
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          # GoReleaser Pro key, for 'goreleaser-pro' distribution
+          # GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml
new file mode 100644
index 0000000..b66b67b
--- /dev/null
+++ b/.github/workflows/security.yml
@@ -0,0 +1,18 @@
+# Run security audit
+# Author: Nyah Check
+name: Run Security Audit
+
+on:
+  push:
+    paths:
+      - '**/Cargo.toml'
+      - '**/Cargo.lock'
+
+jobs:
+  run-security-audit:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - uses: actions-rs/audit-check@v1
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/pkg/download.h b/pkg/download.h
new file mode 100644
index 0000000..f2a446b
--- /dev/null
+++ b/pkg/download.h
@@ -0,0 +1,13 @@
+/** -*- mode: C; -*-
+ * download.h
+ *
+ * Copyright (C) 2021 Nyah Check
+ *
+ **/
+
+#ifndef DOWNLOAD_H
+#define DOWNLOAD_H
+
+char * download(char *url, char *path);
+
+#endif
diff --git a/pkg/download/.gitignore b/pkg/download/.gitignore
new file mode 100644
index 0000000..6351a5d
--- /dev/null
+++ b/pkg/download/.gitignore
@@ -0,0 +1,12 @@
+# rs will have compiled files and executables
+/target/
+Cargo.lock
+
+# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
+# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
+# Cargo.lock
+
+# These are backup files generated by rustfmt
+**/*.rs.bk
+target
+build
diff --git a/pkg/download/.rustfmt.toml b/pkg/download/.rustfmt.toml
new file mode 100644
index 0000000..a6a1306
--- /dev/null
+++ b/pkg/download/.rustfmt.toml
@@ -0,0 +1,5 @@
+max_width = 80
+newline_style = "Unix"
+reorder_imports = true
+use_small_heuristics = "Max"
+use_field_init_shorthand = true
diff --git a/pkg/download/Cargo.toml b/pkg/download/Cargo.toml
new file mode 100644
index 0000000..806c4f2
--- /dev/null
+++ b/pkg/download/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+name            = "ydl"
+description     = "download youtube videos to path"
+version         = "0.1.0"
+authors         = ["Nyah Check <hello@nyah.dev>"]
+license         = "MIT"
+homepage        = "https://github.com/ch3ck"
+repository      = "https://github.com/ch3ck/ydl"
+readme          = "README.md"
+categories      = ["web-programming"]
+keywords        = [ "rust"]
+edition         = "2018"
+documentation   = "https://docs.rs/ydl"
+
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.release]
+debug               = true
+overflow-checks     = true
+panic               = "abort"
+
+[dependencies]
+clippy      = "0.0.302"
+env_logger  = "0.9.0"
+log         = "0.4.14"
+rustube     = "0.3.6"
+tokio       = { version = "1.15.0", features = ["macros", "io-util", "sync", "rt-multi-thread"] }
diff --git a/pkg/download/src/lib.rs b/pkg/download/src/lib.rs
new file mode 100644
index 0000000..79ba49d
--- /dev/null
+++ b/pkg/download/src/lib.rs
@@ -0,0 +1,42 @@
+//! -*- mode: rust; -*-
+//!
+//! download - downloads youtube files
+use rustube::{Id, Video};
+use std::ffi;
+
+#[no_mangle]
+pub async extern "C" fn download<'a>(
+    url: &'a str,
+    path: &'a str,
+) -> Result<(), Box<dyn std::error::Error>> {
+    env_logger::init();
+
+    let id = Id::from_raw(&url)?;
+    let video = Video::from_id(id.into_owned()).await?;
+
+    let _result = video
+        .streams()
+        .iter()
+        .filter(|stream| {
+            stream.includes_video_track && stream.includes_audio_track
+        })
+        .max_by_key(|stream| stream.quality_label)
+        .unwrap()
+        .download_to_dir(&path)
+        .await
+        .unwrap();
+
+    Ok(())
+}
+
+#[cfg(test)]
+pub mod tests {
+    use super::*;
+
+    #[tokio::test]
+    async fn test_download() {
+        let url = String::from("https://www.youtube.com/watch?v=lWEbEtr_Vng");
+        let fp = String::from("~/Downloads");
+        download(url.as_str(), fp.as_str()).await.expect("expect an OK(_) response");
+    }
+}
diff --git a/pkg/downloader/download.go b/pkg/downloader/download.go
deleted file mode 100644
index 6eae3bc..0000000
--- a/pkg/downloader/download.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package downloader
-
-import (
-	"context"
-	"io"
-	"os"
-	"strings"
-	"unicode"
-
-	"github.com/sirupsen/logrus"
-	"github.com/wader/goutubedl"
-)
-
-// removeWhiteSpace removes white spaces from string
-// removeWhiteSpace returns a filename without whitespaces
-func removeWhiteSpace(str string) string {
-	return strings.Map(func(r rune) rune {
-		if unicode.IsSpace(r) {
-			return -1
-		}
-		return r
-	}, str)
-}
-
-// fixExtension is a helper function that
-// fixes file the extension
-func fixExtension(str string) string {
-	if strings.Contains(str, "mp3") {
-		str = ".mp3"
-	} else {
-		str = ".flv"
-	}
-
-	return str
-}
-
-// DecodeVideoStream processes downloaded video stream and
-// DecodeVideoStream calls helper functions and writes the
-// output in the required format
-func DecodeVideoStream(videoUrl, format string) error {
-
-	// Get video data
-	res, err := goutubedl.New(context.Background(), videoUrl, goutubedl.Options{})
-	if err != nil {
-		logrus.Errorf("Unable to create goutube object %s: %v", videoUrl, err)
-		return err
-	}
-
-	file := removeWhiteSpace(res.Info.Title) + fixExtension(format)
-	videoStream, err := res.Download(context.Background(), "best")
-	if err != nil {
-		logrus.Errorf("Unable to download %s stream: %v", format, err)
-		return err
-	}
-	defer videoStream.Close()
-
-	// Create output file
-	fp, err := os.OpenFile(file, os.O_CREATE, 0755)
-	if err != nil {
-		logrus.Errorf("Unable to create output file: %v", err)
-		return err
-	}
-	defer fp.Close()
-
-	io.Copy(fp, videoStream)
-
-	return nil
-}
diff --git a/pkg/downloader/download_test.go b/pkg/downloader/download_test.go
deleted file mode 100644
index 937ea6f..0000000
--- a/pkg/downloader/download_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package downloader
-
-import (
-	"testing"
-)
-
-var tables = []struct {
-	url, id string // input
-}{
-	{"https://www.youtube.com/watch?v=lWEbEtr_Vng", "lWEbEtr_Vng"},
-	{"https://www.youtube.com/watch?v=ALWmcO8S-dc", "ALWmcO8S-dc"},
-	{"", ""},
-	{"https://www.facebook.com/mark/videos?v=RDHpNluHOAJFA", ""},
-	{"https://www.youtube.com/watch?v=ALWmcO8S-dc", "ALWmcO8S-dc"},
-	{"https://www.wsj.com/articles/trump-administration-wont-withdraw-from-paris-climate-deal-1505593922", ""},
-	{"https://vimeo.com/101522071", ""},
-}
-
-var vid []string
-
-func TestApi(t *testing.T) {
-
-	// path := "test"
-	for i, table := range tables {
-		err := DecodeVideoStream(table.url, "mp3")
-		if err != nil {
-			t.Errorf("videoId(%d): expected %q, actual %q", i, table.id, err)
-		}
-	}
-}
-
-func BenchmarkVideoId(b *testing.B) {
-	for n := 0; n < b.N; n++ {
-		if err := DecodeVideoStream(tables[0].url, "mp3"); err != nil {
-			b.Errorf("Error downloading video: %v", err)
-		}
-	}
-}

From 60c782952394e83e217045cd16d1018d361be532 Mon Sep 17 00:00:00 2001
From: Nyah Check <nyah.check@anchorlabs.com>
Date: Thu, 23 Dec 2021 05:51:02 +0000
Subject: [PATCH 9/9] combine cgo with rust ffi capabilities

---
 .dockerignore            |   3 -
 .github/workflows/ci.yml |   2 +-
 Dockerfile               |  19 ------
 LICENSE                  |   2 +-
 Makefile                 |  69 ++++++++-------------
 README.md                |  62 ++++++------------
 cmd/main.go              | 131 ---------------------------------------
 go.mod                   |   9 +--
 go.sum                   |  16 -----
 main.go                  |  99 +++++++++++++++++++++++++++++
 10 files changed, 145 insertions(+), 267 deletions(-)
 delete mode 100644 .dockerignore
 delete mode 100644 Dockerfile
 delete mode 100644 cmd/main.go
 create mode 100644 main.go

diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index dc8f861..0000000
--- a/.dockerignore
+++ /dev/null
@@ -1,3 +0,0 @@
-Dockerfile
-**.md
-.git
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e74a40a..b517db2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -37,4 +37,4 @@ jobs:
     - name: Test
       run: go test -v -coverage ./...
     - name: Build
-      run: make all
+      run: make
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 0feca45..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,19 +0,0 @@
-
-# Build container
-FROM golang:1.13-alpine AS go-base
-RUN apk add --no-cache git
-
-MAINTAINER Nyah Check <hello@nyah.dev>
-
-ENV CGO_ENABLED=1
-ENV GO111MODULE=on
-WORKDIR /app
-RUN echo "Build container"
-COPY . .
-RUN CGO_ENABLED=0 GOOS=linux go build -o /ydl .
-
-
-# Runtime container
-FROM scratch
-COPY --from=go-base /ydl /ydl
-ENTRYPOINT ["/ydl"]
diff --git a/LICENSE b/LICENSE
index d769fd0..de1237c 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2020 ydl
+Copyright (c) 2022 ydl
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile b/Makefile
index b07ac37..34464dd 100644
--- a/Makefile
+++ b/Makefile
@@ -1,45 +1,26 @@
-# Setup package name variables
-NAME := ytd
-PKG := github.com/ch3ck/$(NAME)
-PREFIX?=$(shell pwd)
-BUILDTAGS=
-version=v1.1
-
-.PHONY: clean all fmt vet build test install static
-.DEFAULT: default
-
-all: clean fmt vet build test install
-
-build: clean fmt
-	@echo "+ $@"
-	CGO_ENABLED=1 go build -tags "$(BUILDTAGS) cgo" .
-
-static:
-	@echo "+ $@"
-	CGO_ENABLED=1 go build -tags "$(BUILDTAGS) cgo static_build" -ldflags "-w -extldflags -static" -o ytd .
-
-fmt:
-	@echo "+ $@"
-	@gofmt -s -l -w . | tee /dev/stderr
-
-test:
-	@echo "+ $@"
-	@find . -name \*.mp3 -delete #clean previous test files.
-	@go test -v -tags "$(BUILDTAGS) cgo" $(shell go list)
-	@find . -name \*.mp3 -delete # clean previous test downloads
-	@go test -bench=. $(shell go list)
-
-vet:
-	@echo "+ $@"
-	@go vet $(shell go list | grep -v vendor)
-
+.PHONY: build-all
+build-all: build-static
+
+.PHONY: run-all
+run-all: run-static
+
+.PHONY: build-static
+build-static:
+	rustup toolchain install nightly
+	cd pkg/download && cargo +nightly build --release
+	cp pkg/download/target/release/libydl.a pkg/
+	go build -v ./...
+
+.PHONY: run-static
+run-static:
+	RUST_LOG=trace ./ydl
+
+# test rust lib
+.PHONY: test-rs
+test-rs:
+	cd pkg/download && RUST_LOG=trace cargo test -- --nocapture
+
+# clean all packages
+.PHONY: clean
 clean:
-	@echo "+ $@"
-	@rm -rf ytd
-	@find . -name \*.mp3 -delete
-	@find . -name \*.flv -delete
-
-install:
-	@echo "+ $@"
-	@docker build -t ch3ck/youtube-dl:$(version) . 
-	@go install .
+	rm -rf main_static pkg/libydl.so pkg/libydl.a pkg/download/target
diff --git a/README.md b/README.md
index dfb558a..65a4f57 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,18 @@
 # ydl
 
-[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/ch3ck/ydl/Build?style=for-the-badge)](https://github.com/ch3ck/ydl/actions)
-[![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4.svg?style=for-the-badge)](https://godoc.org/github.com/ch3ck/ydl)
-[![GitHub license](https://img.shields.io/github/license/ch3ck/ydl?style=for-the-badge)](https://github.com/ch3ck/ydl/blob/master/LICENSE)
+[![Build](https://github.com/ch3ck/youtube-dl/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/ch3ck/youtube-dl/actions/workflows/ci.yml)
+[![CodeQL](https://github.com/ch3ck/youtube-dl/actions/workflows/codeql-analysis.yml/badge.svg?branch=master)](https://github.com/ch3ck/youtube-dl/actions/workflows/codeql-analysis.yml))
+[![forthebadge](https://forthebadge.com/images/badges/contains-technical-debt.svg)](https://forthebadge.com)
 
 `ydl` is a simple youtube video downloader.
 
 
-## Build
+## Build and Test
+
+## Pre-requisites
+
+1. Install [rust nightly](https://rust-lang.github.io/rustup/concepts/channels.html)
+2. Install the [go]https://go.dev/doc/install()
 
 ```bash
 $ git clone https://github.com/Ch3ck/ydl
@@ -15,55 +20,24 @@ $ cd ydl
 $ make
 ```
 
+## Install and Run
 
-## Usage
-
-To install ydl
-
-```console
-$ go get github.com/ch3ck/ydl
-```
-
-To run download:
-
-```console
-ydl -h
-ydl - Simple youtube video/audio downloader
-
-Usage: ydl [OPTIONS] [ARGS]
-
-Flags:
-  -bitrate        Audio Bitrate (default 123)
-  -format         File Format(mp3, webm, flv)
-  -id             Youtube Video ID
-  -path           Output Path (default ".")
-  -version        print version and exit
-  -h              Help page
-```
-
-### Example
+*NOTE: * release coming soon!
+Once a release is ready, you could just download one of the [binaries]https://github.com/nyanchor/ydl/releases() and run:
 
 ```bash
-$ ./ydl -format mp3 -id lWEbEtr_Vng
+$ ydl -id url # -id lWEbEtr_Vng
 ```
 
-## Roadmap
-
-* Download youtube video with video id or link and converts to flv or mp3.
-* Support HD Video download.
-* Concurrent downloads.
-* Web App(PWA, Basic JS Web UI).
-
-
-## Contributing
-
-Follow the basic instruction in the [CONTRIBUTING](CONTRIBUTING.md) file.
 
 ## Licence
 
 `ydl` is licensed under [The MIT Licence](LICENSE.md).
 
 
-## Support
+## License
+The scripts and documentation in this project are released under the [MIT License](LICENSE.md)
+
 
-This project was created and is maintained by [Nyah Check](https://twitter.com/ch3ck_)
+## Author
+- [Nyah Check](https://nyah.dev)
\ No newline at end of file
diff --git a/cmd/main.go b/cmd/main.go
deleted file mode 100644
index d49b80e..0000000
--- a/cmd/main.go
+++ /dev/null
@@ -1,131 +0,0 @@
-// main program entry
-package main
-
-import (
-	"flag"
-	"fmt"
-	_ "net/http/pprof"
-	"os"
-	"runtime"
-	"runtime/pprof"
-	"strings"
-	"sync"
-
-	"youtube-dl/pkg/downloader"
-
-	"github.com/sirupsen/logrus"
-)
-
-const (
-
-	// help Banner
-	BANNER = `` +
-		`youtube-dl - Simple youtube video/audio DownloadStreams` + "\n\n" +
-		`Usage: youtube-dl [OPTIONS] [ARGS]` + "\n"
-
-	// current version
-	VERSION = "v0.2"
-
-	// default maximum concurrent downloads
-	MAXDOWNLOADS = 5
-)
-
-var (
-	// Command line flags
-	ids     string
-	version bool
-	format  string
-	path    string
-	bitrate uint
-)
-
-var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
-
-func init() {
-	// parse flags
-	flag.StringVar(&ids, "id", "", "video url or video id; separate multiple ids with a comma.")
-	flag.StringVar(&format, "format", "flv", "download file format(mp3 or flv)")
-	flag.StringVar(&path, "path", ".", "download file path")
-	flag.BoolVar(&version, "version", false, "print version number")
-	flag.UintVar(&bitrate, "bitrate", 192, "audio bitrate")
-
-	flag.Usage = func() {
-		fmt.Fprint(os.Stderr, fmt.Sprintf("%s \t %s", BANNER, VERSION))
-		flag.PrintDefaults()
-	}
-}
-
-func main() {
-	flag.Parse()
-
-	if *cpuprofile != "" {
-		f, err := os.Create(*cpuprofile)
-		if err != nil {
-			logrus.Fatalf("%v", err)
-		}
-		pprof.StartCPUProfile(f)
-		defer pprof.StopCPUProfile()
-	}
-	runtime.SetBlockProfileRate(20)
-
-	args := os.Args
-	if len(args) < 2 {
-		usageAndExit(BANNER, 2)
-	}
-	if path == "" {
-		path, _ = os.Getwd()
-	}
-
-	urls := parseUrls(ids)
-	beginDownload(urls)
-}
-
-// parseUrls for video download
-func parseUrls(urls string) []string {
-	if ids == "" {
-		return []string{os.Args[1]}
-	} else {
-		return strings.Split(ids, ",")
-	}
-}
-
-// beginDownload of videos from specified url(s)
-// and returns error if it fails
-func beginDownload(urls []string) <-chan error {
-	if err := concurrentDownload(MAXDOWNLOADS, format, urls); err != nil {
-		logrus.Errorf("Unable to download video(s): %v with errors => %v", urls, err)
-		return err
-	}
-	return nil
-}
-
-//DownloadStreams download a batch of elements asynchronously
-func concurrentDownload(maxOperations int, format string, urls []string) <-chan error {
-	var wg sync.WaitGroup
-	wg.Add(len(urls))
-
-	ch := make(chan error, maxOperations)
-	for _, url := range urls {
-		go func(url string) {
-			defer wg.Done()
-			ch <- downloader.DecodeVideoStream(url, format)
-		}(url)
-	}
-
-	go func() {
-		wg.Wait()
-		close(ch)
-	}()
-
-	return ch
-}
-
-func usageAndExit(message string, exitCode int) {
-	if message != "" {
-		fmt.Fprintf(os.Stderr, message)
-		fmt.Fprintf(os.Stderr, "\n\n")
-	}
-	flag.Usage()
-	fmt.Fprintf(os.Stderr, "\n")
-	os.Exit(exitCode)
-}
diff --git a/go.mod b/go.mod
index 7b580ec..7b51fdf 100644
--- a/go.mod
+++ b/go.mod
@@ -1,10 +1,3 @@
-module youtube-dl
+module ydl
 
 go 1.17
-
-require (
-	github.com/sirupsen/logrus v1.8.1
-	github.com/wader/goutubedl v0.0.0-20211221155015-039073da1ac8
-)
-
-require golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
diff --git a/go.sum b/go.sum
index 9477086..e69de29 100644
--- a/go.sum
+++ b/go.sum
@@ -1,16 +0,0 @@
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
-github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/wader/goutubedl v0.0.0-20211221155015-039073da1ac8 h1:sAGy4o7qRHWJ8kM8fr69VWVdANx4BC8Q4BAU/eTqfvE=
-github.com/wader/goutubedl v0.0.0-20211221155015-039073da1ac8/go.mod h1:5KXd5tImdbmz4JoVhePtbIokCwAfEhUVVx3WLHmjYuw=
-github.com/wader/osleaktest v0.0.0-20191111175233-f643b0fed071 h1:QkrG4Zr5OVFuC9aaMPmFI0ibfhBZlAgtzDYWfu7tqQk=
-github.com/wader/osleaktest v0.0.0-20191111175233-f643b0fed071/go.mod h1:XD6emOFPHVzb0+qQpiNOdPL2XZ0SRUM0N5JHuq6OmXo=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..2c65c7c
--- /dev/null
+++ b/main.go
@@ -0,0 +1,99 @@
+package main
+
+// #cgo LDFLAGS: ./pkg/libydl.a -ldl
+// #include "./pkg/download.h"
+import "C"
+
+import (
+	"flag"
+	"log"
+	"os"
+	"strings"
+)
+
+const (
+
+	// help Banner
+	BANNER = `` +
+		`ydl - simple youtube downloader` + "\n\n" +
+		`Usage: [OPTIONS] [ARGS]` + "\n" +
+		"\t" + `ydl -id video url or id` + "\n" +
+		"\t" + `ydl -path download path (defaults to '.')` + "\n" +
+		"\t" + `Example: ydl -id https://www.youtube.com/watch?v=lWEbEtr_Vng` + "\n\n\n"
+
+	// current version
+	VERSION = "v1.0"
+
+	// default maximum concurrent downloads
+	MAXDOWNLOADS = 5
+)
+
+var (
+	// Command line flags
+	ids     string
+	version bool
+	format  string
+	path    string
+	bitrate uint
+)
+
+func init() {
+	// parse flags
+	flag.StringVar(&ids, "id", "", "video url or video id; separate multiple ids with a comma.")
+	flag.StringVar(&path, "path", ".", "download file path")
+
+	flag.Usage = func() {
+		log.Fatalf("%s \t %s", BANNER, VERSION)
+		flag.PrintDefaults()
+	}
+}
+
+func main() {
+	flag.Parse()
+	args := os.Args
+	if len(args) < 2 {
+		usageAndExit(BANNER, 2)
+	}
+	if path == "" {
+		path, _ = os.Getwd()
+	}
+
+	// parse urls
+	urls := parseUrls(ids)
+
+	// start download
+	if err := concurrentDownload(MAXDOWNLOADS, format, urls); err != nil {
+		log.Fatalf("Unable to download video(s): %v with errors => %v", urls, err)
+	}
+}
+
+// parseUrls for video download
+func parseUrls(urls string) []string {
+	if ids == "" {
+		return []string{os.Args[1]}
+	} else {
+		return strings.Split(ids, ",")
+	}
+}
+
+//DownloadStreams download a batch of elements asynchronously
+func concurrentDownload(maxOperations int, format string, urls []string) error {
+	for _, url := range urls {
+		// download video
+		go func(url string) {
+			cUrl := C.CString(url)
+			cPath := C.CString(path)
+
+			C.download(cUrl, cPath)
+		}(url)
+	}
+	return nil
+}
+
+func usageAndExit(message string, exitCode int) {
+	if message != "" {
+		log.Fatalf(message)
+	}
+	flag.Usage()
+	os.Exit(exitCode)
+}