initial commit

This commit is contained in:
hybris 2018-12-28 03:27:34 +01:00
commit e439b6c309
21 changed files with 17722 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

61
auth.go Normal file
View File

@ -0,0 +1,61 @@
package main
import (
"fmt"
"log"
"net/http"
"github.com/zmb3/spotify"
)
var oauthToken string
func StartAuthorizationCodeFlow() (authClient *spotify.Client) {
// first start an HTTP server
http.HandleFunc("/callback", completeAuth)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// log.Println("Got request for:", r.URL.String())
})
go http.ListenAndServe(":8080", nil)
url := auth.AuthURL(state)
fmt.Println("Please log in to Spotify by visiting the following page in your browser:\n", url)
client := <-ch
oauthToken = extractToken(client)
// use the client to make calls that require authorization
user, spotify_auth_err := client.CurrentUser()
if spotify_auth_err != nil {
log.Fatal(spotify_auth_err)
}
fmt.Println("You are logged in as:", user.ID)
return client
}
func completeAuth(w http.ResponseWriter, r *http.Request) {
tok, err := auth.Token(state, r)
if err != nil {
http.Error(w, "Couldn't get token", http.StatusForbidden)
log.Fatal(err)
}
if st := r.FormValue("state"); st != state {
http.NotFound(w, r)
log.Fatalf("State mismatch: %s != %s\n", st, state)
}
// use the token to get an authenticated client
client := auth.NewClient(tok)
status = 2
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprint(w, "test <script>window.close()</script>")
ch <- &client
}
func extractToken(client *spotify.Client) (tokenString string) {
token, err := client.Token()
if err != nil {
log.Fatal(err)
}
return token.AccessToken
}

BIN
freedom Executable file

Binary file not shown.

68
freedom.go Normal file
View File

@ -0,0 +1,68 @@
package main
import (
"fmt"
)
func DownloadTrack() {
fmt.Print("Please provide a spotify track id: ")
// track_id
var track_id string
_, _ = fmt.Scanln(&track_id)
// folder
var folder = root_track_folder
var userFolder string
if check_if_track_is_valid(track_id) {
fmt.Print("Please provide a folder name: "+root_track_folder)
_, _ = fmt.Scanln(&userFolder)
} else {
fmt.Println("Not a valid spotify track id.\nPlease provide a correct one.\n")
waitForInput()
main()
}
lens := len(userFolder)
var newVal string
if lens > 0 {
newVal = userFolder[lens-1:]
} else {
newVal = folder[len(folder)-1:]
}
if string(newVal) != "/" {
userFolder = userFolder + "/"
}
folder = folder + userFolder
fmt.Println(folder)
download_track_to_folder(track_id,folder)
waitForInput()
}
func DownloadPlaylist() {
fmt.Print("Please provide a spotify playlist id: ")
// playlist_id
var playlist_id string
_, _ = fmt.Scanln(&playlist_id)
fmt.Print("Please provide the user id of the playlists owner: ")
// owner_id
var owner_id string
_, _ = fmt.Scanln(&owner_id)
download_playlist_to_folder(playlist_id,owner_id,root_playlists_folder)
waitForInput()
}
func DownloadAllPlaylistsOfUser() {
// fmt.Print("Please provide a spotify user id: ")
// user_id
var user_id = ""
// _, _ = fmt.Scanln(&user_id)
download_all_playlist_of_user(user_id,root_user_folder+user_id+"/")
waitForInput()
}

20
help.go Normal file
View File

@ -0,0 +1,20 @@
package main
import(
"fmt"
)
func HowToSetEnvVariables() {
fmt.Println("=> How To: Set Client ID")
fmt.Println("Set the SPOTIFY_ID environment variable")
fmt.Println("Examples:") // YOUTUBE_TOKEN
fmt.Println(" $ export SPOTIFY_ID=\"aebff49ecd9e446ba573989feda8cb05\" && \\")
fmt.Println(" export SPOTIFY_SECRET=\"a43f00a0d8734109aef7c881062eb97b\" && \\")
fmt.Println(" export YOUTUBE_TOKEN=\"AIzaSyBbaWwezUJgCdYAxYyqViGcVsRRpWgTKLw\"")
fmt.Println("")
fmt.Println(" $ setenv SPOTIFY_ID \"aebff49ecd9e446ba573989feda8cb05\" && setenv SPOTIFY_SECRET=\"a43f00a0d8734109aef7c881062eb97b\" && \\")
fmt.Println(" setenv SPOTIFY_SECRET \"a43f00a0d8734109aef7c881062eb97b\" && \\")
fmt.Println(" setenv YOUTUBE_TOKEN \"AIzaSyBbaWwezUJgCdYAxYyqViGcVsRRpWgTKLw\"")
waitForInput()
}

89
main.go Normal file
View File

@ -0,0 +1,89 @@
// This example demonstrates how to authenticate with Spotify using the authorization code flow.
// In order to run this example yourself, you'll need to:
//
// 1. Register an application at: https://developer.spotify.com/my-applications/
// - Use "http://localhost:8080/callback" as the redirect URI
// 2. Set the SPOTIFY_ID environment variable to the client ID you got in step 1.
// 3. Set the SPOTIFY_SECRET environment variable to the client secret from step 1.
package main
import (
"fmt"
"log"
"github.com/dixonwille/wmenu"
"gopkg.in/dixonwille/wlog.v2"
"github.com/zmb3/spotify"
"github.com/ahmetalpbalkan/go-cursor"
)
// and enter this value.
const redirectURI = "http://localhost:8080/callback"
const root_track_folder = "music/tracks/"
const root_playlists_folder = "music/playlists/"
const root_user_folder = "music/users/"
var (
auth = get_spotify_auth();
ch = make(chan *spotify.Client)
state = "abc123"
status = 1
client *spotify.Client
)
func main() {
menu := wmenu.NewMenu("Choose your Option (0-9). <return> to get back to menu.")
menu.Action(
func (opts []wmenu.Opt) error {
switch opts[0].Value {
case 1:
HowToSetEnvVariables()
case 2:
fmt.Println("~ starting 'Authorization Code Flow' Sequence ~")
client = StartAuthorizationCodeFlow()
case 3:
fmt.Println("~ starting 'Dowload a Track' Sequence ~")
DownloadTrack()
case 4:
fmt.Println("~ starting 'Download a Playlist' Sequence ~")
DownloadPlaylist()
case 5:
fmt.Println("~ starting 'Download all of my Playlists' Sequence ~")
DownloadAllPlaylistsOfUser()
case 6:
fmt.Println("~ starting 'Go to webapp' Sequence~")
startWebServer()
}
main()
return nil
})
fmt.Print(cursor.ClearEntireScreen())
fmt.Print(cursor.MoveTo(0,0))
if status > 1 {
fmt.Println("~ status => authenticated ~")
menu.Option(" Download a Track", 3, true, nil)
menu.Option(" Download a Playlist", 4, true, nil)
menu.Option(" Download all of my Playlists", 5, true, nil)
menu.Option(" Go to webapp", 6, true, nil)
} else {
fmt.Println("~ status => not authenticated ~")
menu.Option(" Set Client ID", 1, true, nil)
menu.Option(" Start Authorization Code Flow", 2, false, nil)
}
optionColor := wlog.None
questionColor := wlog.Color{}
responseColor := wlog.Color{}
errorColor := wlog.Color{}
menu.AddColor(optionColor, questionColor, responseColor, errorColor)
// menu.AddColor("green", "blue", "yellow", "yellow")
mainMenu := menu.Run()
if mainMenu != nil{
log.Fatal(mainMenu)
}
}

