Compare commits
17 Commits
8460d56d55
...
0.5.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 426793e56a | |||
| a794b77654 | |||
| c510c2a138 | |||
| 8cbf5cb20c | |||
| 54a8924384 | |||
| d70153064f | |||
| 7960f8e26d | |||
| 2e5a4a4493 | |||
| 874b3952ee | |||
| 60eac10545 | |||
| 6d66d711ff | |||
| cd62e6c658 | |||
| 063c5016f3 | |||
| 5c4caf68e6 | |||
| c10e853564 | |||
| cd043d093f | |||
| 6db01f7f9f |
@@ -93,6 +93,7 @@ func (a *App) GetAniListItem(aniId int, login bool) AniListGetSingleAnime {
|
||||
timeUntilAiring
|
||||
episode
|
||||
}
|
||||
genres
|
||||
tags{
|
||||
id
|
||||
name
|
||||
@@ -222,6 +223,7 @@ func (a *App) AniListSearch(query string) any {
|
||||
timeUntilAiring
|
||||
episode
|
||||
}
|
||||
genres
|
||||
tags{
|
||||
id
|
||||
name
|
||||
@@ -307,6 +309,7 @@ func (a *App) GetAniListUserWatchingList(page int, perPage int, sort string) Ani
|
||||
timeUntilAiring
|
||||
episode
|
||||
}
|
||||
genres
|
||||
tags{
|
||||
id
|
||||
name
|
||||
|
||||
@@ -74,6 +74,7 @@ type MediaList struct {
|
||||
TimeUntilAiring int `json:"timeUntilAiring"`
|
||||
Episode int `json:"episode"`
|
||||
} `json:"nextAiringEpisode"`
|
||||
Genres []string `json:"genres"`
|
||||
Tags []struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -308,7 +308,16 @@ func refreshMyAnimeListAuthorizationToken() {
|
||||
|
||||
func (a *App) GetMyAnimeListLoggedInUser() MyAnimeListUser {
|
||||
a.MyAnimeListLogin()
|
||||
user := createUser()
|
||||
if user.Name == "" {
|
||||
refreshMyAnimeListAuthorizationToken()
|
||||
user = createUser()
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func createUser() MyAnimeListUser {
|
||||
client := &http.Client{}
|
||||
|
||||
req, _ := http.NewRequest("GET", "https://api.myanimelist.net/v2/users/@me?fields=anime_statistics", nil)
|
||||
@@ -335,6 +344,7 @@ func (a *App) GetMyAnimeListLoggedInUser() MyAnimeListUser {
|
||||
}
|
||||
|
||||
return user
|
||||
|
||||
}
|
||||
|
||||
func (a *App) LogoutMyAnimeList() string {
|
||||
|
||||
15
app.go
15
app.go
@@ -3,9 +3,11 @@ package main
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
@@ -43,3 +45,14 @@ func (a *App) onSecondInstanceLaunch(secondInstanceData options.SecondInstanceDa
|
||||
runtime.Show(*wailsContext)
|
||||
go runtime.EventsEmit(*wailsContext, "launchArgs", secondInstanceArgs)
|
||||
}
|
||||
|
||||
func (a *App) ShowVersion() {
|
||||
version := gjson.Get(wailsJSON, "info.productVersion")
|
||||
_, err := runtime.MessageDialog(*wailsContext, runtime.MessageDialogOptions{
|
||||
Title: "Version",
|
||||
Message: "AniTrack Version: " + version.String(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ body:graphql {
|
||||
english
|
||||
native
|
||||
}
|
||||
genre
|
||||
description
|
||||
coverImage {
|
||||
large
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
aniListAnime,
|
||||
GetAnimeSingleItem,
|
||||
aniListLoggedIn,
|
||||
malLoggedIn,
|
||||
simklLoggedIn,
|
||||
} from "./helperModules/GlobalVariablesAndHelperFunctions.svelte";
|
||||
import {onMount} from "svelte";
|
||||
import Router from "svelte-spa-router"
|
||||
@@ -13,12 +14,19 @@
|
||||
import { CheckIfMALLoggedInAndSetUser } from "./helperModules/CheckIfMyAnimeListLoggedIn.svelte";
|
||||
import {CheckIfSimklLoggedInAndSetUser} from "./helperModules/CheckIsSimklLoggedIn.svelte"
|
||||
import {CheckIfAniListLoggedIn} from "../wailsjs/go/main/App";
|
||||
import {AniListGetSingleAnimeDefaultData} from "./helperDefaults/AniListGetSingleAnime";
|
||||
|
||||
onMount(async () => {
|
||||
await CheckIfAniListLoggedInAndLoadWatchList()
|
||||
await CheckIfMALLoggedInAndSetUser()
|
||||
await CheckIfSimklLoggedInAndSetUser()
|
||||
let isAniListLoggedIn: boolean
|
||||
let isMALLoggedIn: boolean
|
||||
let isSimklLoggedIn: boolean
|
||||
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
|
||||
malLoggedIn.subscribe((value) => isMALLoggedIn = value)
|
||||
simklLoggedIn.subscribe((value) => isSimklLoggedIn = value)
|
||||
|
||||
console.log(isAniListLoggedIn)
|
||||
!isAniListLoggedIn && await CheckIfAniListLoggedInAndLoadWatchList()
|
||||
!isMALLoggedIn && await CheckIfMALLoggedInAndSetUser()
|
||||
!isSimklLoggedIn && await CheckIfSimklLoggedInAndSetUser()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -27,17 +35,7 @@
|
||||
'/': Home,
|
||||
'/anime/:id': wrap({
|
||||
asyncComponent: () => import('./routes/AnimeRoutePage.svelte'),
|
||||
conditions: [
|
||||
async () => await CheckIfAniListLoggedIn(),
|
||||
async (detail) => {
|
||||
aniListAnime.update(value => {
|
||||
value = AniListGetSingleAnimeDefaultData
|
||||
return value
|
||||
})
|
||||
await GetAnimeSingleItem(Number(detail.params.id), true)
|
||||
return Object.keys($aniListAnime).length!==0
|
||||
},
|
||||
],
|
||||
conditions: [async () => await CheckIfAniListLoggedIn()],
|
||||
loadingComponent: Spinner
|
||||
}),
|
||||
// '*': "Not Found"
|
||||
|
||||
@@ -2,79 +2,93 @@ export interface AniListCurrentUserWatchList {
|
||||
data: {
|
||||
Page: {
|
||||
pageInfo: {
|
||||
total: number
|
||||
perPage: number
|
||||
currentPage: number
|
||||
lastPage: number
|
||||
hasNextPage: boolean
|
||||
},
|
||||
mediaList: MediaList[]
|
||||
}
|
||||
}
|
||||
total: number;
|
||||
perPage: number;
|
||||
currentPage: number;
|
||||
lastPage: number;
|
||||
hasNextPage: boolean;
|
||||
};
|
||||
mediaList: MediaList[];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface AniListGetSingleAnime {
|
||||
data: {
|
||||
MediaList: MediaList
|
||||
}
|
||||
MediaList: MediaList;
|
||||
};
|
||||
}
|
||||
|
||||
export interface MediaList {
|
||||
id: number
|
||||
mediaId: number
|
||||
userId: number
|
||||
id: number;
|
||||
mediaId: number;
|
||||
userId: number;
|
||||
media: {
|
||||
id: number
|
||||
idMal: number
|
||||
id: number;
|
||||
idMal: number;
|
||||
title: {
|
||||
romaji: string
|
||||
english?: string
|
||||
native: string
|
||||
}
|
||||
description: string
|
||||
romaji: string;
|
||||
english?: string;
|
||||
native: string;
|
||||
};
|
||||
description: string;
|
||||
coverImage: {
|
||||
large: string
|
||||
}
|
||||
season: string
|
||||
seasonYear: number
|
||||
status: string
|
||||
episodes?: number
|
||||
large: string;
|
||||
};
|
||||
season: string;
|
||||
seasonYear: number;
|
||||
status: string;
|
||||
episodes?: number;
|
||||
nextAiringEpisode?: {
|
||||
airingAt: number
|
||||
timeUntilAiring: number
|
||||
episode: number
|
||||
}
|
||||
}
|
||||
status: string
|
||||
airingAt: number;
|
||||
timeUntilAiring: number;
|
||||
episode: number;
|
||||
};
|
||||
genres: string[];
|
||||
tags: [
|
||||
{
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
rank: number;
|
||||
isMediaSpoiler: boolean;
|
||||
isAdult: boolean;
|
||||
},
|
||||
];
|
||||
isAdult: boolean;
|
||||
};
|
||||
status: string;
|
||||
startedAt: {
|
||||
year: number
|
||||
month: number
|
||||
day: number
|
||||
}
|
||||
year: number;
|
||||
month: number;
|
||||
day: number;
|
||||
};
|
||||
completedAt: {
|
||||
year?: number
|
||||
month?: number
|
||||
day?: number
|
||||
}
|
||||
notes?: string
|
||||
progress: number
|
||||
score: number
|
||||
repeat: number
|
||||
year?: number;
|
||||
month?: number;
|
||||
day?: number;
|
||||
};
|
||||
notes?: string;
|
||||
progress: number;
|
||||
score: number;
|
||||
repeat: number;
|
||||
user: {
|
||||
id: number
|
||||
name: string
|
||||
id: number;
|
||||
name: string;
|
||||
avatar: {
|
||||
large: string
|
||||
medium: string
|
||||
}
|
||||
large: string;
|
||||
medium: string;
|
||||
};
|
||||
statistics: {
|
||||
anime: {
|
||||
count: number
|
||||
statuses: [{
|
||||
status: string
|
||||
count: number
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
count: number;
|
||||
statuses: [
|
||||
{
|
||||
status: string;
|
||||
count: number;
|
||||
},
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
simklLoggedIn,
|
||||
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
|
||||
import { push } from "svelte-spa-router";
|
||||
import WebsiteLink from "./WebsiteLink.svelte";
|
||||
import type { AniListGetSingleAnime } from "../anilist/types/AniListCurrentUserWatchListType";
|
||||
import Rating from "./Rating.svelte";
|
||||
import {
|
||||
@@ -22,7 +23,10 @@
|
||||
} from "../mal/types/MALTypes";
|
||||
import type { SimklAnime } from "../simkl/types/simklTypes";
|
||||
import { writable } from "svelte/store";
|
||||
import type { StatusOption, StatusOptions } from "../helperTypes/StatusTypes";
|
||||
import type {
|
||||
StatusOption,
|
||||
StatusOptions,
|
||||
} from "../helperTypes/StatusTypes";
|
||||
import type { AniListUpdateVariables } from "../anilist/types/AniListTypes";
|
||||
import { convertDateToAniList } from "../helperFunctions/convertDateToAniList";
|
||||
import {
|
||||
@@ -38,6 +42,7 @@
|
||||
import { AddAnimeServiceToTable } from "../helperModules/AddAnimeServiceToTable.svelte";
|
||||
import { CheckIfAniListLoggedInAndLoadWatchList } from "../helperModules/CheckIfAniListLoggedInAndLoadWatchList.svelte";
|
||||
import Datepicker from "./Datepicker.svelte";
|
||||
import { Badge, Tooltip } from "flowbite-svelte";
|
||||
const re = /^([0-9]{4})-([0-9]{2})-([0-9]{2})/;
|
||||
|
||||
let isAniListLoggedIn: boolean;
|
||||
@@ -76,7 +81,8 @@
|
||||
{ id: 5, aniList: "REPEATING", mal: "rewatching", simkl: "watching" },
|
||||
];
|
||||
let startingAnilistStatusOption: StatusOption = statusOptions.filter(
|
||||
(option) => currentAniListAnime.data.MediaList.status === option.aniList,
|
||||
(option) =>
|
||||
currentAniListAnime.data.MediaList.status === option.aniList,
|
||||
)[0];
|
||||
let startedAtDate: Date | null = convertAniListDateToDate(
|
||||
currentAniListAnime.data.MediaList.startedAt,
|
||||
@@ -107,11 +113,15 @@
|
||||
let startDate = "";
|
||||
let finishDate = "";
|
||||
if (currentMalAnime.my_list_status.start_date !== "") {
|
||||
const startArray = re.exec(currentMalAnime.my_list_status.start_date);
|
||||
const startArray = re.exec(
|
||||
currentMalAnime.my_list_status.start_date,
|
||||
);
|
||||
startDate = `${startArray[2]}-${startArray[3]}-${startArray[1]}`;
|
||||
}
|
||||
if (currentMalAnime.my_list_status.finish_date !== "") {
|
||||
const finishArray = re.exec(currentMalAnime.my_list_status.finish_date);
|
||||
const finishArray = re.exec(
|
||||
currentMalAnime.my_list_status.finish_date,
|
||||
);
|
||||
finishDate = `${finishArray[2]}-${finishArray[3]}-${finishArray[1]}`;
|
||||
}
|
||||
AddAnimeServiceToTable({
|
||||
@@ -188,7 +198,10 @@
|
||||
submitData[key] = value;
|
||||
}
|
||||
|
||||
if (isAniListLoggedIn && currentAniListAnime.data.MediaList.mediaId !== 0) {
|
||||
if (
|
||||
isAniListLoggedIn &&
|
||||
currentAniListAnime.data.MediaList.mediaId !== 0
|
||||
) {
|
||||
let body: AniListUpdateVariables = {
|
||||
mediaId: currentAniListAnime.data.MediaList.mediaId,
|
||||
progress: submitData.episodes,
|
||||
@@ -199,10 +212,10 @@
|
||||
startedAt: convertDateToAniList(startedAtDate),
|
||||
completedAt: convertDateToAniList(completedAtDate),
|
||||
};
|
||||
await AniListUpdateEntry(body).then((value: AniListGetSingleAnime) => {
|
||||
/* TODO in future when you inevitably add tags to typescript, until Anilist fixes the api bug
|
||||
where tags break the SaveMediaListEntry return, you'll want to use this delete line
|
||||
delete value.data.MediaList.media.tags */
|
||||
await AniListUpdateEntry(body).then(
|
||||
(value: AniListGetSingleAnime) => {
|
||||
value.data.MediaList.media.tags =
|
||||
currentAniListAnime.data.MediaList.media.tags;
|
||||
aniListAnime.update((newValue) => {
|
||||
newValue = value;
|
||||
return newValue;
|
||||
@@ -223,7 +236,8 @@
|
||||
repeat: currentAniListAnime.data.MediaList.repeat,
|
||||
notes: currentAniListAnime.data.MediaList.notes,
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (malLoggedIn && currentMalAnime.id !== 0) {
|
||||
@@ -240,7 +254,8 @@
|
||||
(malAnimeReturn: MalListStatus) => {
|
||||
malAnime.update((value) => {
|
||||
value.my_list_status.status = malAnimeReturn.status;
|
||||
value.my_list_status.is_rewatching = malAnimeReturn.is_rewatching;
|
||||
value.my_list_status.is_rewatching =
|
||||
malAnimeReturn.is_rewatching;
|
||||
value.my_list_status.score = malAnimeReturn.score;
|
||||
value.my_list_status.num_episodes_watched =
|
||||
malAnimeReturn.num_episodes_watched;
|
||||
@@ -267,12 +282,14 @@
|
||||
id: `m-${currentMalAnime.id}`,
|
||||
title: currentMalAnime.title,
|
||||
service: "MyAnimeList",
|
||||
progress: currentMalAnime.my_list_status.num_episodes_watched,
|
||||
progress:
|
||||
currentMalAnime.my_list_status.num_episodes_watched,
|
||||
status: currentMalAnime.my_list_status.status,
|
||||
startedAt: startDate,
|
||||
completedAt: finishDate,
|
||||
score: currentMalAnime.my_list_status.score,
|
||||
repeat: currentMalAnime.my_list_status.num_times_rewatched,
|
||||
repeat: currentMalAnime.my_list_status
|
||||
.num_times_rewatched,
|
||||
notes: currentMalAnime.my_list_status.comments,
|
||||
});
|
||||
},
|
||||
@@ -280,9 +297,13 @@
|
||||
}
|
||||
|
||||
if (simklLoggedIn && currentSimklAnime.show.ids.simkl !== 0) {
|
||||
if (currentSimklAnime.watched_episodes_count !== submitData.episodes) {
|
||||
await SimklSyncEpisodes(currentSimklAnime, submitData.episodes).then(
|
||||
(value: SimklAnime) => {
|
||||
if (
|
||||
currentSimklAnime.watched_episodes_count !== submitData.episodes
|
||||
) {
|
||||
await SimklSyncEpisodes(
|
||||
currentSimklAnime,
|
||||
submitData.episodes,
|
||||
).then((value: SimklAnime) => {
|
||||
AddAnimeServiceToTable({
|
||||
id: `s-${value.show.ids.simkl}`,
|
||||
title: value.show.title,
|
||||
@@ -299,13 +320,14 @@
|
||||
newValue = value;
|
||||
return newValue;
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (currentSimklAnime.user_rating !== submitData.rating) {
|
||||
await SimklSyncRating(currentSimklAnime, submitData.rating).then(
|
||||
(value) => {
|
||||
await SimklSyncRating(
|
||||
currentSimklAnime,
|
||||
submitData.rating,
|
||||
).then((value) => {
|
||||
AddAnimeServiceToTable({
|
||||
id: `s-${value.show.ids.simkl}`,
|
||||
title: value.show.title,
|
||||
@@ -322,13 +344,14 @@
|
||||
newValue = value;
|
||||
return newValue;
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (currentSimklAnime.status !== submitData.status.simkl) {
|
||||
await SimklSyncStatus(currentSimklAnime, submitData.status.simkl).then(
|
||||
(value) => {
|
||||
await SimklSyncStatus(
|
||||
currentSimklAnime,
|
||||
submitData.status.simkl,
|
||||
).then((value) => {
|
||||
AddAnimeServiceToTable({
|
||||
id: `s-${value.show.ids.simkl}`,
|
||||
title: value.show.title,
|
||||
@@ -345,8 +368,7 @@
|
||||
newValue = value;
|
||||
return newValue;
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,7 +379,10 @@
|
||||
|
||||
const deleteEntries = async () => {
|
||||
submitting.set(true);
|
||||
if (isAniListLoggedIn && currentAniListAnime.data.MediaList.mediaId !== 0) {
|
||||
if (
|
||||
isAniListLoggedIn &&
|
||||
currentAniListAnime.data.MediaList.mediaId !== 0
|
||||
) {
|
||||
await AniListDeleteEntry(currentAniListAnime.data.MediaList.id);
|
||||
AddAnimeServiceToTable({
|
||||
id: `a-${currentAniListAnime.data.MediaList.mediaId}`,
|
||||
@@ -417,7 +442,8 @@
|
||||
currentAniListAnime.data.MediaList.media.nextAiringEpisode.episode !== 0
|
||||
) {
|
||||
max =
|
||||
currentAniListAnime.data.MediaList.media.nextAiringEpisode.episode - 1;
|
||||
currentAniListAnime.data.MediaList.media.nextAiringEpisode.episode -
|
||||
1;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -453,11 +479,17 @@
|
||||
on:click={() => {
|
||||
currentAniListAnime.data.MediaList.progress -= 1;
|
||||
if (
|
||||
currentAniListAnime.data.MediaList.progress <
|
||||
currentAniListAnime.data.MediaList.media.episodes
|
||||
currentAniListAnime.data.MediaList
|
||||
.progress <
|
||||
currentAniListAnime.data.MediaList.media
|
||||
.episodes
|
||||
) {
|
||||
startingAnilistStatusOption = statusOptions[0];
|
||||
if (currentAniListAnime.data.MediaList.repeat === 0)
|
||||
startingAnilistStatusOption =
|
||||
statusOptions[0];
|
||||
if (
|
||||
currentAniListAnime.data.MediaList
|
||||
.repeat === 0
|
||||
)
|
||||
completedAtDate = null;
|
||||
}
|
||||
}}
|
||||
@@ -487,18 +519,22 @@
|
||||
id="episodes"
|
||||
class="border border-x-0 p-2.5 h-11 text-center text-sm block w-full placeholder-gray-400 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none
|
||||
{currentAniListAnime.data.MediaList.progress < 0 ||
|
||||
(currentAniListAnime.data.MediaList.media.episodes > 0 &&
|
||||
(currentAniListAnime.data.MediaList.media.episodes >
|
||||
0 &&
|
||||
currentAniListAnime.data.MediaList.progress >
|
||||
currentAniListAnime.data.MediaList.media.episodes) ||
|
||||
(currentAniListAnime.data.MediaList.media.nextAiringEpisode
|
||||
.episode > 0 &&
|
||||
currentAniListAnime.data.MediaList.media
|
||||
.episodes) ||
|
||||
(currentAniListAnime.data.MediaList.media
|
||||
.nextAiringEpisode.episode > 0 &&
|
||||
currentAniListAnime.data.MediaList.progress >
|
||||
currentAniListAnime.data.MediaList.media.nextAiringEpisode
|
||||
.episode -
|
||||
currentAniListAnime.data.MediaList.media
|
||||
.nextAiringEpisode.episode -
|
||||
1)
|
||||
? 'border-red-500 border-[2px] text-rose-300 focus:ring-red-500 focus:border-red-500'
|
||||
: 'bg-gray-700 hover:bg-gray-600 border-gray-600 text-white focus:ring-blue-500 focus:border-blue-500'} w-24"
|
||||
bind:value={currentAniListAnime.data.MediaList.progress}
|
||||
bind:value={
|
||||
currentAniListAnime.data.MediaList.progress
|
||||
}
|
||||
required
|
||||
/>
|
||||
<button
|
||||
@@ -508,15 +544,24 @@
|
||||
on:click={() => {
|
||||
currentAniListAnime.data.MediaList.progress += 1;
|
||||
if (
|
||||
currentAniListAnime.data.MediaList.media.episodes ===
|
||||
currentAniListAnime.data.MediaList.media
|
||||
.episodes ===
|
||||
currentAniListAnime.data.MediaList.progress
|
||||
) {
|
||||
startingAnilistStatusOption = statusOptions[2];
|
||||
startingAnilistStatusOption =
|
||||
statusOptions[2];
|
||||
completedAtDate = new Date();
|
||||
}
|
||||
if (currentAniListAnime.data.MediaList.progress - 1 === 0) {
|
||||
startingAnilistStatusOption = statusOptions[0];
|
||||
if (startedAtDate === null) startedAtDate = new Date();
|
||||
if (
|
||||
currentAniListAnime.data.MediaList
|
||||
.progress -
|
||||
1 ===
|
||||
0
|
||||
) {
|
||||
startingAnilistStatusOption =
|
||||
statusOptions[0];
|
||||
if (startedAtDate === null)
|
||||
startedAtDate = new Date();
|
||||
}
|
||||
}}
|
||||
class="bg-gray-700 hover:bg-gray-600 border-gray-600 border rounded-e-lg p-3 h-11 focus:ring-gray-700 focus:ring-2 focus:outline-none"
|
||||
@@ -539,15 +584,16 @@
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
/ {currentAniListAnime.data.MediaList.media.nextAiringEpisode
|
||||
.episode !== 0
|
||||
? currentAniListAnime.data.MediaList.media.nextAiringEpisode
|
||||
.episode - 1
|
||||
/ {currentAniListAnime.data.MediaList.media
|
||||
.nextAiringEpisode.episode !== 0
|
||||
? currentAniListAnime.data.MediaList.media
|
||||
.nextAiringEpisode.episode - 1
|
||||
: currentAniListAnime.data.MediaList.media.episodes}
|
||||
</div>
|
||||
{#if currentAniListAnime.data.MediaList.media.nextAiringEpisode.episode !== 0}
|
||||
<div>
|
||||
of {currentAniListAnime.data.MediaList.media.episodes}
|
||||
of {currentAniListAnime.data.MediaList.media
|
||||
.episodes}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -619,7 +665,8 @@
|
||||
name="repeat"
|
||||
min="0"
|
||||
id="repeat"
|
||||
class="border {currentAniListAnime.data.MediaList.repeat < 0
|
||||
class="border {currentAniListAnime.data.MediaList
|
||||
.repeat < 0
|
||||
? 'border-red-500 border-[2px] text-rose-300 focus:ring-red-500 focus:border-red-500'
|
||||
: 'border-gray-500 text-white focus:ring-blue-500 focus:border-blue-500'} text-sm rounded-lg block w-24 p-2.5 bg-gray-600 placeholder-gray-400 text-white"
|
||||
bind:value={currentAniListAnime.data.MediaList.repeat}
|
||||
@@ -779,8 +826,46 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex m-5">
|
||||
<div>
|
||||
<h3 class="text-2xl">Genres</h3>
|
||||
{#each currentAniListAnime.data.MediaList.media.genres as genre}
|
||||
<div>
|
||||
<Badge large border color="blue" class="m-1 w-52">
|
||||
<div>
|
||||
<WebsiteLink
|
||||
id={genre}
|
||||
url="https://anilist.co/search/anime/{genre}"
|
||||
/>
|
||||
</div>
|
||||
</Badge>
|
||||
<Tooltip>{genre}</Tooltip>
|
||||
</div>
|
||||
{/each}
|
||||
<h3 class="text-2xl">Tags</h3>
|
||||
<div class="mt-2">
|
||||
{#each currentAniListAnime.data.MediaList.media.tags as tag}
|
||||
<div>
|
||||
<Badge large border color="blue" class="m-1 w-52">
|
||||
<div>
|
||||
<WebsiteLink
|
||||
id={tag.name}
|
||||
url="https://anilist.co/search/anime/?genres={tag.name}"
|
||||
/>
|
||||
<span class="text-xs">({tag.rank}%)</span>
|
||||
</div>
|
||||
</Badge>
|
||||
<Tooltip>{tag.description}</Tooltip>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-5">
|
||||
<h3 class="text-2xl">Summary</h3>
|
||||
<p>{@html currentAniListAnime.data.MediaList.media.description}</p>
|
||||
<p class="rounded border border-gray-700 p-2 mt-2">
|
||||
{@html currentAniListAnime.data.MediaList.media.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -13,11 +13,12 @@
|
||||
loginToSimkl,
|
||||
logoutOfAniList,
|
||||
logoutOfMAL,
|
||||
logoutOfSimkl,
|
||||
logoutOfSimkl
|
||||
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
|
||||
import * as runtime from "../../wailsjs/runtime";
|
||||
import type {MyAnimeListUser} from "../mal/types/MALTypes";
|
||||
import type {SimklUser} from "../simkl/types/simklTypes";
|
||||
import { ShowVersion } from "../../wailsjs/go/main/App";
|
||||
|
||||
let currentAniListUser: AniListUser;
|
||||
let currentMALUser: MyAnimeListUser;
|
||||
@@ -36,6 +37,20 @@
|
||||
function dropdownUser(): void {
|
||||
let dropdown = document.querySelector("#userDropdown");
|
||||
dropdown.classList.toggle("hidden");
|
||||
|
||||
if (!dropdown.classList.contains("hidden")) {
|
||||
document.addEventListener("click", clickOutside)
|
||||
}
|
||||
}
|
||||
|
||||
function clickOutside(event: Event): void {
|
||||
let dropdown = document.querySelector("#userDropdown")
|
||||
let toggleBtn = document.querySelector("#userDropdownButton")
|
||||
|
||||
if (!dropdown.contains(event.target as Node) && !toggleBtn.contains(event.target as Node)) {
|
||||
dropdown.classList.add("hidden")
|
||||
document.removeEventListener("click", clickOutside)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -77,7 +92,10 @@
|
||||
</li>
|
||||
{:else}
|
||||
<li>
|
||||
<button on:click={loginToAniList}
|
||||
<button on:click={() => {
|
||||
dropdownUser()
|
||||
loginToAniList()
|
||||
}}
|
||||
class="block px-4 py-2 w-full hover:bg-gray-600 truncate hover:text-white">
|
||||
<span class="maple-font text-lg mr-4">A</span>Login to AniList
|
||||
</button>
|
||||
@@ -94,7 +112,10 @@
|
||||
</li>
|
||||
{:else}
|
||||
<li>
|
||||
<button on:click={loginToMAL}
|
||||
<button on:click={() => {
|
||||
dropdownUser()
|
||||
loginToMAL()
|
||||
}}
|
||||
class="block px-4 py-2 w-full hover:bg-gray-600 truncate hover:text-white">
|
||||
<span class="maple-font text-lg mr-4">M</span>Login to MyAnimeList
|
||||
</button>
|
||||
@@ -111,7 +132,10 @@
|
||||
</li>
|
||||
{:else}
|
||||
<li>
|
||||
<button on:click={loginToSimkl}
|
||||
<button on:click={() => {
|
||||
dropdownUser()
|
||||
loginToSimkl()
|
||||
}}
|
||||
class="block px-4 py-2 w-full hover:bg-gray-600 truncate hover:text-white">
|
||||
<span class="maple-font text-lg mr-4">S</span>Login to Simkl
|
||||
</button>
|
||||
@@ -119,6 +143,15 @@
|
||||
{/if}
|
||||
</ul>
|
||||
<div class="py-2">
|
||||
<button
|
||||
on:click={() => {
|
||||
dropdownUser()
|
||||
ShowVersion()
|
||||
}}
|
||||
class="block px-4 py-2 w-full text-sm hover:bg-gray-600 text-gray-200 over:text-white"
|
||||
>
|
||||
Version
|
||||
</button>
|
||||
<button
|
||||
on:click={() => runtime.Quit()}
|
||||
class="block px-4 py-2 w-full text-sm hover:bg-gray-600 text-gray-200 over:text-white"
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
<script lang="ts">
|
||||
import {BrowserOpenURL} from "../../wailsjs/runtime"
|
||||
import { BrowserOpenURL } from "../../wailsjs/runtime";
|
||||
|
||||
export let id: string
|
||||
let url = ""
|
||||
let isAniList = false
|
||||
let isMAL = false
|
||||
let isSimkl = false
|
||||
let newId = id
|
||||
let re = /[ams]?-?(.*)/
|
||||
export let id: string;
|
||||
export let url = "";
|
||||
let isAniList = false;
|
||||
let isMAL = false;
|
||||
let isSimkl = false;
|
||||
let newId = id;
|
||||
let re = /[ams]?-?(.*)/;
|
||||
if (id !== undefined && id.length > 0) {
|
||||
isAniList = id.includes("a-")
|
||||
isMAL = id.includes("m-")
|
||||
isSimkl = id.includes("s-")
|
||||
newId = id.match(re)[1]
|
||||
isAniList = id.includes("a-");
|
||||
isMAL = id.includes("m-");
|
||||
isSimkl = id.includes("s-");
|
||||
if (isAniList || isMAL || isSimkl) newId = id.match(re)[1];
|
||||
else newId = id;
|
||||
}
|
||||
|
||||
|
||||
if (isAniList) url = `https://anilist.co/anime/${newId}`
|
||||
if (isMAL) url = `https://myanimelist.net/anime/${newId}`
|
||||
if (isSimkl) url = `https://simkl.com/anime/${newId}`
|
||||
if (isAniList) url = `https://anilist.co/anime/${newId}`;
|
||||
if (isMAL) url = `https://myanimelist.net/anime/${newId}`;
|
||||
if (isSimkl) url = `https://simkl.com/anime/${newId}`;
|
||||
</script>
|
||||
|
||||
{#if url.length > 0}
|
||||
<button class="underline underline-offset-2 px-4 py-1" on:click={() => BrowserOpenURL(url)}>{newId}</button>
|
||||
<button
|
||||
type="button"
|
||||
class="underline underline-offset-2 px-4 py-1"
|
||||
on:click={() => BrowserOpenURL(url)}>{newId}</button
|
||||
>
|
||||
{:else}
|
||||
{id}
|
||||
{/if}
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { aniListAnime, GetAnimeSingleItem } from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
|
||||
import Anime from "../helperComponents/Anime.svelte"
|
||||
import { AniListGetSingleAnimeDefaultData } from "../helperDefaults/AniListGetSingleAnime";
|
||||
import Spinner from "../helperComponents/Spinner.svelte";
|
||||
|
||||
export let params: Record<string, string>
|
||||
let loadPromise = load(params.id)
|
||||
$: loadPromise = load(params.id)
|
||||
|
||||
async function load(id: string) {
|
||||
aniListAnime.update(() => AniListGetSingleAnimeDefaultData)
|
||||
await GetAnimeSingleItem(Number(id), true)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#key params.id}
|
||||
{#await loadPromise}
|
||||
<Spinner />
|
||||
{:then _}
|
||||
<Anime />
|
||||
{/await}
|
||||
{/key}
|
||||
2
frontend/wailsjs/go/main/App.d.ts
vendored
2
frontend/wailsjs/go/main/App.d.ts
vendored
@@ -42,6 +42,8 @@ export function MyAnimeListLogin():Promise<void>;
|
||||
|
||||
export function MyAnimeListUpdate(arg1:main.MALAnime,arg2:main.MALUploadStatus):Promise<main.MalListStatus>;
|
||||
|
||||
export function ShowVersion():Promise<void>;
|
||||
|
||||
export function SimklGetUserWatchlist():Promise<main.SimklWatchListType>;
|
||||
|
||||
export function SimklLogin():Promise<void>;
|
||||
|
||||
@@ -82,6 +82,10 @@ export function MyAnimeListUpdate(arg1, arg2) {
|
||||
return window['go']['main']['App']['MyAnimeListUpdate'](arg1, arg2);
|
||||
}
|
||||
|
||||
export function ShowVersion() {
|
||||
return window['go']['main']['App']['ShowVersion']();
|
||||
}
|
||||
|
||||
export function SimklGetUserWatchlist() {
|
||||
return window['go']['main']['App']['SimklGetUserWatchlist']();
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ export namespace main {
|
||||
id: number;
|
||||
mediaId: number;
|
||||
userId: number;
|
||||
// Go type: 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\""; Tags []struct { Id int "json:\"id\""; Name string "json:\"name\""; Description string "json:\"description\""; Rank int "json:\"rank\""; IsMediaSpoiler bool "json:\"isMediaSpoiler\""; IsAdult bool "json:\"isAdult\"" } "json:\"tags\""; IsAdult bool "json:\"isAdult\"" }
|
||||
// Go type: 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\""; Genres []string "json:\"genres\""; Tags []struct { Id int "json:\"id\""; Name string "json:\"name\""; Description string "json:\"description\""; Rank int "json:\"rank\""; IsMediaSpoiler bool "json:\"isMediaSpoiler\""; IsAdult bool "json:\"isAdult\"" } "json:\"tags\""; IsAdult bool "json:\"isAdult\"" }
|
||||
media: any;
|
||||
status: string;
|
||||
// Go type: struct { Year int "json:\"year\""; Month int "json:\"month\""; Day int "json:\"day\"" }
|
||||
|
||||
10
go.mod
10
go.mod
@@ -39,11 +39,11 @@ require (
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.19 // indirect
|
||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||
golang.org/x/crypto v0.35.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/term v0.29.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/crypto v0.45.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
)
|
||||
|
||||
// replace github.com/wailsapp/wails/v2 v2.9.1 => /home/nymusicman/go/pkg/mod
|
||||
|
||||
20
go.sum
20
go.sum
@@ -85,24 +85,24 @@ github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhw
|
||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||
github.com/wailsapp/wails/v2 v2.10.1 h1:QWHvWMXII2nI/nXz77gpPG8P3ehl6zKe+u4su5BWIns=
|
||||
github.com/wailsapp/wails/v2 v2.10.1/go.mod h1:zrebnFV6MQf9kx8HI4iAv63vsR5v67oS7GTEZ7Pz1TY=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/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.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
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=
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
},
|
||||
"info": {
|
||||
"productName": "AniTrack",
|
||||
"productVersion": "0.1.8"
|
||||
"productVersion": "0.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user