Skip to content

Commit

Permalink
feat: support syncing people lists
Browse files Browse the repository at this point in the history
fixes #56
  • Loading branch information
cecobask committed Jul 29, 2024
1 parent 95e8eb9 commit ab61739
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 41 deletions.
1 change: 0 additions & 1 deletion cmd/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@ const (
CommandNameSync = "sync"
ConfigFileDefault = "config.yaml"
FlagNameConfigFile = "config-file"
FlagNameInteractive = "interactive"
)
8 changes: 6 additions & 2 deletions internal/entities/imdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ const (
imdbItemTypeTvEpisode = "TV Episode"
imdbItemTypeTvMiniSeries = "TV Mini Series"
imdbItemTypeTvSeries = "TV Series"
imdbItemTypePerson = "Person"
)

type IMDbItem struct {
ID string
TitleType string
Kind string
Rating *int
RatingDate *time.Time
}
Expand All @@ -31,7 +32,7 @@ func (i *IMDbItem) toTraktItem() TraktItem {
tiSpec.WatchedAt = &ratedAt
tiSpec.Rating = i.Rating
}
switch i.TitleType {
switch i.Kind {
case imdbItemTypeMovie:
ti.Type = TraktItemTypeMovie
ti.Movie = tiSpec
Expand All @@ -44,6 +45,9 @@ func (i *IMDbItem) toTraktItem() TraktItem {
case imdbItemTypeTvEpisode:
ti.Type = TraktItemTypeEpisode
ti.Episode = tiSpec
case imdbItemTypePerson:
ti.Type = TraktItemTypePerson
ti.Person = tiSpec
default:
ti.Type = TraktItemTypeMovie
ti.Movie = tiSpec
Expand Down
6 changes: 6 additions & 0 deletions internal/entities/trakt.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
TraktItemTypeMovie = "movie"
TraktItemTypeSeason = "season"
TraktItemTypeShow = "show"
TraktItemTypePerson = "person"
)

type TraktAuthCodesBody struct {
Expand Down Expand Up @@ -63,6 +64,7 @@ type TraktItem struct {
Movie TraktItemSpec `json:"movie,omitempty"`
Show TraktItemSpec `json:"show,omitempty"`
Episode TraktItemSpec `json:"episode,omitempty"`
Person TraktItemSpec `json:"person,omitempty"`
}

type TraktItems []TraktItem
Expand All @@ -77,6 +79,8 @@ func (item *TraktItem) GetItemID() (*string, error) {
return &item.Episode.IDMeta.IMDb, nil
case TraktItemTypeSeason:
return nil, nil
case TraktItemTypePerson:
return &item.Person.IDMeta.IMDb, nil
default:
return nil, fmt.Errorf("unknown trakt item type %s", item.Type)
}
Expand All @@ -86,6 +90,7 @@ type TraktListBody struct {
Movies TraktItemSpecs `json:"movies,omitempty"`
Shows TraktItemSpecs `json:"shows,omitempty"`
Episodes TraktItemSpecs `json:"episodes,omitempty"`
People TraktItemSpecs `json:"people,omitempty"`
}

type TraktListAddBody struct {
Expand All @@ -102,6 +107,7 @@ type TraktCrudItem struct {
Movies int `json:"movies,omitempty"`
Shows int `json:"shows,omitempty"`
Episodes int `json:"episodes,omitempty"`
People int `json:"people,omitempty"`
}

type TraktResponse struct {
Expand Down
125 changes: 89 additions & 36 deletions pkg/client/imdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ func (c *IMDbClient) ratingsDownload(resource *rod.Element) ([]entities.IMDbItem
if err = downloadButton.Click(proto.InputMouseButtonLeft, 1); err != nil {
return nil, fmt.Errorf("failure clicking on download button: %w", err)
}
items, err := transformRatingsData(wait())
items, err := transformData(wait())
if err != nil {
return nil, fmt.Errorf("failure transforming ratings data: %w", err)
}
Expand Down Expand Up @@ -323,7 +323,7 @@ func (c *IMDbClient) listDownload(resource *rod.Element) (*entities.IMDbList, er
if err = downloadButton.Click(proto.InputMouseButtonLeft, 1); err != nil {
return nil, fmt.Errorf("failure clicking on download button: %w", err)
}
items, err := transformListData(wait())
items, err := transformData(wait())
if err != nil {
return nil, fmt.Errorf("failure transforming list data: %w", err)
}
Expand Down Expand Up @@ -552,45 +552,88 @@ func isRatingsHyperlink(href, userID string) bool {
return strings.HasPrefix(href, prefix)
}

func transformListData(data []byte) ([]entities.IMDbItem, error) {
csvReader := csv.NewReader(bytes.NewReader(data))
csvReader.LazyQuotes = true
csvReader.FieldsPerRecord = -1
csvData, err := csvReader.ReadAll()
if err != nil {
return nil, fmt.Errorf("failure reading list csv records: %w", err)
}
var items []entities.IMDbItem
for i, record := range csvData {
if i == 0 {
if len(record) == 8 {
if record[7] == "Birth Date" {
slog.Info("people lists are not yet supported")
return items, nil
}
}
continue
}
func isPeopleList(header []string) bool {
return slices.Equal(header, []string{
"Position",
"Const",
"Created",
"Modified",
"Description",
"Name",
"Known For",
"Birth Date",
})
}

items = append(items, entities.IMDbItem{
ID: record[1],
TitleType: record[8],
})
}
return items, nil
func isTitlesList(header []string) bool {
return slices.Equal(header, []string{
"Position",
"Const",
"Created",
"Modified",
"Description",
"Title",
"Original Title",
"URL",
"Title Type",
"IMDb Rating",
"Runtime (mins)",
"Year",
"Genres",
"Num Votes",
"Release Date",
"Directors",
"Your Rating",
"Date Rated",
})
}

func transformRatingsData(data []byte) ([]entities.IMDbItem, error) {
func isRatingsList(header []string) bool {
return slices.Equal(header, []string{
"Const",
"Your Rating",
"Date Rated",
"Title",
"Original Title",
"URL",
"Title Type",
"IMDb Rating",
"Runtime (mins)",
"Year",
"Genres",
"Num Votes",
"Release Date",
"Directors",
})
}

func transformData(data []byte) ([]entities.IMDbItem, error) {
csvReader := csv.NewReader(bytes.NewReader(data))
csvReader.LazyQuotes = true
csvReader.FieldsPerRecord = -1
csvData, err := csvReader.ReadAll()
if err != nil {
return nil, fmt.Errorf("failure reading ratings csv records: %w", err)
return nil, fmt.Errorf("failure reading csv records: %w", err)
}
if len(csvData) == 0 {
return nil, fmt.Errorf("expected csv records to have at least header row, but got empty result")
}
var (
header = csvData[0]
records = csvData[1:]
items = make([]entities.IMDbItem, len(records))
)
if isTitlesList(header) {
for i, record := range records {
items[i] = entities.IMDbItem{
ID: record[1],
Kind: record[8],
}
}
return items, nil
}
var ratings []entities.IMDbItem
for i, record := range csvData {
if i > 0 {
if isRatingsList(header) {
for i, record := range records {
rating, err := strconv.Atoi(record[1])
if err != nil {
return nil, fmt.Errorf("failure parsing rating value to integer: %w", err)
Expand All @@ -599,15 +642,25 @@ func transformRatingsData(data []byte) ([]entities.IMDbItem, error) {
if err != nil {
return nil, fmt.Errorf("failure parsing rating date: %w", err)
}
ratings = append(ratings, entities.IMDbItem{
items[i] = entities.IMDbItem{
ID: record[0],
TitleType: record[6],
Kind: record[6],
Rating: &rating,
RatingDate: &ratingDate,
})
}
}
return items, nil
}
if isPeopleList(header) {
for i, record := range records {
items[i] = entities.IMDbItem{
ID: record[1],
Kind: "Person",
}
}
return items, nil
}
return ratings, nil
return nil, fmt.Errorf("unrecognized list type with header %s", header)
}

func idExtract(href string) (string, error) {
Expand Down
16 changes: 16 additions & 0 deletions pkg/client/testdata/trakt_list.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,21 @@
"tmdb": 98
}
}
},
{
"rank": 4,
"id": 954810079,
"listed_at": "2023-12-31T15:22:02.000Z",
"notes": null,
"type": "person",
"person": {
"name": "Garrett Hedlund",
"ids": {
"trakt": 69,
"slug": "garrett-hedlund",
"imdb": "nm1330560",
"tmdb": 9828
}
}
}
]
2 changes: 2 additions & 0 deletions pkg/client/trakt.go
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,8 @@ func mapTraktItemsToTraktBody(items entities.TraktItems) entities.TraktListBody
res.Shows = append(res.Shows, items[i].Show)
case entities.TraktItemTypeEpisode:
res.Episodes = append(res.Episodes, items[i].Episode)
case entities.TraktItemTypePerson:
res.People = append(res.People, items[i].Person)
default:
continue
}
Expand Down
12 changes: 10 additions & 2 deletions pkg/client/trakt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ var (
{
Type: entities.TraktItemTypeSeason,
},
{
Type: entities.TraktItemTypePerson,
Person: entities.TraktItemSpec{
IDMeta: entities.TraktIDMeta{
IMDb: "nm1330560",
},
},
},
}
dummyRequestFields = requestFields{
Method: http.MethodPost,
Expand Down Expand Up @@ -273,7 +281,7 @@ func TestTraktClient_WatchlistGet(t *testing.T) {
assertions.NoError(err)
assertions.Equal("watchlist", list.IDMeta.Slug)
assertions.Equal(true, list.IsWatchlist)
assertions.Equal(3, len(list.ListItems))
assertions.Equal(4, len(list.ListItems))
},
},
{
Expand Down Expand Up @@ -531,7 +539,7 @@ func TestTraktClient_ListGet(t *testing.T) {
assertions.NoError(err)
assertions.Equal(dummyListID, list.IDMeta.Slug)
assertions.Equal(false, list.IsWatchlist)
assertions.Equal(3, len(list.ListItems))
assertions.Equal(4, len(list.ListItems))
},
},
{
Expand Down

0 comments on commit ab61739

Please sign in to comment.