53
manual-download.log Normal file
View File

@ -0,0 +1,53 @@
Ótta - Sólstafir
Ótta - Sólstafir
Ótta - Sólstafir
Ótta - Sólstafir
Ótta - Sólstafir
Ótta - Sólstafir
Ótta - Sólstafir
Sie nannten ihn Putte - Erdmöbel
L'Exèrcit Que Vindrà - Els Pets
Þar Sem Enginn Fer - Sjálfviljugur - Árstíðir
Morgunn - Svavar Knútur
L'échappée - Barbagallo
La millor flor del balcó - La iaia
Posa'm més gin, David! - Mishima
Univers parallèles - Damien Robitaille
Croisières méditerranéennes - Bernard Lavilliers
Oppure no - Greta Panettieri
L'emmerdeuse - Eskelina
Bättre än så här - Pernilla Andersson
Dråba i sjøen - Tønes
Sommartjej - Josef Park
Arrastarte-Ei - Céu
Nonedaless - Wermonster
Borsch Antistar - Wermonster
Von den Identitäten - Manfred Groove
Gorilla Scapes - Lützenkirchen
Pillenkäfer - Boris Brejcha
Liitäjä - Antti Rasi
Ótta - Sólstafir
Ótta - Sólstafir
Ótta - Sólstafir
Sie nannten ihn Putte - Erdmöbel
L'Exèrcit Que Vindrà - Els Pets
Þar Sem Enginn Fer - Sjálfviljugur - Árstíðir
Ótta - Sólstafir
Sie nannten ihn Putte - Erdmöbel
Ótta - Sólstafir
Sie nannten ihn Putte - Erdmöbel
L'Exèrcit Que Vindrà - Els Pets
Þar Sem Enginn Fer - Sjálfviljugur - Árstíðir
Morgunn - Svavar Knútur
Ótta - Sólstafir
Sie nannten ihn Putte - Erdmöbel
L'Exèrcit Que Vindrà - Els Pets
Þar Sem Enginn Fer - Sjálfviljugur - Árstíðir
Morgunn - Svavar Knútur
Ótta - Sólstafir
Ótta - Sólstafir
Ótta - Sólstafir
Sie nannten ihn Putte - Erdmöbel
L'Exèrcit Que Vindrà - Els Pets
Þar Sem Enginn Fer - Sjálfviljugur - Árstíðir
Morgunn - Svavar Knútur

6
pages/head.html Normal file
View File

@ -0,0 +1,6 @@
{{define "head"}}
<head>
<title>freedom - for your music</title>
<link href="http://localhost:8088/static/tables.css" type="text/css" rel="stylesheet" />
</head>
{{end}}

27
pages/playlists.html Normal file
View File

@ -0,0 +1,27 @@
{{define "playlists"}}
<html>
{{template "head"}}
<body>
<form method="post" name="submitDownloadQueue" action="http://localhost:8088/submitDownloadQueue">
<input type="submit">
<table class="overview" cellspacing="0">
<tr class ="overview">
<th class="overview">ID</th>
<th class="overview">Name</th>
<th class="overview">Owner</th>
<th class="overview"></th>
</tr>
{{range .Items}}
<tr class="overview">
<td>{{.ID}}</td>
<td>{{.Name}}</td>
<td>{{.Owner}}</td>
<td><input type="checkbox" id="ID_{{.ID}}" name="name_{{.ID}}" value="value_{{.ID}}" checked></td>
</tr>
{{end}}
</table>
</form>
</body>
</html>
{{end}}

7957
playlist.json Normal file

File diff suppressed because it is too large Load Diff

7916
playlists_tracks.json Normal file

File diff suppressed because it is too large Load Diff

296
spotify-structs.go Normal file
View File

