Skip to content

Commit

Permalink
Merge pull request #4 from AudDMusic/v0.2.0-preview3
Browse files Browse the repository at this point in the history
Added Long Poll
  • Loading branch information
Mihonarium authored Dec 11, 2020
2 parents 8db061d + aaf11ca commit f86f7db
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 48 deletions.
72 changes: 25 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[![PkgGoDev](https://pkg.go.dev/badge/github.com/AudDMusic/audd-go@v0.1.0)](https://pkg.go.dev/github.com/AudDMusic/audd-go@v0.1.0)
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](./LICENSE)
[![GoDoc](https://godoc.org/github.com/AudDMusic/audd-go?status.svg)](https://godoc.org/github.com/AudDMusic/audd-go)
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
[![Twitter Follow](https://img.shields.io/twitter/follow/helloAudD.svg?style=social&label=Follow)](https://twitter.com/helloAudD)

## Table of Contents
Expand All @@ -15,18 +15,14 @@
`go get github.com/AudDMusic/audd-go`

## API Token
To send >10 requests, obtain an api_token from [our Dashboard](https://dashboard.audd.io/) and change "test" to the obtained token in `NewClient("test")`.
To send >10 requests, obtain an api_token from [our Telegram bot](https://t.me/auddbot?start=api) and change "test" to the obtained token in `NewClient("test")`.

## Send the files
For `recognize` and `recognizeWithOffset` API methods, as well as for using the enterprise endpoint (which accepts long audio files, usually useful for hours-long mixes), you have to send a file for recognition. There are two ways to send files to our API, you can either
## Sending the files
For `recognize` and `recognizeWithOffset` API methods you have to send a file for recognition. There are two ways to send files to our API, you can either
- 🔗 provide an HTTP URL of the file (our server will download and recognize the music from the file), or
- 📤 post the file using multipart/form-data in the usual way that files are uploaded via the browser.

There are functions for the both ways. `RecognizeByFile` and `RecognizeByUrl` for the `recognize` method, `RecognizeLongAudioByFile` and `RecognizeLongAudioByUrl` for the enterprise endpoint, `RecognizeHumming` and `RecognizeHummingByUrl` for the `recognizeWithOffset` method. The In the pairs, the first functions accept `io.Reader`, the second accept `string` with an URL.

There are also `Recognize` and `RecognizeLongAudio` functions that accept an interface that could be `io.Reader` or `[]byte` for files, `string` or `url.URL` for URLs.

### Recognize music from a file with URL
## Recognize music from a file with URL
It's really easy.
```
package main
Expand All @@ -37,11 +33,10 @@ import (
)
func main() {
// initialize the client with "test" as a token
// initialize the client with "test" as a token
client := audd.NewClient("test")
// recognize music in audd.tech/example1.mp3 and return Apple Music, Deezer and Spotify metadata
Url := "https://audd.tech/example1.mp3"
song, err := client.RecognizeByUrl(Url, "apple_music,deezer,spotify", nil)
// recognize music in audd.tech/example1.mp3 and return Apple Music, Deezer and Spotify metadata
song, err := client.RecognizeByUrl("https://audd.tech/example1.mp3", "apple_music,deezer,spotify", nil)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -71,47 +66,30 @@ Or directly on:
Preview: https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview118/v4/65/07/f5/6507f5c5-dba8-f2d5-d56b-39dbb62a5f60/mzaf_1124211745011045566.plus.aac.p.m4a
```

### Recognize music from a local file
## Recognize music from a local file
You can also send your local files to the API.
```
file, _ := os.Open("/path/to/example.mp3/path/to/example.mp3")
result, err := client.RecognizeByFile(file, "apple_music,deezer,spotify", nil)
file.Close()
file, _ := os.Open("/path/to/example.mp3/path/to/example.mp3")
result, err := client.RecognizeByFile(file, "apple_music,deezer,spotify", nil)
file.Close()
```
`file` in `client.RecognizeByFile` could be any variable that implements the io.Reader interface. If you have e.g. `var data []byte`, you can use `bytes.NewReader(data)` as `file`.

`file` in `client.RecognizeByFile` could be any variable that implements the io.Reader interface.
There is also the `Recognize` function that accepts io.Reader and []byte for local files; string and url.URL for HTTP addresses of files.

### Search lyrics
It's easy with the `FindLyrics` function.
```
result, err := client.FindLyrics("You were the shadow to my light", nil)
if len(result) == 0 {
fmt.Println("AudD can't find any lyrics by this query")
return
}
firstSong := result[0]
fmt.Printf("First match: %s - %s\n\n%s", firstSong.Artist, firstSong.Title, firstSong.Lyrics)
```
Also, there's `client.UseExperimentalUploading()` that allows to start sending a file before it's loaded in the memory. Useful for large files sent to the enterprise endpoint (see [the scanFiles example](examples/scanFiles)).

### Recognize music from a hour-long mix
There are the enterprise endpoint that accepts long audio files (see [docs-e.audd.io](https://docs-e.audd.io)).
## Searching the lyrics
It's easy with the `FindLyrics` function.
```
client.SetEndpoint(audd.EnterpriseAPIEndpoint)
data := map[string]string{"skip": "3", "every": "1"}
file := "https://audd.tech/djatwork_example.mp3"
result, _ := client.RecognizeLongAudio(file, data)
b, _ := json.Marshall(result)
fmt.Println(string(b))
result, err := client.FindLyrics("You were the shadow to my light", nil)
if len(result) == 0 {
fmt.Println("AudD can't find any lyrics by this query")
return
}
firstSong := result[0]
fmt.Printf("First match: %s - %s\n\n%s", firstSong.Artist, firstSong.Title, firstSong.Lyrics)
```

Also, there's `UseExperimentalUploading()` that allows to start sending a file before it's loaded in the memory. Useful for large local files sent to the enterprise endpoint (see [the example](examples/scanFiles)).

## Use other API methods

See the [package docs](https://pkg.go.dev/github.com/AudDMusic/audd-go@v0.1.0). Most of the public API methods are available via functions with the same names.

For other methods, there are `Send`, `SendFile`, `SendUrl` functions that may help you with sending the API requests.

<a name="use-cases"></a>
# Use Cases
How you can use the AudD [Music Recognition API](https://audd.io/):
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module github.com/AudDMusic/audd-go

go 1.14
go 1.15

require github.com/bogem/id3v2 v1.2.0 // indirect
require github.com/Mihonarium/golongpoll v1.2.0
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/Mihonarium/golongpoll v1.2.0 h1:VU5xi0fivNMjBbCUuobO9gl5UXLbv5n4lbEvqnDAbKQ=
github.com/Mihonarium/golongpoll v1.2.0/go.mod h1:/WQya0ObrWZhOvqig6ZdKENj7B01FXSdIHbyCcnE1ok=
github.com/bogem/id3v2 v1.2.0 h1:hKDF+F1gOgQ5r1QmBCEZUk4MveJbKxCeIDSBU7CQ4oI=
github.com/bogem/id3v2 v1.2.0/go.mod h1:t78PK5AQ56Q47kizpYiV6gtjj3jfxlz87oFpty8DYs8=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
Expand Down
62 changes: 62 additions & 0 deletions longpoll.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package audd

import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"github.com/Mihonarium/golongpoll/go-client/glpclient"
"net/url"
"strconv"
)

const longPollingUrl = MainAPIEndpoint + "longpoll/"

func getMD5Hash(text string) string {
hasher := md5.New()
hasher.Write([]byte(text))
return hex.EncodeToString(hasher.Sum(nil))
}

func (c *Client) getLongPollChannel(RadioID int) string {
return getMD5Hash(getMD5Hash(c.ApiToken) + strconv.Itoa(RadioID))[0:9]
}

type LongPoll struct {
stop chan interface{}
ResultsChan chan StreamCallback
}

// Stops the LongPoll connection
func (lp *LongPoll) Stop() {
lp.stop <- struct {}{}
}

// Opens a LongPoll connection to the AudD API and receives the callbacks via LongPoll.
// The callbacks will be sent to both the callback URL and all the LongPoll listeners.
// Won't work unless some URL is set as the URL for callbacks. More info: docs.audd.io/streams/#longpoll
func (c *Client) NewLongPoll(RadioID int) LongPoll {
u, _ := url.Parse(longPollingUrl)
lpC := glpclient.NewClient(u, c.getLongPollChannel(RadioID))
lpC.LoggingEnabled = false
lp := LongPoll{
stop: make(chan interface{}, 1),
ResultsChan: make(chan StreamCallback, 1),
}
go func() {
lpC.Start()
for {
select {
case e := <-lpC.EventsChan:
var song StreamCallback
err := json.Unmarshal(e.Data, &song)
if err == nil {
lp.ResultsChan <- song
}
case <-lp.stop:
lpC.Stop()
return
}
}
}()
return lp
}
21 changes: 21 additions & 0 deletions metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,27 @@ type Stream struct {
StreamRunning bool `json:"stream_running"`
}

type StreamCallback struct {
Status string `json:"status"`
Notification *StreamNotification `json:"notification"`
Result *StreamRecognitionResult `json:"result"`
Time int64 `json:"time"`
}

type StreamRecognitionResult struct {
RadioID int `json:"radio_id"`
Timestamp string `json:"timestamp"`
PlayLength int `json:"play_length,omitempty"`
Results []RecognitionResult `json:"results"`
}

type StreamNotification struct {
RadioID int `json:"radio_id"`
StreamRunning bool `json:"stream_running"`
Code int `json:"notification_code"`
Message string `json:"notification_message"`
}

type NapsterResult struct {
Type string `json:"type"`
ID string `json:"id"`
Expand Down
Binary file added test/04. Dragon.mp3
Binary file not shown.
Binary file added test/04.Unstoppable Music - Hyperhero.mp3
Binary file not shown.
11 changes: 11 additions & 0 deletions test/audd.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
File name,Plays On [file],Plays On [song],Artist,Title,Album,Label,Release date,Listen online
04. Dragon.mp3,00:00,02:37,Nick Phoenix,Dragon,Dragon,Two Steps From Hell,2019-01-18,https://lis.tn/Dragon
04. Dragon.mp3,00:00,02:37,"Two Steps From Hell, Nick Phoenix",Dragon,Dragon,Two Steps From Hell,2019-01-18,https://lis.tn/Dragon
04. Dragon.mp3,00:54,01:21,The A.M. Experiment,"Empty House Filled with Memories Haunting Me, Pt. 3",Ex Nihilo,555983 Records DK,2016-11-19,https://lis.tn/tBbZB
04. Dragon.mp3,00:54,02:53,Emanuel Satie,Don't Forget to Go Home (feat. Billy Cobham) [Nicolosi Ambient Mix] (Nicolosi Ambient Mix),Don't Forget to Go Home,Rebirth,2018-06-08,https://lis.tn/atQWk
04. Dragon.mp3,00:54,02:47,Emre Madak,Gelip de Halimi Gördün mü?,Gelip de Halimi Gördün mü?,ARMONİ MÜZİK,2015-09-23,https://lis.tn/FQamD
04.Unstoppable Music - Hyperhero.mp3,00:00,02:00,Eric Prydz,Proper Education,Proper Education,Universal Music Italia srL.,2006-01-01,https://lis.tn/ProperEducation
04.Unstoppable Music - Hyperhero.mp3,00:00,00:12,Fourward,Levels,Lose Control,Elevate Records,2020-07-31,https://lis.tn/aMreaf
04.Unstoppable Music - Hyperhero.mp3,00:00,02:15,Alberico,Caledonia,Caledonia EP,BeatFreak Limited,2019-10-04,https://lis.tn/Caledonia
04.Unstoppable Music - Hyperhero.mp3,00:54,01:08,Unstoppable Music,Hyperhero,The Pulse,AudD Music,2019-10-15,https://lis.tn/Hyperhero
04.Unstoppable Music - Hyperhero.mp3,01:48,02:01,Unstoppable Music,Hyperhero,The Pulse,AudD Music,2019-10-15,https://lis.tn/Hyperhero
Loading

0 comments on commit f86f7db

Please sign in to comment.