Skip to content

Commit

Permalink
Missed package added
Browse files Browse the repository at this point in the history
  • Loading branch information
vpoluyaktov committed Nov 5, 2023
1 parent 85c4bd8 commit 49bc421
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 5 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ jobs:
uses: actions/setup-go@v4
with:
go-version: '1.20'

- name: Go Init
run: go mod tidy


- name: Build
run: go build -v ./...

Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ dist/
__debug_bin
abb_ia.log
config.yaml
audiobookshelf
68 changes: 68 additions & 0 deletions internal/audiobookshelf/audiobookshelf_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package audiobookshelf_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/vpoluyaktov/abb_ia/internal/audiobookshelf"
"github.com/vpoluyaktov/abb_ia/internal/config"
)

func TestLogin(t *testing.T) {
config.Load()
url := config.AudiobookshelfUrl()
username := config.AudiobookshelfUser()
password := config.AudiobookshelfPassword()

if url != "" && username != "" && password != "" {
loginResp, err := audiobookshelf.Login(url+"/login", username, password)

assert.NoError(t, err)
assert.NotNil(t, loginResp.User.ID)
assert.NotNil(t, loginResp.User.Token)
}
}

func TestLibraries(t *testing.T) {
config.Load()
url := config.AudiobookshelfUrl()
username := config.AudiobookshelfUser()
password := config.AudiobookshelfPassword()

if url != "" && username != "" && password != "" {
loginResp, err := audiobookshelf.Login(url+"/login", username, password)
assert.NoError(t, err)
if err == nil {
libraryResponse , err := audiobookshelf.Libraries(url, loginResp.User.Token)
assert.NoError(t, err)
assert.NotNil(t, libraryResponse)
assert.NotEmpty(t, libraryResponse.Libraries)
}
}
}

func TestScan(t *testing.T) {
config.Load()
url := config.AudiobookshelfUrl()
username := config.AudiobookshelfUser()
password := config.AudiobookshelfPassword()
libraryName := config.AudiobookshelfLibrary()

if url != "" && username != "" && password != "" && libraryName != "" {
loginResp, err := audiobookshelf.Login(url+"/login", username, password)
if err == nil {
assert.NoError(t, err)
libraryResponse , err := audiobookshelf.Libraries(url, loginResp.User.Token)
if err == nil {
assert.NoError(t, err)
libraryID, err := audiobookshelf.GetLibraryByName(libraryResponse.Libraries, libraryName)
if err == nil {
err = audiobookshelf.ScanLibrary(url, loginResp.User.Token, libraryID)
assert.NoError(t, err)
assert.NotNil(t, libraryResponse)
assert.NotEmpty(t, libraryResponse.Libraries)
}
}
}
}
}
107 changes: 107 additions & 0 deletions internal/audiobookshelf/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package audiobookshelf

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)

// Call the Audiobookshelf API login method.
func Login(absUrl string, username, password string) (LoginResponse, error) {
requestBody := LoginRequest{
Username: username,
Password: password,
}

requestBodyBytes, err := json.Marshal(requestBody)
if err != nil {
return LoginResponse{}, fmt.Errorf("failed to marshal login response body: %v", err)
}

resp, err := http.Post(absUrl, "application/json", bytes.NewBuffer(requestBodyBytes))
if err != nil {
return LoginResponse{}, fmt.Errorf("failed to make login API call: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return LoginResponse{}, fmt.Errorf("login API call returned status code: %d", resp.StatusCode)
}

var loginResp LoginResponse
err = json.NewDecoder(resp.Body).Decode(&loginResp)
if err != nil {
return LoginResponse{}, fmt.Errorf("failed to decode login response: %v", err)
}

return loginResp, nil
}

// Call the Audiobookshelf API libraries method
func Libraries(url string, token string) (LibrariesResponse, error) {

client := &http.Client{}
url = url + "/api/libraries"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return LibrariesResponse{}, fmt.Errorf("error creating request: %v", err)
}

req.Header.Add("Authorization", "Bearer "+token)

resp, err := client.Do(req)
if err != nil {
return LibrariesResponse{}, fmt.Errorf("error sending request: %v", err)
}
defer resp.Body.Close()

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return LibrariesResponse{}, fmt.Errorf("error reading response body: %v", err)
}

var response LibrariesResponse
err = json.Unmarshal(body, &response)
if err != nil {
return LibrariesResponse{}, fmt.Errorf("error parsing response body: %v", err)
}

return response, nil
}

func GetLibraryByName(libraries []Library, libraryName string) (libraryID string, err error) {

for _, library := range libraries {
if library.Name == libraryName {
return library.ID, nil
}
}
return "", fmt.Errorf("no library with name '%s' found", libraryName)
}

// Call the Audiobookshelf API
func ScanLibrary(url string, authToken string, libraryID string) error {
url = url + "/api/libraries/" + libraryID + "/scan"
req, err := http.NewRequest("POST", url, nil)
if err != nil {
return fmt.Errorf("error creating request: %v", err)
}
req.Header.Set("Authorization", "Bearer "+authToken)

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("error sending request: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode == http.StatusForbidden {
return fmt.Errorf("an admin user is required to start a scan")
} else if resp.StatusCode == http.StatusNotFound {
return fmt.Errorf("the user cannot access the library or no library with the provided ID exists")
} else {
return nil
}
}
121 changes: 121 additions & 0 deletions internal/audiobookshelf/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package audiobookshelf