@ -0,0 +1,296 @@
package main
import (
"time"
)
type spotifyTrack struct {
Album struct {
AlbumType string `json:"album_type"`
Artists []struct {
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"artists"`
AvailableMarkets []string `json:"available_markets"`
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Images []struct {
Height int `json:"height"`
URL string `json:"url"`
Width int `json:"width"`
} `json:"images"`
Name string `json:"name"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"album"`
Artists []struct {
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"artists"`
AvailableMarkets []string `json:"available_markets"`
DiscNumber int `json:"disc_number"`
DurationMs int `json:"duration_ms"`
Explicit bool `json:"explicit"`
ExternalIds struct {
Isrc string `json:"isrc"`
} `json:"external_ids"`
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Name string `json:"name"`
Popularity int `json:"popularity"`
PreviewURL string `json:"preview_url"`
TrackNumber int `json:"track_number"`
Type string `json:"type"`
URI string `json:"uri"`
IsLocal bool `json:"is_local"`
}
type spotifyPlaylist struct {
Collaborative bool `json:"collaborative"`
Description interface{} `json:"description"`
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Followers struct {
Href interface{} `json:"href"`
Total int `json:"total"`
} `json:"followers"`
Href string `json:"href"`
ID string `json:"id"`
Images []struct {
Height int `json:"height"`
URL string `json:"url"`
Width int `json:"width"`
} `json:"images"`
Name string `json:"name"`
Owner struct {
DisplayName interface{} `json:"display_name"`
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"owner"`
Public bool `json:"public"`
SnapshotID string `json:"snapshot_id"`
Tracks struct {
Href string `json:"href"`
Items []struct {
AddedAt time.Time `json:"added_at"`
AddedBy struct {
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"added_by"`
IsLocal bool `json:"is_local"`
Track struct {
Album struct {
AlbumType string `json:"album_type"`
Artists []struct {
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"artists"`
AvailableMarkets []interface{} `json:"available_markets"`
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Images []struct {
Height int `json:"height"`
URL string `json:"url"`
Width int `json:"width"`
} `json:"images"`
Name string `json:"name"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"album"`
Artists []struct {
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"artists"`
AvailableMarkets []interface{} `json:"available_markets"`
DiscNumber int `json:"disc_number"`
DurationMs int `json:"duration_ms"`
Explicit bool `json:"explicit"`
ExternalIds struct {
Isrc string `json:"isrc"`
} `json:"external_ids"`
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Name string `json:"name"`
Popularity int `json:"popularity"`
PreviewURL interface{} `json:"preview_url"`
TrackNumber int `json:"track_number"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"track"`
} `json:"items"`
Limit int `json:"limit"`
Next string `json:"next"`
Offset int `json:"offset"`
Previous interface{} `json:"previous"`
Total int `json:"total"`
} `json:"tracks"`
Type string `json:"type"`
URI string `json:"uri"`
}
type spotifyPlaylistsOfUser struct {
Href string `json:"href"`
Items []struct {
Collaborative bool `json:"collaborative"`
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Images []struct {
Height int `json:"height"`
URL string `json:"url"`
Width int `json:"width"`
} `json:"images"`
Name string `json:"name"`
Owner struct {
DisplayName interface{} `json:"display_name"`
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"owner"`
Public bool `json:"public"`
SnapshotID string `json:"snapshot_id"`
Tracks struct {
Href string `json:"href"`
Total int `json:"total"`
} `json:"tracks"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"items"`
Limit int `json:"limit"`
Next *string `json:"next"`
Offset int `json:"offset"`
Previous interface{} `json:"previous"`
Total int `json:"total"`
}
type spotifyPlaylistsTracks struct {
Href string `json:"href"`
Items []struct {
AddedAt time.Time `json:"added_at"`
AddedBy struct {
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"added_by"`
IsLocal bool `json:"is_local"`
Track struct {
Album struct {
AlbumType string `json:"album_type"`
Artists []struct {
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"artists"`
AvailableMarkets []interface{} `json:"available_markets"`
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Images []struct {
Height int `json:"height"`
URL string `json:"url"`
Width int `json:"width"`
} `json:"images"`
Name string `json:"name"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"album"`
Artists []struct {
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"artists"`
AvailableMarkets []interface{} `json:"available_markets"`
DiscNumber int `json:"disc_number"`
DurationMs int `json:"duration_ms"`
Explicit bool `json:"explicit"`
ExternalIds struct {
Isrc string `json:"isrc"`
} `json:"external_ids"`
ExternalUrls struct {
Spotify string `json:"spotify"`
} `json:"external_urls"`
Href string `json:"href"`
ID string `json:"id"`
Name string `json:"name"`
Popularity int `json:"popularity"`
PreviewURL interface{} `json:"preview_url"`
TrackNumber int `json:"track_number"`
Type string `json:"type"`
URI string `json:"uri"`
} `json:"track"`
} `json:"items"`
Limit int `json:"limit"`
Next *string `json:"next"`
Offset int `json:"offset"`
Previous *string `json:"previous"`
Total int `json:"total"`
}

167
spotify.go Normal file
View File

@ -0,0 +1,167 @@
package main
import (
"encoding/json"
// "log"
"fmt"
"net/http"
"github.com/zmb3/spotify"
"io/ioutil"
)
const baseURL_track = "https://api.spotify.com/v1/tracks/"
const baseURL_playlist = "https://api.spotify.com/v1/playlists/"
const baseURL_playlists = "https://api.spotify.com/v1/me/playlists"
func get_spotify_auth() (auth spotify.Authenticator){
auth = spotify.NewAuthenticator(redirectURI, spotify.ScopeUserReadPrivate, spotify.ScopePlaylistReadPrivate, spotify.ScopePlaylistReadCollaborative, spotify.ScopeUserLibraryRead)
return
}
// TODO: write this fkn func
func check_if_track_is_valid(track_id string) (state bool) {
state = true
// url := baseURL_track + track_id
// httpClient := &http.Client{}
// req, _ := http.NewRequest("GET", url, nil)
// req.Header.Set("Authorization", "Bearer "+oauthToken)
// res, _ := httpClient.Do(req)
// body, _ := ioutil.ReadAll(res.Body)
// data := new(spotifyTrack)
// json.Unmarshal(body, &data)
// if data.IsLocal {
// state = false
// }
return state
}
func download_all_playlist_of_user(owner_id string, folder string) {
url := baseURL_playlists + "?limit=50&offset=0"
httpClient := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer "+oauthToken)
res, _ := httpClient.Do(req)
body, _ := ioutil.ReadAll(res.Body)
data := new(spotifyPlaylistsOfUser)
json.Unmarshal(body, &data)
var counter = 0
for _,playlist := range data.Items {
fmt.Printf("Downloading Playlist => %s <=\n",playlist.Name)
download_playlist_to_folder(playlist.ID,playlist.Owner.ID,folder)
}
if data.Total > 50 {
for(data.Next != nil) {
nextUrl := *data.Next
request, _ := http.NewRequest("GET",nextUrl, nil)
request.Header.Set("Authorization", "Bearer "+oauthToken)
response, _ := httpClient.Do(request)
body, _ = ioutil.ReadAll(response.Body)
json.Unmarshal(body, &data)
for _,playlist := range data.Items {
counter++
fmt.Printf("Downloading Playlist: => %s <=\n",playlist.Name)
download_playlist_to_folder(playlist.ID,playlist.Owner.ID,folder)
}
}
}
}
func download_playlist_to_folder(playlist_id string, owner_id string, folder string) {
playlist_name := get_name_of_playlist(playlist_id,owner_id)
url := baseURL_playlist + playlist_id + "/tracks?limit=100&offset=0"
httpClient := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer "+oauthToken)
res, _ := httpClient.Do(req)
body, _ := ioutil.ReadAll(res.Body)
data := new(spotifyPlaylistsTracks)
json.Unmarshal(body, &data)
folder = folder + playlist_name+"/"
var counter = 0
for _,track := range data.Items {
counter++
fmt.Println("Nr: ",counter," | Title: ",track.Track.Name," | Artist: ",track.Track.Artists[0].Name)
if track.Track.ID == "" {
// TODO: add file to manual_download list if no spotify id exist
fmt.Printf("track '%s - %s' is a local file. please download this track manually",track.Track.Artists[0].Name,track.Track.Name)
} else {
download_track_to_folder(track.Track.ID,folder)
}
}
if data.Total > 100 {
for(data.Next != nil) {
nextUrl := *data.Next
request, _ := http.NewRequest("GET",nextUrl, nil)
request.Header.Set("Authorization", "Bearer "+oauthToken)
response, _ := httpClient.Do(request)
body, _ = ioutil.ReadAll(response.Body)
json.Unmarshal(body, &data)
for _,track := range data.Items {
counter++
fmt.Println("Nr: ",counter," | Title: ",track.Track.Name," | Artist: ",track.Track.Artists[0].Name)
if track.Track.ID == "" {
// TODO: add file to manual_download list if no spotify id exist
fmt.Printf("track '%s - %s' is a local file. please download this track manually\n",track.Track.Artists[0].Name,track.Track.Name)
} else {
download_track_to_folder(track.Track.ID,folder)
}
}
}
}
fmt.Println("--------------------")
}
func get_name_of_playlist(playlist_id string, owner_id string) (name string) {
url := baseURL_playlist + playlist_id
httpClient := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer "+oauthToken)
res, _ := httpClient.Do(req)
body, _ := ioutil.ReadAll(res.Body)
data := new(spotifyPlaylist)
json.Unmarshal(body, &data)
name = data.Name
return
}
func download_track_to_folder(track_id string, folder string) {
track_name, artist_name := get_track_and_artist_name(track_id)
filename := track_name+" - "+artist_name
youtube_url := search_on_youtube(filename)
download_mp3_from_youtube(youtube_url,folder,filename)
}
// TODO: return error on failure
func get_track_and_artist_name(track_id string) (track_name string, artist_name string){
url := baseURL_track + track_id + "?market=DE"
httpClient := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer "+oauthToken)
res, _ := httpClient.Do(req)
body, _ := ioutil.ReadAll(res.Body)
data := new(spotifyTrack)
json.Unmarshal(body, &data)
return data.Name, data.Artists[0].Name
}

71
static/tables.css Normal file
View File

@ -0,0 +1,71 @@
/* jailOverview */
table.overview {
overflow:hidden;
border:2px solid #d3d3d3;
width:100%;
margin:0% auto 0;
-moz-border-radius:9px; /* FF1+ */
-webkit-border-radius:5px; /* Saf3-4 */
border-radius:9px;
-moz-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
}
tr.overview:nth-child(even) {background: #CCC}
th.overview {
text-align: left;
}
/* jailDetails */
table.details {
overflow:hidden;
border:1px solid #d3d3d3;
width:25%;
margin:2% 0;
-moz-border-radius:9px; /* FF1+ */
-webkit-border-radius:5px; /* Saf3-4 */
border-radius:9px;
-moz-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
}
table.state {
display: block;
text-align: left;
overflow:hidden;
border:2px solid #d3d3d3;
width:15%;
margin-left: 50px;
-moz-border-radius:9px; /* FF1+ */
-webkit-border-radius:5px; /* Saf3-4 */
border-radius:9px;
-moz-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
}
table.not-running {
background: red;
}
table.running {
background: green;
}
table.details tr:hover {background-color: #f5f5f5}
table.details th {
text-align: left;
}
.status-light {
height: 20px;
width: 20px;
margin-right: 10px;
border-radius: 50%;
margin-left: 10px;
}
.status-light.up {
background-color: #0b0;
}
.status-light.down {
background-color: #b00;
}

65
track.json Normal file
View File

@ -0,0 +1,65 @@
{
"album" : {
"album_type" : "album",
"artists" : [ {
"external_urls" : {
"spotify" : "https://open.spotify.com/artist/0C0XlULifJtAgn6ZNCW2eu"
},
"href" : "https://api.spotify.com/v1/artists/0C0XlULifJtAgn6ZNCW2eu",
"id" : "0C0XlULifJtAgn6ZNCW2eu",
"name" : "The Killers",
"type" : "artist",
"uri" : "spotify:artist:0C0XlULifJtAgn6ZNCW2eu"
} ],
"available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "ID", "IE", "IS", "IT", "JP", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "SE", "SG", "SK", "SV", "TH", "TR", "TW", "US", "UY", "VN" ],
"external_urls" : {
"spotify" : "https://open.spotify.com/album/4OHNH3sDzIxnmUADXzv2kT"
},
"href" : "https://api.spotify.com/v1/albums/4OHNH3sDzIxnmUADXzv2kT",
"id" : "4OHNH3sDzIxnmUADXzv2kT",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/ac68a9e4a867ec3ce8249cd90a2d7c73755fb487",
"width" : 629
}, {
"height" : 300,
"url" : "https://i.scdn.co/image/d0186ad64df7d6fc5f65c20c7d16f4279ffeb815",
"width" : 295
}, {
"height" : 64,
"url" : "https://i.scdn.co/image/7c3ec33d478f5f517eeb5339c2f75f150e4d601e",
"width" : 63
} ],
"name" : "Hot Fuss (Deluxe Version)",
"type" : "album",
"uri" : "spotify:album:4OHNH3sDzIxnmUADXzv2kT"
},
"artists" : [ {
"external_urls" : {
"spotify" : "https://open.spotify.com/artist/0C0XlULifJtAgn6ZNCW2eu"
},
"href" : "https://api.spotify.com/v1/artists/0C0XlULifJtAgn6ZNCW2eu",
"id" : "0C0XlULifJtAgn6ZNCW2eu",
"name" : "The Killers",
"type" : "artist",
"uri" : "spotify:artist:0C0XlULifJtAgn6ZNCW2eu"
} ],
"available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "ID", "IE", "IS", "IT", "JP", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "SE", "SG", "SK", "SV", "TH", "TR", "TW", "US", "UY", "VN" ],
"disc_number" : 1,
"duration_ms" : 222200,
"explicit" : false,
"external_ids" : {
"isrc" : "GBFFP0300052"
},
"external_urls" : {
"spotify" : "https://open.spotify.com/track/3n3Ppam7vgaVa1iaRUc9Lp"
},
"href" : "https://api.spotify.com/v1/tracks/3n3Ppam7vgaVa1iaRUc9Lp",
"id" : "3n3Ppam7vgaVa1iaRUc9Lp",
"name" : "Mr. Brightside",
"popularity" : 82,
"preview_url" : "https://p.scdn.co/mp3-preview/4839b070015ab7d6de9fec1756e1f3096d908fba?cid=aebff49ecd9e446ba573989feda8cb05",
"track_number" : 2,
"type" : "track",
"uri" : "spotify:track:3n3Ppam7vgaVa1iaRUc9Lp"
}

669
user_playlists.json Normal file
View File

@ -0,0 +1,669 @@
{
"href" : "https://api.spotify.com/v1/users/fireno/playlists?offset=0&limit=20",
"items" : [ {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/5SakrMHEosUtR34BCvuIB4"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/5SakrMHEosUtR34BCvuIB4",
"id" : "5SakrMHEosUtR34BCvuIB4",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/63cf47c5df6fa98c10fc26f1bb6c54e05761f961",
"width" : 640
} ],
"name" : "Wermonster Katalyst Sessions, Vol. 2",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "HrTm3haQXscVBeJEI2i2d0t6EqeY/VIYe6GNdbZSuOfjYd5fFQXmj5PjmsyLp8K8",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/5SakrMHEosUtR34BCvuIB4/tracks",
"total" : 11
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:5SakrMHEosUtR34BCvuIB4"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/spudodud/playlist/2rJq9tx7Oq7ugp8LtIU1Sq"
},
"href" : "https://api.spotify.com/v1/users/spudodud/playlists/2rJq9tx7Oq7ugp8LtIU1Sq",
"id" : "2rJq9tx7Oq7ugp8LtIU1Sq",
"images" : [ {
"height" : 640,
"url" : "https://mosaic.scdn.co/640/34c7435de0f8bcec06fa4290fd995bd3a719b1b615718e786d040966ce6b14be51481f0440d7fa1a1204cb8c2590bc23a08213b489442ddc17392a91770de29f3912e2ac8b69dd61c05871e287bfe71f",
"width" : 640
}, {
"height" : 300,
"url" : "https://mosaic.scdn.co/300/34c7435de0f8bcec06fa4290fd995bd3a719b1b615718e786d040966ce6b14be51481f0440d7fa1a1204cb8c2590bc23a08213b489442ddc17392a91770de29f3912e2ac8b69dd61c05871e287bfe71f",
"width" : 300
}, {
"height" : 60,
"url" : "https://mosaic.scdn.co/60/34c7435de0f8bcec06fa4290fd995bd3a719b1b615718e786d040966ce6b14be51481f0440d7fa1a1204cb8c2590bc23a08213b489442ddc17392a91770de29f3912e2ac8b69dd61c05871e287bfe71f",
"width" : 60
} ],
"name" : "Cabvno - F e e l i n g s",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/spudodud"
},
"href" : "https://api.spotify.com/v1/users/spudodud",
"id" : "spudodud",
"type" : "user",
"uri" : "spotify:user:spudodud"
},
"public" : false,
"snapshot_id" : "LGfDqFtGvnlOnmWQDsJlPAPfPDx2ZCWeeKOUgySmZ3vpoZu5S+EuU7i15t0lqaUB",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/spudodud/playlists/2rJq9tx7Oq7ugp8LtIU1Sq/tracks",
"total" : 16
},
"type" : "playlist",
"uri" : "spotify:user:spudodud:playlist:2rJq9tx7Oq7ugp8LtIU1Sq"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/1138694516/playlist/3ZeOTuO6V51syAUQ0SxRCr"
},
"href" : "https://api.spotify.com/v1/users/1138694516/playlists/3ZeOTuO6V51syAUQ0SxRCr",
"id" : "3ZeOTuO6V51syAUQ0SxRCr",
"images" : [ {
"height" : 640,
"url" : "https://mosaic.scdn.co/640/1a7fbb2c31ef7f97f29e5199d229fde047a7beea9b5be0773fe25bc5a34a66f237a08758528500aad19096594fe2d8a972629ac0fe1ecaa5f6c0b13594a13f0b0a4acd42bf2f8d72b5b0b9447235d6ce",
"width" : 640
}, {
"height" : 300,
"url" : "https://mosaic.scdn.co/300/1a7fbb2c31ef7f97f29e5199d229fde047a7beea9b5be0773fe25bc5a34a66f237a08758528500aad19096594fe2d8a972629ac0fe1ecaa5f6c0b13594a13f0b0a4acd42bf2f8d72b5b0b9447235d6ce",
"width" : 300
}, {
"height" : 60,
"url" : "https://mosaic.scdn.co/60/1a7fbb2c31ef7f97f29e5199d229fde047a7beea9b5be0773fe25bc5a34a66f237a08758528500aad19096594fe2d8a972629ac0fe1ecaa5f6c0b13594a13f0b0a4acd42bf2f8d72b5b0b9447235d6ce",
"width" : 60
} ],
"name" : "Chaos Computer Club",
"owner" : {
"display_name" : "Max Jakob",
"external_urls" : {
"spotify" : "https://open.spotify.com/user/1138694516"
},
"href" : "https://api.spotify.com/v1/users/1138694516",
"id" : "1138694516",
"type" : "user",
"uri" : "spotify:user:1138694516"
},
"public" : false,
"snapshot_id" : "yNg/Gg9EiK3sJaxWx5ir56snYMONwrPS3XnUS297nwvGmYGWOHMKzcVf8Zq1CdPw",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/1138694516/playlists/3ZeOTuO6V51syAUQ0SxRCr/tracks",
"total" : 120
},
"type" : "playlist",
"uri" : "spotify:user:1138694516:playlist:3ZeOTuO6V51syAUQ0SxRCr"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/1NFtmluZwJwjSyYg01C4ci"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/1NFtmluZwJwjSyYg01C4ci",
"id" : "1NFtmluZwJwjSyYg01C4ci",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/a7e3151a7f9d8b4acf6c60002d3ce51820a8a906",
"width" : 640
} ],
"name" : "Monophonics — Sound of Sinning",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "kQ7tUJvphWbhapFWOV9wDVCoVE8BlBZqiBnTyaVUryNut7IbDjYKxsboqe3BT+P8",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/1NFtmluZwJwjSyYg01C4ci/tracks",
"total" : 11
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:1NFtmluZwJwjSyYg01C4ci"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/spotify/playlist/37i9dQZF1E9KaZS06fvYeF"
},
"href" : "https://api.spotify.com/v1/users/spotify/playlists/37i9dQZF1E9KaZS06fvYeF",
"id" : "37i9dQZF1E9KaZS06fvYeF",
"images" : [ {
"height" : null,
"url" : "https://lineup-images.scdn.co/your-top-songs-2017_DEFAULT-en.jpg",
"width" : null
} ],
"name" : "Your Top Songs 2017",
"owner" : {
"display_name" : "Spotify",
"external_urls" : {
"spotify" : "https://open.spotify.com/user/spotify"
},
"href" : "https://api.spotify.com/v1/users/spotify",
"id" : "spotify",
"type" : "user",
"uri" : "spotify:user:spotify"
},
"public" : false,
"snapshot_id" : "MAJs40+OEEDiN6WXWsV2+ULBssCJKIkQZP11ns+iOvy9nJK2YkqSv1wWhce0k8H/NdaY6iHEEns=",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/spotify/playlists/37i9dQZF1E9KaZS06fvYeF/tracks",
"total" : 100
},
"type" : "playlist",
"uri" : "spotify:user:spotify:playlist:37i9dQZF1E9KaZS06fvYeF"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/0g6NEmZTsiiWTOqpiK0haQ"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/0g6NEmZTsiiWTOqpiK0haQ",
"id" : "0g6NEmZTsiiWTOqpiK0haQ",
"images" : [ {
"height" : 640,
"url" : "https://mosaic.scdn.co/640/b2819b73e847485a96534c94f51d80d61762596480f4d7cd0dc9d0d095b469b698804c502baaf0bd95b83949bcbcf6391e1100239e73644e144edb0aa38fa4e806f58470a4c0a899f79f1c49e9299be0",
"width" : 640
}, {
"height" : 300,
"url" : "https://mosaic.scdn.co/300/b2819b73e847485a96534c94f51d80d61762596480f4d7cd0dc9d0d095b469b698804c502baaf0bd95b83949bcbcf6391e1100239e73644e144edb0aa38fa4e806f58470a4c0a899f79f1c49e9299be0",
"width" : 300
}, {
"height" : 60,
"url" : "https://mosaic.scdn.co/60/b2819b73e847485a96534c94f51d80d61762596480f4d7cd0dc9d0d095b469b698804c502baaf0bd95b83949bcbcf6391e1100239e73644e144edb0aa38fa4e806f58470a4c0a899f79f1c49e9299be0",
"width" : 60
} ],
"name" : "The Ones That Got Away",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "ZtdUslCA0tFlmpKMeG/J+LUJ2BRqp1OUi/8pjddmY3uKeC5DUH44DPjkcmB8J+AL",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/0g6NEmZTsiiWTOqpiK0haQ/tracks",
"total" : 30
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:0g6NEmZTsiiWTOqpiK0haQ"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/0lcf7RFedS7iASJwVNVO2z"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/0lcf7RFedS7iASJwVNVO2z",
"id" : "0lcf7RFedS7iASJwVNVO2z",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/005b3e947c5496795a20168cd0de619fe44ad611",
"width" : 640
} ],
"name" : "Spitkid Punk Is Dad",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "aU3zrm4ciec16HfcIzb8e6j7vSuz58pH28H5qsjOEVLTTaJeIzorkQ4Er25nzxMl",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/0lcf7RFedS7iASJwVNVO2z/tracks",
"total" : 5
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:0lcf7RFedS7iASJwVNVO2z"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/4hx02vTCeVkU5qOsfVKLUx"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/4hx02vTCeVkU5qOsfVKLUx",
"id" : "4hx02vTCeVkU5qOsfVKLUx",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/b8bd07481c4a13efac013aba7f51d6fb55fa002b",
"width" : 640
} ],
"name" : "6 Feet Beneath the Moon",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : true,
"snapshot_id" : "3E0WEU+RYHwfoHTqOIiF+9rRfhqSotsJTk4tQTK9MFjOL+JtEZ86zfOH+B/Mm6Ns",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/4hx02vTCeVkU5qOsfVKLUx/tracks",
"total" : 14
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:4hx02vTCeVkU5qOsfVKLUx"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/1138581523/playlist/6jlYVxyao58RK5R8Awvw4L"
},
"href" : "https://api.spotify.com/v1/users/1138581523/playlists/6jlYVxyao58RK5R8Awvw4L",
"id" : "6jlYVxyao58RK5R8Awvw4L",
"images" : [ {
"height" : null,
"url" : "https://pl.scdn.co/images/pl/default/44c71263440bab6033b7b0e81c61a7c895a3f955",
"width" : null
} ],
"name" : "Gott zieht alles.",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/1138581523"
},
"href" : "https://api.spotify.com/v1/users/1138581523",
"id" : "1138581523",
"type" : "user",
"uri" : "spotify:user:1138581523"
},
"public" : false,
"snapshot_id" : "XCDqMhkHDlCcE4dGFjnuzZD1Lfw/97l0wkajPGq/Jh/QSWU942cak0r2ln026eXE",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/1138581523/playlists/6jlYVxyao58RK5R8Awvw4L/tracks",
"total" : 505
},
"type" : "playlist",
"uri" : "spotify:user:1138581523:playlist:6jlYVxyao58RK5R8Awvw4L"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/chillhopmusic/playlist/74sUjcvpGfdOvCHvgzNEDO"
},
"href" : "https://api.spotify.com/v1/users/chillhopmusic/playlists/74sUjcvpGfdOvCHvgzNEDO",
"id" : "74sUjcvpGfdOvCHvgzNEDO",
"images" : [ {
"height" : null,
"url" : "https://pl.scdn.co/images/pl/default/ceaa77e94addd83567eb2eafeea3db5b912f5aa8",
"width" : null
} ],
"name" : "lofi hip hop beats [lo-fi hip hop] Chillhop Music \\ Chilledcow",
"owner" : {
"display_name" : "Chillhop Music",
"external_urls" : {
"spotify" : "https://open.spotify.com/user/chillhopmusic"
},
"href" : "https://api.spotify.com/v1/users/chillhopmusic",
"id" : "chillhopmusic",
"type" : "user",
"uri" : "spotify:user:chillhopmusic"
},
"public" : false,
"snapshot_id" : "ZJ+886d2bJtcFeJKO4uk983aNF+gTBCX7PIA4xNPBb0aqQMkUxHR1Bhbgb4XD18n",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/chillhopmusic/playlists/74sUjcvpGfdOvCHvgzNEDO/tracks",
"total" : 150
},
"type" : "playlist",
"uri" : "spotify:user:chillhopmusic:playlist:74sUjcvpGfdOvCHvgzNEDO"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/3ZNXU8xlURnX63R3KLTJZB"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/3ZNXU8xlURnX63R3KLTJZB",
"id" : "3ZNXU8xlURnX63R3KLTJZB",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/2d8dd23437aaed8331fe93a7a944cf39ffd0dbf1",
"width" : 640
} ],
"name" : "Lee Hazlewood Lounge Legends: Lee Hazelwood",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "rUtjLfYGcy+AbCacQJF2Qh6oiDT2sUyb2tratprNKYvNjS+JP0FyQfrePFvno+Lx",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/3ZNXU8xlURnX63R3KLTJZB/tracks",
"total" : 20
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:3ZNXU8xlURnX63R3KLTJZB"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/6xLSmobth6DhSBr5MgWxjF"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/6xLSmobth6DhSBr5MgWxjF",
"id" : "6xLSmobth6DhSBr5MgWxjF",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/ea33d6ce252ca8c556c67ee500f5c2891dc0dcbc",
"width" : 640
} ],
"name" : "Vini Vici Future Classics",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "YeZbovTdyerZIqkefPE+1DwbngUf1GSn2fFv1Wo56W0oXMarj64tbx0sk1Zp4s2b",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/6xLSmobth6DhSBr5MgWxjF/tracks",
"total" : 9
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:6xLSmobth6DhSBr5MgWxjF"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/7oSTKcnx9xzfkj7NaJYpAX"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/7oSTKcnx9xzfkj7NaJYpAX",
"id" : "7oSTKcnx9xzfkj7NaJYpAX",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/d9b728446d892db1627ef5c1f1f6990d934e2517",
"width" : 640
} ],
"name" : "Judas Priest Painkiller",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "B1GAuizaIMuYqUVkEtNnWwk0YmvtZC9PKIxVmtIEUe2C+8aUFxym7XaleRJOatFk",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/7oSTKcnx9xzfkj7NaJYpAX/tracks",
"total" : 12
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:7oSTKcnx9xzfkj7NaJYpAX"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/6kgeO8Mo44Kw6aNYkvc5Wq"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/6kgeO8Mo44Kw6aNYkvc5Wq",
"id" : "6kgeO8Mo44Kw6aNYkvc5Wq",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/f526bf6ad7ba2907a95cf96db6e134f61d92bef0",
"width" : 640
} ],
"name" : "Prong Cleansing",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "2lnKxC0dD48eVJB/kYD9HwpRfGBpYRcMet6rzfTj80pb1amMY4JrwNv49OTDCJLn",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/6kgeO8Mo44Kw6aNYkvc5Wq/tracks",
"total" : 12
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:6kgeO8Mo44Kw6aNYkvc5Wq"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/cahwilms/playlist/2aPPzVTFqvhTFkjVesKGF4"
},
"href" : "https://api.spotify.com/v1/users/cahwilms/playlists/2aPPzVTFqvhTFkjVesKGF4",
"id" : "2aPPzVTFqvhTFkjVesKGF4",
"images" : [ {
"height" : 640,
"url" : "https://mosaic.scdn.co/640/072567be42da35e4320d85b209e7008283af521f3ba36422dc3cc216c6c039d182a6237383360999da66ee97e80ceba8af4c04ff931a4ade9a97713c38d3737416634d1af503643ca6fc011a45322dab",
"width" : 640
}, {
"height" : 300,
"url" : "https://mosaic.scdn.co/300/072567be42da35e4320d85b209e7008283af521f3ba36422dc3cc216c6c039d182a6237383360999da66ee97e80ceba8af4c04ff931a4ade9a97713c38d3737416634d1af503643ca6fc011a45322dab",
"width" : 300
}, {
"height" : 60,
"url" : "https://mosaic.scdn.co/60/072567be42da35e4320d85b209e7008283af521f3ba36422dc3cc216c6c039d182a6237383360999da66ee97e80ceba8af4c04ff931a4ade9a97713c38d3737416634d1af503643ca6fc011a45322dab",
"width" : 60
} ],
"name" : "Anders",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/cahwilms"
},
"href" : "https://api.spotify.com/v1/users/cahwilms",
"id" : "cahwilms",
"type" : "user",
"uri" : "spotify:user:cahwilms"
},
"public" : false,
"snapshot_id" : "R2SlBvks37Ig91TgWHjgMgNG5OCGrUt6tyE27WW5V0Eyx90HCle/Bc+Iuahz2wwO",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/cahwilms/playlists/2aPPzVTFqvhTFkjVesKGF4/tracks",
"total" : 36
},
"type" : "playlist",
"uri" : "spotify:user:cahwilms:playlist:2aPPzVTFqvhTFkjVesKGF4"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/4yzjygtb9g0s7RjTbGtykg"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/4yzjygtb9g0s7RjTbGtykg",
"id" : "4yzjygtb9g0s7RjTbGtykg",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/fbba1f95f668d8a8189fd56a44bb8140965a4dcf",
"width" : 640
} ],
"name" : "Limp Bizkit Results May Vary",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "928IsyzrP7f95eI0MHIOzAJ5Y1O8re825AIIc+Pzd5r8NHaPlQMj/e+Gj8T9NwyA",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/4yzjygtb9g0s7RjTbGtykg/tracks",
"total" : 18
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:4yzjygtb9g0s7RjTbGtykg"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/4VHuFikSCbrbsAOBNZMuc0"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/4VHuFikSCbrbsAOBNZMuc0",
"id" : "4VHuFikSCbrbsAOBNZMuc0",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/995f6d56c0930a316f025e88f1b67d046fc785ce",
"width" : 640
} ],
"name" : "Limp Bizkit New Old Songs",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "IOqztjtE8QOBiAMcEpzg5Zc0iKRvVyPUCfzkRn8cgHksWxCRXeiEIricxG+ARbWp",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/4VHuFikSCbrbsAOBNZMuc0/tracks",
"total" : 16
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:4VHuFikSCbrbsAOBNZMuc0"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/1166762945/playlist/16SVZnYC3bIffe8wzeec2g"
},
"href" : "https://api.spotify.com/v1/users/1166762945/playlists/16SVZnYC3bIffe8wzeec2g",
"id" : "16SVZnYC3bIffe8wzeec2g",
"images" : [ {
"height" : 640,
"url" : "https://mosaic.scdn.co/640/6d62004edf00a46a0a405e2a3e26f16f4758729ca096eb8d085c2ad3967684a3ce3e329e5ded731f6793b455c8cfc0852ee13bca5cb5e6ad575377d11f2c920d3f98d0d69608fddedaef133b43afe325",
"width" : 640
}, {
"height" : 300,
"url" : "https://mosaic.scdn.co/300/6d62004edf00a46a0a405e2a3e26f16f4758729ca096eb8d085c2ad3967684a3ce3e329e5ded731f6793b455c8cfc0852ee13bca5cb5e6ad575377d11f2c920d3f98d0d69608fddedaef133b43afe325",
"width" : 300
}, {
"height" : 60,
"url" : "https://mosaic.scdn.co/60/6d62004edf00a46a0a405e2a3e26f16f4758729ca096eb8d085c2ad3967684a3ce3e329e5ded731f6793b455c8cfc0852ee13bca5cb5e6ad575377d11f2c920d3f98d0d69608fddedaef133b43afe325",
"width" : 60
} ],
"name" : "Hotline Miami 2 OST",
"owner" : {
"display_name" : "Szczepan Kozal",
"external_urls" : {
"spotify" : "https://open.spotify.com/user/1166762945"
},
"href" : "https://api.spotify.com/v1/users/1166762945",
"id" : "1166762945",
"type" : "user",
"uri" : "spotify:user:1166762945"
},
"public" : false,
"snapshot_id" : "WJqWiq1eJI0UhSiPk2ZG962ijsgiFMrNmGkO87fW+vkVHjE5Y0eF6xDsj0kipSM0",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/1166762945/playlists/16SVZnYC3bIffe8wzeec2g/tracks",
"total" : 40
},
"type" : "playlist",
"uri" : "spotify:user:1166762945:playlist:16SVZnYC3bIffe8wzeec2g"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/2ETuPRlZewzyOQqD2mRENg"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/2ETuPRlZewzyOQqD2mRENg",
"id" : "2ETuPRlZewzyOQqD2mRENg",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/b32b1124650dbd323cd111dbbccbb49be8e65057",
"width" : 640
} ],
"name" : "winter / metals",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "Zc5+uJIE8K9YfulH3BOgmW//tNxWUyKBsz9qfjyzLuIZFXPLRFNTvX+xZttLYixT",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/2ETuPRlZewzyOQqD2mRENg/tracks",
"total" : 1
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:2ETuPRlZewzyOQqD2mRENg"
}, {
"collaborative" : false,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno/playlist/7geF25MVtBAgrT2D5wZWCS"
},
"href" : "https://api.spotify.com/v1/users/fireno/playlists/7geF25MVtBAgrT2D5wZWCS",
"id" : "7geF25MVtBAgrT2D5wZWCS",
"images" : [ {
"height" : null,
"url" : "https://pl.scdn.co/images/pl/default/49eb388d415f6b5765fa7f666ca2a8f9c68c05f0",
"width" : null
} ],
"name" : "dark souls",
"owner" : {
"display_name" : null,
"external_urls" : {
"spotify" : "https://open.spotify.com/user/fireno"
},
"href" : "https://api.spotify.com/v1/users/fireno",
"id" : "fireno",
"type" : "user",
"uri" : "spotify:user:fireno"
},
"public" : false,
"snapshot_id" : "8cfsxUDwg1p9xjDNparGBtskV3Y88F9NpD3vtY9TbFEU0tdt8d4kTh1/Sav7zw56",
"tracks" : {
"href" : "https://api.spotify.com/v1/users/fireno/playlists/7geF25MVtBAgrT2D5wZWCS/tracks",
"total" : 8
},
"type" : "playlist",
"uri" : "spotify:user:fireno:playlist:7geF25MVtBAgrT2D5wZWCS"
} ],
"limit" : 20,
"next" : "https://api.spotify.com/v1/users/fireno/playlists?offset=20&limit=20",
"offset" : 0,
"previous" : null,
"total" : 71
}

