Skip to content

Commit 27a4655

Browse files
authored
Merge branch 'dev' into fix/make-linter-happy
2 parents 77f3dba + e95dd88 commit 27a4655

File tree

3 files changed

+83
-47
lines changed

3 files changed

+83
-47
lines changed

.github/workflows/release.yml

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ jobs:
3232
contents: write
3333
name: Create Release
3434
runs-on: 'ubuntu-latest'
35+
if: startsWith(github.ref, 'refs/tags/v')
3536
strategy:
3637
matrix:
3738
# List of GOOS and GOARCH pairs from `go tool dist list`
@@ -70,12 +71,12 @@ jobs:
7071
build:
7172
name: Build/publish container image
7273
runs-on: ubuntu-latest
74+
if: startsWith(github.ref, 'refs/tags/v') # only build latest from tagged versions
75+
needs: release
7376
permissions:
7477
contents: read
7578
packages: write
7679
id-token: write
77-
if: "!contains(github.ref, 'dev')" # skip building container for dev
78-
needs: release
7980

8081
steps:
8182
- name: Checkout repository
@@ -110,3 +111,41 @@ jobs:
110111
cache-from: type=gha
111112
cache-to: type=gha,mode=max
112113
platforms: linux/amd64,linux/386
114+
115+
build-dev:
116+
name: Build/publish dev image
117+
runs-on: ubuntu-latest
118+
if: github.ref == 'refs/heads/dev'
119+
permissions:
120+
contents: read
121+
packages: write
122+
id-token: write
123+
124+
steps:
125+
- name: Checkout repository
126+
uses: actions/checkout@v4
127+
with:
128+
fetch-depth: 0
129+
130+
- name: Login to ghcr.io
131+
uses: docker/login-action@v2
132+
with:
133+
registry: ghcr.io
134+
username: ${{ github.actor }}
135+
password: ${{ secrets.GITHUB_TOKEN }}
136+
137+
- name: Convert repository name to lowercase
138+
run: echo "REPO_LC=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
139+
140+
- name: Set up Docker Buildx
141+
uses: docker/setup-buildx-action@v2
142+
143+
- name: Build and push dev image
144+
uses: docker/build-push-action@v5
145+
with:
146+
context: .
147+
push: true
148+
tags: ghcr.io/${{ env.REPO_LC }}:dev
149+
cache-from: type=gha
150+
cache-to: type=gha,mode=max
151+
platforms: linux/amd64,linux/386

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ COPY ./ .
88

99
# Build the Go binary based on the target architecture
1010
ARG TARGETARCH
11-
RUN GOOS=linux GOARCH=${TARGETARCH} go build -o explo ./src/
11+
RUN GOOS=linux GOARCH=${TARGETARCH} go build -o explo ./src/main/
1212

1313
FROM alpine
1414

src/client/jellyfin.go

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"encoding/json"
66
"fmt"
77
"net/url"
8-
"strings"
98

109
"explo/src/config"
1110
"explo/src/debug"
@@ -14,24 +13,24 @@ import (
1413
)
1514

1615
type Paths []struct {
17-
Name string `json:"Name"`
18-
Locations []string `json:"Locations"`
19-
CollectionType string `json:"CollectionType"`
20-
ItemID string `json:"ItemId"`
21-
RefreshStatus string `json:"RefreshStatus"`
16+
Name string `json:"Name"`
17+
Locations []string `json:"Locations"`
18+
CollectionType string `json:"CollectionType"`
19+
ItemID string `json:"ItemId"`
20+
RefreshStatus string `json:"RefreshStatus"`
2221
}
2322

2423
type Search struct {
2524
SearchHints []SearchHints `json:"SearchHints"`
2625
TotalRecordCount int `json:"TotalRecordCount"`
2726
}
2827
type SearchHints struct {
29-
ItemID string `json:"ItemId"`
30-
ID string `json:"Id"`
31-
Name string `json:"Name"`
32-
Album string `json:"Album"`
33-
AlbumID string `json:"AlbumId"`
34-
AlbumArtist string `json:"AlbumArtist"`
28+
ItemID string `json:"ItemId"`
29+
ID string `json:"Id"`
30+
Name string `json:"Name"`
31+
Album string `json:"Album"`
32+
AlbumID string `json:"AlbumId"`
33+
AlbumArtist string `json:"AlbumArtist"`
3534
}
3635

3736
type Audios struct {
@@ -41,27 +40,27 @@ type Audios struct {
4140
}
4241

4342
type Items struct {
44-
Name string `json:"Name"`
45-
ServerID string `json:"ServerId"`
46-
ID string `json:"Id"`
47-
Path string `json:"Path"`
48-
Album string `json:"Album,omitempty"`
49-
AlbumArtist string `json:"AlbumArtist,omitempty"`
43+
Name string `json:"Name"`
44+
ServerID string `json:"ServerId"`
45+
ID string `json:"Id"`
46+
Path string `json:"Path"`
47+
Album string `json:"Album,omitempty"`
48+
AlbumArtist string `json:"AlbumArtist,omitempty"`
5049
}
5150

5251
type JFPlaylist struct {
5352
ID string `json:"Id"`
5453
}
5554

5655
type Jellyfin struct {
57-
LibraryID string
56+
LibraryID string
5857
HttpClient *util.HttpClient
59-
Cfg config.ClientConfig
58+
Cfg config.ClientConfig
6059
}
6160

6261
func NewJellyfin(cfg config.ClientConfig, httpClient *util.HttpClient) *Jellyfin {
6362
return &Jellyfin{Cfg: cfg,
64-
HttpClient: httpClient}
63+
HttpClient: httpClient}
6564
}
6665

