Compare commits

...

4 Commits

15 changed files with 655 additions and 105 deletions

View File

@ -355,43 +355,10 @@ func (a *App) GetAniListUserWatchingList(page int, perPage int, sort string) Ani
return post return post
} }
func (a *App) AniListUpdateEntry( func (a *App) AniListUpdateEntry(updateBody AniListUpdateVariables) interface{} {
mediaId int,
progress int,
status string,
score float64,
repeat int,
notes string,
startYear int,
startMonth int,
startDay int,
completeYear int,
completeMonth int,
completeDay int,
) interface{} {
type StartedAt struct {
Year int `json:"year"`
Month int `json:"month"`
Day int `json:"day"`
}
type CompletedAt struct {
Year int `json:"year"`
Month int `json:"month"`
Day int `json:"day"`
}
type Variables struct {
MediaId int `json:"mediaId"`
Progress int `json:"progress"`
Status string `json:"status"`
Score float64 `json:"score"`
Repeat int `json:"repeat"`
Notes string `json:"notes"`
StartedAt StartedAt `json:"startedAt"`
CompletedAt CompletedAt `json:"completedAt"`
}
body := struct { body := struct {
Query string `json:"query"` Query string `json:"query"`
Variables Variables `json:"variables"` Variables AniListUpdateVariables `json:"variables"`
}{ }{
Query: ` Query: `
mutation( mutation(
@ -433,24 +400,8 @@ func (a *App) AniListUpdateEntry(
} }
} }
`, `,
Variables: Variables{ Variables: updateBody,
MediaId: mediaId, }
Progress: progress,
Status: status,
Score: score,
Repeat: repeat,
Notes: notes,
StartedAt: StartedAt{
Year: startYear,
Month: startMonth,
Day: startDay,
},
CompletedAt: CompletedAt{
Year: completeYear,
Month: completeMonth,
Day: completeDay,
},
}}
returnedBody, _ := AniListQuery(body, true) returnedBody, _ := AniListQuery(body, true)

View File

@ -112,6 +112,27 @@ type MediaList struct {
} `json:"user"` } `json:"user"`
} }
type StartedAt struct {
Year int `json:"year"`
Month int `json:"month"`
Day int `json:"day"`
}
type CompletedAt struct {
Year int `json:"year"`
Month int `json:"month"`
Day int `json:"day"`
}
type AniListUpdateVariables struct {
MediaId int `json:"mediaId"`
Progress int `json:"progress"`
Status string `json:"status"`
Score float64 `json:"score"`
Repeat int `json:"repeat"`
Notes string `json:"notes"`
StartedAt StartedAt `json:"startedAt"`
CompletedAt CompletedAt `json:"completedAt"`
}
//var MediaListSort = struct { //var MediaListSort = struct {
// MediaId string // MediaId string
// MediaIdDesc string // MediaIdDesc string

View File

@ -54,3 +54,21 @@ func (a *App) GetMyAnimeList(count int) MALWatchlist {
return malList return malList
} }
func (a *App) MyAnimeListUpdate(anime MALAnime, update interface{}) MyListStatus {
//var body url.Values
return MyListStatus{}
}
func (a *App) GetMyAnimeListAnime(id int) MALAnime {
malUrl := "https://api.myanimelist.net/v2/anime/" + strconv.Itoa(id) + "?fields=id,title,main_picture,alternative_titles,start_date,end_date,synopsis,mean,rank,popularity,num_list_users,num_scoring_users,nsfw,genres,created_at,updated_at,media_type,status,my_list_status,num_episodes,start_season,broadcast,source,average_episode_duration,rating,pictures,background,related_anime,recommendations,studios,statistics"
respBody := MALHelper("GET", malUrl, nil)
var malAnime MALAnime
err := json.Unmarshal(respBody, &malAnime)
if err != nil {
log.Printf("Failed to unmarshal json response, %s\n", err)
}
return malAnime
}

View File