17
utils.go Normal file
View File

@ -0,0 +1,17 @@
package main
import (
"fmt"
"regexp"
)
func waitForInput() {
var dummy string
_, _ = fmt.Scanln(&dummy)
}
func cleanString(s string) (cleans string){
reg, _ := regexp.Compile("[^a-zA-Z0-9 ]+")
cleans = reg.ReplaceAllString(s, "")
return
}

107
web.go Normal file
View File

@ -0,0 +1,107 @@
package main
import (
// "os"
"fmt"
"net/http"
"html/template"
"regexp"
"io/ioutil"
"encoding/json"
)
var templates = template.Must(template.ParseGlob("pages/*.html"))
var validPath = regexp.MustCompile("^/(webclient)/(.*)$")
type Page struct {
Title string
Body []byte
}
// func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
// fmt.Println("Running makeHandler")
// return func(w http.ResponseWriter, r *http.Request) {
// m := validPath.FindStringSubmatch(r.URL.Path)
// if m == nil {
// http.NotFound(w, r)
// return
// }
// fmt.Println("makeHandler::request::" + r.RequestURI)
// fn(w, r, m[2])
// }
// }
type testStructForWeb struct {
ID string
Name string
Owner string
}
type Context struct {
Items []testStructForWeb
}
func serveSingle(pattern string, filename string) {
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, filename)
})
}
func webclientHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("webclientHandler called")
var result []testStructForWeb
url := baseURL_playlists + "?limit=50&offset=0"
httpClient := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer "+oauthToken)
res, _ := httpClient.Do(req)
body, _ := ioutil.ReadAll(res.Body)
data := new(spotifyPlaylistsOfUser)
json.Unmarshal(body, &data)
var counter = 0
for _,playlist := range data.Items {
counter++
result = append(result, testStructForWeb{ID: playlist.ID, Name: playlist.Name, Owner: (playlist.Owner.ID)})
}
if data.Total > 50 {
for(data.Next != nil) {
nextUrl := *data.Next
request, _ := http.NewRequest("GET",nextUrl, nil)
request.Header.Set("Authorization", "Bearer "+oauthToken)
response, _ := httpClient.Do(request)
body, _ = ioutil.ReadAll(response.Body)
json.Unmarshal(body, &data)
for _,playlist := range data.Items {
counter++
result = append(result, testStructForWeb{ID: playlist.ID, Name: playlist.Name, Owner: playlist.Owner.ID})
}
}
}
playlists := Context{Items: result}
templates.ExecuteTemplate(w, "playlists", playlists)
}
func submitDownloadQueueHandler(w http.ResponseWriter, r *http.Request) {
// for playlist_id in all_playlists
// if r.PostFormValue(playlist_id)
// end for
}
func startWebServer() {
http.HandleFunc("/webclient/", webclientHandler)
http.HandleFunc("/submitDownloadQueue/", submitDownloadQueueHandler)
serveSingle("/static/tables.css", "./static/tables.css")
fmt.Println("http://localhost:8088/webclient")
http.ListenAndServe("localhost:8088", nil)
}

