8 Commits
0.5.2 ... 0.6.0

Author SHA1 Message Date
b2a8a504f3 fix: resolve syntax error in App.svelte
Fixed TypeScript compilation error caused by import statement and function declaration being on the same line.

Changes:
- Separated import statement and onMount declaration onto different lines
- Resolved svelte-preprocess type error
- File now compiles correctly

This was a typo from previous commit where the loc import line was incorrectly merged with the existing onMount function declaration.
2026-03-21 13:28:33 -04:00
c85a53a278 chore: remove VSCode extensions.json
Removed the .vscode/extensions.json file from the frontend directory.

This file contained workspace-level VSCode extension recommendations which are better managed:
- At user level through personal VSCode settings
- Through project README documentation
- Via devcontainer or editors preferences if needed

Cleanup reduces repository clutter and avoids imposing specific extension recommendations on contributors.
2026-03-21 13:25:49 -04:00
2cf3844e76 chore: bump version to 0.6.0
Incremented version from 0.5.3 to 0.6.0 for release with new features.

This release includes:
- Smart watchlist refresh on navigation
- Improved WatchList UI with manual refresh button
- Client-side routing for logo navigation
- Better UX with automatic data updates

Version bump reflects significant feature additions and improvements to the user experience.
2026-03-21 13:25:46 -04:00
6ed5fe8b71 feat: improve WatchList UI with refresh button
Enhanced the WatchList component with better layout and manual refresh functionality.

Changes:
- Added Refresh WatchList button with loading state handling
- Restructured header layout using flexbox with justify-between
- Title on left, refresh button on right, vertically aligned with items-center
- Improved button styling with consistent py-2 px-4 padding
- Added CheckIfAniListLoggedInAndLoadWatchList import for refresh functionality
- Maintained mb-4 spacing for consistent vertical rhythm

This gives users manual control over watchlist updates and provides better visual balance to the header section.

UI improvements:
- Horizontal flex container for proper left/right alignment
- Responsive button sizing
- Clear visual separation between title and action
2026-03-21 13:25:45 -04:00
8a8baf7f8f feat: implement smart watchlist refresh on navigation
Added intelligent watchlist refresh mechanism that only refetches data when changes are actually made, preventing unnecessary API calls and improving performance.

Changes:
- Added watchlistNeedsRefresh store to track when watchlist data has changed
- Implemented reactive watcher in App.svelte that uses svelte-spa-router's loc store to detect navigation to home
- Set dirty flag in Anime.svelte after successful status updates and entry deletions
- Added conditional refresh logic that checks user's primary service (AniList, MAL, or Simkl)
- Parallel refresh support for multiple services when logged in

This resolves the issue where clicking the logo would cause full page reloads and unnecessary re-authentication checks, while also ensuring watchlist data stays current when users make changes.

Technical details:
- Uses $loc.location to detect route changes
- IIFE pattern for async operations in reactive statements
- Only refreshes for logged-in primary services
- Flag resets after successful refresh

Related to: Header.svelte client-side routing fix
2026-03-21 13:25:43 -04:00
ca8c8beaf3 Bump version to 0.5.3
- Update productVersion in wails.json from 0.5.2 to 0.5.3
2026-03-20 15:53:33 -04:00
3e7f7d1c95 fix(frontend): resolve submit spinner hang and data loss issues
- Add try-catch-finally error handling to handleSubmit and deleteEntries
  functions to ensure submitting state is always reset, even when API calls
  fail or timeout. This fixes the infinite loading spinner bug.

- Preserve genres field after AniList updates, matching the existing tags
  preservation pattern. Prevents genres array from being lost after form
  submission, which was causing "{#each} only works with iterable values"
  error when the page re-rendered.

- Add fallback (|| []) to genres each block to prevent rendering errors
  when genres is undefined or null for entries without genre data.

These fixes ensure robust error handling and data consistency during anime
list updates across AniList, MAL, and Simkl services.

Fixes: submit button spinner never stopping after form submission
Fixes: "{#each} only works with iterable values" error on genres display
2026-03-20 15:51:55 -04:00
b0ca864dfe chore: exclude build tarball artifacts from version control
Add *.tar.gz pattern to build directory exclusion in .gitignore to prevent
build artifacts like Anitrack-0.5.2.tar.gz from being committed to the
repository. These generated files are ephemeral build outputs that should
not be tracked in version control.
2026-03-20 15:51:37 -04:00
7 changed files with 1127 additions and 1069 deletions