6766
func (c *Jellyfin) AddHeader() error {
@@ -70,8 +69,8 @@ func (c *Jellyfin) AddHeader() error {
7069
}
7170

7271
if c.Cfg.Creds.APIKey != "" {
73-
c.Cfg.Creds.Headers["Authorization"] = fmt.Sprintf("MediaBrowser Token=%s, Client=%s", c.Cfg.Creds.APIKey, c.Cfg.ClientID)
74-
return nil
72+
c.Cfg.Creds.Headers["Authorization"] = fmt.Sprintf("MediaBrowser Token=%s, Client=%s", c.Cfg.Creds.APIKey, c.Cfg.ClientID)
73+
return nil
7574
}
7675
return fmt.Errorf("API_KEY not set")
7776
}
@@ -82,7 +81,7 @@ func (c *Jellyfin) GetAuth() error {
8281

8382
func (c *Jellyfin) GetLibrary() error {
8483
reqParam := "/Library/VirtualFolders"
85-
84+
8685
body, err := c.HttpClient.MakeRequest("GET", c.Cfg.URL+reqParam, nil, c.Cfg.Creds.Headers)
8786
if err != nil {
8887
return err
@@ -92,7 +91,7 @@ func (c *Jellyfin) GetLibrary() error {
9291
if err = util.ParseResp(body, &paths); err != nil {
9392
return err
9493
}
95-
94+
9695
for _, path := range paths {
9796
if path.Name == c.Cfg.LibraryName {
9897
c.LibraryID = path.ItemID
@@ -120,7 +119,7 @@ func (c *Jellyfin) AddLibrary() error {
120119
}
121120

122121
func (c *Jellyfin) RefreshLibrary() error {
123-
reqParam := fmt.Sprintf("/Items/%s/Refresh", c.LibraryID)
122+
reqParam := fmt.Sprintf("/Items/%s/Refresh?metadataRefreshMode=FullRefresh", c.LibraryID)
124123

125124
if _, err := c.HttpClient.MakeRequest("POST", c.Cfg.URL+reqParam, nil, c.Cfg.Creds.Headers); err != nil {
126125
return err
@@ -129,37 +128,35 @@ func (c *Jellyfin) RefreshLibrary() error {
129128
}
130129

131130
func (c *Jellyfin) SearchSongs(tracks []*models.Track) error {
132-
queryParams := fmt.Sprintf("/Items?parentId=%s&fields=Path&mediaTypes=Audio&sortBy=DateCreated&sortOrder=Descending&limit=200", c.LibraryID) // limit 200 recently added audio tracks to search from
133-
134-
body, err := c.HttpClient.MakeRequest("GET", c.Cfg.URL+queryParams, nil, c.Cfg.Creds.Headers)
135-
if err != nil {
136-
return fmt.Errorf("request failed to get songs from %s library: %s", c.Cfg.LibraryName, err.Error())
137-
}
131+
for _, track := range tracks {
132+
queryParams := fmt.Sprintf("/Items?parentId=%s&mediaTypes=Audio&searchTerm=%s&recursive=true", c.LibraryID, url.QueryEscape(track.CleanTitle))
138133

139-
var results Audios
140-
if err = util.ParseResp(body, &results); err != nil {
141-
return err
142-
}
134+
body, err := c.HttpClient.MakeRequest("GET", c.Cfg.URL+queryParams, nil, c.Cfg.Creds.Headers)
135+
if err != nil {
136+
return fmt.Errorf("request failed to get songs from %s library: %s", c.Cfg.LibraryName, err.Error())
137+
}
143138

144-
for _, track := range tracks {
139+
var results Audios
140+
if err = util.ParseResp(body, &results); err != nil {
141+
return err
142+
}
145143

146144
for _, item := range results.Items {
147-
if strings.Contains(item.Path, track.File) {
145+
if track.MainArtist == item.AlbumArtist && item.Name == track.CleanTitle {
148146
track.ID = item.ID
149147
track.Present = true
150148
break
151149
}
152150
}
153151
if !track.Present {
154-
debug.Debug(fmt.Sprintf("failed to find '%s' by '%s' in %s album", track.Title, track.Artist, track.Album))
152+
debug.Debug(fmt.Sprintf("failed to find '%s' by '%s' in %s album", track.Title, track.Artist, track.Album))
155153
}
156154
}
157155
return nil
158156
}
159157

160158
func (c *Jellyfin) SearchPlaylist() error {
161-
queryParams := fmt.Sprintf("/Search/Hints?searchTerm=%s&mediaTypes=Playlist", c.Cfg.PlaylistName)
162-
159+
queryParams := fmt.Sprintf("/Items?mediaTypes=Playlist&searchTerm=%s&recursive=true", c.Cfg.PlaylistName)
163160
body, err := c.HttpClient.MakeRequest("GET", c.Cfg.URL+queryParams, nil, c.Cfg.Creds.Headers)
164161
if err != nil {
165162
return err
@@ -169,7 +166,7 @@ func (c *Jellyfin) SearchPlaylist() error {
169166
if err = util.ParseResp(body, &results); err != nil {
170167
return err
171168
}
172-
169+
173170
if len(results.SearchHints) != 0 {
174171
c.Cfg.PlaylistID = results.SearchHints[0].ID
175172
return nil
@@ -237,12 +234,12 @@ func formatJFSongs(tracks []*models.Track) ([]byte, error) { // marshal track ID
237234
songIDs := make([]string, 0, len(tracks))
238235
for _, track := range tracks {
239236
if track.Present {
240-
songIDs = append(songIDs,track.ID)
237+
songIDs = append(songIDs, track.ID)
241238
}
242239
}
243240
songs, err := json.Marshal(songIDs)
244241
if err != nil {
245242
return nil, err
246243
}
247244
return songs, nil
248-
}
245+
}

0 commit comments

Comments
 (0)