26
youtube-dl.go Normal file
View File

@ -0,0 +1,26 @@
package main
import (
// "fmt"
// "net/http"
// "net/url"
// "strings"
)
// TODO: make POST url global configurable
func download_mp3_from_youtube(youtube_url string, folder string, filename string) {
if (youtube_url != "" && folder != "" && filename != "") {
// form := url.Values{}
// form.Add("url", youtube_url)
// form.Add("folder", folder)
// form.Add("filename", filename)
// httpClient := &http.Client{}
// req, _ := http.NewRequest("POST", "http://127.0.0.1:1234/work", strings.NewReader(form.Encode()))
// _, err := httpClient.Do(req)
// if err != nil {
// fmt.Printf("Command finished with error: %v", err)
// }
}
}

49
youtube-structs.go Normal file
View File

@ -0,0 +1,49 @@
package main
import(
"time"
)
type youtubeSearchResult struct {
Kind string `json:"kind"`
Etag string `json:"etag"`
NextPageToken string `json:"nextPageToken"`
RegionCode string `json:"regionCode"`
PageInfo struct {
TotalResults int `json:"totalResults"`
ResultsPerPage int `json:"resultsPerPage"`
} `json:"pageInfo"`
Items []struct {
Kind string `json:"kind"`
Etag string `json:"etag"`
ID struct {
Kind string `json:"kind"`
VideoID string `json:"videoId"`
} `json:"id"`
Snippet struct {
PublishedAt time.Time `json:"publishedAt"`
ChannelID string `json:"channelId"`
Title string `json:"title"`
Description string `json:"description"`
Thumbnails struct {
Default struct {
URL string `json:"url"`
Width int `json:"width"`
Height int `json:"height"`
} `json:"default"`
Medium struct {
URL string `json:"url"`
Width int `json:"width"`
Height int `json:"height"`
} `json:"medium"`
High struct {
URL string `json:"url"`
Width int `json:"width"`
Height int `json:"height"`
} `json:"high"`
} `json:"thumbnails"`
ChannelTitle string `json:"channelTitle"`
LiveBroadcastContent string `json:"liveBroadcastContent"`
} `json:"snippet"`
} `json:"items"`
}

