diff --git a/.github/README.md b/.github/README.md
index 5a641a5..9084b46 100644
--- a/.github/README.md
+++ b/.github/README.md
@@ -1,3 +1,3 @@
-# Spotitube
+# Spotitube
Documentation available at [davidepucci.it/doc/spotitube](https://davidepucci.it/doc/spotitube).
diff --git a/.github/linters/.golangci.yml b/.github/linters/.golangci.yml
new file mode 100644
index 0000000..16573a0
--- /dev/null
+++ b/.github/linters/.golangci.yml
@@ -0,0 +1,28 @@
+---
+issues:
+ exclude-rules:
+ - path: _test\.go
+ linters:
+ - dupl
+ - gosec
+ - goconst
+linters:
+ enable:
+ - gosec
+ - unconvert
+ - gocyclo
+ - goconst
+ - goimports
+ - gocritic
+ - govet
+ - revive
+linters-settings:
+ errcheck:
+ check-blank: true
+ govet:
+ enable:
+ - shadowing
+ gocyclo:
+ min-complexity: 20
+ maligned:
+ suggest-new: true
diff --git a/.github/linters/.hadolint.yaml b/.github/linters/.hadolint.yaml
new file mode 100644
index 0000000..2200bac
--- /dev/null
+++ b/.github/linters/.hadolint.yaml
@@ -0,0 +1,6 @@
+---
+failure-threshold: warning
+
+ignored:
+ - DL3018 # Pin versions in apk add
+ - SC2215 # This flag is used as a command name
diff --git a/.github/linters/.jscpd.json b/.github/linters/.jscpd.json
new file mode 100644
index 0000000..d015e48
--- /dev/null
+++ b/.github/linters/.jscpd.json
@@ -0,0 +1,6 @@
+{
+ "threshold": 3,
+ "reporters": ["consoleFull"],
+ "ignore": ["**/__snapshots__/**", "**/node_modules/**", "**/*_test.go"],
+ "absolute": true
+}
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 64d973d..a57c3c7 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -8,7 +8,21 @@ on:
branches:
- master
-permissions: write-all
+permissions:
+ actions: read
+ attestations: none
+ checks: none
+ contents: read
+ deployments: none
+ id-token: none
+ issues: none
+ discussions: none
+ packages: write
+ pages: none
+ pull-requests: read
+ repository-projects: none
+ security-events: none
+ statuses: none
jobs:
commitlint:
@@ -25,18 +39,23 @@ jobs:
- uses: codespell-project/actions-codespell@v2
with:
check_filenames: true
- golangci-lint:
+ super-linter:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - uses: golangci/golangci-lint-action@v6
+ - uses: super-linter/super-linter@latest
+ env:
+ GITHUB_TOKEN: ${{ secrets.GH_ACTIONS_SPOTITUBE }}
+ VALIDATE_ALL_CODEBASE: false
+ VALIDATE_GO: false
gofumpt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- run: |
- export PATH=$PATH:$(go env GOPATH)/bin
+ PATH="$PATH:$(go env GOPATH)/bin"
+ export PATH
go install mvdan.cc/gofumpt@latest
if gofumpt -l -e . | grep '^' -q; then exit 1; fi
go-channel-closure:
@@ -56,7 +75,16 @@ jobs:
- run: test "$(grep -cr 'defer gomonkey\.')" = "$(grep -cr 'Reset()$')"
test:
runs-on: ubuntu-latest
- needs: [commitlint, codespell, golangci-lint, gofumpt, go-channel-closure, go-http-body-closure, go-monkey-unpatch]
+ needs:
+ [
+ commitlint,
+ codespell,
+ super-linter,
+ gofumpt,
+ go-channel-closure,
+ go-http-body-closure,
+ go-monkey-unpatch,
+ ]
if: success()
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/scrape.yml b/.github/workflows/scrape.yml
index a1ebcc8..174286c 100644
--- a/.github/workflows/scrape.yml
+++ b/.github/workflows/scrape.yml
@@ -12,7 +12,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- - run: go test -v -run ^TestScraping$ ./...
+ - run: go test -v -run ^TestScraping$ ./...
env:
TEST_SCRAPING: true
GENIUS_TOKEN: ${{ secrets.GENIUS_TOKEN }}
diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml
index 465fbc2..c3ae169 100644
--- a/.github/workflows/tag.yml
+++ b/.github/workflows/tag.yml
@@ -3,9 +3,23 @@ name: tag
on:
push:
tags:
- - 'v*.*.*'
+ - "v*.*.*"
-permissions: write-all
+permissions:
+ actions: read
+ attestations: none
+ checks: none
+ contents: read
+ deployments: none
+ id-token: none
+ issues: none
+ discussions: none
+ packages: write
+ pages: none
+ pull-requests: read
+ repository-projects: none
+ security-events: none
+ statuses: none
jobs:
test:
diff --git a/Dockerfile b/Dockerfile
index 012a343..b66c9b2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,20 +2,23 @@
FROM golang:alpine AS builder
WORKDIR /workspace
COPY . .
-RUN go mod download
-RUN --mount=type=secret,id=SPOTIFY_ID \
+RUN go mod download && \
+ --mount=type=secret,id=SPOTIFY_ID \
--mount=type=secret,id=SPOTIFY_KEY \
--mount=type=secret,id=GENIUS_TOKEN \
go build -ldflags="-s -w -X github.com/streambinder/spotitube/spotify.fallbackSpotifyID=$(cat /run/secrets/SPOTIFY_ID) -X github.com/streambinder/spotitube/spotify.fallbackSpotifyKey=$(cat /run/secrets/SPOTIFY_KEY) -X github.com/streambinder/spotitube/lyrics.fallbackGeniusToken=$(cat /run/secrets/GENIUS_TOKEN)"
-FROM alpine:latest
-RUN apk add --no-cache ffmpeg yt-dlp
-RUN mkdir /data
-RUN mkdir /cache
+FROM alpine:3
+RUN apk add --no-cache ffmpeg yt-dlp && \
+ mkdir /data && \
+ mkdir /cache && \
+ useradd -m spotitube
+USER spotitube
WORKDIR /data
ENV XDG_MUSIC_DIR=/data
ENV XDG_CACHE_HOME=/cache
COPY --from=builder /workspace/spotitube /usr/sbin/
+HEALTHCHECK CMD [ "/usr/sbin/spotitube", "--help" ]
EXPOSE 65535/tcp
ENTRYPOINT ["/usr/sbin/spotitube"]
LABEL org.opencontainers.image.source=https://github.com/streambinder/spotitube
diff --git a/cmd/attach.go b/cmd/attach.go
index f8d5b8e..208d274 100644
--- a/cmd/attach.go
+++ b/cmd/attach.go
@@ -26,9 +26,9 @@ func cmdAttach() *cobra.Command {
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
var (
- path = args[0]
- id = args[1]
- rename, _ = cmd.Flags().GetBool("rename")
+ path = args[0]
+ id = args[1]
+ rename = util.ErrWrap(false)(cmd.Flags().GetBool("rename"))
)
localTrack, err := id3.Open(path, id3v2.Options{Parse: false})
diff --git a/cmd/auth.go b/cmd/auth.go
index 3a039ac..21383f4 100644
--- a/cmd/auth.go
+++ b/cmd/auth.go
@@ -25,10 +25,10 @@ func cmdAuth() *cobra.Command {
Use: "auth",
Short: "Establish a Spotify session for future uses",
SilenceUsage: true,
- RunE: func(cmd *cobra.Command, args []string) error {
+ RunE: func(cmd *cobra.Command, _ []string) error {
var (
- remote, _ = cmd.Flags().GetBool("remote")
- logout, _ = cmd.Flags().GetBool("logout")
+ remote = util.ErrWrap(false)(cmd.Flags().GetBool("remote"))
+ logout = util.ErrWrap(false)(cmd.Flags().GetBool("logout"))
callback = "127.0.0.1"
processor = spotify.BrowserProcessor
)
diff --git a/cmd/lookup.go b/cmd/lookup.go
index ef0944f..afb1ec7 100644
--- a/cmd/lookup.go
+++ b/cmd/lookup.go
@@ -30,10 +30,10 @@ func cmdLookup() *cobra.Command {
Short: "Utility to lookup for tracks in order to investigate general querying behaviour",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
- library, _ := cmd.Flags().GetBool("library")
- random, _ := cmd.Flags().GetBool("random")
- randomSize, _ := cmd.Flags().GetInt("random-size")
- libraryLimit, _ := cmd.Flags().GetInt("library-limit")
+ library := util.ErrWrap(false)(cmd.Flags().GetBool("library"))
+ random := util.ErrWrap(false)(cmd.Flags().GetBool("random"))
+ randomSize := util.ErrWrap(defaultRandomSize)(cmd.Flags().GetInt("random-size"))
+ libraryLimit := util.ErrWrap(0)(cmd.Flags().GetInt("library-limit"))
if !library && !random && len(args) == 0 {
return errors.New("no track has been issued")
}
@@ -48,7 +48,7 @@ func cmdLookup() *cobra.Command {
lyricsChannel = make(chan interface{}, 1)
)
return nursery.RunConcurrently(
- func(ctx context.Context, ch chan error) {
+ func(_ context.Context, ch chan error) {
defer close(providerChannel)
defer close(lyricsChannel)
if random {
@@ -70,7 +70,7 @@ func cmdLookup() *cobra.Command {
}
}
},
- func(ctx context.Context, ch chan error) {
+ func(_ context.Context, _ chan error) {
prefix := "[P]"
for event := range providerChannel {
track := event.(*entity.Track)
diff --git a/cmd/lookup_test.go b/cmd/lookup_test.go
index 701fdb5..58e2ffc 100644
--- a/cmd/lookup_test.go
+++ b/cmd/lookup_test.go
@@ -110,7 +110,7 @@ func TestCmdLookupLibraryFailure(t *testing.T) {
ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) {
return &spotify.Client{}, nil
}).
- ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, ch ...chan interface{}) error {
+ ApplyMethod(&spotify.Client{}, "Library", func(_ *spotify.Client, _ int, _ ...chan interface{}) error {
return errors.New("ko")
}).
Reset()
@@ -125,7 +125,7 @@ func TestCmdLookupTrackFailure(t *testing.T) {
ApplyFunc(spotify.Authenticate, func() (*spotify.Client, error) {
return &spotify.Client{}, nil
}).
- ApplyMethod(&spotify.Client{}, "Track", func(_ *spotify.Client, _ string, ch ...chan interface{}) (*entity.Track, error) {
+ ApplyMethod(&spotify.Client{}, "Track", func(_ *spotify.Client, _ string, _ ...chan interface{}) (*entity.Track, error) {
return nil, errors.New("ko")
}).Reset()
diff --git a/cmd/reset.go b/cmd/reset.go
index e40b0e7..4fcd533 100644
--- a/cmd/reset.go
+++ b/cmd/reset.go
@@ -20,9 +20,9 @@ func cmdReset() *cobra.Command {
Short: "Clear cached objects",
SilenceUsage: true,
Args: cobra.NoArgs,
- RunE: func(cmd *cobra.Command, args []string) error {
+ RunE: func(cmd *cobra.Command, _ []string) error {
var (
- session, _ = cmd.Flags().GetBool("session")
+ session = util.ErrWrap(false)(cmd.Flags().GetBool("session"))
cacheDirectory = util.CacheDirectory()
)
return filepath.WalkDir(cacheDirectory, func(path string, entry fs.DirEntry, err error) error {
diff --git a/cmd/reset_test.go b/cmd/reset_test.go
index ea90390..c1a2d63 100644
--- a/cmd/reset_test.go
+++ b/cmd/reset_test.go
@@ -43,7 +43,7 @@ func BenchmarkReset(b *testing.B) {
func TestCmdReset(t *testing.T) {
// monkey patching
defer gomonkey.NewPatches().
- ApplyFunc(filepath.WalkDir, func(path string, f func(string, fs.DirEntry, error) error) error {
+ ApplyFunc(filepath.WalkDir, func(_ string, f func(string, fs.DirEntry, error) error) error {
_ = f("", DirEntry{name: "", isDir: false}, errors.New("some error"))
_ = f(spotify.TokenBasename, DirEntry{name: spotify.TokenBasename, isDir: false}, nil)
_ = f("fname.txt", DirEntry{name: "fname.txt", isDir: false}, nil)
diff --git a/cmd/root.go b/cmd/root.go
index 702fcea..7fbf54d 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -10,5 +10,7 @@ var cmdRoot = &cobra.Command{
}
func Execute() {
- _ = cmdRoot.Execute()
+ if err := cmdRoot.Execute(); err != nil {
+ cmdRoot.Println(err)
+ }
}
diff --git a/cmd/root_test.go b/cmd/root_test.go
index d306db2..7dc3703 100644
--- a/cmd/root_test.go
+++ b/cmd/root_test.go
@@ -25,7 +25,7 @@ func testExecute(cmd *cobra.Command, args ...string) error {
return cmdTest.Execute()
}
-func TestExecute(t *testing.T) {
+func TestExecute(_ *testing.T) {
cmdRoot.SetOut(io.Discard)
cmdRoot.SetErr(io.Discard)
cmdRoot.SetOutput(io.Discard)
diff --git a/cmd/show.go b/cmd/show.go
index 6e8a518..c29478b 100644
--- a/cmd/show.go
+++ b/cmd/show.go
@@ -24,7 +24,7 @@ func cmdShow() *cobra.Command {
Short: "Show local tracks data",
SilenceUsage: true,
Args: cobra.MinimumNArgs(1),
- RunE: func(cmd *cobra.Command, args []string) error {
+ RunE: func(_ *cobra.Command, args []string) error {
bold := color.New(color.Bold)
for _, path := range args {
if err := func() error {
diff --git a/cmd/sync.go b/cmd/sync.go
index 7c8118d..71fe018 100644
--- a/cmd/sync.go
+++ b/cmd/sync.go
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
+ "log"
"os"
"path/filepath"
"strconv"
@@ -54,18 +55,18 @@ func cmdSync() *cobra.Command {
Short: "Synchronize collections",
SilenceUsage: true,
Args: cobra.NoArgs,
- RunE: func(cmd *cobra.Command, args []string) error {
+ RunE: func(cmd *cobra.Command, _ []string) error {
var (
- path, _ = cmd.Flags().GetString("output")
- playlistEncoding, _ = cmd.Flags().GetString("playlist-encoding")
- manual, _ = cmd.Flags().GetBool("manual")
- library, _ = cmd.Flags().GetBool("library")
- playlists, _ = cmd.Flags().GetStringArray("playlist")
- playlistsTracks, _ = cmd.Flags().GetStringArray("playlist-tracks")
- albums, _ = cmd.Flags().GetStringArray("album")
- tracks, _ = cmd.Flags().GetStringArray("track")
- fixes, _ = cmd.Flags().GetStringArray("fix")
- libraryLimit, _ = cmd.Flags().GetInt("library-limit")
+ path = util.ErrWrap(xdg.UserDirs.Music)(cmd.Flags().GetString("output"))
+ playlistEncoding = util.ErrWrap("m3u")(cmd.Flags().GetString("playlist-encoding"))
+ manual = util.ErrWrap(false)(cmd.Flags().GetBool("manual"))
+ library = util.ErrWrap(false)(cmd.Flags().GetBool("library"))
+ playlists = util.ErrWrap([]string{})(cmd.Flags().GetStringArray("playlist"))
+ playlistsTracks = util.ErrWrap([]string{})(cmd.Flags().GetStringArray("playlist-tracks"))
+ albums = util.ErrWrap([]string{})(cmd.Flags().GetStringArray("album"))
+ tracks = util.ErrWrap([]string{})(cmd.Flags().GetStringArray("track"))
+ fixes = util.ErrWrap([]string{})(cmd.Flags().GetStringArray("fix"))
+ libraryLimit = util.ErrWrap(0)(cmd.Flags().GetInt("library-limit"))
)
for index, path := range fixes {
@@ -89,7 +90,7 @@ func cmdSync() *cobra.Command {
routineMix(playlistEncoding),
)
},
- PreRun: func(cmd *cobra.Command, args []string) {
+ PreRun: func(cmd *cobra.Command, _ []string) {
routineSemaphores = map[int](chan bool){
routineTypeIndex: make(chan bool, 1),
routineTypeAuth: make(chan bool, 1),
@@ -104,16 +105,18 @@ func cmdSync() *cobra.Command {
}
var (
- playlists, _ = cmd.Flags().GetStringArray("playlist")
- playlistsTracks, _ = cmd.Flags().GetStringArray("playlist-tracks")
- albums, _ = cmd.Flags().GetStringArray("album")
- tracks, _ = cmd.Flags().GetStringArray("track")
- fixes, _ = cmd.Flags().GetStringArray("fix")
+ playlists = util.ErrWrap([]string{})(cmd.Flags().GetStringArray("playlist"))
+ playlistsTracks = util.ErrWrap([]string{})(cmd.Flags().GetStringArray("playlist-tracks"))
+ albums = util.ErrWrap([]string{})(cmd.Flags().GetStringArray("album"))
+ tracks = util.ErrWrap([]string{})(cmd.Flags().GetStringArray("track"))
+ fixes = util.ErrWrap([]string{})(cmd.Flags().GetStringArray("fix"))
)
if len(playlists)+len(playlistsTracks)+len(albums)+len(tracks)+len(fixes) == 0 {
cmd.LocalFlags().VisitAll(func(f *pflag.Flag) {
if f.Name == "library" {
- _ = f.Value.Set("true")
+ if err := f.Value.Set("true"); err != nil {
+ log.Fatal(err)
+ }
}
})
}
diff --git a/docs/README.md b/docs/README.md
index dd802bf..1bd8ed2 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,3 +1,5 @@
+# Documentation
+
1. [About](about.md)
2. [Installation](installation.md)
3. [Design](design.md)
diff --git a/docs/about.md b/docs/about.md
index ea3c064..89bd6b7 100644
--- a/docs/about.md
+++ b/docs/about.md
@@ -1,6 +1,6 @@
# About
-![](assets/demo.gif)
+![demo](assets/demo.gif)
Spotitube is a CLI application to authenticate to Spotify account, fetch music collections — such as account library, playlists, albums or specific tracks —, look them up on a defined set of providers — such as YouTube —, download them and inflate the downloaded assets with metadata collected from Spotify, further enriched with lyrics.
@@ -55,8 +55,8 @@ docker run -it --rm \
The only real issue to be addressed when working with Spotitube running in headless mode, is the redirect during Spotify authentication.
-By default, once authenticated to Spotify via web, Spotify itself redirects to a predefined callback URL, which corresponds to http://localhost:65535.
-In order to make that redirect go against a custom server, on Spotitube Spotify app, a further callback URL has been defined, i.e. http://spotitube.local:65535.
+By default, once authenticated to Spotify via web, Spotify itself redirects to a predefined callback URL, which corresponds to `http://localhost:65535`.
+In order to make that redirect go against a custom server, on Spotitube Spotify app, a further callback URL has been defined, i.e. `http://spotitube.local:65535`.
This is the one that is set as callback at runtime when Spotitube goes through authentication with the `--remote` flag.
So, assuming the server on which Spotitube is running is reachable at 1.2.3.4, make sure the client can correctly resolve `spotitube.local` as 1.2.3.4.
diff --git a/docs/design.md b/docs/design.md
index 771e84b..d82575a 100644
--- a/docs/design.md
+++ b/docs/design.md
@@ -8,8 +8,7 @@ Such queues usually carry a specific track (be it part of synchronization of use
The assembly line is made of the following routines:
-
-![](assets/design.svg)
+![design](assets/design.svg)
## Indexer
diff --git a/downloader/youtubedl.go b/downloader/youtubedl.go
index b386b10..47467f4 100644
--- a/downloader/youtubedl.go
+++ b/downloader/youtubedl.go
@@ -19,7 +19,7 @@ func (youTubeDl) supports(url string) bool {
return strings.Contains(url, "://youtu.be") || strings.Contains(url, "://youtube.com")
}
-func (youTubeDl) download(url, path string, processor processor.Processor, channels ...chan []byte) error {
+func (youTubeDl) download(url, path string, _ processor.Processor, channels ...chan []byte) error {
// in this case, data won't be passed through channels
// as too heavy
for _, ch := range channels {
diff --git a/entity/track.go b/entity/track.go
index 92d3d69..d2bfc5f 100644
--- a/entity/track.go
+++ b/entity/track.go
@@ -27,7 +27,7 @@ type Track struct {
UpstreamURL string // URL to the upstream blob the song's been downloaded from
}
-type trackPath struct {
+type TrackPath struct {
track *Track
}
@@ -53,28 +53,28 @@ func (track *Track) Song() (song string) {
return
}
-func (track *Track) Path() trackPath {
- return trackPath{track}
+func (track *Track) Path() TrackPath {
+ return TrackPath{track}
}
-func (trackPath trackPath) Final() string {
- return util.LegalizeFilename(fmt.Sprintf("%s - %s.%s", trackPath.track.Artists[0], trackPath.track.Title, TrackFormat))
+func (TrackPath TrackPath) Final() string {
+ return util.LegalizeFilename(fmt.Sprintf("%s - %s.%s", TrackPath.track.Artists[0], TrackPath.track.Title, TrackFormat))
}
-func (trackPath trackPath) Download() string {
+func (TrackPath TrackPath) Download() string {
return util.CacheFile(
- util.LegalizeFilename(fmt.Sprintf("%s.%s", slug.Make(trackPath.track.ID), TrackFormat)),
+ util.LegalizeFilename(fmt.Sprintf("%s.%s", slug.Make(TrackPath.track.ID), TrackFormat)),
)
}
-func (trackPath trackPath) Artwork() string {
+func (TrackPath TrackPath) Artwork() string {
return util.CacheFile(
- util.LegalizeFilename(fmt.Sprintf("%s.%s", slug.Make(path.Base(trackPath.track.Artwork.URL)), ArtworkFormat)),
+ util.LegalizeFilename(fmt.Sprintf("%s.%s", slug.Make(path.Base(TrackPath.track.Artwork.URL)), ArtworkFormat)),
)
}
-func (trackPath trackPath) Lyrics() string {
+func (TrackPath TrackPath) Lyrics() string {
return util.CacheFile(
- util.LegalizeFilename(fmt.Sprintf("%s.%s", slug.Make(trackPath.track.ID), LyricsFormat)),
+ util.LegalizeFilename(fmt.Sprintf("%s.%s", slug.Make(TrackPath.track.ID), LyricsFormat)),
)
}
diff --git a/provider/youtube.go b/provider/youtube.go
index c340aaf..9a41212 100644
--- a/provider/youtube.go
+++ b/provider/youtube.go
@@ -30,7 +30,7 @@ type youTubeInitialData struct {
ItemSectionRenderer struct {
Contents []struct {
VideoRenderer struct {
- VideoId string
+ VideoID string
Title struct {
Runs []Run
}
@@ -123,7 +123,7 @@ func (provider youTube) search(track *entity.Track) ([]*Match, error) {
return nil, err
}
- json := strings.Join(document.Find("script").Map(func(i int, selection *goquery.Selection) string {
+ json := strings.Join(document.Find("script").Map(func(_ int, selection *goquery.Selection) string {
prefix := "var ytInitialData ="
if !strings.HasPrefix(strings.TrimPrefix(selection.Text(), " "), prefix) {
return ""
@@ -147,7 +147,7 @@ func (provider youTube) search(track *entity.Track) ([]*Match, error) {
match := youTubeResult{
track: track,
query: query,
- id: result.VideoRenderer.VideoId,
+ id: result.VideoRenderer.VideoID,
title: title.Text,
owner: result.VideoRenderer.OwnerText.Runs[run].Text,
description: util.First(result.VideoRenderer.DetailedMetadataSnippets, DetailedMetadataSnippet{
diff --git a/spotify/auth.go b/spotify/auth.go
index de47ab2..97df3a8 100644
--- a/spotify/auth.go
+++ b/spotify/auth.go
@@ -8,6 +8,7 @@ import (
"net/http"
"os"
"path/filepath"
+ "time"
"github.com/arunsworld/nursery"
"github.com/streambinder/spotitube/util"
@@ -39,9 +40,13 @@ type Client struct {
func Authenticate(urlProcessor func(string) error, callbacks ...string) (*Client, error) {
var (
- client Client
- serverMux = http.NewServeMux()
- server = &http.Server{Addr: fmt.Sprintf("0.0.0.0:%d", port), Handler: serverMux}
+ client Client
+ serverMux = http.NewServeMux()
+ server = &http.Server{
+ Addr: fmt.Sprintf("0.0.0.0:%d", port),
+ Handler: serverMux,
+ ReadHeaderTimeout: 2 * time.Second,
+ }
state = randstr.Hex(20)
callback = "127.0.0.1"
clientChannel = make(chan *spotify.Client, 1)
diff --git a/spotify/id_test.go b/spotify/id_test.go
index 2da5359..90d1f98 100644
--- a/spotify/id_test.go
+++ b/spotify/id_test.go
@@ -16,10 +16,10 @@ func BenchmarkID(b *testing.B) {
func TestID(t *testing.T) {
var (
target = "1234567890123456789012"
- spotifyId = spotify.ID(target)
+ spotifyID = spotify.ID(target)
)
- assert.Equal(t, id(target), spotifyId)
- assert.Equal(t, id("spotify:track:"+target), spotifyId)
- assert.Equal(t, id("https://open.spotify.com/track/"+target), spotifyId)
- assert.Equal(t, id("https://open.spotify.com/track/"+target+"?si=abcdefghijklmnop"), spotifyId)
+ assert.Equal(t, id(target), spotifyID)
+ assert.Equal(t, id("spotify:track:"+target), spotifyID)
+ assert.Equal(t, id("https://open.spotify.com/track/"+target), spotifyID)
+ assert.Equal(t, id("https://open.spotify.com/track/"+target+"?si=abcdefghijklmnop"), spotifyID)
}