@ -65,3 +65,90 @@ type MALWatchlist struct {
Next string `json:"next" ts_type:"next"` Next string `json:"next" ts_type:"next"`
} `json:"paging" ts_type:"paging"` } `json:"paging" ts_type:"paging"`
} }
type MALAnime struct {
Id int `json:"id" ts_type:"id"`
Title string `json:"title" ts_type:"title"`
MainPicture struct {
Large string `json:"large" json:"large"`
Medium string `json:"medium" json:"medium"`
} `json:"main_picture" json:"mainPicture"`
AlternativeTitles struct {
Synonyms []string `json:"synonyms" ts_type:"synonyms"`
En string `json:"en" ts_type:"en"`
Ja string `json:"ja" ts_type:"ja"`
} `json:"alternative_titles" ts_type:"alternativeTitles"`
StartDate string `json:"start_date" ts_type:"startDate"`
EndDate string `json:"end_date" ts_type:"endDate"`
Synopsis string `json:"synopsis" ts_type:"synopsis"`
Mean float64 `json:"mean" ts_type:"mean"`
Rank int `json:"rank" ts_type:"rank"`
Popularity int `json:"popularity" ts_type:"popularity"`
NumListUsers int `json:"num_list_users" ts_type:"numListUsers"`
NumScoringUsers int `json:"num_scoring_users" ts_type:"numScoringUsers"`
NSFW string `json:"nsfw" ts_type:"nsfw"`
Genres []struct {
Id int `json:"id" ts_type:"id"`
Name string `json:"name" ts_type:"name"`
} `json:"genres" ts_type:"genres"`
CreatedAt string `json:"created_at" ts_type:"createdAt"`
UpdatedAt string `json:"updated_at" ts_type:"updatedAt"`
MediaType string `json:"media_type" ts_type:"mediaType"`
Status string `json:"status" ts_type:"status"`
MyListStatus MyListStatus `json:"my_list_status" ts_type:"myListStatus"`
NumEpisodes int `json:"num_episodes" ts_type:"numEpisodes"`
StartSeason struct {
Year int `json:"year" ts_type:"year"`
Season string `json:"season" ts_type:"season"`
} `json:"start_season" ts_type:"startSeason"`
Broadcast struct {
DayOfTheWeek string `json:"day_of_the_week" ts_type:"dayOfTheWeek"`
StartTime string `json:"start_time" ts_type:"startTime"`
} `json:"broadcast" ts_type:"broadcast"`
Source string `json:"source" ts_type:"source"`
AverageEpisodeDuration int `json:"average_episode_duration" ts_type:"averageEpisodeDuration"`
Rating string `json:"rating" ts_type:"rating"`
Studios []struct {
Id int `json:"id" ts_type:"id"`
Name string `json:"name" ts_type:"name"`
} `json:"studios" ts_type:"studios"`
Pictures []struct {
Large string `json:"large" ts_type:"large"`
Medium string `json:"medium" ts_type:"medium"`
} `json:"pictures" ts_type:"pictures"`
Background string `json:"background" ts_type:"background"`
RelatedAnime []struct {
Node MALAnime `json:"node" ts_type:"node"`
RelationType string `json:"relation_type" ts_type:"relationType"`
RelationTypeFormatted string `json:"relation_type_formatted" ts_type:"relationTypeFormatted"`
} `json:"related_anime" ts_type:"relatedAnime"`
Recommendations []struct {
Node MALAnime `json:"node" ts_type:"node"`
NumRecommendations int `json:"num_recommendations" ts_type:"numRecommendations"`
} `json:"recommendations" ts_type:"recommendations"`
Statistics struct {
NumListUsers int `json:"num_list_users" ts_type:"numListUsers"`
Status struct {
Watching string `json:"watching" ts_type:"watching"`
Completed string `json:"completed" ts_type:"completed"`
OnHold string `json:"on_hold" ts_type:"onHold"`
Dropped string `json:"dropped" ts_type:"dropped"`
PlanToWatch string `json:"plan_to_watch" ts_type:"planToWatch"`
}
}
}
type MyListStatus 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"`
StartDate string `json:"start_date" ts_type:"startDate"`
FinishDate string `json:"finish_date" ts_type:"finishDate"`
Priority int `json:"priority" ts_type:"priority"`
NumTimesRewatched int `json:"num_times_rewatched" ts_type:"numTimesRewatched"`
RewatchValue int `json:"rewatch_value" ts_type:"rewatchValue"`
Tags []string `json:"tags" ts_type:"tags"`
Comments string `json:"comments" ts_type:"comments"`
UpdatedAt string `json:"updated_at" ts_type:"updatedAt"`
}

View File

@ -0,0 +1,19 @@
meta {
name: Get Single Anime
type: http
seq: 5
}
get {
url: https://api.myanimelist.net/v2/anime/52991?fields=id,title,main_picture,alternative_titles,start_date,end_date,synopsis,mean,rank,popularity,num_list_users,num_scoring_users,nsfw,genres,created_at,updated_at,media_type,status,my_list_status,num_episodes,start_season,broadcast,source,average_episode_duration,rating,pictures,background,related_anime,recommendations,studios,statistics
body: none
auth: bearer
}
params:query {
fields: id,title,main_picture,alternative_titles,start_date,end_date,synopsis,mean,rank,popularity,num_list_users,num_scoring_users,nsfw,genres,created_at,updated_at,media_type,status,my_list_status,num_episodes,start_season,broadcast,source,average_episode_duration,rating,pictures,background,related_anime,recommendations,studios,statistics
}
auth:bearer {
token: {{MAL_ACCESS_TOKEN}}
}

View File

@ -0,0 +1,15 @@
meta {
name: Update Anime Status
type: http
seq: 4
}
patch {
url: https://api.myanimelist.net/v2/anime/50205/my_list_status
body: formUrlEncoded
auth: bearer
}
auth:bearer {
token: {{MAL_ACCESS_TOKEN}}
}

View File