58
youtube.go Normal file
View File

@ -0,0 +1,58 @@
package main
import(
"fmt"
"log"
"encoding/json"
"os"
"net/http"
"net/url"
"io/ioutil"
"regexp"
)
var youtubeToken = os.Getenv("YOUTUBE_TOKEN")
var youtube_api = "https://www.googleapis.com/youtube/v3/search"
var youtube_video_baseurl = "https://youtube.com/watch?v="
func search_on_youtube(searchString string) (youtube_url string) {
reg, _ := regexp.Compile("[^a-zA-Z0-9 -]+")
processedString := reg.ReplaceAllString(searchString, "")
t := &url.URL{Path: processedString}
http_request := t.String()
http_request_encoded := (youtube_api+"?part=snippet&maxResults=1&q="+http_request+"&key="+youtubeToken)
response, err := http.Get(http_request_encoded)
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
} else {
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
}
data := new(youtubeSearchResult)
json.Unmarshal(contents, &data)
if len(data.Items) > 0 {
youtube_url = youtube_video_baseurl + data.Items[0].ID.VideoID
} else {
// TODO: put this spotify track on 'manual donwload queue'
// youtube_url = "could not find track on yt"
f, err := os.OpenFile("manual-download.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
if _, err := f.Write([]byte(searchString+"\n")); err != nil {
log.Fatal(err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
}
}
return
}