9 Commits

12 changed files with 206 additions and 152 deletions

View File

@ -31,12 +31,15 @@ func AniListQuery(body interface{}, login bool) (json.RawMessage, string) {
defer res.Body.Close() defer res.Body.Close()
returnedBody, err := io.ReadAll(res.Body) returnedBody, err := io.ReadAll(res.Body)
if err != nil {
return nil, "Could not read the returned body."
}
return returnedBody, res.Status return returnedBody, res.Status
} }
func (a *App) GetAniListItem(aniId int, login bool) AniListGetSingleAnime { func (a *App) GetAniListItem(aniId int, login bool) AniListGetSingleAnime {
var user = a.GetAniListLoggedInUser() user := a.GetAniListLoggedInUser()
var neededVariables interface{} var neededVariables interface{}
@ -141,7 +144,7 @@ func (a *App) GetAniListItem(aniId int, login bool) AniListGetSingleAnime {
returnedBody, status := AniListQuery(body, login) returnedBody, status := AniListQuery(body, login)
var post AniListGetSingleAnime var post AniListGetSingleAnime
if status == "404 Not Found" && login == false { if status == "404 Not Found" && !login {
return post return post
} }
@ -154,7 +157,7 @@ func (a *App) GetAniListItem(aniId int, login bool) AniListGetSingleAnime {
log.Printf("Failed at unmarshal, %s\n", err) log.Printf("Failed at unmarshal, %s\n", err)
} }
if login == false { if !login {
post.Data.MediaList.UserID = user.Data.Viewer.ID post.Data.MediaList.UserID = user.Data.Viewer.ID
post.Data.MediaList.Status = "" post.Data.MediaList.Status = ""
post.Data.MediaList.StartedAt.Year = 0 post.Data.MediaList.StartedAt.Year = 0
@ -249,7 +252,7 @@ func (a *App) AniListSearch(query string) any {
} }
func (a *App) GetAniListUserWatchingList(page int, perPage int, sort string) AniListCurrentUserWatchList { func (a *App) GetAniListUserWatchingList(page int, perPage int, sort string) AniListCurrentUserWatchList {
var user = a.GetAniListLoggedInUser() user := a.GetAniListLoggedInUser()
type Variables struct { type Variables struct {
Page int `json:"page"` Page int `json:"page"`
PerPage int `json:"perPage"` PerPage int `json:"perPage"`

View File

@ -30,11 +30,11 @@ var aniCtxShutdown, aniCancel = context.WithCancel(context.Background())
func (a *App) CheckIfAniListLoggedIn() bool { func (a *App) CheckIfAniListLoggedIn() bool {
if (AniListJWT{} == aniListJwt) { if (AniListJWT{} == aniListJwt) {
tokenType, err := aniRing.Get("anilistTokenType") tokenType, tokenErr := aniRing.Get("anilistTokenType")
expiresIn, err := aniRing.Get("anilistTokenExpiresIn") expiresIn, expiresInErr := aniRing.Get("anilistTokenExpiresIn")
accessToken, err := aniRing.Get("anilistAccessToken") refreshToken, refreshTokenErr := aniRing.Get("anilistRefreshToken")
refreshToken, err := aniRing.Get("anilistRefreshToken") accessToken, accessTokenErr := aniRing.Get("anilistAccessToken")
if err != nil || len(accessToken.Data) == 0 { if (tokenErr != nil || expiresInErr != nil || refreshTokenErr != nil || accessTokenErr != nil) || len(accessToken.Data) == 0 {
return false return false
} else { } else {
aniListJwt.TokenType = string(tokenType.Data) aniListJwt.TokenType = string(tokenType.Data)
@ -50,11 +50,11 @@ func (a *App) CheckIfAniListLoggedIn() bool {
func (a *App) AniListLogin() { func (a *App) AniListLogin() {
if (AniListJWT{} == aniListJwt) { if (AniListJWT{} == aniListJwt) {
tokenType, err := aniRing.Get("anilistTokenType") tokenType, tokenErr := aniRing.Get("anilistTokenType")
expiresIn, err := aniRing.Get("anilistTokenExpiresIn") expiresIn, expiresInErr := aniRing.Get("anilistTokenExpiresIn")
accessToken, err := aniRing.Get("anilistAccessToken") refreshToken, refreshTokenErr := aniRing.Get("anilistRefreshToken")
refreshToken, err := aniRing.Get("anilistRefreshToken") accessToken, accessTokenErr := aniRing.Get("anilistAccessToken")
if err != nil || len(accessToken.Data) == 0 { if (tokenErr != nil || expiresInErr != nil || refreshTokenErr != nil || accessTokenErr != nil) || len(accessToken.Data) == 0 {
getAniListCodeUrl := "https://anilist.co/api/v2/oauth/authorize?client_id=" + Environment.ANILIST_APP_ID + "&redirect_uri=" + Environment.ANILIST_CALLBACK_URI + "&response_type=code" getAniListCodeUrl := "https://anilist.co/api/v2/oauth/authorize?client_id=" + Environment.ANILIST_APP_ID + "&redirect_uri=" + Environment.ANILIST_CALLBACK_URI + "&response_type=code"
runtime.BrowserOpenURL(*wailsContext, getAniListCodeUrl) runtime.BrowserOpenURL(*wailsContext, getAniListCodeUrl)
@ -160,6 +160,9 @@ func getAniListAuthorizationToken(content string) AniListJWT {
defer res.Body.Close() defer res.Body.Close()
returnedBody, err := io.ReadAll(res.Body) returnedBody, err := io.ReadAll(res.Body)
if err != nil {
log.Printf("Could not read returned body, %s\n.", err)
}
var post AniListJWT var post AniListJWT
err = json.Unmarshal(returnedBody, &post) err = json.Unmarshal(returnedBody, &post)
@ -204,13 +207,12 @@ func (a *App) GetAniListLoggedInUser() AniListUser {
func (a *App) LogoutAniList() string { func (a *App) LogoutAniList() string {
if (AniListJWT{} != aniListJwt) { if (AniListJWT{} != aniListJwt) {
err := aniRing.Remove("anilistTokenType") typeErr := aniRing.Remove("anilistTokenType")
err = aniRing.Remove("anilistTokenExpiresIn") expiresInErr := aniRing.Remove("anilistTokenExpiresIn")
err = aniRing.Remove("anilistAccessToken") accessTokenErr := aniRing.Remove("anilistAccessToken")
err = aniRing.Remove("anilistRefreshToken") refreshTokenErr := aniRing.Remove("anilistRefreshToken")
if typeErr != nil || expiresInErr != nil || accessTokenErr != nil || refreshTokenErr != nil {
if err != nil { fmt.Println("AniList Logout Failed")
fmt.Println("AniList Logout Failed", err)
} }
aniListJwt = AniListJWT{} aniListJwt = AniListJWT{}
} }

View File

@ -46,10 +46,10 @@ type MALWatchlist struct {
Id int `json:"id" ts_type:"id"` Id int `json:"id" ts_type:"id"`
Title string `json:"title" ts_type:"title"` Title string `json:"title" ts_type:"title"`
MainPicture struct { MainPicture struct {
Medium string `json:"medium" json:"medium"` Medium string `json:"medium" ts_type:"medium"`
Large string `json:"large" json:"large"` Large string `json:"large" ts_type:"large"`
} `json:"main_picture" json:"mainPicture"` } `json:"main_picture" ts_type:"mainPicture"`
} `json:"node" json:"node"` } `json:"node" ts_type:"node"`
ListStatus struct { ListStatus struct {
Status string `json:"status" ts_type:"status"` Status string `json:"status" ts_type:"status"`
Score int `json:"score" ts_type:"score"` Score int `json:"score" ts_type:"score"`
@ -59,7 +59,7 @@ type MALWatchlist struct {
StartDate string `json:"start_date" ts_type:"startDate"` StartDate string `json:"start_date" ts_type:"startDate"`
FinishDate string `json:"finish_date" ts_type:"finishDate"` FinishDate string `json:"finish_date" ts_type:"finishDate"`
} `json:"list_status" ts_type:"listStatus"` } `json:"list_status" ts_type:"listStatus"`
} `json:"data" json:"data"` } `json:"data" ts_type:"data"`
Paging struct { Paging struct {
Previous string `json:"previous" ts_type:"previous"` Previous string `json:"previous" ts_type:"previous"`
Next string `json:"next" ts_type:"next"` Next string `json:"next" ts_type:"next"`
@ -70,9 +70,9 @@ type MALAnime struct {
Id int `json:"id" ts_type:"id"` Id int `json:"id" ts_type:"id"`
Title string `json:"title" ts_type:"title"` Title string `json:"title" ts_type:"title"`
MainPicture struct { MainPicture struct {
Large string `json:"large" json:"large"` Large string `json:"large" ts_type:"large"`
Medium string `json:"medium" json:"medium"` Medium string `json:"medium" ts_type:"medium"`
} `json:"main_picture" json:"mainPicture"` } `json:"main_picture" ts_type:"mainPicture"`
AlternativeTitles struct { AlternativeTitles struct {
Synonyms []string `json:"synonyms" ts_type:"synonyms"` Synonyms []string `json:"synonyms" ts_type:"synonyms"`
En string `json:"en" ts_type:"en"` En string `json:"en" ts_type:"en"`

View File

@ -50,7 +50,7 @@ func base64URLEncode(str []byte) string {
func verifier() (*CodeVerifier, error) { func verifier() (*CodeVerifier, error) {
r := rand.New(rand.NewSource(time.Now().UnixNano())) r := rand.New(rand.NewSource(time.Now().UnixNano()))
b := make([]byte, length, length) b := make([]byte, length)
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
b[i] = byte(r.Intn(255)) b[i] = byte(r.Intn(255))
} }
@ -70,17 +70,19 @@ func (v *CodeVerifier) CodeChallengeS256() string {
} }
func (a *App) CheckIfMyAnimeListLoggedIn() bool { func (a *App) CheckIfMyAnimeListLoggedIn() bool {
fmt.Println("check function reached")
if (MyAnimeListJWT{} == myAnimeListJwt) { if (MyAnimeListJWT{} == myAnimeListJwt) {
tokenType, err := myAnimeListRing.Get("MyAnimeListTokenType") tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType")
expiresIn, err := myAnimeListRing.Get("MyAnimeListExpiresIn") expiresIn, expiresInErr := myAnimeListRing.Get("MyAnimeListExpiresIn")
accessToken, err := myAnimeListRing.Get("MyAnimeListAccessToken") refreshToken, refreshTokenErr := myAnimeListRing.Get("MyAnimeListAccessToken")
refreshToken, err := myAnimeListRing.Get("MyAnimeListRefreshToken") accessToken, accessTokenErr := myAnimeListRing.Get("MyAnimeListRefreshToken")
if err != nil || len(accessToken.Data) == 0 { if (tokenErr != nil || expiresInErr != nil || refreshTokenErr != nil || accessTokenErr != nil) || len(accessToken.Data) == 0 {
return false return false
} else { } else {
var expresInConvertErr error
myAnimeListJwt.TokenType = string(tokenType.Data) myAnimeListJwt.TokenType = string(tokenType.Data)
myAnimeListJwt.ExpiresIn, err = strconv.Atoi(string(expiresIn.Data)) myAnimeListJwt.ExpiresIn, expresInConvertErr = strconv.Atoi(string(expiresIn.Data))
if err != nil { if expresInConvertErr != nil {
fmt.Println("unable to convert string to int") fmt.Println("unable to convert string to int")
} }
myAnimeListJwt.AccessToken = string(accessToken.Data) myAnimeListJwt.AccessToken = string(accessToken.Data)
@ -93,12 +95,14 @@ func (a *App) CheckIfMyAnimeListLoggedIn() bool {
} }
func (a *App) MyAnimeListLogin() { func (a *App) MyAnimeListLogin() {
if a.CheckIfMyAnimeListLoggedIn() == false { fmt.Println("login function reached")
tokenType, err := myAnimeListRing.Get("MyAnimeListTokenType") if !a.CheckIfMyAnimeListLoggedIn() {
expiresIn, err := myAnimeListRing.Get("MyAnimeListExpiresIn") fmt.Println("check logged in function failed")
accessToken, err := myAnimeListRing.Get("MyAnimeListAccessToken") tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType")
refreshToken, err := myAnimeListRing.Get("MyAnimeListRefreshToken") expiresIn, expiresInErr := myAnimeListRing.Get("MyAnimeListExpiresIn")
if err != nil || len(accessToken.Data) == 0 { refreshToken, refreshTokenErr := myAnimeListRing.Get("MyAnimeListAccessToken")
accessToken, accessTokenErr := myAnimeListRing.Get("MyAnimeListRefreshToken")
if (tokenErr != nil || expiresInErr != nil || refreshTokenErr != nil || accessTokenErr != nil) || len(accessToken.Data) == 0 {
verifier, _ := verifier() verifier, _ := verifier()
getMyAnimeListCodeUrl := "https://myanimelist.net/v1/oauth2/authorize?response_type=code&client_id=" + Environment.MAL_CLIENT_ID + "&redirect_uri=" + Environment.MAL_CALLBACK_URI + "&code_challenge=" + verifier.Value + "&code_challenge_method=plain" getMyAnimeListCodeUrl := "https://myanimelist.net/v1/oauth2/authorize?response_type=code&client_id=" + Environment.MAL_CLIENT_ID + "&redirect_uri=" + Environment.MAL_CALLBACK_URI + "&code_challenge=" + verifier.Value + "&code_challenge_method=plain"
runtime.BrowserOpenURL(*wailsContext, getMyAnimeListCodeUrl) runtime.BrowserOpenURL(*wailsContext, getMyAnimeListCodeUrl)
@ -107,9 +111,10 @@ func (a *App) MyAnimeListLogin() {
a.handleMyAnimeListCallback(serverDone, verifier) a.handleMyAnimeListCallback(serverDone, verifier)
serverDone.Wait() serverDone.Wait()
} else { } else {
var expresInConvertErr error
myAnimeListJwt.TokenType = string(tokenType.Data) myAnimeListJwt.TokenType = string(tokenType.Data)
myAnimeListJwt.ExpiresIn, err = strconv.Atoi(string(expiresIn.Data)) myAnimeListJwt.ExpiresIn, expresInConvertErr = strconv.Atoi(string(expiresIn.Data))
if err != nil { if expresInConvertErr != nil {
fmt.Println("unable to convert string to int in Login function") fmt.Println("unable to convert string to int in Login function")
} }
myAnimeListJwt.AccessToken = string(accessToken.Data) myAnimeListJwt.AccessToken = string(accessToken.Data)
@ -218,6 +223,9 @@ func getMyAnimeListAuthorizationToken(content string, verifier *CodeVerifier) My
defer res.Body.Close() defer res.Body.Close()
returnedBody, err := io.ReadAll(res.Body) returnedBody, err := io.ReadAll(res.Body)
if err != nil {
log.Printf("Could not read returned body, %s\n", err)
}
var post MyAnimeListJWT var post MyAnimeListJWT
err = json.Unmarshal(returnedBody, &post) err = json.Unmarshal(returnedBody, &post)
@ -265,6 +273,9 @@ func refreshMyAnimeListAuthorizationToken() {
defer res.Body.Close() defer res.Body.Close()
returnedBody, err := io.ReadAll(res.Body) returnedBody, err := io.ReadAll(res.Body)
if err != nil {
log.Printf("Could not read returned body, %s\n", err)
}
err = json.Unmarshal(returnedBody, &myAnimeListJwt) err = json.Unmarshal(returnedBody, &myAnimeListJwt)
if err != nil { if err != nil {
@ -291,12 +302,9 @@ func refreshMyAnimeListAuthorizationToken() {
Title: "MyAnimeList Authorization", Title: "MyAnimeList Authorization",
Message: "It is now safe to close your browser tab", Message: "It is now safe to close your browser tab",
}) })
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
return
} }
func (a *App) GetMyAnimeListLoggedInUser() MyAnimeListUser { func (a *App) GetMyAnimeListLoggedInUser() MyAnimeListUser {
@ -311,7 +319,6 @@ func (a *App) GetMyAnimeListLoggedInUser() MyAnimeListUser {
req.Header.Add("myAnimeList-api-key", Environment.MAL_CLIENT_ID) req.Header.Add("myAnimeList-api-key", Environment.MAL_CLIENT_ID)
response, err := client.Do(req) response, err := client.Do(req)
if err != nil { if err != nil {
log.Printf("Failed at request, %s\n", err) log.Printf("Failed at request, %s\n", err)
return MyAnimeListUser{} return MyAnimeListUser{}
@ -333,13 +340,12 @@ func (a *App) GetMyAnimeListLoggedInUser() MyAnimeListUser {
func (a *App) LogoutMyAnimeList() string { func (a *App) LogoutMyAnimeList() string {
if (MyAnimeListJWT{} != myAnimeListJwt) { if (MyAnimeListJWT{} != myAnimeListJwt) {
err := myAnimeListRing.Remove("MyAnimeListTokenType") typeErr := myAnimeListRing.Remove("MyAnimeListTokenType")
err = myAnimeListRing.Remove("MyAnimeListExpiresIn") expiresInErr := myAnimeListRing.Remove("MyAnimeListExpiresIn")
err = myAnimeListRing.Remove("MyAnimeListAccessToken") accessTokenErr := myAnimeListRing.Remove("MyAnimeListAccessToken")
err = myAnimeListRing.Remove("MyAnimeListRefreshToken") refreshTokenErr := myAnimeListRing.Remove("MyAnimeListRefreshToken")
if typeErr != nil || expiresInErr != nil || accessTokenErr != nil || refreshTokenErr != nil {
if err != nil { fmt.Println("MAL Logout Failed")
fmt.Println("MAL Logout Failed", err)
} }
myAnimeListJwt = MyAnimeListJWT{} myAnimeListJwt = MyAnimeListJWT{}
} }

View File

@ -31,7 +31,6 @@ func SimklHelper(method string, url string, body interface{}) json.RawMessage {
req.Header.Add("simkl-api-key", Environment.SIMKL_CLIENT_ID) req.Header.Add("simkl-api-key", Environment.SIMKL_CLIENT_ID)
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
fmt.Println("Errored when sending request to the server") fmt.Println("Errored when sending request to the server")
message, _ := json.Marshal(struct { message, _ := json.Marshal(struct {
@ -47,7 +46,6 @@ func SimklHelper(method string, url string, body interface{}) json.RawMessage {
respBody, _ := io.ReadAll(resp.Body) respBody, _ := io.ReadAll(resp.Body)
return respBody return respBody
} }
func (a *App) SimklGetUserWatchlist() SimklWatchListType { func (a *App) SimklGetUserWatchlist() SimklWatchListType {
@ -62,7 +60,6 @@ func (a *App) SimklGetUserWatchlist() SimklWatchListType {
} }
err := json.Unmarshal(respBody, &errCheck) err := json.Unmarshal(respBody, &errCheck)
if err != nil { if err != nil {
log.Printf("Failed at unmarshal, %s\n", err) log.Printf("Failed at unmarshal, %s\n", err)
} }
@ -85,7 +82,6 @@ func (a *App) SimklGetUserWatchlist() SimklWatchListType {
} }
func (a *App) SimklSyncEpisodes(anime SimklAnime, progress int) SimklAnime { func (a *App) SimklSyncEpisodes(anime SimklAnime, progress int) SimklAnime {
var episodes []Episode var episodes []Episode
var url string var url string
var shows []SimklPostShow var shows []SimklPostShow
@ -140,7 +136,7 @@ func (a *App) SimklSyncEpisodes(anime SimklAnime, progress int) SimklAnime {
func (a *App) SimklSyncRating(anime SimklAnime, rating int) SimklAnime { func (a *App) SimklSyncRating(anime SimklAnime, rating int) SimklAnime {
var url string var url string
var showWithRating = ShowWithRating{ showWithRating := ShowWithRating{
Title: anime.Show.Title, Title: anime.Show.Title,
Ids: Ids{ Ids: Ids{
Simkl: anime.Show.Ids.Simkl, Simkl: anime.Show.Ids.Simkl,
@ -150,7 +146,7 @@ func (a *App) SimklSyncRating(anime SimklAnime, rating int) SimklAnime {
Rating: rating, Rating: rating,
} }
var showWithoutRating = ShowWithoutRating{ showWithoutRating := ShowWithoutRating{
Title: anime.Show.Title, Title: anime.Show.Title,
Ids: Ids{ Ids: Ids{
Simkl: anime.Show.Ids.Simkl, Simkl: anime.Show.Ids.Simkl,
@ -197,7 +193,7 @@ func (a *App) SimklSyncRating(anime SimklAnime, rating int) SimklAnime {
func (a *App) SimklSyncStatus(anime SimklAnime, status string) SimklAnime { func (a *App) SimklSyncStatus(anime SimklAnime, status string) SimklAnime {
url := "https://api.simkl.com/sync/add-to-list" url := "https://api.simkl.com/sync/add-to-list"
var show = SimklShowStatus{ show := SimklShowStatus{
Title: anime.Show.Title, Title: anime.Show.Title,
Ids: Ids{ Ids: Ids{
Simkl: anime.Show.Ids.Simkl, Simkl: anime.Show.Ids.Simkl,
@ -300,7 +296,7 @@ func (a *App) SimklSyncRemove(anime SimklAnime) bool {
url := "https://api.simkl.com/sync/history/remove" url := "https://api.simkl.com/sync/history/remove"
var showArray []SimklShowStatus var showArray []SimklShowStatus
var singleShow = SimklShowStatus{ singleShow := SimklShowStatus{
Title: anime.Show.Title, Title: anime.Show.Title,
Ids: Ids{ Ids: Ids{
Simkl: anime.Show.Ids.Simkl, Simkl: anime.Show.Ids.Simkl,
@ -349,5 +345,4 @@ func WatchListUpdate(anime SimklAnime) {
if !updated { if !updated {
SimklWatchList.Anime = append(SimklWatchList.Anime, anime) SimklWatchList.Anime = append(SimklWatchList.Anime, anime)
} }
return
} }

View File

@ -28,10 +28,10 @@ var simklCtxShutdown, simklCancel = context.WithCancel(context.Background())
func (a *App) CheckIfSimklLoggedIn() bool { func (a *App) CheckIfSimklLoggedIn() bool {
if (SimklJWT{} == simklJwt) { if (SimklJWT{} == simklJwt) {
tokenType, err := simklRing.Get("SimklTokenType") tokenType, tokenTypeErr := simklRing.Get("SimklTokenType")
accessToken, err := simklRing.Get("SimklAccessToken") accessToken, accessTokenErr := simklRing.Get("SimklAccessToken")
scope, err := simklRing.Get("SimklScope") scope, scopeErr := simklRing.Get("SimklScope")
if err != nil || len(accessToken.Data) == 0 { if (tokenTypeErr != nil || accessTokenErr != nil || scopeErr != nil) || len(accessToken.Data) == 0 {
return false return false
} else { } else {
simklJwt.TokenType = string(tokenType.Data) simklJwt.TokenType = string(tokenType.Data)
@ -45,11 +45,11 @@ func (a *App) CheckIfSimklLoggedIn() bool {
} }
func (a *App) SimklLogin() { func (a *App) SimklLogin() {
if a.CheckIfSimklLoggedIn() == false { if !a.CheckIfSimklLoggedIn() {
tokenType, err := simklRing.Get("SimklTokenType") tokenType, tokenTypeErr := simklRing.Get("SimklTokenType")
accessToken, err := simklRing.Get("SimklAccessToken") accessToken, accessTokenErr := simklRing.Get("SimklAccessToken")
scope, err := simklRing.Get("SimklScope") scope, scopeErr := simklRing.Get("SimklScope")
if err != nil || len(accessToken.Data) == 0 { if (tokenTypeErr != nil || accessTokenErr != nil || scopeErr != nil) || len(accessToken.Data) == 0 {
getSimklCodeUrl := "https://simkl.com/oauth/authorize?response_type=code&client_id=" + Environment.SIMKL_CLIENT_ID + "&redirect_uri=" + Environment.SIMKL_CALLBACK_URI getSimklCodeUrl := "https://simkl.com/oauth/authorize?response_type=code&client_id=" + Environment.SIMKL_CLIENT_ID + "&redirect_uri=" + Environment.SIMKL_CALLBACK_URI
runtime.BrowserOpenURL(*wailsContext, getSimklCodeUrl) runtime.BrowserOpenURL(*wailsContext, getSimklCodeUrl)
@ -155,6 +155,9 @@ func getSimklAuthorizationToken(content string) SimklJWT {
defer res.Body.Close() defer res.Body.Close()
returnedBody, err := io.ReadAll(res.Body) returnedBody, err := io.ReadAll(res.Body)
if err != nil {
log.Printf("Could not read returned body, %s\n.", err)
}
var post SimklJWT var post SimklJWT
err = json.Unmarshal(returnedBody, &post) err = json.Unmarshal(returnedBody, &post)
@ -177,7 +180,6 @@ func (a *App) GetSimklLoggedInUser() SimklUser {
req.Header.Add("simkl-api-key", Environment.SIMKL_CLIENT_ID) req.Header.Add("simkl-api-key", Environment.SIMKL_CLIENT_ID)
response, err := client.Do(req) response, err := client.Do(req)
if err != nil { if err != nil {
log.Printf("Failed at request, %s\n", err) log.Printf("Failed at request, %s\n", err)
return SimklUser{} return SimklUser{}
@ -193,7 +195,6 @@ func (a *App) GetSimklLoggedInUser() SimklUser {
} }
err = json.Unmarshal(respBody, &errCheck) err = json.Unmarshal(respBody, &errCheck)
if err != nil { if err != nil {
log.Printf("Failed at unmarshal, %s\n", err) log.Printf("Failed at unmarshal, %s\n", err)
} }
@ -215,12 +216,12 @@ func (a *App) GetSimklLoggedInUser() SimklUser {
func (a *App) LogoutSimkl() string { func (a *App) LogoutSimkl() string {
if (SimklJWT{} != simklJwt) { if (SimklJWT{} != simklJwt) {
err := simklRing.Remove("SimklTokenType") tokenTypeErr := simklRing.Remove("SimklTokenType")
err = simklRing.Remove("SimklAccessToken") accessTokenErr := simklRing.Remove("SimklAccessToken")
err = simklRing.Remove("SimklScope") scopeErr := simklRing.Remove("SimklScope")
if err != nil { if tokenTypeErr != nil || accessTokenErr != nil || scopeErr != nil {
fmt.Println("Simkl Logout Failed", err) fmt.Println("Simkl Logout Failed")
} }
simklJwt = SimklJWT{} simklJwt = SimklJWT{}
} }

11
build/AniTrack.desktop Executable file
View File

@ -0,0 +1,11 @@
[Desktop Entry]
Name=AniTrack
Comment=A manual synchronizer for various Anime trackers.
Exec=/home/nymusicman/Applications/AniTrack
Icon=AniTrack
Terminal=false
Type=Application
StartupNotify=true
Categories=Internet
Keywords=anitrack;anilist;simkl;mal;myanimelist;anime;sync
Path=

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -193,9 +193,9 @@
}; };
await AniListUpdateEntry(body).then( await AniListUpdateEntry(body).then(
(value: AniListGetSingleAnime) => { (value: AniListGetSingleAnime) => {
// in future when you inevitably add tags to typescript, until Anilist fixes the api bug /* TODO in future when you inevitably add tags to typescript, until Anilist fixes the api bug
// where tags break the SaveMediaListEntry return, you'll want to use this delete line where tags break the SaveMediaListEntry return, you'll want to use this delete line
// delete value.data.MediaList.media.tags delete value.data.MediaList.media.tags */
aniListAnime.update((newValue) => { aniListAnime.update((newValue) => {
newValue = value; newValue = value;
return newValue; return newValue;
@ -397,6 +397,20 @@
submitSuccess.set(true); submitSuccess.set(true);
setTimeout(() => submitSuccess.set(false), 2000); setTimeout(() => submitSuccess.set(false), 2000);
}; };
let max = 999;
if (currentAniListAnime.data.MediaList.media.episodes !== 0) {
max = currentAniListAnime.data.MediaList.media.episodes;
}
if (
currentAniListAnime.data.MediaList.media.episodes === 0 &&
currentAniListAnime.data.MediaList.media.nextAiringEpisode.episode !== 0
) {
max =
currentAniListAnime.data.MediaList.media.nextAiringEpisode.episode -
1;
}
</script> </script>
<form on:submit|preventDefault={handleSubmit} class="container pt-3 pb-10"> <form on:submit|preventDefault={handleSubmit} class="container pt-3 pb-10">
@ -423,24 +437,81 @@
class="text-left block mb-2 text-sm font-medium text-white" class="text-left block mb-2 text-sm font-medium text-white"
>Episode Progress</label >Episode Progress</label
> >
<input <div class="relative flex items-center max-w-[8rem]">
type="number" <button
name="episodes" type="button"
min="0" id="decrement-button"
max={currentAniListAnime.data.MediaList.media.episodes} data-input-counter-decrement="quantity-input"
id="episodes" on:click={() =>
class="border {currentAniListAnime.data.MediaList (currentAniListAnime.data.MediaList.progress -= 1)}
.progress < 0 || class="bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 dark:border-gray-600 hover:bg-gray-200 border border-gray-300 rounded-s-lg p-3 h-11 focus:ring-gray-100 dark:focus:ring-gray-700 focus:ring-2 focus:outline-none"
(currentAniListAnime.data.MediaList.media.episodes > >
0 && <svg
currentAniListAnime.data.MediaList.progress > class="w-3 h-3 text-gray-900 dark:text-white"
currentAniListAnime.data.MediaList.media aria-hidden="true"
.episodes) xmlns="http://www.w3.org/2000/svg"
? 'border-red-500 border-[2px] text-rose-300 focus:ring-red-500 focus:border-red-500' fill="none"
: 'border-gray-500 text-white focus:ring-blue-500 focus:border-blue-500'} text-sm rounded-lg block w-24 p-2.5 bg-gray-600 placeholder-gray-400" viewBox="0 0 18 2"
bind:value={currentAniListAnime.data.MediaList.progress} >
required <path
/> stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M1 1h16"
/>
</svg>
</button>
<input
type="number"
name="episodes"
min="0"
{max}
id="episodes"
class="border border-x-0 p-2.5 h-11 text-center text-sm block w-full placeholder-gray-400 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none
{currentAniListAnime.data.MediaList.progress < 0 ||
(currentAniListAnime.data.MediaList.media.episodes >
0 &&
currentAniListAnime.data.MediaList.progress >
currentAniListAnime.data.MediaList.media
.episodes) ||
(currentAniListAnime.data.MediaList.media
.nextAiringEpisode.episode > 0 &&
currentAniListAnime.data.MediaList.progress >
currentAniListAnime.data.MediaList.media
.nextAiringEpisode.episode -
1)
? 'border-red-500 border-[2px] text-rose-300 focus:ring-red-500 focus:border-red-500'
: 'bg-gray-700 hover:bg-gray-600 border-gray-600 text-white focus:ring-blue-500 focus:border-blue-500'} w-24"
bind:value={currentAniListAnime.data.MediaList
.progress}
required
/>
<button
type="button"
id="increment-button"
data-input-counter-increment="quantity-input"
on:click={() =>
(currentAniListAnime.data.MediaList.progress += 1)}
class="bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 dark:border-gray-600 hover:bg-gray-200 border border-gray-300 rounded-e-lg p-3 h-11 focus:ring-gray-100 dark:focus:ring-gray-700 focus:ring-2 focus:outline-none"
>
<svg
class="w-3 h-3 text-gray-900 dark:text-white"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 18 18"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 1v16M1 9h16"
/>
</svg>
</button>
</div>
<div> <div>
/ {currentAniListAnime.data.MediaList.media / {currentAniListAnime.data.MediaList.media
.nextAiringEpisode.episode !== 0 .nextAiringEpisode.episode !== 0
@ -448,9 +519,12 @@
.nextAiringEpisode.episode - 1 .nextAiringEpisode.episode - 1
: currentAniListAnime.data.MediaList.media.episodes} : currentAniListAnime.data.MediaList.media.episodes}
</div> </div>
<div> {#if currentAniListAnime.data.MediaList.media.nextAiringEpisode.episode !== 0}
of {currentAniListAnime.data.MediaList.media.episodes} <div>
</div> of {currentAniListAnime.data.MediaList.media
.episodes}
</div>
{/if}
</div> </div>
<div> <div>

View File

@ -202,8 +202,7 @@ export namespace main {
export class MALAnime { export class MALAnime {
id: id; id: id;
title: title; title: title;
// Go type: struct { Large string "json:\"large\" json:\"large\""; Medium string "json:\"medium\" json:\"medium\"" } main_picture: mainPicture;
main_picture: any;
alternative_titles: alternativeTitles; alternative_titles: alternativeTitles;
start_date: startDate; start_date: startDate;
end_date: endDate; end_date: endDate;
@ -242,7 +241,7 @@ export namespace main {
if ('string' === typeof source) source = JSON.parse(source); if ('string' === typeof source) source = JSON.parse(source);
this.id = source["id"]; this.id = source["id"];
this.title = source["title"]; this.title = source["title"];
this.main_picture = this.convertValues(source["main_picture"], Object); this.main_picture = source["main_picture"];
this.alternative_titles = source["alternative_titles"]; this.alternative_titles = source["alternative_titles"];
this.start_date = source["start_date"]; this.start_date = source["start_date"];
this.end_date = source["end_date"]; this.end_date = source["end_date"];
@ -314,7 +313,7 @@ export namespace main {
} }
} }
export class MALWatchlist { export class MALWatchlist {
data: struct { Node struct { Id int "json:\"id\" ts_type:\"id\""; Title string "json:\"title\" ts_type:\"title\""; MainPicture struct { Medium string "json:\"medium\" json:\"medium\""; Large string "json:\"large\" json:\"large\"" } "json:\"main_picture\" json:\"mainPicture\"" } "json:\"node\" json:\"node\""; ListStatus struct { Status string "json:\"status\" ts_type:\"status\""; Score int "json:\"score\" ts_type:\"score\""; NumEpisodesWatched int "json:\"num_episodes_watched\" ts_type:\"numEpisodesWatched\""; IsRewatching bool "json:\"is_rewatching\" ts_type:\"isRewatching\""; UpdatedAt time.Time "json:\"updated_at\" ts_type:\"updatedAt\""; StartDate string "json:\"start_date\" ts_type:\"startDate\""; FinishDate string "json:\"finish_date\" ts_type:\"finishDate\"" } "json:\"list_status\" ts_type:\"listStatus\"" }[]; data: data;
paging: paging; paging: paging;
static createFrom(source: any = {}) { static createFrom(source: any = {}) {
@ -323,27 +322,9 @@ export namespace main {
constructor(source: any = {}) { constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source); if ('string' === typeof source) source = JSON.parse(source);
this.data = this.convertValues(source["data"], struct { Node struct { Id int "json:\"id\" ts_type:\"id\""; Title string "json:\"title\" ts_type:\"title\""; MainPicture struct { Medium string "json:\"medium\" json:\"medium\""; Large string "json:\"large\" json:\"large\"" } "json:\"main_picture\" json:\"mainPicture\"" } "json:\"node\" json:\"node\""; ListStatus struct { Status string "json:\"status\" ts_type:\"status\""; Score int "json:\"score\" ts_type:\"score\""; NumEpisodesWatched int "json:\"num_episodes_watched\" ts_type:\"numEpisodesWatched\""; IsRewatching bool "json:\"is_rewatching\" ts_type:\"isRewatching\""; UpdatedAt time.Time "json:\"updated_at\" ts_type:\"updatedAt\""; StartDate string "json:\"start_date\" ts_type:\"startDate\""; FinishDate string "json:\"finish_date\" ts_type:\"finishDate\"" } "json:\"list_status\" ts_type:\"listStatus\"" }); this.data = source["data"];
this.paging = source["paging"]; this.paging = source["paging"];
} }
convertValues(a: any, classs: any, asMap: boolean = false): any {
if (!a) {
return a;
}
if (a.slice && a.map) {
return (a as any[]).map(elem => this.convertValues(elem, classs));
} else if ("object" === typeof a) {
if (asMap) {
for (const key of Object.keys(a)) {
a[key] = new classs(a[key]);
}
return a;
}
return new classs(a);
}
return a;
}
} }
export class MalListStatus { export class MalListStatus {
status: status; status: status;
@ -624,11 +605,10 @@ export namespace struct { Node main {
} }
export namespace struct { Node struct { Id int "json:\"id\" ts_type:\"id\""; Title string "json:\"title\" ts_type:\"title\""; MainPicture struct { Medium string "json:\"medium\" json:\"medium\""; Large string "json:\"large\" json:\"large\"" } "json:\"main_picture\" json:\"mainPicture\"" } "json:\"node\" json:\"node\""; ListStatus struct { Status string "json:\"status\" ts_type:\"status\""; Score int "json:\"score\" ts_type:\"score\""; NumEpisodesWatched int "json:\"num_episodes_watched\" ts_type:\"numEpisodesWatched\""; IsRewatching bool "json:\"is_rewatching\" ts_type:\"isRewatching\""; UpdatedAt time { export namespace struct { Node struct { Id int "json:\"id\" ts_type:\"id\""; Title string "json:\"title\" ts_type:\"title\""; MainPicture struct { Medium string "json:\"medium\" ts_type:\"medium\""; Large string "json:\"large\" ts_type:\"large\"" } "json:\"main_picture\" ts_type:\"mainPicture\"" } "json:\"node\" ts_type:\"node\""; ListStatus struct { Status string "json:\"status\" ts_type:\"status\""; Score int "json:\"score\" ts_type:\"score\""; NumEpisodesWatched int "json:\"num_episodes_watched\" ts_type:\"numEpisodesWatched\""; IsRewatching bool "json:\"is_rewatching\" ts_type:\"isRewatching\""; UpdatedAt time {
export class { export class {
// Go type: struct { Id int "json:\"id\" ts_type:\"id\""; Title string "json:\"title\" ts_type:\"title\""; MainPicture struct { Medium string "json:\"medium\" json:\"medium\""; Large string "json:\"large\" json:\"large\"" } "json:\"main_picture\" json:\"mainPicture\"" } node: node;
node: any;
list_status: listStatus; list_status: listStatus;
static createFrom(source: any = {}) { static createFrom(source: any = {}) {
@ -637,27 +617,9 @@ export namespace struct { Node struct { Id int "json:\"id\" ts_type:\"id\""; Tit
constructor(source: any = {}) { constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source); if ('string' === typeof source) source = JSON.parse(source);
this.node = this.convertValues(source["node"], Object); this.node = source["node"];
this.list_status = source["list_status"]; this.list_status = source["list_status"];
} }
convertValues(a: any, classs: any, asMap: boolean = false): any {
if (!a) {
return a;
}
if (a.slice && a.map) {
return (a as any[]).map(elem => this.convertValues(elem, classs));
} else if ("object" === typeof a) {
if (asMap) {
for (const key of Object.keys(a)) {
a[key] = new classs(a[key]);
}
return a;
}
return new classs(a);
}
return a;
}
} }
} }

View File

@ -34,7 +34,7 @@ func main() {
app, app,
}, },
Linux: &linux.Options{ Linux: &linux.Options{
Icon: []byte("./build/appicon.png"), Icon: []byte("./build/AniTrack.png"),
WindowIsTranslucent: false, WindowIsTranslucent: false,
WebviewGpuPolicy: linux.WebviewGpuPolicyAlways, WebviewGpuPolicy: linux.WebviewGpuPolicyAlways,
ProgramName: "AniTrack", ProgramName: "AniTrack",

View File

@ -12,6 +12,6 @@
}, },
"info": { "info": {
"productName": "AniTrack", "productName": "AniTrack",
"productVersion": "0.1.2" "productVersion": "0.1.4"
} }
} }