@ -14,7 +14,8 @@
title, title,
watchListPage, watchListPage,
animePerPage, animePerPage,
malWatchList malWatchList,
malPrimary
} from "./GlobalVariablesAndHelperFunctions.svelte"; } from "./GlobalVariablesAndHelperFunctions.svelte";
import { import {
CheckIfAniListLoggedIn, CheckIfAniListLoggedIn,
@ -38,11 +39,13 @@
let isAniListLoggedIn: boolean let isAniListLoggedIn: boolean
let isAniListPrimary: boolean let isAniListPrimary: boolean
let isMalPrimary: boolean
let aniListWatchListLoaded: AniListCurrentUserWatchList let aniListWatchListLoaded: AniListCurrentUserWatchList
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value) aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
aniListPrimary.subscribe((value) => isAniListPrimary = value) aniListPrimary.subscribe((value) => isAniListPrimary = value)
aniListWatchlist.subscribe((value) => aniListWatchListLoaded = value) aniListWatchlist.subscribe((value) => aniListWatchListLoaded = value)
malPrimary.subscribe((value) => isMalPrimary = value)
let page: number let page: number
@ -72,10 +75,14 @@
if (loggedIn) { if (loggedIn) {
GetMyAnimeListLoggedInUser().then(user => { GetMyAnimeListLoggedInUser().then(user => {
malUser.set(user) malUser.set(user)
GetMyAnimeList(1000).then(watchList => { if (isMalPrimary){
malWatchList.set(watchList) GetMyAnimeList(1000).then(watchList => {
malWatchList.set(watchList)
malLoggedIn.set(loggedIn)
})
} else {
malLoggedIn.set(loggedIn) malLoggedIn.set(loggedIn)
}) }
}) })
} }
}) })
@ -98,7 +105,14 @@
<main> <main>
{#if isAniListLoggedIn} {#if isAniListLoggedIn}
<div class="mx-auto max-w-2xl p-4 sm:p-6 lg:max-w-7xl lg:px-8"> <div class="mx-auto max-w-2xl p-4 sm:p-6 lg:max-w-7xl lg:px-8 relative items-center">
<div id="spinner" role="status" class="fixed hidden -translate-x-1/2 -translate-y-1/2 top-2/4 left-1/2">
<svg aria-hidden="true" class="inline w-16 h-16 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600" viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/>
<path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z" fill="currentFill"/>
</svg>
<span class="sr-only">Loading...</span>
</div>
<h1 class="text-left text-xl font-bold mb-4">Your AniList WatchList</h1> <h1 class="text-left text-xl font-bold mb-4">Your AniList WatchList</h1>
<Pagination /> <Pagination />
@ -107,7 +121,11 @@
{#each aniListWatchListLoaded.data.Page.mediaList as media} {#each aniListWatchListLoaded.data.Page.mediaList as media}
<div class="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-lg xl:aspect-h-8 xl:aspect-w-7"> <div class="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-lg xl:aspect-h-8 xl:aspect-w-7">
<div class="flex flex-col items-center group"> <div class="flex flex-col items-center group">
<button on:click={() => GetAniListSingleItemAndOpenModal(media.media.id, true)}> <button on:click={() => {
let spinner = document.querySelector("#spinner")
spinner.classList.toggle("hidden", false)
GetAniListSingleItemAndOpenModal(media.media.id, true).then(() => spinner.classList.toggle("hidden", true))
}}>
<img class="rounded-lg" src={media.media.coverImage.large} alt={ <img class="rounded-lg" src={media.media.coverImage.large} alt={
media.media.title.english === "" ? media.media.title.english === "" ?
media.media.title.romaji : media.media.title.romaji :

View File

@ -3,7 +3,9 @@
anilistModal, anilistModal,
simklWatchList, simklWatchList,
aniListLoggedIn, aniListLoggedIn,
simklLoggedIn simklLoggedIn,
malLoggedIn,
malAnime
} from "./GlobalVariablesAndHelperFunctions.svelte"; } from "./GlobalVariablesAndHelperFunctions.svelte";
import {aniListAnime} from "./GlobalVariablesAndHelperFunctions.svelte"; import {aniListAnime} from "./GlobalVariablesAndHelperFunctions.svelte";
import {Button} from "flowbite-svelte"; import {Button} from "flowbite-svelte";
@ -14,16 +16,28 @@
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
import type {SimklAnime} from "./simkl/types/simklTypes"; import type {SimklAnime} from "./simkl/types/simklTypes";
import { get } from 'svelte/store'; import { get } from 'svelte/store';
import {AniListUpdateEntry, SimklSyncEpisodes, SimklSyncRating, SimklSyncStatus} from "../wailsjs/go/main/App"; import {
AniListUpdateEntry,
SimklSyncEpisodes,
SimklSyncRating,
SimklSyncStatus
} from "../wailsjs/go/main/App";
import type {MALAnime} from "./mal/types/MALTypes";
import type {AniListUpdateVariables} from "./anilist/types/AniListTypes";
const simklWatch = get(simklWatchList); const simklWatch = get(simklWatchList);
let isAniListLoggedIn: boolean let isAniListLoggedIn: boolean
let isMalLoggedIn: boolean
let isSimklLoggedIn: boolean let isSimklLoggedIn: boolean
let simklAnimeIndex: number let simklAnimeIndex: number
let currentMalAnime: MALAnime
let simklAnime: SimklAnime | undefined = undefined let simklAnime: SimklAnime | undefined = undefined
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value) aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
malLoggedIn.subscribe((value) => isMalLoggedIn = value)
simklLoggedIn.subscribe((value) => isSimklLoggedIn = value) simklLoggedIn.subscribe((value) => isSimklLoggedIn = value)
malAnime.subscribe((value) => currentMalAnime = value)
for (let i = 0; i < simklWatch.anime.length; i++) { for (let i = 0; i < simklWatch.anime.length; i++) {
if (Number(simklWatch.anime[i].show.ids.mal) === aniListAnime.data.MediaList.media.idMal) { if (Number(simklWatch.anime[i].show.ids.mal) === aniListAnime.data.MediaList.media.idMal) {
@ -35,23 +49,34 @@
type statusOption = { type statusOption = {
id: number, id: number,
aniList: string, aniList: string,
mal: string,
simkl: string, simkl: string,
} }
const statusOptions: statusOption[] = [ const statusOptions: statusOption[] = [
{ id: 0, aniList: "CURRENT", simkl: "watching"}, { id: 0, aniList: "CURRENT", mal: "watching", simkl: "watching"},
{ id: 1, aniList: "PLANNING", simkl: "plantowatch"}, { id: 1, aniList: "PLANNING", mal: "plan_to_watch", simkl: "plantowatch"},
{ id: 2, aniList: "COMPLETED", simkl: "completed"}, { id: 2, aniList: "COMPLETED", mal: "completed", simkl: "completed"},
{ id: 3, aniList: "DROPPED", simkl: "dropped"}, { id: 3, aniList: "DROPPED", mal: "dropped", simkl: "dropped"},
{ id: 4, aniList: "PAUSED", simkl: "hold"}, { id: 4, aniList: "PAUSED", mal: "on_hold", simkl: "hold"},
{ id: 5, aniList: "REPEATING", simkl: "watching"} { id: 5, aniList: "REPEATING", mal: "rewatching", simkl: "watching"}
] ]
let startingAnilistStatusOption: statusOption let startingAnilistStatusOption: statusOption
startingAnilistStatusOption = statusOptions.filter(option => aniListAnime.data.MediaList.status === option.aniList)[0] startingAnilistStatusOption = statusOptions.filter(option => aniListAnime.data.MediaList.status === option.aniList)[0]
let items = []; let items = [] as {
id: number
service: string
progress: number
status: string
startedAt: string
completedAt: string
score: number
repeat: number
notes: string
}[];
if(isAniListLoggedIn) { if(isAniListLoggedIn) {
items.push({ items.push({
@ -67,6 +92,20 @@
}) })
} }
if(isMalLoggedIn) {
items.push({
id: currentMalAnime.id,
service: "MyAnimeList",
progress: currentMalAnime.my_list_status.num_episodes_watched,
status: currentMalAnime.my_list_status.status,
startedAt: currentMalAnime.my_list_status.start_date,
completedAt: currentMalAnime.my_list_status.finish_date,
score: currentMalAnime.my_list_status.score,
repeat: currentMalAnime.my_list_status.num_times_rewatched,
notes: currentMalAnime.my_list_status.comments
})
}
if(isSimklLoggedIn && simklAnime !== undefined) { if(isSimklLoggedIn && simklAnime !== undefined) {
items.push({ items.push({
id: simklAnime.show.ids.simkl, id: simklAnime.show.ids.simkl,
@ -114,7 +153,7 @@
const ratingInWords = { const ratingInWords = {
0: "Not Reviewed", 0: "Not Reviewed",
1: "Apalling", 1: "Appalling",
2: "Horrible", 2: "Horrible",
3: "Very Bad", 3: "Very Bad",
4: "Bad", 4: "Bad",
@ -213,43 +252,45 @@
} }
const submitData = async () => { const submitData = async () => {
await AniListUpdateEntry( let body: AniListUpdateVariables = {
aniListAnime.data.MediaList.mediaId, mediaId: aniListAnime.data.MediaList.mediaId,
values.progress, progress: values.progress,
values.status.aniList, status: values.status.aniList,
values.score, score: values.score,
values.repeat, repeat: values.repeat,
values.notes, notes: values.notes,
values.startedAt.year, startedAt: {
values.startedAt.month, year: values.startedAt.year,
values.startedAt.day, month: values.startedAt.month,
values.completedAt.year, day: values.startedAt.day
values.completedAt.month, },
values.completedAt.day completedAt: {
).then((value) => { year: values.completedAt.year,
month: values.completedAt.month,
day: values.completedAt.day
}
}
await AniListUpdateEntry(body).then((value) => {
console.log(value) console.log(value)
}) })
if (simklLoggedIn) { if (simklLoggedIn) {
if (simklAnime.watched_episodes_count !== values.progress) { if (simklAnime.watched_episodes_count !== values.progress) {
await SimklSyncEpisodes(simklAnime, values.progress).then(value => { await SimklSyncEpisodes(simklAnime, values.progress).then(() => {
console.log(value)
simklAnime.watched_episodes_count = values.progress simklAnime.watched_episodes_count = values.progress
simklWatch.anime[simklAnimeIndex].watched_episodes_count = values.progress simklWatch.anime[simklAnimeIndex].watched_episodes_count = values.progress
}) })
} }
if (simklAnime.user_rating !== values.score) { if (simklAnime.user_rating !== values.score) {
await SimklSyncRating(simklAnime, values.score).then(value => { await SimklSyncRating(simklAnime, values.score).then(() => {
console.log(value)
simklAnime.user_rating = values.score simklAnime.user_rating = values.score
simklWatch.anime[simklAnimeIndex].user_rating = values.score simklWatch.anime[simklAnimeIndex].user_rating = values.score
}) })
} }
if (simklAnime.status !== values.status.simkl) { if (simklAnime.status !== values.status.simkl) {
SimklSyncStatus(simklAnime, values.status.simkl).then(value => { SimklSyncStatus(simklAnime, values.status.simkl).then(() => {
console.log(value)
simklAnime.status = values.status.simkl simklAnime.status = values.status.simkl
simklWatch.anime[simklAnimeIndex].status = values.status.simkl simklWatch.anime[simklAnimeIndex].status = values.status.simkl
}) })

View File

@ -1,7 +1,7 @@
<script lang="ts" context="module"> <script lang="ts" context="module">
import { import {
GetAniListItem, GetAniListItem,
GetAniListLoggedInUser, GetAniListUserWatchingList, GetMyAnimeListLoggedInUser, GetAniListLoggedInUser, GetAniListUserWatchingList, GetMyAnimeListAnime, GetMyAnimeListLoggedInUser,
GetSimklLoggedInUser, LogoutAniList, LogoutMyAnimeList, LogoutSimkl GetSimklLoggedInUser, LogoutAniList, LogoutMyAnimeList, LogoutSimkl
} from "../wailsjs/go/main/App"; } from "../wailsjs/go/main/App";
import type { import type {
@ -11,7 +11,7 @@
import {writable} from 'svelte/store' import {writable} from 'svelte/store'
import type {SimklUser, SimklWatchList} from "./simkl/types/simklTypes"; import type {SimklUser, SimklWatchList} from "./simkl/types/simklTypes";
import {type AniListUser, MediaListSort} from "./anilist/types/AniListTypes"; import {type AniListUser, MediaListSort} from "./anilist/types/AniListTypes";
import type {MALWatchlist, MyAnimeListUser} from "./mal/types/MALTypes"; import type {MALAnime, MALWatchlist, MyAnimeListUser} from "./mal/types/MALTypes";
export let aniListAnime: AniListGetSingleAnime export let aniListAnime: AniListGetSingleAnime
export let title = writable("") export let title = writable("")
@ -21,11 +21,13 @@
export let malLoggedIn = writable(false) export let malLoggedIn = writable(false)
export let simklWatchList = writable({} as SimklWatchList) export let simklWatchList = writable({} as SimklWatchList)
export let aniListPrimary = writable(true) export let aniListPrimary = writable(true)
export let malPrimary = writable(false)
export let simklUser = writable({} as SimklUser) export let simklUser = writable({} as SimklUser)
export let aniListUser = writable({} as AniListUser) export let aniListUser = writable({} as AniListUser)
export let malUser = writable({} as MyAnimeListUser) export let malUser = writable({} as MyAnimeListUser)
export let aniListWatchlist = writable({} as AniListCurrentUserWatchList) export let aniListWatchlist = writable({} as AniListCurrentUserWatchList)
export let malWatchList = writable({} as MALWatchlist) export let malWatchList = writable({} as MALWatchlist)
export let malAnime = writable({} as MALAnime)
export let watchListPage = writable(1) export let watchListPage = writable(1)
export let animePerPage = writable(20) export let animePerPage = writable(20)
@ -35,19 +37,34 @@
let perPage: number let perPage: number
let aniWatchlist: AniListCurrentUserWatchList let aniWatchlist: AniListCurrentUserWatchList
let isMalLoggedIn: boolean
aniListPrimary.subscribe(value => isAniListPrimary = value) aniListPrimary.subscribe(value => isAniListPrimary = value)
watchListPage.subscribe(value => page = value) watchListPage.subscribe(value => page = value)
animePerPage.subscribe(value => perPage = value) animePerPage.subscribe(value => perPage = value)
aniListWatchlist.subscribe(value => aniWatchlist = value) aniListWatchlist.subscribe(value => aniWatchlist = value)
malLoggedIn.subscribe(value => isMalLoggedIn = value)
export function GetAniListSingleItemAndOpenModal(aniId: number, login: boolean): void {
GetAniListItem(aniId, login).then(result => { export async function GetAniListSingleItemAndOpenModal(aniId: number, login: boolean): Promise<""> {
aniListAnime = result await GetAniListItem(aniId, login).then(aniListResult => {
aniListAnime = aniListResult
title.set(aniListAnime.data.MediaList.media.title.english === "" ? title.set(aniListAnime.data.MediaList.media.title.english === "" ?
aniListAnime.data.MediaList.media.title.romaji : aniListAnime.data.MediaList.media.title.romaji :
aniListAnime.data.MediaList.media.title.english) aniListAnime.data.MediaList.media.title.english)
anilistModal.set(true) if(isMalLoggedIn) {
GetMyAnimeListAnime(aniListAnime.data.MediaList.media.idMal).then(malResult => {
console.log(malResult)
malAnime.set(malResult)
anilistModal.set(true)
return ""
})
} else {
anilistModal.set(true)
return ""
}
}) })
return ""
} }
export function loginToSimkl(): void { export function loginToSimkl(): void {

View File

@ -56,14 +56,18 @@
<li class="w-full"> <li class="w-full">
<div class="flex w-full items-start p-1 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white rounded-lg"> <div class="flex w-full items-start p-1 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white rounded-lg">
<button on:click={() => { <button on:click={() => {
GetAniListSingleItemAndOpenModal(media.id, false) let spinner = document.querySelector("#spinner")
spinner.classList.toggle("hidden", false)
GetAniListSingleItemAndOpenModal(media.id, false).then(() => spinner.classList.toggle("hidden", true))
}} }}
> >
<img class="rounded-bl-lg rounded-tl-lg max-w-24 max-h-24" src={media.coverImage.large} <img class="rounded-bl-lg rounded-tl-lg max-w-24 max-h-24" src={media.coverImage.large}
alt="{media.title.english === '' || media.title.english === null ? media.title.romaji : media.title.english} Cover"> alt="{media.title.english === '' || media.title.english === null ? media.title.romaji : media.title.english} Cover">
</button> </button>
<button class="rounded-bl-lg rounded-tl-lg w-full h-24" on:click={() => { <button class="rounded-bl-lg rounded-tl-lg w-full h-24" on:click={() => {
GetAniListSingleItemAndOpenModal(media.id, false) let spinner = document.querySelector("#spinner")
spinner.classList.toggle("hidden", false)
GetAniListSingleItemAndOpenModal(media.id, false).then(() => spinner.classList.toggle("hidden", true))
}} >{media.title.english === '' || media.title.english === null ? media.title.romaji : media.title.english }</button> }} >{media.title.english === '' || media.title.english === null ? media.title.romaji : media.title.english }</button>
</div> </div>
</li> </li>

View File

@ -80,4 +80,27 @@ export enum MediaListSort {
MediaTitleNativeDesc = "MEDIA_TITLE_NATIVE_DESC", MediaTitleNativeDesc = "MEDIA_TITLE_NATIVE_DESC",
MediaPopularity = "MEDIA_POPULARITY", MediaPopularity = "MEDIA_POPULARITY",
MediaPopularityDesc = "MEDIA_POPULARITY_DESC" MediaPopularityDesc = "MEDIA_POPULARITY_DESC"
}
export interface StartedAt {
year: number
month: number
day: number
}
export interface CompletedAt {
year: number
month: number
day: number
}
export interface AniListUpdateVariables {
mediaId: number
progress: number
status: string
score: number
repeat: number
notes: string
startedAt: StartedAt
completedAt: CompletedAt
} }

View File

@ -31,13 +31,15 @@ export interface AnimeStatistics {
} }
export interface MALWatchlist { export interface MALWatchlist {
data: { data: [MALAnimeFromList]
node: Node
listStatus: ListStatus
}[]
paging: Paging paging: Paging
} }
export interface MALAnimeFromList {
node: Node
listStatus: ListStatus | MyListStatus
}
export interface Node { export interface Node {
id: number id: number
title: string title: string
@ -63,3 +65,90 @@ export interface Paging {
previous: string previous: string
next: string next: string
} }
export interface MALAnime {
id: number;
title: string;
main_picture: {
large: string;
medium: string;
};
alternative_titles: {
synonyms: string[];
en: string;
ja: string;
};
start_date: string;
end_date: string;
synopsis: string;
mean: number;
rank: number;
popularity: number;
num_list_users: number;
num_scoring_users: number;
nsfw: string;
genres: {
id: number;
name: string;
}[];
created_at: string;
updated_at: string;
media_type: string;
status: string;
my_list_status: MyListStatus;
num_episodes: number;
start_season: {
year: number;
season: string;
};
broadcast: {
day_of_the_week: string;
start_time: string;
};
source: string;
average_episode_duration: number;
rating: string;
studios: {
id: number;
name: string;
}[];
pictures: {
large: string;
medium: string;
}[];
background: string;
related_anime: {
node: MALAnime;
relation_type: string;
relation_type_formatted: string;
}[];
recommendations: {
node: MALAnime;
num_recommendations: number;
}[];
Statistics: {
num_list_users: number;
Status: {
watching: string;
completed: string;
on_hold: string;
dropped: string;
plan_to_watch: string;
};
};
}
export interface MyListStatus {
status: string;
score: number;
num_episodes_watched: number;
is_rewatching: boolean;
start_date: string;
finish_date: string;
priority: number;
num_times_rewatched: number;
rewatch_value: number;
tags: string[];
comments: string;
updated_at: string;
}

View File

@ -6,7 +6,7 @@ export function AniListLogin():Promise<void>;
export function AniListSearch(arg1:string):Promise<any>; export function AniListSearch(arg1:string):Promise<any>;
export function AniListUpdateEntry(arg1:number,arg2:number,arg3:string,arg4:number,arg5:number,arg6:string,arg7:number,arg8:number,arg9:number,arg10:number,arg11:number,arg12:number):Promise<any>; export function AniListUpdateEntry(arg1:main.AniListUpdateVariables):Promise<any>;
export function CheckIfAniListLoggedIn():Promise<boolean>; export function CheckIfAniListLoggedIn():Promise<boolean>;
@ -22,6 +22,8 @@ export function GetAniListUserWatchingList(arg1:number,arg2:number,arg3:string):
export function GetMyAnimeList(arg1:number):Promise<main.MALWatchlist>; export function GetMyAnimeList(arg1:number):Promise<main.MALWatchlist>;
export function GetMyAnimeListAnime(arg1:number):Promise<main.MALAnime>;
export function GetMyAnimeListLoggedInUser():Promise<main.MyAnimeListUser>; export function GetMyAnimeListLoggedInUser():Promise<main.MyAnimeListUser>;
export function GetSimklLoggedInUser():Promise<main.SimklUser>; export function GetSimklLoggedInUser():Promise<main.SimklUser>;
@ -34,6 +36,8 @@ export function LogoutSimkl():Promise<string>;
export function MyAnimeListLogin():Promise<void>; export function MyAnimeListLogin():Promise<void>;
export function MyAnimeListUpdate(arg1:main.MALAnime,arg2:any):Promise<main.MyListStatus>;
export function SimklGetUserWatchlist():Promise<main.SimklWatchList>; export function SimklGetUserWatchlist():Promise<main.SimklWatchList>;
export function SimklLogin():Promise<void>; export function SimklLogin():Promise<void>;

View File

@ -10,8 +10,8 @@ export function AniListSearch(arg1) {
return window['go']['main']['App']['AniListSearch'](arg1); return window['go']['main']['App']['AniListSearch'](arg1);
} }
export function AniListUpdateEntry(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12) { export function AniListUpdateEntry(arg1) {
return window['go']['main']['App']['AniListUpdateEntry'](arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); return window['go']['main']['App']['AniListUpdateEntry'](arg1);
} }
export function CheckIfAniListLoggedIn() { export function CheckIfAniListLoggedIn() {
@ -42,6 +42,10 @@ export function GetMyAnimeList(arg1) {
return window['go']['main']['App']['GetMyAnimeList'](arg1); return window['go']['main']['App']['GetMyAnimeList'](arg1);
} }
export function GetMyAnimeListAnime(arg1) {
return window['go']['main']['App']['GetMyAnimeListAnime'](arg1);
}
export function GetMyAnimeListLoggedInUser() { export function GetMyAnimeListLoggedInUser() {
return window['go']['main']['App']['GetMyAnimeListLoggedInUser'](); return window['go']['main']['App']['GetMyAnimeListLoggedInUser']();
} }
@ -66,6 +70,10 @@ export function MyAnimeListLogin() {
return window['go']['main']['App']['MyAnimeListLogin'](); return window['go']['main']['App']['MyAnimeListLogin']();
} }
export function MyAnimeListUpdate(arg1, arg2) {
return window['go']['main']['App']['MyAnimeListUpdate'](arg1, arg2);
}
export function SimklGetUserWatchlist() { export function SimklGetUserWatchlist() {
return window['go']['main']['App']['SimklGetUserWatchlist'](); return window['go']['main']['App']['SimklGetUserWatchlist']();
} }

View File

@ -60,6 +60,82 @@ export namespace main {
return a; return a;
} }
} }
export class CompletedAt {
year: number;
month: number;
day: number;
static createFrom(source: any = {}) {
return new CompletedAt(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.year = source["year"];
this.month = source["month"];
this.day = source["day"];
}
}
export class StartedAt {
year: number;
month: number;
day: number;
static createFrom(source: any = {}) {
return new StartedAt(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.year = source["year"];
this.month = source["month"];
this.day = source["day"];
}
}
export class AniListUpdateVariables {
mediaId: number;
progress: number;
status: string;
score: number;
repeat: number;
notes: string;
startedAt: StartedAt;
completedAt: CompletedAt;
static createFrom(source: any = {}) {
return new AniListUpdateVariables(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.mediaId = source["mediaId"];
this.progress = source["progress"];
this.status = source["status"];
this.score = source["score"];
this.repeat = source["repeat"];
this.notes = source["notes"];
this.startedAt = this.convertValues(source["startedAt"], StartedAt);
this.completedAt = this.convertValues(source["completedAt"], CompletedAt);
}
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 { export class AniListUser {
// Go type: struct { Viewer struct { ID int "json:\"id\""; Name string "json:\"name\""; Avatar struct { Large string "json:\"large\""; Medium string "json:\"medium\"" } "json:\"avatar\""; BannerImage string "json:\"bannerImage\""; SiteUrl string "json:\"siteUrl\"" } "json:\"Viewer\"" } // Go type: struct { Viewer struct { ID int "json:\"id\""; Name string "json:\"name\""; Avatar struct { Large string "json:\"large\""; Medium string "json:\"medium\"" } "json:\"avatar\""; BannerImage string "json:\"bannerImage\""; SiteUrl string "json:\"siteUrl\"" } "json:\"Viewer\"" }
data: any; data: any;
@ -121,6 +197,96 @@ export namespace main {
this.anime_type = source["anime_type"]; this.anime_type = source["anime_type"];
} }
} }
export class MALAnime {
id: id;
title: title;
// Go type: struct { Large string "json:\"large\" json:\"large\""; Medium string "json:\"medium\" json:\"medium\"" }
main_picture: any;
alternative_titles: alternativeTitles;
start_date: startDate;
end_date: endDate;
synopsis: synopsis;
mean: mean;
rank: rank;
popularity: popularity;
num_list_users: numListUsers;
num_scoring_users: numScoringUsers;
nsfw: nsfw;
genres: genres;
created_at: createdAt;
updated_at: updatedAt;
media_type: mediaType;
status: status;
my_list_status: myListStatus;
num_episodes: numEpisodes;
start_season: startSeason;
broadcast: broadcast;
source: source;
average_episode_duration: averageEpisodeDuration;
rating: rating;
studios: studios;
pictures: pictures;
background: background;
related_anime: relatedAnime;
recommendations: recommendations;
static createFrom(source: any = {}) {
return new MALAnime(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.id = source["id"];
this.title = source["title"];
this.main_picture = this.convertValues(source["main_picture"], Object);
this.alternative_titles = source["alternative_titles"];
this.start_date = source["start_date"];
this.end_date = source["end_date"];
this.synopsis = source["synopsis"];
this.mean = source["mean"];
this.rank = source["rank"];
this.popularity = source["popularity"];
this.num_list_users = source["num_list_users"];
this.num_scoring_users = source["num_scoring_users"];
this.nsfw = source["nsfw"];
this.genres = source["genres"];
this.created_at = source["created_at"];
this.updated_at = source["updated_at"];
this.media_type = source["media_type"];
this.status = source["status"];
this.my_list_status = source["my_list_status"];
this.num_episodes = source["num_episodes"];
this.start_season = source["start_season"];
this.broadcast = source["broadcast"];
this.source = source["source"];
this.average_episode_duration = source["average_episode_duration"];
this.rating = source["rating"];
this.studios = source["studios"];
this.pictures = source["pictures"];
this.background = source["background"];
this.related_anime = source["related_anime"];
this.recommendations = source["recommendations"];
}
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 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: 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\"" }[];
paging: paging; paging: paging;
@ -267,6 +433,40 @@ export namespace main {
this.is_supporter = source["is_supporter"]; this.is_supporter = source["is_supporter"];
} }
} }
export class MyListStatus {
status: status;
score: score;
num_episodes_watched: numEpisodesWatched;
is_rewatching: isRewatching;
start_date: startDate;
finish_date: finishDate;
priority: priority;
num_times_rewatched: numTimesRewatched;
rewatch_value: rewatchValue;
tags: tags;
comments: comments;
updated_at: updatedAt;
static createFrom(source: any = {}) {
return new MyListStatus(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.status = source["status"];
this.score = source["score"];
this.num_episodes_watched = source["num_episodes_watched"];
this.is_rewatching = source["is_rewatching"];
this.start_date = source["start_date"];
this.finish_date = source["finish_date"];
this.priority = source["priority"];
this.num_times_rewatched = source["num_times_rewatched"];
this.rewatch_value = source["rewatch_value"];
this.tags = source["tags"];
this.comments = source["comments"];
this.updated_at = source["updated_at"];
}
}
export class SimklUser { export class SimklUser {
user: user; user: user;
account: account; account: account;
@ -333,6 +533,41 @@ export namespace struct { MediaList main {
} }
export namespace struct { Node main {
export class {
node: node;
num_recommendations: numRecommendations;
static createFrom(source: any = {}) {
return new (source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.node = source["node"];
this.num_recommendations = source["num_recommendations"];
}
}
export class {
node: node;
relation_type: relationType;
relation_type_formatted: relationTypeFormatted;
static createFrom(source: any = {}) {
return new (source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.node = source["node"];
this.relation_type = source["relation_type"];
this.relation_type_formatted = source["relation_type_formatted"];
}
}
}
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\" 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 class { export class {