3
.gitignore vendored
View File

@@ -33,3 +33,6 @@ environment.go
# REST (http files)
http-client.private.env.json
# Build artifacts
build/*.tar.gz

View File

@@ -1,5 +0,0 @@
{
"recommendations": [
"svelte.svelte-vscode"
]
}

View File

@@ -3,40 +3,68 @@
aniListLoggedIn,
malLoggedIn,
simklLoggedIn,
watchlistNeedsRefresh,
aniListPrimary,
malPrimary,
simklPrimary,
malWatchList,
simklWatchList,
} from "./helperModules/GlobalVariablesAndHelperFunctions.svelte";
import { onMount } from "svelte";
import Router from "svelte-spa-router"
import Router from "svelte-spa-router";
import Home from "./routes/Home.svelte";
import { wrap } from "svelte-spa-router/wrap";
import Spinner from "./helperComponents/Spinner.svelte";
import Header from "./helperComponents/Header.svelte";
import { CheckIfAniListLoggedInAndLoadWatchList } from "./helperModules/CheckIfAniListLoggedInAndLoadWatchList.svelte";
import { CheckIfMALLoggedInAndSetUser } from "./helperModules/CheckIfMyAnimeListLoggedIn.svelte";
import {CheckIfSimklLoggedInAndSetUser} from "./helperModules/CheckIsSimklLoggedIn.svelte"
import {CheckIfAniListLoggedIn} from "../wailsjs/go/main/App";
import { CheckIfSimklLoggedInAndSetUser } from "./helperModules/CheckIsSimklLoggedIn.svelte";
import {
CheckIfAniListLoggedIn,
GetMyAnimeList,
SimklGetUserWatchlist,
} from "../wailsjs/go/main/App";
import { loc } from "svelte-spa-router";
onMount(async () => {
let isAniListLoggedIn: boolean
let isMALLoggedIn: boolean
let isSimklLoggedIn: boolean
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
malLoggedIn.subscribe((value) => isMALLoggedIn = value)
simklLoggedIn.subscribe((value) => isSimklLoggedIn = value)
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()
})
!isAniListLoggedIn && (await CheckIfAniListLoggedInAndLoadWatchList());
!isMALLoggedIn && (await CheckIfMALLoggedInAndSetUser());
!isSimklLoggedIn && (await CheckIfSimklLoggedInAndSetUser());
});
$: if ($loc?.location === "/" && $watchlistNeedsRefresh) {
(async () => {
if ($aniListLoggedIn && $aniListPrimary) {
await CheckIfAniListLoggedInAndLoadWatchList();
}
if ($malLoggedIn && $malPrimary) {
await GetMyAnimeList(1000).then((w) => malWatchList.set(w));
}
if ($simklLoggedIn && $simklPrimary) {
await SimklGetUserWatchlist().then((w) => simklWatchList.set(w));
}
watchlistNeedsRefresh.set(false);
})();
}
</script>
<Header />
<Router routes={{
'/': Home,
'/anime/:id': wrap({
asyncComponent: () => import('./routes/AnimeRoutePage.svelte'),
<Router
routes={{
"/": Home,
"/anime/:id": wrap({
asyncComponent: () => import("./routes/AnimeRoutePage.svelte"),
conditions: [async () => await CheckIfAniListLoggedIn()],
loadingComponent: Spinner
loadingComponent: Spinner,
}),
// '*': "Not Found"
}} />
}}
/>

View File

@@ -6,6 +6,7 @@
malLoggedIn,
simklAnime,
simklLoggedIn,
watchlistNeedsRefresh,
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
import { push } from "svelte-spa-router";
import WebsiteLink from "./WebsiteLink.svelte";
@@ -23,10 +24,7 @@
} 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 {
@@ -81,8 +79,7 @@
{ 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,
@@ -113,15 +110,11 @@
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({
@@ -198,6 +191,7 @@
submitData[key] = value;
}
try {
if (
isAniListLoggedIn &&
currentAniListAnime.data.MediaList.mediaId !== 0
@@ -212,10 +206,11 @@
startedAt: convertDateToAniList(startedAtDate),
completedAt: convertDateToAniList(completedAtDate),
};
await AniListUpdateEntry(body).then(
(value: AniListGetSingleAnime) => {
await AniListUpdateEntry(body).then((value: AniListGetSingleAnime) => {
value.data.MediaList.media.tags =
currentAniListAnime.data.MediaList.media.tags;
value.data.MediaList.media.genres =
currentAniListAnime.data.MediaList.media.genres;
aniListAnime.update((newValue) => {
newValue = value;
return newValue;
@@ -236,8 +231,7 @@
repeat: currentAniListAnime.data.MediaList.repeat,
notes: currentAniListAnime.data.MediaList.notes,
});
},
);
});
}
if (malLoggedIn && currentMalAnime.id !== 0) {
@@ -254,8 +248,7 @@
(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;
@@ -282,14 +275,12 @@
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,
});
},
@@ -297,13 +288,9 @@
}
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,
@@ -320,14 +307,13 @@
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,
@@ -344,7 +330,8 @@
newValue = value;
return newValue;
});
});
},
);
}
if (currentSimklAnime.status !== submitData.status.simkl) {
@@ -371,14 +358,19 @@
});
}
}
} catch (error) {
console.error("Error submitting changes:", error);
} finally {
submitting.set(false);
submitSuccess.set(true);
watchlistNeedsRefresh.set(true);
setTimeout(() => submitSuccess.set(false), 2000);
}
};
const deleteEntries = async () => {
submitting.set(true);
try {
if (
isAniListLoggedIn &&
currentAniListAnime.data.MediaList.mediaId !== 0
@@ -427,9 +419,14 @@
notes: "",
});
}
} catch (error) {
console.error("Error deleting entries:", error);
} finally {
submitting.set(false);
submitSuccess.set(true);
watchlistNeedsRefresh.set(true);
setTimeout(() => submitSuccess.set(false), 2000);
}
};
let max = 999;
@@ -442,8 +439,7 @@
currentAniListAnime.data.MediaList.media.nextAiringEpisode.episode !== 0
) {
max =
currentAniListAnime.data.MediaList.media.nextAiringEpisode.episode -
1;
currentAniListAnime.data.MediaList.media.nextAiringEpisode.episode - 1;
}
</script>
@@ -479,17 +475,11 @@
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;
}
}}
@@ -519,22 +509,18 @@
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
@@ -544,24 +530,15 @@
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"
@@ -584,16 +561,15 @@
</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>
@@ -665,8 +641,7 @@
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}
@@ -730,6 +705,7 @@
Sync Changes
</button>
<button
type="button"
class="text-white bg-gray-800 border border-gray-600 focus:outline-none hover:bg-gray-700 focus:ring-4
focus:ring-gray-700 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2
hover:border-gray-600"
@@ -829,7 +805,7 @@
<div class="flex m-5">
<div>
<h3 class="text-2xl">Genres</h3>
{#each currentAniListAnime.data.MediaList.media.genres as genre}
{#each currentAniListAnime.data.MediaList.media.genres || [] as genre}
<div>
<Badge large border color="blue" class="m-1 w-52">
<div>

View File

@@ -6,30 +6,50 @@
loading,
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
import { push } from "svelte-spa-router";
import type {AniListCurrentUserWatchList} from "../anilist/types/AniListCurrentUserWatchListType"
import type { AniListCurrentUserWatchList } from "../anilist/types/AniListCurrentUserWatchListType";
import { Rating } from "flowbite-svelte";
import loader from '../helperFunctions/loader'
import loader from "../helperFunctions/loader";
import { CheckIfAniListLoggedInAndLoadWatchList } from "../helperModules/CheckIfAniListLoggedInAndLoadWatchList.svelte";
let isAniListLoggedIn: boolean;
let aniListWatchListLoaded: AniListCurrentUserWatchList;
let isAniListLoggedIn: boolean
let aniListWatchListLoaded: AniListCurrentUserWatchList
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
aniListWatchlist.subscribe((value) => aniListWatchListLoaded = value)
aniListLoggedIn.subscribe((value) => (isAniListLoggedIn = value));
aniListWatchlist.subscribe((value) => (aniListWatchListLoaded = value));
</script>
<div>
{#if isAniListLoggedIn}
<div class="mx-auto max-w-2xl p-4 sm:p-6 lg:max-w-7xl lg:px-8 relative items-center">
<h1 class="text-left text-xl font-bold mb-4">Your AniList WatchList</h1>
<div
class="mx-auto max-w-2xl p-4 sm:p-6 lg:max-w-7xl lg:px-8 relative items-center"
>
<div class="flex justify-between items-center mb-4">
<h1 class="text-left text-xl font-bold">Your AniList WatchList</h1>
<button
type="button"
class="py-2 px-4 bg-gray-700 rounded-lg"
on:click={async () => {
loading.set(true);
await CheckIfAniListLoggedInAndLoadWatchList();
loading.set(false);
}}
>
Refresh WatchList
</button>
</div>
<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="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"
>
{#each aniListWatchListLoaded.data.Page.mediaList as media}
<div use:loader={loading} class="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-lg xl:aspect-h-8 xl:aspect-w-7">
<div
use:loader={loading}
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">
<button on:click={() => {
push(`#/anime/${media.media.id}`)
<button
on:click={() => {
push(`#/anime/${media.media.id}`);
// loading.set(true)
// GetAniListSingleItem(media.media.id, true).then(() => {
// loading.set(false)
@@ -37,27 +57,38 @@
// })
}}
>
<img class="rounded-lg" src={media.media.coverImage.large} alt={
media.media.title.english === "" ?
media.media.title.romaji :
media.media.title.english
}/>
<img
class="rounded-lg"
src={media.media.coverImage.large}
alt={media.media.title.english === ""
? media.media.title.romaji
: media.media.title.english}
/>
</button>
<Rating id="anime-rating" total={5} size={35} rating={media.score/2.0}/>
<button class="mt-4 text-md font-semibold text-white-700"
on:click={() => GetAnimeSingleItem(media.media.id, true)}>
{
media.media.title.english === "" ?
media.media.title.romaji :
media.media.title.english
}
<Rating
id="anime-rating"
total={5}
size={35}
rating={media.score / 2.0}
/>
<button
class="mt-4 text-md font-semibold text-white-700"
on:click={() => GetAnimeSingleItem(media.media.id, true)}
>
{media.media.title.english === ""
? media.media.title.romaji
: media.media.title.english}
</button>
<p class="mt-1 text-lg font-medium text-white-900">{media.progress}
/ {media.media.nextAiringEpisode.episode !== 0 ?
media.media.nextAiringEpisode.episode - 1 : media.media.episodes}</p>
<p class="mt-1 text-lg font-medium text-white-900">
{media.progress}
/ {media.media.nextAiringEpisode.episode !== 0
? media.media.nextAiringEpisode.episode - 1
: media.media.episodes}
</p>
{#if media.media.episodes > 0}
<p class="mt-1 text-lg font-medium text-white-900">Total
Episodes: {media.media.episodes}</p>
<p class="mt-1 text-lg font-medium text-white-900">
Total Episodes: {media.media.episodes}
</p>
{/if}
</div>
</div>

View File

@@ -10,153 +10,178 @@
LogoutMyAnimeList,
LogoutSimkl,
SimklGetUserWatchlist,
SimklSearch
SimklSearch,
} from "../../wailsjs/go/main/App";
import type {
AniListCurrentUserWatchList,
AniListGetSingleAnime
AniListGetSingleAnime,
} from "../anilist/types/AniListCurrentUserWatchListType.js";
import {writable} from 'svelte/store'
import type {SimklAnime, SimklUser, SimklWatchList} from "../simkl/types/simklTypes";
import {type AniListUser, MediaListSort} from "../anilist/types/AniListTypes";
import type {MALAnime, MALWatchlist, MyAnimeListUser} from "../mal/types/MALTypes";
import { writable } from "svelte/store";
import type {
SimklAnime,
SimklUser,
SimklWatchList,
} from "../simkl/types/simklTypes";
import {
type AniListUser,
MediaListSort,
} from "../anilist/types/AniListTypes";
import type {
MALAnime,
MALWatchlist,
MyAnimeListUser,
} from "../mal/types/MALTypes";
import type { TableItems } from "../helperTypes/TableTypes";
import { AniListGetSingleAnimeDefaultData } from "../helperDefaults/AniListGetSingleAnime";
export let aniListAnime = writable(AniListGetSingleAnimeDefaultData)
export let title = writable("")
export let aniListLoggedIn = writable(false)
export let simklLoggedIn = writable(false)
export let malLoggedIn = writable(false)
export let simklWatchList = writable({} as SimklWatchList)
export let aniListPrimary = writable(true)
export let simklPrimary = writable(false)
export let malPrimary = writable(false)
export let simklUser = writable({} as SimklUser)
export let aniListUser = writable({} as AniListUser)
export let malUser = writable({} as MyAnimeListUser)
export let aniListWatchlist = writable({} as AniListCurrentUserWatchList)
export let malWatchList = writable({} as MALWatchlist)
export let malAnime = writable({} as MALAnime)
export let simklAnime = writable({} as SimklAnime)
export let loading = writable(false)
export let tableItems = writable([] as TableItems)
export let aniListAnime = writable(AniListGetSingleAnimeDefaultData);
export let title = writable("");
export let aniListLoggedIn = writable(false);
export let simklLoggedIn = writable(false);
export let malLoggedIn = writable(false);
export let simklWatchList = writable({} as SimklWatchList);
export let aniListPrimary = writable(true);
export let simklPrimary = writable(false);
export let malPrimary = writable(false);
export let simklUser = writable({} as SimklUser);
export let aniListUser = writable({} as AniListUser);
export let malUser = writable({} as MyAnimeListUser);
export let aniListWatchlist = writable({} as AniListCurrentUserWatchList);
export let malWatchList = writable({} as MALWatchlist);
export let malAnime = writable({} as MALAnime);
export let simklAnime = writable({} as SimklAnime);
export let loading = writable(false);
export let tableItems = writable([] as TableItems);
export let watchlistNeedsRefresh = writable(false);
export let watchListPage = writable(1)
export let animePerPage = writable(20)
export let watchListPage = writable(1);
export let animePerPage = writable(20);
let isAniListPrimary: boolean
let page: number
let perPage: number
let aniWatchlist: AniListCurrentUserWatchList
let currentAniListAnime: AniListGetSingleAnime
let isAniListPrimary: boolean;
let page: number;
let perPage: number;
let aniWatchlist: AniListCurrentUserWatchList;
let currentAniListAnime: AniListGetSingleAnime;
let isMalLoggedIn: boolean
let isSimklLoggedIn: boolean
let isMalLoggedIn: boolean;
let isSimklLoggedIn: boolean;
aniListPrimary.subscribe(value => isAniListPrimary = value)
watchListPage.subscribe(value => page = value)
animePerPage.subscribe(value => perPage = value)
aniListWatchlist.subscribe(value => aniWatchlist = value)
malLoggedIn.subscribe(value => isMalLoggedIn = value)
simklLoggedIn.subscribe(value => isSimklLoggedIn = value)
aniListAnime.subscribe(value => currentAniListAnime = value)
aniListPrimary.subscribe((value) => (isAniListPrimary = value));
watchListPage.subscribe((value) => (page = value));
animePerPage.subscribe((value) => (perPage = value));
aniListWatchlist.subscribe((value) => (aniWatchlist = value));
malLoggedIn.subscribe((value) => (isMalLoggedIn = value));
simklLoggedIn.subscribe((value) => (isSimklLoggedIn = value));
aniListAnime.subscribe((value) => (currentAniListAnime = value));
export async function GetAnimeSingleItem(aniId: number, login: boolean): Promise<""> {
await GetAniListItem(aniId, login).then(aniListResult => {
let finalResult: AniListGetSingleAnime
finalResult = aniListResult
export async function GetAnimeSingleItem(
aniId: number,
login: boolean,
): Promise<""> {
await GetAniListItem(aniId, login).then((aniListResult) => {
let finalResult: AniListGetSingleAnime;
finalResult = aniListResult;
if (login === false) {
finalResult.data.MediaList.status = ""
finalResult.data.MediaList.score = 0
finalResult.data.MediaList.progress = 0
finalResult.data.MediaList.notes = ""
finalResult.data.MediaList.repeat = 0
finalResult.data.MediaList.startedAt.day = 0
finalResult.data.MediaList.startedAt.month = 0
finalResult.data.MediaList.startedAt.year = 0
finalResult.data.MediaList.completedAt.day = 0
finalResult.data.MediaList.completedAt.month = 0
finalResult.data.MediaList.completedAt.year = 0
finalResult.data.MediaList.status = "";
finalResult.data.MediaList.score = 0;
finalResult.data.MediaList.progress = 0;
finalResult.data.MediaList.notes = "";
finalResult.data.MediaList.repeat = 0;
finalResult.data.MediaList.startedAt.day = 0;
finalResult.data.MediaList.startedAt.month = 0;
finalResult.data.MediaList.startedAt.year = 0;
finalResult.data.MediaList.completedAt.day = 0;
finalResult.data.MediaList.completedAt.month = 0;
finalResult.data.MediaList.completedAt.year = 0;
}
aniListAnime.set(finalResult)
title.set(currentAniListAnime.data.MediaList.media.title.english === "" ?
currentAniListAnime.data.MediaList.media.title.romaji :
currentAniListAnime.data.MediaList.media.title.english)
})
aniListAnime.set(finalResult);
title.set(
currentAniListAnime.data.MediaList.media.title.english === ""
? currentAniListAnime.data.MediaList.media.title.romaji
: currentAniListAnime.data.MediaList.media.title.english,
);
});
if (isMalLoggedIn) {
await GetMyAnimeListAnime(currentAniListAnime.data.MediaList.media.idMal).then(malResult => {
malAnime.set(malResult)
})
await GetMyAnimeListAnime(
currentAniListAnime.data.MediaList.media.idMal,
).then((malResult) => {
malAnime.set(malResult);
});
}
if (isSimklLoggedIn) {
await SimklSearch(currentAniListAnime.data.MediaList).then((value: SimklAnime) => {
simklAnime.set(value)
})
await SimklSearch(currentAniListAnime.data.MediaList).then(
(value: SimklAnime) => {
simklAnime.set(value);
},
);
}
return ""
return "";
}
export function loginToSimkl(): void {
GetSimklLoggedInUser().then(user => {
GetSimklLoggedInUser().then((user) => {
if (Object.keys(user).length === 0) {
simklLoggedIn.set(false)
simklLoggedIn.set(false);
} else {
simklUser.set(user)
SimklGetUserWatchlist().then(result => {
simklWatchList.set(result)
simklLoggedIn.set(true)
})
simklUser.set(user);
SimklGetUserWatchlist().then((result) => {
simklWatchList.set(result);
simklLoggedIn.set(true);
});
}
})
});
}
export function loginToAniList(): void {
GetAniListLoggedInUser().then(result => {
aniListUser.set(result)
GetAniListLoggedInUser().then((result) => {
aniListUser.set(result);
if (isAniListPrimary) {
GetAniListUserWatchingList(page, perPage, MediaListSort.UpdatedTimeDesc).then((result) => {
aniListWatchlist.set(result)
aniListLoggedIn.set(true)
})
GetAniListUserWatchingList(
page,
perPage,
MediaListSort.UpdatedTimeDesc,
).then((result) => {
aniListWatchlist.set(result);
aniListLoggedIn.set(true);
});
} else {
aniListLoggedIn.set(true)
aniListLoggedIn.set(true);
}
})
});
}
export function loginToMAL(): void {
GetMyAnimeListLoggedInUser().then(result => {
malUser.set(result)
malLoggedIn.set(true)
})
GetMyAnimeListLoggedInUser().then((result) => {
malUser.set(result);
malLoggedIn.set(true);
});
}
export function logoutOfAniList(): void {
LogoutAniList().then(result => {
console.log(result)
LogoutAniList().then((result) => {
console.log(result);
if (Object.keys(aniWatchlist).length !== 0) {
aniListWatchlist.set({} as AniListCurrentUserWatchList)
aniListWatchlist.set({} as AniListCurrentUserWatchList);
}
aniListUser.set({} as AniListUser)
aniListLoggedIn.set(false)
})
aniListUser.set({} as AniListUser);
aniListLoggedIn.set(false);
});
}
export function logoutOfMAL(): void {
LogoutMyAnimeList().then(result => {
console.log(result)
malUser.set({} as MyAnimeListUser)
malLoggedIn.set(false)
})
LogoutMyAnimeList().then((result) => {
console.log(result);
malUser.set({} as MyAnimeListUser);
malLoggedIn.set(false);
});
}
export function logoutOfSimkl(): void {
LogoutSimkl().then(result => {
console.log(result)
simklUser.set({} as SimklUser)
simklLoggedIn.set(false)
})
LogoutSimkl().then((result) => {
console.log(result);
simklUser.set({} as SimklUser);
simklLoggedIn.set(false);
});
}
</script>

View File

@@ -12,6 +12,6 @@
},
"info": {
"productName": "AniTrack",
"productVersion": "0.5.2"
"productVersion": "0.6.0"
}
}