15 Commits
0.1.8 ... 0.5.0

Author SHA1 Message Date
2e5a4a4493 finally fixed being able to reload the anime page when searching or changing the url 2025-12-21 13:01:51 -05:00
874b3952ee upped version to 0.4 due to big change 2025-12-21 01:15:39 -05:00
60eac10545 user dropdown now closes when certain actions are taken or clicked outside of dialog 2025-12-21 01:14:46 -05:00
6d66d711ff added a showversion button with popup to the interface 2025-12-21 01:14:05 -05:00
cd62e6c658 fixed MAL not auto logging in when app starts 2025-12-21 00:25:48 -05:00
063c5016f3 fixed MAL not auto logging in when app starts 2025-12-21 00:24:25 -05:00
5c4caf68e6 added tooltip and version change 2025-06-22 21:08:56 -04:00
c10e853564 updated minor version for tag fix 2025-06-06 23:25:24 -04:00
cd043d093f fixed issue where tags would not reload after submit 2025-06-06 23:25:08 -04:00
6db01f7f9f added tags to frontend anime item 2025-05-14 14:31:43 -04:00
8460d56d55 created simple linux install script for AniTrack 2025-05-07 10:03:58 -04:00
8fedbe4607 created xdg icon set instead of one big icon 2025-05-07 10:03:37 -04:00
e069c47242 automated adding anime by moving progress from 0 to 1 2025-03-30 10:03:05 -04:00
aba0f2d1d5 removed console.log 2025-03-30 10:02:38 -04:00
af6cb7f08a removed unecessary button dependency and neovim reformatted 2025-03-30 09:52:46 -04:00
16 changed files with 248 additions and 102 deletions

View File

@@ -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
View File

@@ -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)
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

BIN
build/icon/128/AniTrack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
build/icon/32/AniTrack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
build/icon/48/AniTrack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
build/icon/64/AniTrack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

26
build/install_linux.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
# copy desktop file
if [ -e "~/.local/share/applications/AniTrack.desktop" ]; then
if [ -d "~/.local/share/applications/" ]; then
cp ./AniTrack.desktop ~/.local/share/applications/
else
mkdir -p ~/.local/share/applications/
cp ./AniTrack.desktop ~/.local/share/applications/
fi
fi
# copy icons to xdg folders
for size in 32 48 64 128; do
xdg-icon-resource install --novendor --context apps --size $size ./icon/$size/AniTrack.png AniTrack
done
# copy AniTrack Binary to $HOME/Applications/
if ! [ -d "~/Applications" ]; then
mkdir -p ~/Applications
cp ./bin/AniTrack ~/Applications/
elif ! [[ -e ~/Applications/AniTrack ]]; then
cp ./bin/AniTrack ~/Applications/
fi
echo "AniTrack has been successfully installed."

View File

@@ -1,7 +1,10 @@
<script lang="ts">
import {
aniListAnime,
aniListLoggedIn,
GetAnimeSingleItem,
malLoggedIn,
simklLoggedIn,
} from "./helperModules/GlobalVariablesAndHelperFunctions.svelte";
import {onMount} from "svelte";
import Router from "svelte-spa-router"
@@ -16,9 +19,17 @@
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 +38,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"

View File

@@ -2,79 +2,92 @@ 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;
};
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;
},
];
};
};
};
}

View File

@@ -8,7 +8,6 @@
simklLoggedIn,
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
import { push } from "svelte-spa-router";
import { Button } from "flowbite-svelte";
import type { AniListGetSingleAnime } from "../anilist/types/AniListCurrentUserWatchListType";
import Rating from "./Rating.svelte";
import {
@@ -42,6 +41,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;
@@ -213,9 +213,8 @@
};
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 */
value.data.MediaList.media.tags =
currentAniListAnime.data.MediaList.media.tags;
aniListAnime.update((newValue) => {
newValue = value;
return newValue;
@@ -448,7 +447,6 @@
</script>
<form on:submit|preventDefault={handleSubmit} class="container pt-3 pb-10">
{console.log(startingAnilistStatusOption)}
<h1 class="text-white font-bold text-left text-xl pb-3">
{title}
</h1>
@@ -553,6 +551,17 @@
statusOptions[2];
completedAtDate = 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"
>
@@ -816,8 +825,29 @@
</div>
</div>
<div class="flex m-5">
<div>
<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>
{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>

View File

@@ -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"

View File

@@ -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}

View File

@@ -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>;

View File

@@ -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']();
}

View File

@@ -12,6 +12,6 @@
},
"info": {
"productName": "AniTrack",
"productVersion": "0.1.8"
"productVersion": "0.5.0"
}
}