Skip to content

Commit

Permalink
feat: make adapters private (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgeGorbanev authored Aug 4, 2024
1 parent 3f52036 commit dfbf7b9
Show file tree
Hide file tree
Showing 50 changed files with 2,076 additions and 1,347 deletions.
181 changes: 129 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,25 @@
Streaminx is a library that unifies interactions with various music streaming links into a single system.
With Streaminx, you can integrate platforms such as Apple Music, Spotify, YouTube and Yandex Music into your applications using a unified interface for searching and retrieving data about tracks and albums.

- [Motivation](#motivation)
- [Providers Supported](#providers-supported)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
- [API reference](#api-reference)
- [Registry](#registry)
- [Provider](#provider)
- [EntityType](#entitytype)
- [Entity](#entity)
- [Link](#link)
- [Testing](#testing)
- [Why do we need translator?](#why-do-we-need-translator)
- [Contribution and development](#contribution-and-development)

## Motivation

The main user of this library is the Telegram bot [Vibeshare](https://t.me/vibeshare_bot).
This bot helps users share song links from the streaming services they use, enabling others to listen to the same songs on different platforms.
This bot helps users to share song links from the streaming services they use, enabling others to listen to the same songs on different platforms.
Therefore, the primary use case for this library is *converting links* from one service to another.

## Providers Supported
Expand Down Expand Up @@ -39,7 +54,7 @@ Here are the steps to configure the library:
1) *Google Translator API.* Obtain the Google Translator API key and project ID from the [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
2) *YouTube API*. Obtain the YouTube API key from the [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
3) *Spotify*. Register your application and obtain the Client ID with Client Secret on the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard).
4) *Init registry*. When you have all the necessary credentials, you can initialize the Streaminx *registry* with the following code.
4) *Build registry*. When you have all the necessary credentials, you can initialize the Streaminx *registry* with the following code.

``` golang
package main
Expand All @@ -53,112 +68,174 @@ import (
func main() {
ctx := context.Background()
registry, err := streaminx.NewRegistry(ctx, streaminx.Credentials{
GoogleTranslatorAPIKeyJSON: "YOUR_GOOGLE_TRANSLATOR_API_KEY_JSON",
GoogleTranslatorProjectID: "YOUR_GOOGLE_TRANSLATOR_PROJECT_ID",
YoutubeAPIKey: "YOUR_YOUTUBE_API_KEY",
SpotifyClientID: "YOUR_SPOTIFY_CLIENT_ID",
SpotifyClientSecret: "YOUR_SPOTIFY_CLIENT_SECRET",
GoogleTranslatorAPIKeyJSON: "[your google translator api key json]",
GoogleTranslatorProjectID: "[your google translator project id]",
YoutubeAPIKey: "[your youtube api key]",
SpotifyClientID: "[your spotify client id]",
SpotifyClientSecret: "[your spotify client secret]",
})
if err != nil {
// Handle error
}
defer registry.Close()

// Your code to use the registry
// use the registry to fetch or search for tracks and albums
}
```
Replace the placeholders with your actual API keys and credentials.

## Usage

Here is an example of how to convert a link from Spotify to YouTube:
Here is an example of how to convert a link from Apple to Spotify:

``` golang

func convert(ctx context.Context, link string) string {
spotify := registry.Adapter(streaminx.Spotify)
id, err := spotify.DetectTrackID(link)
func appleTrackToSpotify(ctx context.Context, link string) (string, error) {
parsedLink, err := streaminx.ParseLink(link)
if err != nil {
// Handle error
}
track, err := spotify.GetTrack(ctx, link)

track, err := registry.Fetch(ctx, streaminx.Apple, streaminx.Track, parsedLink.ID)
if err != nil {
// Handle error
}

convertedTrack, err := registry.Adapter(streaminx.Youtube).SearchTrack(ctx, track.Artist, track.Name)
converted, err := registry.Search(ctx, streaminx.Spotify, streaminx.Track, track.Artist, track.Name)
if err != nil {
// Handle error
}

return convertedTrack.URL
return converted.URL
}

```

## API
## API reference

#### Registry

The root of the library is the `Registry` struct.
The purpose of the `Registry` is to provide a unified interface for working with different streaming services.
Basically, `Registry` is a map, where the key is `Provider` and the value is the `Adapter` for this provider.
``` golang
apple := registry.Adapter(streaminx.Apple)
spotify := registry.Adapter(streaminx.Spotify)
yandex := registry.Adapter(streaminx.Yandex)
youtube := registry.Adapter(streaminx.Youtube)
`Registry` struct is the main entry point of the library.

The purpose of the `Registry` is to provide a unified interface for working with streaming services by HTTP API.

It implements two main methods:
```golang
// Fetch(...) – allows to get entities by their ID
entity, err := registry.Fetch(ctx, provider, entityType, entityID)

// Search(...) – allows to search for entities by name and artist
entity, err := registry.Search(ctx, provider, entityType, entityArtist, entityTitle)
```

This methods requires to specify the *provider*, the *entity type* and *identifiers* explained below.

#### Provider

Provider represents a music streaming service. All providers are accessible via the `Providers` enum:
`Provider` represents a music streaming service, implemented as an enum.

All providers are accessible via the `Providers` enum:
``` golang
for _, provider := range streaminx.Providers {
fmt.Println(provider.Name)
fmt.Println(provider.Name())
}

```

#### Adapter
It implements following methods:

``` golang
p := streaminx.Apple

p.Name()
// => "Apple"
// human readable name of the provider

code := p.Code()
// => "ap"
// short code of the provider, useful for runtime provider definition

regions := p.Regions()
// => []string{"us", "es", "fr", "ru", ... }
// optional region codes for the provider, used for region-specific requests and referenced in the URL

trackID, err := p.DetectTrackID("https://music.apple.com/us/album/song-name/1234?i=4567")
// => "4567", nil
// extract track ID from the link

albumID, err := p.DetectAlbumID("https://music.apple.com/us/album/album-name/1234")
// => "1234", nil
// extract album ID from the link


Using *adapters* you can fetch and search for tracks and albums on the supported streaming services.
Each adapter implements the `Adapter` interface, which provides methods for working with tracks and albums.
```

When you need to define a provider in runtime, you can use the `FindProviderByCode(string)` method:

``` golang
type Adapter interface {
DetectTrackID(ctx context.Context, trackURL string) (string, error)
GetTrack(ctx context.Context, id string) (*Track, error)
SearchTrack(ctx context.Context, artistName, trackName string) (*Track, error)

DetectAlbumID(ctx context.Context, albumURL string) (string, error)
GetAlbum(ctx context.Context, id string) (*Album, error)
SearchAlbum(ctx context.Context, artistName, albumName string) (*Album, error)
}
provider := streaminx.FindProviderByCode("ap")
// => streaminx.Apple

```

#### EntityType

`EntityType` simple string enum that represents the type of entity you want to fetch or search for.

For now, it has two values: `Track` and `Album`.

``` golang
streaminx.Track
// => "track"

streaminx.Album
// => "album"
```

#### Track, Album
#### Entity

`Entity` struct implements unified representation of tracks and albums.

`Track` and `Album` are the main entities of the library. They represent a song and an album, respectively.
Each entity has a set of fields that contain information about the song or album, such as the name, artist, album, and URL.
This struct is returned by the `Fetch` and `Search` methods of the `Registry`.

``` golang
type Track struct {
ID string
Title string
Artist string
URL string
Provider *Provider
type Entity struct {
ID string
Title string
Artist string
URL string
Provider *Provider
Type EntityType
}
```

type Album struct {
ID string
Title string
Artist string
#### Link

`Link` struct represents a parsed link to a track or album on a streaming service.

Useful to extract the ID and provider from the link.

``` golang
type Link struct {
URL string
Provider *Provider
Type EntityType
ID string
}
```

It is returned by the `ParseLink` method:

``` golang
link, err := streaminx.ParseLink("https://music.apple.com/us/album/song-name/1234?i=4567")
// => Link{
// URL: "https://music.apple.com/us/album/song-name/1234?i=4567",
// Provider: streaminx.Apple,
// Type: streaminx.Track,
// ID: "4567",
// }, nil
```

## Testing

For testing purposes, you can use the `RegistryOption`.
Expand Down Expand Up @@ -208,7 +285,7 @@ For example Spotify doesn't allow non-latin characters in artist names. If we ha

## Contribution and development

Contributions are welcome. It would be great if you could help us to add more providers or languages to the library.
Contributions are welcome. It would be great if you could help us to add more providers (e.g. Deezer) or entities (e.g. artist, playlist) to the library.

To run the test and linter use the following commands:

Expand Down
15 changes: 4 additions & 11 deletions adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,12 @@ package streaminx

import (
"context"
"fmt"
)

var (
IDNotFoundError = fmt.Errorf("invalid id")
)

type Adapter interface {
DetectTrackID(trackURL string) (string, error)
GetTrack(ctx context.Context, id string) (*Track, error)
SearchTrack(ctx context.Context, artistName, trackName string) (*Track, error)
FetchTrack(ctx context.Context, id string) (*Entity, error)
SearchTrack(ctx context.Context, artistName, trackName string) (*Entity, error)

DetectAlbumID(albumURL string) (string, error)
GetAlbum(ctx context.Context, id string) (*Album, error)
SearchAlbum(ctx context.Context, artistName, albumName string) (*Album, error)
FetchAlbum(ctx context.Context, id string) (*Entity, error)
SearchAlbum(ctx context.Context, artistName, albumName string) (*Entity, error)
}
9 changes: 0 additions & 9 deletions album.go

This file was deleted.

Loading

0 comments on commit dfbf7b9

Please sign in to comment.