Compare commits
No commits in common. "4e11b218be1c8e8fcba154530ec9895aa18fefea" and "d7233a52baf15526653beadf7271255733f5148f" have entirely different histories.
4e11b218be
...
d7233a52ba
@ -2,22 +2,38 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AniListQuery(body interface{}, login bool) (json.RawMessage, string) {
|
type JWT struct {
|
||||||
|
TokenType string `json:"token_type"`
|
||||||
|
ExpiresIn int `json:"expires_in"`
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var jwt JWT
|
||||||
|
|
||||||
|
func AniListQuery(body interface{}, login bool) interface{} {
|
||||||
reader, _ := json.Marshal(body)
|
reader, _ := json.Marshal(body)
|
||||||
response, err := http.NewRequest("POST", "https://graphql.anilist.co", bytes.NewBuffer(reader))
|
response, err := http.NewRequest("POST", "https://graphql.anilist.co", bytes.NewBuffer(reader))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed at response, %s\n", err)
|
log.Printf("Failed at response, %s\n", err)
|
||||||
}
|
}
|
||||||
if login && (AniListJWT{}) != jwt {
|
if login && (JWT{}) != jwt {
|
||||||
response.Header.Add("Authorization", "Bearer "+jwt.AccessToken)
|
response.Header.Add("Authorization", "Bearer "+jwt.AccessToken)
|
||||||
} else if login {
|
} else if login {
|
||||||
return nil, "Please login to anilist to make this request"
|
return "Please login to AniList to make this request"
|
||||||
}
|
}
|
||||||
response.Header.Add("Content-Type", "application/json")
|
response.Header.Add("Content-Type", "application/json")
|
||||||
response.Header.Add("Accept", "application/json")
|
response.Header.Add("Accept", "application/json")
|
||||||
@ -32,7 +48,13 @@ func AniListQuery(body interface{}, login bool) (json.RawMessage, string) {
|
|||||||
|
|
||||||
returnedBody, err := io.ReadAll(res.Body)
|
returnedBody, err := io.ReadAll(res.Body)
|
||||||
|
|
||||||
return returnedBody, ""
|
var post interface{}
|
||||||
|
err = json.Unmarshal(returnedBody, &post)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed at unmarshal, %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return post
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) GetAniListItem(aniId int) any {
|
func (a *App) GetAniListItem(aniId int) any {
|
||||||
@ -79,15 +101,7 @@ func (a *App) GetAniListItem(aniId int) any {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
returnedBody, _ := AniListQuery(body, false)
|
return AniListQuery(body, false)
|
||||||
|
|
||||||
var post interface{}
|
|
||||||
err := json.Unmarshal(returnedBody, &post)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed at unmarshal, %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return post
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) AniListSearch(query string) any {
|
func (a *App) AniListSearch(query string) any {
|
||||||
@ -129,131 +143,95 @@ func (a *App) AniListSearch(query string) any {
|
|||||||
ListType: "ANIME",
|
ListType: "ANIME",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
returnedBody, _ := AniListQuery(body, false)
|
return AniListQuery(body, false)
|
||||||
|
|
||||||
var post interface{}
|
|
||||||
err := json.Unmarshal(returnedBody, &post)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed at unmarshal, %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return post
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) GetAniListUserWatchingList(page int, perPage int, sort string) AniListCurrentUserWatchList {
|
var ctxShutdown, cancel = context.WithCancel(context.Background())
|
||||||
var user = a.GetAniListLoggedInUserId()
|
|
||||||
type Variables struct {
|
|
||||||
Page int `json:"page"`
|
|
||||||
PerPage int `json:"perPage"`
|
|
||||||
UserId int `json:"userId"`
|
|
||||||
ListType string `json:"listType"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Sort string `json:"sort"`
|
|
||||||
}
|
|
||||||
body := struct {
|
|
||||||
Query string `json:"query"`
|
|
||||||
Variables Variables `json:"variables"`
|
|
||||||
}{
|
|
||||||
Query: `
|
|
||||||
query(
|
|
||||||
$page: Int
|
|
||||||
$perPage: Int
|
|
||||||
$userId: Int
|
|
||||||
$listType: MediaType
|
|
||||||
$status: MediaListStatus
|
|
||||||
$sort:[MediaListSort]
|
|
||||||
) {
|
|
||||||
Page(page: $page, perPage: $perPage) {
|
|
||||||
pageInfo {
|
|
||||||
total
|
|
||||||
perPage
|
|
||||||
currentPage
|
|
||||||
lastPage
|
|
||||||
hasNextPage
|
|
||||||
}
|
|
||||||
mediaList(userId: $userId, type: $listType, status: $status, sort: $sort) {
|
|
||||||
id
|
|
||||||
mediaId
|
|
||||||
userId
|
|
||||||
media {
|
|
||||||
id
|
|
||||||
idMal
|
|
||||||
title {
|
|
||||||
romaji
|
|
||||||
english
|
|
||||||
native
|
|
||||||
}
|
|
||||||
description
|
|
||||||
coverImage {
|
|
||||||
large
|
|
||||||
}
|
|
||||||
season
|
|
||||||
seasonYear
|
|
||||||
status
|
|
||||||
episodes
|
|
||||||
nextAiringEpisode{
|
|
||||||
airingAt
|
|
||||||
timeUntilAiring
|
|
||||||
episode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
status
|
|
||||||
notes
|
|
||||||
progress
|
|
||||||
score
|
|
||||||
repeat
|
|
||||||
user {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
avatar{
|
|
||||||
large
|
|
||||||
medium
|
|
||||||
}
|
|
||||||
statistics {
|
|
||||||
anime {
|
|
||||||
count
|
|
||||||
statuses {
|
|
||||||
status
|
|
||||||
count
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
Variables: Variables{
|
|
||||||
Page: page,
|
|
||||||
PerPage: perPage,
|
|
||||||
UserId: user.Data.Viewer.ID,
|
|
||||||
ListType: "ANIME",
|
|
||||||
Status: "CURRENT",
|
|
||||||
Sort: sort,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
returnedBody, _ := AniListQuery(body, true)
|
func (a *App) AniListLogin() {
|
||||||
|
getAniListCodeUrl := "https://anilist.co/api/v2/oauth/authorize?client_id=" + os.Getenv("ANILIST_APP_ID") + "&redirect_uri=" + os.Getenv("ANILIST_CALLBACK_URI") + "&response_type=code"
|
||||||
|
runtime.BrowserOpenURL(a.ctx, getAniListCodeUrl)
|
||||||
|
|
||||||
var post AniListCurrentUserWatchList
|
serverDone := &sync.WaitGroup{}
|
||||||
err := json.Unmarshal(returnedBody, &post)
|
serverDone.Add(1)
|
||||||
if err != nil {
|
handleAniListCallback(serverDone)
|
||||||
log.Printf("Failed at unmarshal, %s\n", err)
|
serverDone.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getting the real total, finding the real last page and storing that in the Page info
|
func handleAniListCallback(wg *sync.WaitGroup) {
|
||||||
statuses := post.Data.Page.MediaList[0].User.Statistics.Anime.Statuses
|
srv := &http.Server{Addr: ":6734"}
|
||||||
var total int
|
http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
|
||||||
for _, status := range statuses {
|
select {
|
||||||
if status.Status == "CURRENT" {
|
case <-ctxShutdown.Done():
|
||||||
total = status.Count
|
fmt.Println("Shutting down...")
|
||||||
|
return
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
|
content := r.FormValue("code")
|
||||||
|
|
||||||
|
if content != "" {
|
||||||
|
jwt = getAniListAuthorizationToken(content)
|
||||||
|
fmt.Println("Shutting down...")
|
||||||
|
cancel()
|
||||||
|
err := srv.Shutdown(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
log.Println("server.Shutdown:", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err := fmt.Fprintf(w, "Getting code failed.")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
|
log.Fatalf("listen: %s\n", err)
|
||||||
|
}
|
||||||
|
fmt.Println("Shutting down...")
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAniListAuthorizationToken(content string) JWT {
|
||||||
|
apiUrl := "https://anilist.co/api/v2/oauth/token"
|
||||||
|
resource := "/api/v2/oauth/token"
|
||||||
|
data := url.Values{}
|
||||||
|
data.Set("grant_type", "authorization_code")
|
||||||
|
data.Set("client_id", os.Getenv("ANILIST_APP_ID"))
|
||||||
|
data.Set("client_secret", os.Getenv("ANILIST_SECRET_TOKEN"))
|
||||||
|
data.Set("redirect_uri", os.Getenv("ANILIST_CALLBACK_URI"))
|
||||||
|
data.Set("code", content)
|
||||||
|
|
||||||
|
u, _ := url.ParseRequestURI(apiUrl)
|
||||||
|
u.Path = resource
|
||||||
|
urlStr := u.String()
|
||||||
|
|
||||||
|
response, err := http.NewRequest("POST", urlStr, strings.NewReader(data.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed at response, %s\n", err)
|
||||||
|
}
|
||||||
|
response.Header.Add("content-type", "application/x-www-form-urlencoded")
|
||||||
|
response.Header.Add("Content-Type", "application/json")
|
||||||
|
response.Header.Add("Accept", "application/json")
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
res, reserr := client.Do(response)
|
||||||
|
if reserr != nil {
|
||||||
|
log.Printf("Failed at res, %s\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lastPage := total / perPage
|
defer res.Body.Close()
|
||||||
|
|
||||||
post.Data.Page.PageInfo.Total = total
|
returnedBody, err := io.ReadAll(res.Body)
|
||||||
post.Data.Page.PageInfo.LastPage = lastPage
|
|
||||||
|
var post JWT
|
||||||
|
err = json.Unmarshal(returnedBody, &post)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed at unmarshal, %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
return post
|
return post
|
||||||
}
|
}
|
||||||
|
144
AniListTypes.go
144
AniListTypes.go
@ -1,144 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
type AniListJWT struct {
|
|
||||||
TokenType string `json:"token_type"`
|
|
||||||
ExpiresIn int `json:"expires_in"`
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
RefreshToken string `json:"refresh_token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AniListUser struct {
|
|
||||||
Data struct {
|
|
||||||
Viewer struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
} `json:"Viewer"`
|
|
||||||
} `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AniListCurrentUserWatchList struct {
|
|
||||||
Data struct {
|
|
||||||
Page struct {
|
|
||||||
PageInfo struct {
|
|
||||||
Total int `json:"total"`
|
|
||||||
PerPage int `json:"perPage"`
|
|
||||||
CurrentPage int `json:"currentPage"`
|
|
||||||
LastPage int `json:"lastPage"`
|
|
||||||
HasNextPage bool `json:"hasNextPage"`
|
|
||||||
} `json:"pageInfo"`
|
|
||||||
MediaList []struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
MediaID int `json:"mediaId"`
|
|
||||||
UserID int `json:"userId"`
|
|
||||||
Media struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
IDMal int `json:"idMal"`
|
|
||||||
Title struct {
|
|
||||||
Romaji string `json:"romaji"`
|
|
||||||
English string `json:"english"`
|
|
||||||
Native string `json:"native"`
|
|
||||||
} `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
CoverImage struct {
|
|
||||||
Large string `json:"large"`
|
|
||||||
} `json:"coverImage"`
|
|
||||||
Season string `json:"season"`
|
|
||||||
SeasonYear int `json:"seasonYear"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Episodes int `json:"episodes"`
|
|
||||||
NextAiringEpisode struct {
|
|
||||||
AiringAt int `json:"airingAt"`
|
|
||||||
TimeUntilAiring int `json:"timeUntilAiring"`
|
|
||||||
Episode int `json:"episode"`
|
|
||||||
} `json:"nextAiringEpisode"`
|
|
||||||
} `json:"media"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Notes string `json:"notes"`
|
|
||||||
Progress int `json:"progress"`
|
|
||||||
Score int `json:"score"`
|
|
||||||
Repeat int `json:"repeat"`
|
|
||||||
User struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Avatar struct {
|
|
||||||
Large string `json:"large"`
|
|
||||||
Medium string `json:"medium"`
|
|
||||||
} `json:"avatar"`
|
|
||||||
Statistics struct {
|
|
||||||
Anime struct {
|
|
||||||
Count int `json:"count"`
|
|
||||||
Statuses []struct {
|
|
||||||
Status string `json:"status"`
|
|
||||||
Count int `json:"count"`
|
|
||||||
} `json:"statuses"`
|
|
||||||
} `json:"anime"`
|
|
||||||
} `json:"statistics"`
|
|
||||||
} `json:"user"`
|
|
||||||
} `json:"mediaList"`
|
|
||||||
} `json:"Page"`
|
|
||||||
} `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var MediaListSort = struct {
|
|
||||||
MediaId string
|
|
||||||
MediaIdDesc string
|
|
||||||
Score string
|
|
||||||
ScoreDesc string
|
|
||||||
Status string
|
|
||||||
StatusDesc string
|
|
||||||
Progress string
|
|
||||||
ProgressDesc string
|
|
||||||
ProgressVolumes string
|
|
||||||
ProgressVolumesDesc string
|
|
||||||
Repeat string
|
|
||||||
RepeatDesc string
|
|
||||||
Priority string
|
|
||||||
PriorityDesc string
|
|
||||||
StartedOn string
|
|
||||||
StartedOnDesc string
|
|
||||||
FinishedOn string
|
|
||||||
FinishedOnDesc string
|
|
||||||
AddedTime string
|
|
||||||
AddedTimeDesc string
|
|
||||||
UpdatedTime string
|
|
||||||
UpdatedTimeDesc string
|
|
||||||
MediaTitleRomaji string
|
|
||||||
MediaTitleRomajiDesc string
|
|
||||||
MediaTitleEnglish string
|
|
||||||
MediaTitleEnglishDesc string
|
|
||||||
MediaTitleNative string
|
|
||||||
MediaTitleNativeDesc string
|
|
||||||
MediaPopularity string
|
|
||||||
MediaPopularityDesc string
|
|
||||||
}{
|
|
||||||
MediaId: "MEDIA_ID",
|
|
||||||
MediaIdDesc: "MEDIA_ID_DESC",
|
|
||||||
Score: "SCORE",
|
|
||||||
ScoreDesc: "SCORE_DESC",
|
|
||||||
Status: "STATUS",
|
|
||||||
StatusDesc: "STATUS_DESC",
|
|
||||||
Progress: "PROGRESS",
|
|
||||||
ProgressDesc: "PROGRESS_DESC",
|
|
||||||
ProgressVolumes: "PROGRESS_VOLUMES",
|
|
||||||
ProgressVolumesDesc: "PROGRESS_VOLUMES_DESC",
|
|
||||||
Repeat: "REPEAT",
|
|
||||||
RepeatDesc: "REPEAT_DESC",
|
|
||||||
Priority: "PRIORITY",
|
|
||||||
PriorityDesc: "PRIORITY_DESC",
|
|
||||||
StartedOn: "STARTED_ON",
|
|
||||||
StartedOnDesc: "STARTED_ON_DESC",
|
|
||||||
FinishedOn: "FINISHED_ON",
|
|
||||||
FinishedOnDesc: "FINISHED_ON_DESC",
|
|
||||||
AddedTime: "ADDED_TIME",
|
|
||||||
AddedTimeDesc: "ADDED_TIME_DESC",
|
|
||||||
UpdatedTime: "UPDATED_TIME",
|
|
||||||
UpdatedTimeDesc: "UPDATED_TIME_DESC",
|
|
||||||
MediaTitleRomaji: "MEDIA_TITLE_ROMAJI",
|
|
||||||
MediaTitleRomajiDesc: "MEDIA_TITLE_ROMAJI_DESC",
|
|
||||||
MediaTitleEnglish: "MEDIA_TITLE_ENGLISH",
|
|
||||||
MediaTitleEnglishDesc: "MEDIA_TITLE_ENGLISH_DESC",
|
|
||||||
MediaTitleNative: "MEDIA_TITLE_NATIVE",
|
|
||||||
MediaTitleNativeDesc: "MEDIA_TITLE_NATIVE_DESC",
|
|
||||||
MediaPopularity: "MEDIA_POPULARITY",
|
|
||||||
MediaPopularityDesc: "MEDIA_POPULARITY_DESC",
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"github.com/99designs/keyring"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var jwt AniListJWT
|
|
||||||
|
|
||||||
var ring, _ = keyring.Open(keyring.Config{
|
|
||||||
ServiceName: "AniTrack",
|
|
||||||
})
|
|
||||||
|
|
||||||
var ctxShutdown, cancel = context.WithCancel(context.Background())
|
|
||||||
|
|
||||||
func (a *App) AniListLogin() {
|
|
||||||
if (AniListJWT{}) == jwt {
|
|
||||||
tokenType, err := ring.Get("anilistTokenType")
|
|
||||||
expiresIn, err := ring.Get("anilistTokenExpiresIn")
|
|
||||||
accessToken, err := ring.Get("anilistAccessToken")
|
|
||||||
refreshToken, err := ring.Get("anilistRefreshToken")
|
|
||||||
if err != nil {
|
|
||||||
getAniListCodeUrl := "https://anilist.co/api/v2/oauth/authorize?client_id=" + os.Getenv("ANILIST_APP_ID") + "&redirect_uri=" + os.Getenv("ANILIST_CALLBACK_URI") + "&response_type=code"
|
|
||||||
runtime.BrowserOpenURL(a.ctx, getAniListCodeUrl)
|
|
||||||
|
|
||||||
serverDone := &sync.WaitGroup{}
|
|
||||||
serverDone.Add(1)
|
|
||||||
handleAniListCallback(serverDone)
|
|
||||||
serverDone.Wait()
|
|
||||||
} else {
|
|
||||||
jwt.TokenType = string(tokenType.Data)
|
|
||||||
jwt.AccessToken = string(accessToken.Data)
|
|
||||||
jwt.RefreshToken = string(refreshToken.Data)
|
|
||||||
expiresInString := string(expiresIn.Data)
|
|
||||||
jwt.ExpiresIn, _ = strconv.Atoi(expiresInString)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleAniListCallback(wg *sync.WaitGroup) {
|
|
||||||
srv := &http.Server{Addr: ":6734"}
|
|
||||||
http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
select {
|
|
||||||
case <-ctxShutdown.Done():
|
|
||||||
fmt.Println("Shutting down...")
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
content := r.FormValue("code")
|
|
||||||
|
|
||||||
if content != "" {
|
|
||||||
jwt = getAniListAuthorizationToken(content)
|
|
||||||
_ = ring.Set(keyring.Item{
|
|
||||||
Key: "anilistTokenType",
|
|
||||||
Data: []byte(jwt.TokenType),
|
|
||||||
})
|
|
||||||
_ = ring.Set(keyring.Item{
|
|
||||||
Key: "anilistTokenExpiresIn",
|
|
||||||
Data: []byte(string(jwt.ExpiresIn)),
|
|
||||||
})
|
|
||||||
_ = ring.Set(keyring.Item{
|
|
||||||
Key: "anilistAccessToken",
|
|
||||||
Data: []byte(jwt.AccessToken),
|
|
||||||
})
|
|
||||||
_ = ring.Set(keyring.Item{
|
|
||||||
Key: "anilistRefreshToken",
|
|
||||||
Data: []byte(jwt.RefreshToken),
|
|
||||||
})
|
|
||||||
fmt.Println("Shutting down...")
|
|
||||||
cancel()
|
|
||||||
err := srv.Shutdown(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
log.Println("server.Shutdown:", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_, err := fmt.Fprintf(w, "Getting code failed.")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
||||||
log.Fatalf("listen: %s\n", err)
|
|
||||||
}
|
|
||||||
fmt.Println("Shutting down...")
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAniListAuthorizationToken(content string) AniListJWT {
|
|
||||||
apiUrl := "https://anilist.co/api/v2/oauth/token"
|
|
||||||
resource := "/api/v2/oauth/token"
|
|
||||||
data := url.Values{}
|
|
||||||
data.Set("grant_type", "authorization_code")
|
|
||||||
data.Set("client_id", os.Getenv("ANILIST_APP_ID"))
|
|
||||||
data.Set("client_secret", os.Getenv("ANILIST_SECRET_TOKEN"))
|
|
||||||
data.Set("redirect_uri", os.Getenv("ANILIST_CALLBACK_URI"))
|
|
||||||
data.Set("code", content)
|
|
||||||
|
|
||||||
u, _ := url.ParseRequestURI(apiUrl)
|
|
||||||
u.Path = resource
|
|
||||||
urlStr := u.String()
|
|
||||||
|
|
||||||
response, err := http.NewRequest("POST", urlStr, strings.NewReader(data.Encode()))
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed at response, %s\n", err)
|
|
||||||
}
|
|
||||||
response.Header.Add("content-type", "application/x-www-form-urlencoded")
|
|
||||||
response.Header.Add("Content-Type", "application/json")
|
|
||||||
response.Header.Add("Accept", "application/json")
|
|
||||||
|
|
||||||
client := &http.Client{}
|
|
||||||
res, reserr := client.Do(response)
|
|
||||||
if reserr != nil {
|
|
||||||
log.Printf("Failed at res, %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
returnedBody, err := io.ReadAll(res.Body)
|
|
||||||
|
|
||||||
var post AniListJWT
|
|
||||||
err = json.Unmarshal(returnedBody, &post)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed at unmarshal, %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return post
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) GetAniListLoggedInUserId() AniListUser {
|
|
||||||
a.AniListLogin()
|
|
||||||
body := struct {
|
|
||||||
Query string `json:"query"`
|
|
||||||
}{
|
|
||||||
Query: `
|
|
||||||
query {
|
|
||||||
Viewer {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
}
|
|
||||||
|
|
||||||
user, _ := AniListQuery(body, true)
|
|
||||||
|
|
||||||
var post AniListUser
|
|
||||||
err := json.Unmarshal(user, &post)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed at unmarshal, %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return post
|
|
||||||
|
|
||||||
}
|
|
@ -29,6 +29,16 @@ body:graphql {
|
|||||||
coverImage {
|
coverImage {
|
||||||
large
|
large
|
||||||
}
|
}
|
||||||
|
tags {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
category
|
||||||
|
rank
|
||||||
|
isGeneralSpoiler
|
||||||
|
isMediaSpoiler
|
||||||
|
isAdult
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,19 +50,3 @@ body:graphql:vars {
|
|||||||
"listType": "ANIME"
|
"listType": "ANIME"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
docs {
|
|
||||||
Title
|
|
||||||
|
|
||||||
Image
|
|
||||||
|
|
||||||
Description
|
|
||||||
|
|
||||||
Episodes
|
|
||||||
|
|
||||||
Status
|
|
||||||
|
|
||||||
Season
|
|
||||||
|
|
||||||
External & Streaming Links
|
|
||||||
}
|
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
meta {
|
|
||||||
name: AniList MediaList User Query
|
|
||||||
type: graphql
|
|
||||||
seq: 6
|
|
||||||
}
|
|
||||||
|
|
||||||
post {
|
|
||||||
url: https://graphql.anilist.co
|
|
||||||
body: graphql
|
|
||||||
auth: none
|
|
||||||
}
|
|
||||||
|
|
||||||
headers {
|
|
||||||
Content-Type: "application/json"
|
|
||||||
Accept: "application/json"
|
|
||||||
}
|
|
||||||
|
|
||||||
body:graphql {
|
|
||||||
# Write your query or mutation here
|
|
||||||
query(
|
|
||||||
$page: Int
|
|
||||||
$perPage: Int
|
|
||||||
$userId: Int
|
|
||||||
$listType: MediaType
|
|
||||||
$status: MediaListStatus
|
|
||||||
) {
|
|
||||||
Page(page: $page, perPage: $perPage) {
|
|
||||||
pageInfo {
|
|
||||||
total
|
|
||||||
perPage
|
|
||||||
currentPage
|
|
||||||
lastPage
|
|
||||||
hasNextPage
|
|
||||||
}
|
|
||||||
mediaList(userId: $userId, type: $listType, status: $status) {
|
|
||||||
id
|
|
||||||
mediaId
|
|
||||||
userId
|
|
||||||
media {
|
|
||||||
id
|
|
||||||
idMal
|
|
||||||
title {
|
|
||||||
romaji
|
|
||||||
english
|
|
||||||
native
|
|
||||||
}
|
|
||||||
description
|
|
||||||
coverImage {
|
|
||||||
large
|
|
||||||
}
|
|
||||||
season
|
|
||||||
seasonYear
|
|
||||||
episodes
|
|
||||||
}
|
|
||||||
status
|
|
||||||
notes
|
|
||||||
progress
|
|
||||||
score
|
|
||||||
repeat
|
|
||||||
user {
|
|
||||||
id
|
|
||||||
statistics {
|
|
||||||
anime {
|
|
||||||
count
|
|
||||||
statuses {
|
|
||||||
status
|
|
||||||
count
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
body:graphql:vars {
|
|
||||||
{
|
|
||||||
"page": 1,
|
|
||||||
"perPage": 20,
|
|
||||||
"userId": 413504,
|
|
||||||
"listType": "ANIME",
|
|
||||||
"status": "CURRENT"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
docs {
|
|
||||||
Title
|
|
||||||
Image
|
|
||||||
Description
|
|
||||||
Episodes
|
|
||||||
Status
|
|
||||||
Season
|
|
||||||
External & Streaming Links
|
|
||||||
|
|
||||||
User Stuff Per Item
|
|
||||||
Status
|
|
||||||
Score
|
|
||||||
Episode Progress
|
|
||||||
Total Rewatches
|
|
||||||
Notes
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
meta {
|
|
||||||
name: AniList MediaList User
|
|
||||||
type: http
|
|
||||||
seq: 5
|
|
||||||
}
|
|
||||||
|
|
||||||
post {
|
|
||||||
url: https://graphql.anilist.co
|
|
||||||
body: none
|
|
||||||
auth: none
|
|
||||||
}
|
|
||||||
|
|
||||||
docs {
|
|
||||||
Title
|
|
||||||
Image
|
|
||||||
Description
|
|
||||||
Episodes
|
|
||||||
Status
|
|
||||||
Season
|
|
||||||
External & Streaming Links
|
|
||||||
|
|
||||||
User Stuff Per Item
|
|
||||||
Status
|
|
||||||
Score
|
|
||||||
Episode Progress
|
|
||||||
Total Rewatches
|
|
||||||
Notes
|
|
||||||
}
|
|
@ -12,17 +12,11 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
||||||
"@tsconfig/svelte": "^3.0.0",
|
"@tsconfig/svelte": "^3.0.0",
|
||||||
"autoprefixer": "^10.4.19",
|
|
||||||
"postcss": "^8.4.39",
|
|
||||||
"svelte": "^3.49.0",
|
"svelte": "^3.49.0",
|
||||||
"svelte-check": "^2.8.0",
|
"svelte-check": "^2.8.0",
|
||||||
"svelte-preprocess": "^4.10.7",
|
"svelte-preprocess": "^4.10.7",
|
||||||
"tailwindcss": "^3.4.6",
|
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"typescript": "^4.6.4",
|
"typescript": "^4.6.4",
|
||||||
"vite": "^3.0.7"
|
"vite": "^3.0.7"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@tailwindcss/aspect-ratio": "^0.4.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +0,0 @@
|
|||||||
export default {
|
|
||||||
plugins: {
|
|
||||||
tailwindcss: {},
|
|
||||||
autoprefixer: {},
|
|
||||||
},
|
|
||||||
}
|
|
@ -44,7 +44,6 @@ export interface AniSearchList {
|
|||||||
title: {
|
title: {
|
||||||
romaji: string,
|
romaji: string,
|
||||||
english: string,
|
english: string,
|
||||||
native: string,
|
|
||||||
},
|
},
|
||||||
coverImage: {
|
coverImage: {
|
||||||
extraLarge: string,
|
extraLarge: string,
|
||||||
@ -53,46 +52,4 @@ export interface AniSearchList {
|
|||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export interface AniListUser {
|
|
||||||
"data": {
|
|
||||||
"Viewer": {
|
|
||||||
id: number,
|
|
||||||
name: string,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum MediaListSort {
|
|
||||||
MediaId = "MEDIA_ID",
|
|
||||||
MediaIdDesc = "MEDIA_ID_DESC",
|
|
||||||
Score = "SCORE",
|
|
||||||
ScoreDesc = "SCORE_DESC",
|
|
||||||
Status = "STATUS",
|
|
||||||
StatusDesc = "STATUS_DESC",
|
|
||||||
Progress = "PROGRESS",
|
|
||||||
ProgressDesc = "PROGRESS_DESC",
|
|
||||||
ProgressVolumes = "PROGRESS_VOLUMES",
|
|
||||||
ProgressVolumesDesc = "PROGRESS_VOLUMES_DESC",
|
|
||||||
Repeat = "REPEAT",
|
|
||||||
RepeatDesc = "REPEAT_DESC",
|
|
||||||
Priority = "PRIORITY",
|
|
||||||
PriorityDesc = "PRIORITY_DESC",
|
|
||||||
StartedOn = "STARTED_ON",
|
|
||||||
StartedOnDesc = "STARTED_ON_DESC",
|
|
||||||
FinishedOn = "FINISHED_ON",
|
|
||||||
FinishedOnDesc = "FINISHED_ON_DESC",
|
|
||||||
AddedTime = "ADDED_TIME",
|
|
||||||
AddedTimeDesc = "ADDED_TIME_DESC",
|
|
||||||
UpdatedTime = "UPDATED_TIME",
|
|
||||||
UpdatedTimeDesc = "UPDATED_TIME_DESC",
|
|
||||||
MediaTitleRomaji = "MEDIA_TITLE_ROMAJI",
|
|
||||||
MediaTitleRomajiDesc = "MEDIA_TITLE_ROMAJI_DESC",
|
|
||||||
MediaTitleEnglish = "MEDIA_TITLE_ENGLISH",
|
|
||||||
MediaTitleEnglishDesc = "MEDIA_TITLE_ENGLISH_DESC",
|
|
||||||
MediaTitleNative = "MEDIA_TITLE_NATIVE",
|
|
||||||
MediaTitleNativeDesc = "MEDIA_TITLE_NATIVE_DESC",
|
|
||||||
MediaPopularity = "MEDIA_POPULARITY",
|
|
||||||
MediaPopularityDesc = "MEDIA_POPULARITY_DESC"
|
|
||||||
}
|
}
|
@ -1,134 +1,125 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import logo from './assets/images/logo-universal.png'
|
||||||
AniListSearch,
|
import {Greet} from '../wailsjs/go/main/App.js'
|
||||||
GetAniListItem,
|
import {AniListLogin, AniListSearch, GetAniListItem} from "../wailsjs/go/main/App";
|
||||||
GetAniListLoggedInUserId,
|
import type {AniListItem, AniSearchList} from "./AniListTypes";
|
||||||
GetAniListUserWatchingList
|
|
||||||
} from "../wailsjs/go/main/App";
|
|
||||||
import {type AniListItem, type AniSearchList, MediaListSort} from "./anilist/types/AniListTypes";
|
|
||||||
import type {AniListCurrentUserWatchList} from "./anilist/types/AniListCurrentUserWatchListType"
|
|
||||||
|
|
||||||
let aniId = "157371"
|
let resultText: string = "Please enter your name below 👇"
|
||||||
let aniSearch = ""
|
let name: string
|
||||||
let aniListItem: AniListItem
|
let aniId = "157371"
|
||||||
let aniListSearch: AniSearchList
|
let aniSearch = ""
|
||||||
let aniListLoggedIn = false
|
let aniListItem: AniListItem
|
||||||
let aniListWatchlist: AniListCurrentUserWatchList
|
let aniListSearch: AniSearchList
|
||||||
let page = 1
|
let aniListLoggedIn = false
|
||||||
let perPage = 20
|
|
||||||
|
|
||||||
function getAniListitem(): void {
|
function greet(): void {
|
||||||
GetAniListItem(Number(aniId)).then(result => aniListItem = result)
|
Greet(name).then(result => resultText = result)
|
||||||
}
|
}
|
||||||
|
|
||||||
function runAniListSearch(): void {
|
function getAniListitem(): void {
|
||||||
AniListSearch(aniSearch).then(result => aniListSearch = result)
|
GetAniListItem(Number(aniId)).then(result => aniListItem = result)
|
||||||
}
|
}
|
||||||
|
|
||||||
function anilistGetUserWatchlist(): void {
|
function runAniListSearch(): void {
|
||||||
GetAniListUserWatchingList(page, perPage, MediaListSort.UpdatedTimeDesc).then((result) => {
|
AniListSearch(aniSearch).then(result => aniListSearch = result)
|
||||||
aniListWatchlist = result
|
}
|
||||||
aniListLoggedIn = true
|
|
||||||
})
|
function loginToAniList(): void {
|
||||||
}
|
AniListLogin().then(() => aniListLoggedIn = true)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<div class="input-box" id="aniSearch">
|
<img alt="Wails logo" id="logo" src="{aniListItem === undefined ? logo : aniListItem.data.Media.coverImage.extraLarge}">
|
||||||
<input autocomplete="off" bind:value={aniSearch} class="input" id="aniSearchInput" type="text"/>
|
<!-- <div class="result" id="result">{resultText}</div>-->
|
||||||
<button class="btn" on:click={runAniListSearch}>Search AniList</button>
|
<!-- <div class="input-box" id="input">-->
|
||||||
</div>
|
<!-- <input autocomplete="off" bind:value={name} class="input" id="name" type="text"/>-->
|
||||||
|
<!-- <button class="btn" on:click={greet}>Greet</button>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
|
||||||
<button class="btn" on:click={anilistGetUserWatchlist}>Login to AniList</button>
|
<div class="result" id="AniTest">{aniListItem !== undefined ? aniListItem.data.Media.title.english : ""}</div>
|
||||||
{#if aniListLoggedIn}
|
<div class="input-box" id="aniButton">
|
||||||
<div>You are logged in {aniListWatchlist.data.Page.mediaList[0].user.name}!</div>
|
<input autocomplete="off" bind:value={aniId} class="input" id="aniId" type="text"/>
|
||||||
{/if}
|
<button class="btn" on:click={getAniListitem}>Get AniList Item</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{#if aniListLoggedIn}
|
<button class="btn" on:click={loginToAniList}>Login to AniList</button>
|
||||||
<div class="mx-auto max-w-2xl px-4 py-16 sm:px-6 sm:py-24 lg:max-w-7xl lg:px-8">
|
{#if aniListLoggedIn}
|
||||||
<h1>Your Watching List</h1>
|
<div>You are logged in!</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8">
|
<div class="input-box" id="aniSearch">
|
||||||
{#each aniListWatchlist.data.Page.mediaList as media}
|
<input autocomplete="off" bind:value={aniSearch} class="input" id="aniSearchInput" type="text"/>
|
||||||
<a href="#" class="group">
|
<button class="btn" on:click={runAniListSearch}>Search AniList</button>
|
||||||
<!-- <div class="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-lg bg-gray-200 xl:aspect-h-8 xl:aspect-w-7">-->
|
</div>
|
||||||
<div class="justify-center rounded-lg bg-gray-200">
|
{#if aniListSearch !== undefined}
|
||||||
<img src={media.media.coverImage.large} alt="anime cover"/>
|
<ul>
|
||||||
</div>
|
{#each aniListSearch.data.Page.media as media, index (media.id)}
|
||||||
<h3 class="mt-4 text-sm text-white-700">{
|
<li>
|
||||||
media.media.title.english === "" ?
|
<div>{media.title.english !== null ? media.title.english : media.title.romaji}</div>
|
||||||
media.media.title.romaji :
|
</li>
|
||||||
media.media.title.english
|
{:else}
|
||||||
}</h3>
|
<div>No Results Yet...</div>
|
||||||
<p class="mt-1 text-lg font-medium text-white-900">{media.progress}
|
{/each}
|
||||||
/ {media.media.nextAiringEpisode.episode !== 0 ?
|
</ul>
|
||||||
media.media.nextAiringEpisode.episode - 1 : media.media.episodes}</p>
|
{/if}
|
||||||
{#if media.media.episodes > 0}
|
|
||||||
<p class="mt-1 text-lg font-medium text-white-900">Total
|
|
||||||
Episodes: {media.media.episodes}</p>
|
|
||||||
{/if}
|
|
||||||
</a>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
#logo {
|
#logo {
|
||||||
display: block;
|
display: block;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
height: 50%;
|
height: 50%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 10% 0 0;
|
padding: 10% 0 0;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
background-origin: content-box;
|
background-origin: content-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result {
|
.result {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
margin: 1.5rem auto;
|
margin: 1.5rem auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-box .btn {
|
.input-box .btn {
|
||||||
/*width: 60px;*/
|
/*width: 60px;*/
|
||||||
height: 30px;
|
height: 30px;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
border: none;
|
border: none;
|
||||||
margin: 0 0 0 20px;
|
margin: 0 0 0 20px;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-box .btn:hover {
|
.input-box .btn:hover {
|
||||||
background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%);
|
background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%);
|
||||||
color: #333333;
|
color: #333333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-box .input {
|
.input-box .input {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
outline: none;
|
outline: none;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
background-color: rgba(240, 240, 240, 1);
|
background-color: rgba(240, 240, 240, 1);
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-box .input:hover {
|
.input-box .input:hover {
|
||||||
border: none;
|
border: none;
|
||||||
background-color: rgba(255, 255, 255, 1);
|
background-color: rgba(255, 255, 255, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-box .input:focus {
|
.input-box .input:focus {
|
||||||
border: none;
|
border: none;
|
||||||
background-color: rgba(255, 255, 255, 1);
|
background-color: rgba(255, 255, 255, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
export interface AniListCurrentUserWatchList {
|
|
||||||
data: Data
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Data {
|
|
||||||
Page: Page
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Page {
|
|
||||||
pageInfo: PageInfo
|
|
||||||
mediaList: MediaList[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PageInfo {
|
|
||||||
total: number
|
|
||||||
perPage: number
|
|
||||||
currentPage: number
|
|
||||||
lastPage: number
|
|
||||||
hasNextPage: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MediaList {
|
|
||||||
id: number
|
|
||||||
mediaId: number
|
|
||||||
userId: number
|
|
||||||
media: Media
|
|
||||||
status: string
|
|
||||||
notes?: string
|
|
||||||
progress: number
|
|
||||||
score: number
|
|
||||||
repeat: number
|
|
||||||
user: User
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Media {
|
|
||||||
id: number
|
|
||||||
idMal: number
|
|
||||||
title: Title
|
|
||||||
description: string
|
|
||||||
coverImage: CoverImage
|
|
||||||
season: string
|
|
||||||
seasonYear: number
|
|
||||||
status: string
|
|
||||||
episodes?: number
|
|
||||||
nextAiringEpisode?: NextAiringEpisode
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Title {
|
|
||||||
romaji: string
|
|
||||||
english?: string
|
|
||||||
native: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CoverImage {
|
|
||||||
large: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NextAiringEpisode {
|
|
||||||
airingAt: number
|
|
||||||
timeUntilAiring: number
|
|
||||||
episode: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface User {
|
|
||||||
id: number
|
|
||||||
name: string
|
|
||||||
avatar: Avatar
|
|
||||||
statistics: Statistics
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Avatar {
|
|
||||||
large: string
|
|
||||||
medium: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Statistics {
|
|
||||||
anime: Anime
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Anime {
|
|
||||||
count: number
|
|
||||||
statuses: Status[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Status {
|
|
||||||
status: string
|
|
||||||
count: number
|
|
||||||
}
|
|
@ -1,7 +1,3 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
html {
|
html {
|
||||||
background-color: rgba(27, 38, 54, 1);
|
background-color: rgba(27, 38, 54, 1);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
export default {
|
|
||||||
content: [
|
|
||||||
"./index.html",
|
|
||||||
"./src/**/*.{svelte,js,ts,jsx,tsx}",
|
|
||||||
],
|
|
||||||
theme: {
|
|
||||||
extend: {},
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
require('@tailwindcss/aspect-ratio'),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
5
frontend/wailsjs/go/main/App.d.ts
vendored
5
frontend/wailsjs/go/main/App.d.ts
vendored
@ -1,6 +1,5 @@
|
|||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
import {main} from '../models';
|
|
||||||
|
|
||||||
export function AniListLogin():Promise<void>;
|
export function AniListLogin():Promise<void>;
|
||||||
|
|
||||||
@ -8,8 +7,4 @@ export function AniListSearch(arg1:string):Promise<any>;
|
|||||||
|
|
||||||
export function GetAniListItem(arg1:number):Promise<any>;
|
export function GetAniListItem(arg1:number):Promise<any>;
|
||||||
|
|
||||||
export function GetAniListLoggedInUserId():Promise<main.AniListUser>;
|
|
||||||
|
|
||||||
export function GetAniListUserWatchingList(arg1:number,arg2:number,arg3:string):Promise<main.AniListCurrentUserWatchList>;
|
|
||||||
|
|
||||||
export function Greet(arg1:string):Promise<string>;
|
export function Greet(arg1:string):Promise<string>;
|
||||||
|
@ -14,14 +14,6 @@ export function GetAniListItem(arg1) {
|
|||||||
return window['go']['main']['App']['GetAniListItem'](arg1);
|
return window['go']['main']['App']['GetAniListItem'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetAniListLoggedInUserId() {
|
|
||||||
return window['go']['main']['App']['GetAniListLoggedInUserId']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetAniListUserWatchingList(arg1, arg2, arg3) {
|
|
||||||
return window['go']['main']['App']['GetAniListUserWatchingList'](arg1, arg2, arg3);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Greet(arg1) {
|
export function Greet(arg1) {
|
||||||
return window['go']['main']['App']['Greet'](arg1);
|
return window['go']['main']['App']['Greet'](arg1);
|
||||||
}
|
}
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
export namespace main {
|
|
||||||
|
|
||||||
export class AniListCurrentUserWatchList {
|
|
||||||
// Go type: struct { Page struct { PageInfo struct { Total int "json:\"total\""; PerPage int "json:\"perPage\""; CurrentPage int "json:\"currentPage\""; LastPage int "json:\"lastPage\""; HasNextPage bool "json:\"hasNextPage\"" } "json:\"pageInfo\""; MediaList []struct { ID int "json:\"id\""; MediaID int "json:\"mediaId\""; UserID int "json:\"userId\""; Media struct { ID int "json:\"id\""; IDMal int "json:\"idMal\""; Title struct { Romaji string "json:\"romaji\""; English string "json:\"english\""; Native string "json:\"native\"" } "json:\"title\""; Description string "json:\"description\""; CoverImage struct { Large string "json:\"large\"" } "json:\"coverImage\""; Season string "json:\"season\""; SeasonYear int "json:\"seasonYear\""; Status string "json:\"status\""; Episodes int "json:\"episodes\""; NextAiringEpisode struct { AiringAt int "json:\"airingAt\""; TimeUntilAiring int "json:\"timeUntilAiring\""; Episode int "json:\"episode\"" } "json:\"nextAiringEpisode\"" } "json:\"media\""; Status string "json:\"status\""; Notes string "json:\"notes\""; Progress int "json:\"progress\""; Score int "json:\"score\""; Repeat int "json:\"repeat\""; User struct { ID int "json:\"id\""; Name string "json:\"name\""; Avatar struct { Large string "json:\"large\""; Medium string "json:\"medium\"" } "json:\"avatar\""; Statistics struct { Anime struct { Count int "json:\"count\""; Statuses []struct { Status string "json:\"status\""; Count int "json:\"count\"" } "json:\"statuses\"" } "json:\"anime\"" } "json:\"statistics\"" } "json:\"user\"" } "json:\"mediaList\"" } "json:\"Page\"" }
|
|
||||||
data: any;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
|
||||||
return new AniListCurrentUserWatchList(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
|
||||||
if ('string' === typeof source) source = JSON.parse(source);
|
|
||||||
this.data = this.convertValues(source["data"], Object);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 AniListUser {
|
|
||||||
// Go type: struct { Viewer struct { ID int "json:\"id\""; Name string "json:\"name\"" } "json:\"Viewer\"" }
|
|
||||||
data: any;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
|
||||||
return new AniListUser(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
|
||||||
if ('string' === typeof source) source = JSON.parse(source);
|
|
||||||
this.data = this.convertValues(source["data"], Object);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
8
go.mod
8
go.mod
@ -5,21 +5,15 @@ go 1.21
|
|||||||
toolchain go1.21.11
|
toolchain go1.21.11
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/99designs/keyring v1.2.2
|
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/wailsapp/wails/v2 v2.9.1
|
github.com/wailsapp/wails/v2 v2.9.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
|
|
||||||
github.com/bep/debounce v1.2.1 // indirect
|
github.com/bep/debounce v1.2.1 // indirect
|
||||||
github.com/danieljoos/wincred v1.1.2 // indirect
|
|
||||||
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
|
|
||||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
|
|
||||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
|
|
||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||||
github.com/labstack/echo/v4 v4.12.0 // indirect
|
github.com/labstack/echo/v4 v4.12.0 // indirect
|
||||||
github.com/labstack/gommon v0.4.2 // indirect
|
github.com/labstack/gommon v0.4.2 // indirect
|
||||||
@ -29,7 +23,6 @@ require (
|
|||||||
github.com/leaanthony/u v1.1.1 // indirect
|
github.com/leaanthony/u v1.1.1 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mtibben/percent v0.2.1 // indirect
|
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
@ -42,7 +35,6 @@ require (
|
|||||||
golang.org/x/crypto v0.25.0 // indirect
|
golang.org/x/crypto v0.25.0 // indirect
|
||||||
golang.org/x/net v0.27.0 // indirect
|
golang.org/x/net v0.27.0 // indirect
|
||||||
golang.org/x/sys v0.22.0 // indirect
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
golang.org/x/term v0.22.0 // indirect
|
|
||||||
golang.org/x/text v0.16.0 // indirect
|
golang.org/x/text v0.16.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
31
go.sum
31
go.sum
@ -1,33 +1,17 @@
|
|||||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
|
|
||||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
|
|
||||||
github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0=
|
|
||||||
github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk=
|
|
||||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||||
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||||
github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0=
|
|
||||||
github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM=
|
|
||||||
github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
|
|
||||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
|
|
||||||
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
|
||||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
|
|
||||||
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
|
|
||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
|
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
|
||||||
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
|
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
|
||||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||||
@ -50,10 +34,6 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
|||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
|
|
||||||
github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
|
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
@ -65,10 +45,6 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
|||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/samber/lo v1.46.0 h1:w8G+oaCPgz1PoCJztqymCFaKwXt+5cCXn51uPxExFfQ=
|
github.com/samber/lo v1.46.0 h1:w8G+oaCPgz1PoCJztqymCFaKwXt+5cCXn51uPxExFfQ=
|
||||||
github.com/samber/lo v1.46.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
|
github.com/samber/lo v1.46.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
|
|
||||||
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE=
|
github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE=
|
||||||
@ -92,22 +68,15 @@ golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
|
||||||
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
Loading…
Reference in New Issue
Block a user