type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}

type LoginResponse struct {
User User `json:"user"`
UserDefaultLibraryID string `json:"userDefaultLibraryId"`
ServerSettings ServerSettings `json:"serverSettings"`
Source string `json:"Source"`
}

type User struct {
ID string `json:"id"`
Username string `json:"username"`
Type string `json:"type"`
Token string `json:"token"`
MediaProgress []MediaProgress `json:"mediaProgress"`
SeriesHideFromContinueListening []interface{} `json:"seriesHideFromContinueListening"`
Bookmarks []interface{} `json:"bookmarks"`
IsActive bool `json:"isActive"`
IsLocked bool `json:"isLocked"`
LastSeen int64 `json:"lastSeen"`
CreatedAt int64 `json:"createdAt"`
Permissions Permissions `json:"permissions"`
LibrariesAccessible []interface{} `json:"librariesAccessible"`
ItemTagsAccessible []interface{} `json:"itemTagsAccessible"`
}

type MediaProgress struct {
ID string `json:"id"`
LibraryItemID string `json:"libraryItemId"`
EpisodeID string `json:"episodeId"`
Duration float64 `json:"duration"`
Progress float64 `json:"progress"`
CurrentTime float64 `json:"currentTime"`
IsFinished bool `json:"isFinished"`
HideFromContinueListening bool `json:"hideFromContinueListening"`
LastUpdate int64 `json:"lastUpdate"`
StartedAt int64 `json:"startedAt"`
FinishedAt *int64 `json:"finishedAt"`
}

type Permissions struct {
Download bool `json:"download"`
Update bool `json:"update"`
Delete bool `json:"delete"`
Upload bool `json:"upload"`
AccessAllLibraries bool `json:"accessAllLibraries"`
AccessAllTags bool `json:"accessAllTags"`
AccessExplicitContent bool `json:"accessExplicitContent"`
}

type ServerSettings struct {
ID string `json:"id"`
ScannerFindCovers bool `json:"scannerFindCovers"`
ScannerCoverProvider string `json:"scannerCoverProvider"`
ScannerParseSubtitle bool `json:"scannerParseSubtitle"`
ScannerPreferAudioMetadata bool `json:"scannerPreferAudioMetadata"`
ScannerPreferOpfMetadata bool `json:"scannerPreferOpfMetadata"`
ScannerPreferMatchedMetadata bool `json:"scannerPreferMatchedMetadata"`
ScannerDisableWatcher bool `json:"scannerDisableWatcher"`
ScannerPreferOverdriveMediaMarker bool `json:"scannerPreferOverdriveMediaMarker"`
ScannerUseSingleThreadedProber bool `json:"scannerUseSingleThreadedProber"`
ScannerMaxThreads int `json:"scannerMaxThreads"`
ScannerUseTone bool `json:"scannerUseTone"`
StoreCoverWithItem bool `json:"storeCoverWithItem"`
StoreMetadataWithItem bool `json:"storeMetadataWithItem"`
MetadataFileFormat string `json:"metadataFileFormat"`
RateLimitLoginRequests int `json:"rateLimitLoginRequests"`
RateLimitLoginWindow int `json:"rateLimitLoginWindow"`
BackupSchedule string `json:"backupSchedule"`
BackupsToKeep int `json:"backupsToKeep"`
MaxBackupSize int `json:"maxBackupSize"`
BackupMetadataCovers bool `json:"backupMetadataCovers"`
LoggerDailyLogsToKeep int `json:"loggerDailyLogsToKeep"`
LoggerScannerLogsToKeep int `json:"loggerScannerLogsToKeep"`
HomeBookshelfView int `json:"homeBookshelfView"`
BookshelfView int `json:"bookshelfView"`
SortingIgnorePrefix bool `json:"sortingIgnorePrefix"`
SortingPrefixes []string `json:"sortingPrefixes"`
ChromecastEnabled bool `json:"chromecastEnabled"`
DateFormat string `json:"dateFormat"`
Language string `json:"language"`
LogLevel int `json:"logLevel"`
Version string `json:"version"`
}

type LibrariesResponse struct {
Libraries []Library `json:"libraries"`
}

type Library struct {
ID string `json:"id"`
Name string `json:"name"`
Folders []Folder `json:"folders"`
DisplayOrder int `json:"displayOrder"`
Icon string `json:"icon"`
MediaType string `json:"mediaType"`
Provider string `json:"provider"`
Settings LibrarySettings `json:"settings"`
CreatedAt int64 `json:"createdAt"`
LastUpdate int64 `json:"lastUpdate"`
}

type Folder struct {
ID string `json:"id"`
FullPath string `json:"fullPath"`
LibraryID string `json:"libraryId"`
AddedAt int64 `json:"addedAt,omitempty"`
}

type LibrarySettings struct {
CoverAspectRatio float64 `json:"coverAspectRatio"`
DisableWatcher bool `json:"disableWatcher"`
SkipMatchingMediaWithASIN bool `json:"skipMatchingMediaWithAsin"`
SkipMatchingMediaWithISBN bool `json:"skipMatchingMediaWithIsbn"`
AutoScanCronExpression string `json:"autoScanCronExpression,omitempty"`
}

0 comments on commit 49bc421

Please sign in to comment.