Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/wraient/curd
Browse files Browse the repository at this point in the history
  • Loading branch information
Wraient committed Feb 14, 2025
2 parents 6cabe21 + 3ff5478 commit 0b4ca32
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 84 deletions.
30 changes: 19 additions & 11 deletions cmd/curd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import (
"fmt"
"os"
"path/filepath"
"strconv"
"runtime"
"strconv"
"sync"
"time"

"github.com/wraient/curd/internal"
)

Expand Down Expand Up @@ -475,7 +476,7 @@ func main() {
}()

// Skip OP and ED and Save MPV Speed
skipLoop:
skipLoop:
for {
select {
case <-skipLoopDone:
Expand Down Expand Up @@ -520,17 +521,24 @@ func main() {
}()

anime.Ep.IsCompleted = false
// internal.CurdOut(anime.Ep.Number, anime.TotalEpisodes, &userCurdConfig)
if anime.Ep.Number-1 == anime.TotalEpisodes && userCurdConfig.ScoreOnCompletion {
anime.Ep.Number = anime.Ep.Number - 1
internal.CurdOut("Completed anime.")
err = internal.RateAnime(user.Token, anime.AnilistId)
// Only mark as complete and prompt for rating if we've reached the total episodes
// AND the anime is not currently airing (total episodes > 0)
if anime.Ep.Number-1 == anime.TotalEpisodes && userCurdConfig.ScoreOnCompletion && anime.TotalEpisodes > 0 {
// Get updated anime data to check if it's still airing
updatedAnime, err := internal.GetAnimeDataByID(anime.AnilistId, user.Token)
if err != nil {
internal.Log("Error rating anime: "+err.Error(), logFile)
internal.CurdOut("Error rating anime: " + err.Error())
internal.Log("Error getting updated anime data: "+err.Error(), logFile)
} else if !updatedAnime.IsAiring {
anime.Ep.Number = anime.Ep.Number - 1
internal.CurdOut("Completed anime.")
err = internal.RateAnime(user.Token, anime.AnilistId)
if err != nil {
internal.Log("Error rating anime: "+err.Error(), logFile)
internal.CurdOut("Error rating anime: " + err.Error())
}
internal.LocalDeleteAnime(databaseFile, anime.AnilistId, anime.AllanimeId)
internal.ExitCurd(nil)
}
internal.LocalDeleteAnime(databaseFile, anime.AnilistId, anime.AllanimeId)
internal.ExitCurd(nil)
}
}
if anime.Rewatching && anime.Ep.IsCompleted && anime.Ep.Number-1 == anime.TotalEpisodes {
Expand Down
105 changes: 44 additions & 61 deletions internal/anilist.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
Expand Down Expand Up @@ -33,7 +32,7 @@ func GetAnimeMap(animeList AnimeList) map[string]string {
for _, entry := range entries {
// Only include entries with a non-empty English title

if entry.Media.Title.English != "" && userCurdConfig.AnimeNameLanguage == "english" {
if entry.Media.Title.English != "" && userCurdConfig.AnimeNameLanguage == "english" {
animeMap[strconv.Itoa(entry.Media.ID)] = entry.Media.Title.English
} else {
animeMap[strconv.Itoa(entry.Media.ID)] = entry.Media.Title.Romaji
Expand Down Expand Up @@ -63,12 +62,12 @@ func GetAnimeMapPreview(animeList AnimeList) map[string]RofiSelectPreview {
Log(fmt.Sprintf("AnimeNameLanguage: ", userCurdConfig.AnimeNameLanguage), logFile)
if entry.Media.Title.English != "" && userCurdConfig.AnimeNameLanguage == "english" {
animeMap[strconv.Itoa(entry.Media.ID)] = RofiSelectPreview{
Title: entry.Media.Title.English,
Title: entry.Media.Title.English,
CoverImage: entry.CoverImage,
}
} else {
animeMap[strconv.Itoa(entry.Media.ID)] = RofiSelectPreview{
Title: entry.Media.Title.Romaji,
Title: entry.Media.Title.Romaji,
CoverImage: entry.CoverImage,
}
}
Expand Down Expand Up @@ -459,9 +458,9 @@ func SearchAnimeByTitle(jsonData map[string]interface{}, searchTitle string) []m

if strings.Contains(strings.ToLower(romajiTitle), strings.ToLower(searchTitle)) || strings.Contains(strings.ToLower(englishTitle), strings.ToLower(searchTitle)) {
result := map[string]interface{}{
"id": media["id"],
"progress": entry.(map[string]interface{})["progress"],
"romaji_title": romajiTitle,
"id": media["id"],
"progress": entry.(map[string]interface{})["progress"],
"romaji_title": romajiTitle,
"english_title": englishTitle,
"episodes": episodes,
"duration": duration,
Expand Down Expand Up @@ -609,7 +608,7 @@ func makePostRequest(url, query string, variables map[string]interface{}, header
return nil, fmt.Errorf("failed to create request: %w", err)
}

req.Header.Set("Content-Type", "application/json") // <-- Important!
req.Header.Set("Content-Type", "application/json") // <-- Important!
for key, value := range headers {
req.Header.Set(key, value)
}
Expand Down Expand Up @@ -691,9 +690,9 @@ func ParseAnimeList(input map[string]interface{}) AnimeList {
Episodes: toInt(media["episodes"]),
ID: toInt(media["id"]),
Title: AnimeTitle{
English: safeString(media["title"].(map[string]interface{})["english"]),
Romaji: safeString(media["title"].(map[string]interface{})["romaji"]),
Japanese: safeString(media["title"].(map[string]interface{})["native"]),
English: safeString(media["title"].(map[string]interface{})["english"]),
Romaji: safeString(media["title"].(map[string]interface{})["romaji"]),
Japanese: safeString(media["title"].(map[string]interface{})["native"]),
},
},
Progress: toInt(entryData["progress"]),
Expand Down Expand Up @@ -763,78 +762,62 @@ func FindAnimeByAnilistIDInAnimes(animes []Anime, anilistID int) (*Anime, error)
}

// GetAnimeDataByID retrieves detailed anime data from AniList using the anime's ID and user token
func GetAnimeDataByID(anilistID int, token string) (Anime, error) {
func GetAnimeDataByID(id int, token string) (Anime, error) {
url := "https://graphql.anilist.co"
query := `
query ($id: Int) {
Media (id: $id, type: ANIME) {
Media(id: $id, type: ANIME) {
id
title {
romaji
english
native
}
episodes
duration
status
nextAiringEpisode {
episode
}
}
}
`

}`

variables := map[string]interface{}{
"id": anilistID,
"id": id,
}

jsonValue, _ := json.Marshal(map[string]interface{}{
"query": query,
"variables": variables,
})
headers := map[string]string{
"Authorization": "Bearer " + token,
"Content-Type": "application/json",
}

req, err := http.NewRequest("POST", "https://graphql.anilist.co", bytes.NewBuffer(jsonValue))
response, err := makePostRequest(url, query, variables, headers)
if err != nil {
return Anime{}, fmt.Errorf("error creating request: %v", err)
return Anime{}, fmt.Errorf("failed to get anime data: %w", err)
}

req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
data, ok := response["data"].(map[string]interface{})
if !ok {
return Anime{}, fmt.Errorf("invalid response format: data field missing")
}

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return Anime{}, fmt.Errorf("error sending request: %v", err)
media, ok := data["Media"].(map[string]interface{})
if !ok {
return Anime{}, fmt.Errorf("invalid response format: Media field missing")
}
defer resp.Body.Close()

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return Anime{}, fmt.Errorf("error reading response: %v", err)
anime := Anime{
AnilistId: id,
IsAiring: false,
}

var result struct {
Data struct {
Media struct {
ID int `json:"id"`
Title AnimeTitle `json:"title"`
Episodes int `json:"episodes"`
Duration int `json:"duration"`
Status string `json:"status"`
CoverImage struct {
Large string `json:"large"`
} `json:"coverImage"`
Genres []string `json:"genres"`
AverageScore int `json:"averageScore"`
} `json:"Media"`
} `json:"data"`
// Safely handle episodes field which might be nil for currently airing shows
if episodes, ok := media["episodes"].(float64); ok {
anime.TotalEpisodes = int(episodes)
}

if err := json.Unmarshal(body, &result); err != nil {
return Anime{}, fmt.Errorf("error unmarshaling JSON: %v", err)
// Check status
if status, ok := media["status"].(string); ok {
anime.IsAiring = status == "RELEASING"
}

anime := Anime{
AnilistId: result.Data.Media.ID,
Title: result.Data.Media.Title,
TotalEpisodes: result.Data.Media.Episodes,
CoverImage: result.Data.Media.CoverImage.Large,
// Double check with nextAiringEpisode
if nextEp, ok := media["nextAiringEpisode"].(map[string]interface{}); ok && nextEp != nil {
anime.IsAiring = true
}

return anime, nil
Expand Down
25 changes: 13 additions & 12 deletions internal/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ type AnimeTitle struct {
}

type Anime struct {
Title AnimeTitle `json:"title"`
Ep Episode `json:"ep"`
CoverImage string `json:"url"` // Assuming this field corresponds to the cover image URL
TotalEpisodes int `json:"total_episodes"` // If provided by the API
MalId int `json:"mal_id"`
AnilistId int `json:"anilist_id"` // Assuming you have an Anilist ID in your struct
Rewatching bool
AllanimeId string // Can be populated as necessary
FillerEpisodes []int
Title AnimeTitle `json:"title"`
Ep Episode `json:"ep"`
CoverImage string `json:"url"` // Assuming this field corresponds to the cover image URL
TotalEpisodes int `json:"total_episodes"` // If provided by the API
MalId int `json:"mal_id"`
AnilistId int `json:"anilist_id"` // Assuming you have an Anilist ID in your struct
Rewatching bool
AllanimeId string // Can be populated as necessary
FillerEpisodes []int
IsAiring bool
}

type Skip struct {
Expand All @@ -37,7 +38,7 @@ type Episode struct {
Started bool `json:"started"`
Duration int `json:"duration"`
Links []string `json:"links"`
NextEpisode NextEpisode `json:"next_episode"`
NextEpisode NextEpisode `json:"next_episode"`
IsFiller bool `json:"filler"`
IsRecap bool `json:"recap"`
Aired string `json:"aired"`
Expand All @@ -48,8 +49,8 @@ type Episode struct {
}

type NextEpisode struct {
Number int
Links []string
Number int
Links []string
}

type playingVideo struct {
Expand Down

0 comments on commit 0b4ca32

Please sign in to comment.