2 Commits

Author SHA1 Message Date
b934276342 chore(version): bump version to 0.5.1
Increment version number from 0.5.0 to 0.5.1 for the upcoming release.
2026-03-20 10:56:39 -04:00
6860a5541a style(frontend): format Header.svelte with consistent code style
Apply consistent formatting to Header.svelte:
- Add semicolons to all statements
- Improve JSX/HTML attribute formatting for better readability
- Add link import from svelte-spa-router for SPA navigation
- Format multi-line attributes with proper indentation

These changes improve code consistency and maintainability without
altering any functionality.
2026-03-20 10:56:37 -04:00
7 changed files with 1065 additions and 1123 deletions

3
.gitignore vendored
View File

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

5
frontend/.vscode/extensions.json vendored Normal file
View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,99 +1,68 @@
<script lang="ts"> <script lang="ts">
import { import {
aniListLoggedIn, aniListLoggedIn,
aniListWatchlist, aniListWatchlist,
GetAnimeSingleItem, GetAnimeSingleItem,
loading, loading,
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte"; } from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
import { push } from "svelte-spa-router"; 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 {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;
aniListLoggedIn.subscribe((value) => (isAniListLoggedIn = value)); let isAniListLoggedIn: boolean
aniListWatchlist.subscribe((value) => (aniListWatchListLoaded = value)); let aniListWatchListLoaded: AniListCurrentUserWatchList
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
aniListWatchlist.subscribe((value) => aniListWatchListLoaded = value)
</script> </script>
<div> <div>
{#if isAniListLoggedIn} {#if isAniListLoggedIn}
<div <div class="mx-auto max-w-2xl p-4 sm:p-6 lg:max-w-7xl lg:px-8 relative items-center">
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="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 <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">
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">
{#each aniListWatchListLoaded.data.Page.mediaList as media} <div class="flex flex-col items-center group">
<div <button on:click={() => {
use:loader={loading} push(`#/anime/${media.media.id}`)
class="aspect-h-1 aspect-w-1 w-full overflow-hidden rounded-lg xl:aspect-h-8 xl:aspect-w-7" // loading.set(true)
> // GetAniListSingleItem(media.media.id, true).then(() => {
<div class="flex flex-col items-center group"> // loading.set(false)
<button //
on:click={() => { // })
push(`#/anime/${media.media.id}`); }}
// loading.set(true) >
// GetAniListSingleItem(media.media.id, true).then(() => { <img class="rounded-lg" src={media.media.coverImage.large} alt={
// loading.set(false) media.media.title.english === "" ?
// media.media.title.romaji :
// }) media.media.title.english
}} }/>
> </button>
<img <Rating id="anime-rating" total={5} size={35} rating={media.score/2.0}/>
class="rounded-lg" <button class="mt-4 text-md font-semibold text-white-700"
src={media.media.coverImage.large} on:click={() => GetAnimeSingleItem(media.media.id, true)}>
alt={media.media.title.english === "" {
? media.media.title.romaji media.media.title.english === "" ?
: media.media.title.english} media.media.title.romaji :
/> media.media.title.english
</button> }
<Rating </button>
id="anime-rating" <p class="mt-1 text-lg font-medium text-white-900">{media.progress}
total={5} / {media.media.nextAiringEpisode.episode !== 0 ?
size={35} media.media.nextAiringEpisode.episode - 1 : media.media.episodes}</p>
rating={media.score / 2.0} {#if media.media.episodes > 0}
/> <p class="mt-1 text-lg font-medium text-white-900">Total
<button Episodes: {media.media.episodes}</p>
class="mt-4 text-md font-semibold text-white-700" {/if}
on:click={() => GetAnimeSingleItem(media.media.id, true)} </div>
> </div>
{media.media.title.english === "" {/each}
? 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>
{#if media.media.episodes > 0}
<p class="mt-1 text-lg font-medium text-white-900">
Total Episodes: {media.media.episodes}
</p>
{/if}
</div> </div>
</div> </div>
{/each} {/if}
</div>
</div>
{/if}
</div> </div>

View File

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

View File

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