25 Commits

Author SHA1 Message Date
23ec111c60 upped minor version for episode button 2024-12-14 13:50:09 -05:00
f24ee9edfd improved episode input in Anime Page 2024-12-14 13:48:55 -05:00
1fd453f399 upped version number for bug fix 2024-12-06 16:32:06 -05:00
3ab77ea8d3 fixed bug in episode input when 0 2024-12-06 16:30:53 -05:00
3edfed6272 updated version number to distinguish ep count 2024-12-01 19:12:48 -05:00
aa81102194 added currentl episode release to anime single page 2024-11-14 20:11:41 -05:00
0c90c3e29d added check for 403 in get anilist watchlist 2024-11-14 20:10:41 -05:00
2292ae32c2 updated bruno files 2024-11-14 18:50:51 -05:00
31cc19ba7a removed logged in buttons from navigation 2024-10-26 21:33:42 -04:00
5c712454d5 fixed bug in tailwind build and updated minor version 2024-10-26 19:55:13 -04:00
10430caddf added login, icons and theming to user dropdown 2024-10-26 18:02:05 -04:00
9a6c844691 added code plist to see window on mac 2024-10-26 18:01:36 -04:00
476507a695 added MapleMono font to project 2024-10-26 18:01:04 -04:00
1fdb859f05 upgraded vite from vulnerability 2024-10-18 23:21:59 -04:00
064a2c7f7d added info for mac keychain 2024-10-18 22:06:33 -04:00
bd39268c0a bumped minor version number 2024-10-02 19:32:24 -04:00
2cffd54c4d made anime Id in table a link to their respective sites 2024-10-02 19:26:52 -04:00
7e3369d0f0 fixed buttons colors 2024-10-01 18:53:34 -04:00
e229311190 made entire app only work in dark mode 2024-10-01 16:57:42 -04:00
753ecd968e made header permanently dark mode 2024-10-01 16:01:13 -04:00
30c48dcf9b Added versions numbers and display on titlebar 2024-10-01 15:53:57 -04:00
9b28f2fb0a test simkl urls 2024-10-01 15:52:32 -04:00
0bf784562a fixed bug that was stopping anilist from logging in 2024-10-01 15:07:02 -04:00
ea2c4475de changed url for simkl to pull all lists, not just watching fixed several simkl bugs 2024-09-24 18:44:42 -04:00
572366eb91 updated table when entries are deleted and fixed simkl watchlist 2024-09-18 15:06:35 -04:00
28 changed files with 1055 additions and 524 deletions

View File

@ -360,27 +360,47 @@ func (a *App) GetAniListUserWatchingList(page int, perPage int, sort string) Ani
},
}
returnedBody, _ := AniListQuery(body, true)
returnedBody, status := AniListQuery(body, true)
var badPost struct {
Errors []struct {
Message string `json:"message"`
Status int `json:"status"`
Locations []struct {
Line int `json:"line"`
Column int `json:"column"`
} `json:"locations"`
} `json:"errors"`
Data any `json:"data"`
}
var post AniListCurrentUserWatchList
err := json.Unmarshal(returnedBody, &post)
if err != nil {
log.Printf("Failed at unmarshal, %s\n", err)
}
// Getting the real total, finding the real last page and storing that in the Page info
statuses := post.Data.Page.MediaList[0].User.Statistics.Anime.Statuses
var total int
for _, status := range statuses {
if status.Status == "CURRENT" {
total = status.Count
if status == "200 OK" {
err := json.Unmarshal(returnedBody, &post)
if err != nil {
log.Printf("Failed at unmarshal, %s\n", err)
}
// Getting the real total, finding the real last page and storing that in the Page info
statuses := post.Data.Page.MediaList[0].User.Statistics.Anime.Statuses
var total int
for _, status := range statuses {
if status.Status == "CURRENT" {
total = status.Count
}
}
lastPage := total / perPage
post.Data.Page.PageInfo.Total = total
post.Data.Page.PageInfo.LastPage = lastPage
}
lastPage := total / perPage
post.Data.Page.PageInfo.Total = total
post.Data.Page.PageInfo.LastPage = lastPage
if status == "403 Forbidden" {
err := json.Unmarshal(returnedBody, &badPost)
if err != nil {
log.Printf("Failed at unmarshal, %s\n", err)
}
log.Fatal(badPost.Errors[0].Message)
}
return post
}

View File

@ -19,7 +19,11 @@ import (
var aniListJwt AniListJWT
var aniRing, _ = keyring.Open(keyring.Config{
ServiceName: "AniTrack",
ServiceName: "AniTrack",
KeychainName: "AniTrack",
KeychainSynchronizable: false,
KeychainTrustApplication: true,
KeychainAccessibleWhenUnlocked: true,
})
var aniCtxShutdown, aniCancel = context.WithCancel(context.Background())
@ -78,7 +82,6 @@ func (a *App) handleAniListCallback(wg *sync.WaitGroup) {
default:
}
content := r.FormValue("code")
if content != "" {
aniListJwt = getAniListAuthorizationToken(content)
_ = aniRing.Set(keyring.Item{
@ -145,8 +148,7 @@ func getAniListAuthorizationToken(content string) AniListJWT {
if err != nil {
log.Printf("Failed at response, %s\n", err)
}
response.Header.Add("content-type", "application/x-www-form-urlencoded")
response.Header.Add("Content-Type", "application/json")
response.Header.Add("Content-type", "application/x-www-form-urlencoded")
response.Header.Add("Accept", "application/json")
client := &http.Client{}

View File

@ -23,7 +23,11 @@ import (
var myAnimeListJwt MyAnimeListJWT
var myAnimeListRing, _ = keyring.Open(keyring.Config{
ServiceName: "AniTrack",
ServiceName: "AniTrack",
KeychainName: "AniTrack",
KeychainSynchronizable: false,
KeychainTrustApplication: true,
KeychainAccessibleWhenUnlocked: true,
})
var myAnimeListCtxShutdown, myAnimeListCancel = context.WithCancel(context.Background())

View File

@ -8,6 +8,7 @@ import (
"log"
"net/http"
"reflect"
"slices"
"strconv"
)
@ -51,7 +52,7 @@ func SimklHelper(method string, url string, body interface{}) json.RawMessage {
func (a *App) SimklGetUserWatchlist() SimklWatchListType {
method := "GET"
url := "https://api.simkl.com/sync/all-items/anime/watching"
url := "https://api.simkl.com/sync/all-items/anime"
respBody := SimklHelper(method, url, nil)
@ -132,6 +133,8 @@ func (a *App) SimklSyncEpisodes(anime SimklAnime, progress int) SimklAnime {
anime.WatchedEpisodesCount = progress
WatchListUpdate(anime)
return anime
}
@ -187,6 +190,8 @@ func (a *App) SimklSyncRating(anime SimklAnime, rating int) SimklAnime {
anime.UserRating = rating
WatchListUpdate(anime)
return anime
}
@ -227,6 +232,8 @@ func (a *App) SimklSyncStatus(anime SimklAnime, status string) SimklAnime {
anime.Status = status
WatchListUpdate(anime)
return anime
}
@ -291,7 +298,9 @@ func (a *App) SimklSearch(aniListAnime MediaList) SimklAnime {
func (a *App) SimklSyncRemove(anime SimklAnime) bool {
url := "https://api.simkl.com/sync/history/remove"
var show = SimklShowStatus{
var showArray []SimklShowStatus
var singleShow = SimklShowStatus{
Title: anime.Show.Title,
Ids: Ids{
Simkl: anime.Show.Ids.Simkl,
@ -300,6 +309,14 @@ func (a *App) SimklSyncRemove(anime SimklAnime) bool {
},
}
showArray = append(showArray, singleShow)
show := struct {
Shows []SimklShowStatus `json:"shows"`
}{
Shows: showArray,
}
respBody := SimklHelper("POST", url, show)
var success SimklDeleteType
@ -310,8 +327,27 @@ func (a *App) SimklSyncRemove(anime SimklAnime) bool {
}
if success.Deleted.Shows >= 1 {
for i, simklAnime := range SimklWatchList.Anime {
if simklAnime.Show.Ids.Simkl == anime.Show.Ids.Simkl {
SimklWatchList.Anime = slices.Delete(SimklWatchList.Anime, i, i+1)
}
}
return true
} else {
return false
}
}
func WatchListUpdate(anime SimklAnime) {
updated := false
for i, simklAnime := range SimklWatchList.Anime {
if simklAnime.Show.Ids.Simkl == anime.Show.Ids.Simkl {
SimklWatchList.Anime[i] = anime
updated = true
}
}
if !updated {
SimklWatchList.Anime = append(SimklWatchList.Anime, anime)
}
return
}

View File

@ -17,7 +17,11 @@ import (
var simklJwt SimklJWT
var simklRing, _ = keyring.Open(keyring.Config{
ServiceName: "AniTrack",
ServiceName: "AniTrack",
KeychainName: "AniTrack",
KeychainSynchronizable: false,
KeychainTrustApplication: true,
KeychainAccessibleWhenUnlocked: true,
})
var simklCtxShutdown, simklCancel = context.WithCancel(context.Background())

8
app.go
View File

@ -2,11 +2,17 @@ package main
import (
"context"
_ "embed"
"github.com/wailsapp/wails/v2/pkg/options"
"github.com/wailsapp/wails/v2/pkg/runtime"
"strings"
"github.com/tidwall/gjson"
)
//go:embed wails.json
var wailsJSON string
var wailsContext *context.Context
// App struct
@ -22,7 +28,9 @@ func NewApp() *App {
// startup is called when the app starts. The context is saved
// so we can call the runtime methods
func (a *App) startup(ctx context.Context) {
version := gjson.Get(wailsJSON, "info.productVersion")
wailsContext = &ctx
runtime.WindowSetTitle(ctx, "AniTrack "+version.String())
//runtime.WindowMaximise(ctx)
}

View File

@ -0,0 +1,90 @@
meta {
name: AniChart
type: graphql
seq: 5
}
post {
url: https://graphql.anilist.co
body: graphql
auth: none
}
body:graphql {
# Write your query or mutation here
query ($page: Int, $perPage: Int, $airingAt_greater:Int) {
Page(page: $page, perPage: $perPage) {
pageInfo {
total
perPage
currentPage
lastPage
hasNextPage
}
airingSchedules(airingAt_greater:$airingAt_greater){
id
airingAt
timeUntilAiring
episode
mediaId
media{
id
title{
english
romaji
native
}
type
format
status
startDate{
year
month
day
}
endDate{
year
month
day
}
season
seasonYear
episodes
duration
coverImage{
medium
large
color
extraLarge
}
bannerImage
genres
averageScore
meanScore
popularity
trending
favourites
tags{
id
name
description
category
rank
isGeneralSpoiler
isMediaSpoiler
isAdult
}
isAdult
}
}
}
}
}
body:graphql:vars {
{
"page": 50,
"perPage": 20,
"airingAt_greater": 1730260800
}
}

View File

@ -25,7 +25,7 @@ body:graphql {
media {
id
idMal
tags{
tags {
id
name
description

View File

@ -5,7 +5,7 @@ meta {
}
get {
url: https://api.simkl.com/anime/1579943?extended=full
url: https://api.simkl.com/anime/40084?extended=full
body: none
auth: none
}

View File

@ -5,7 +5,7 @@ meta {
}
get {
url: https://api.simkl.com/sync/all-items/anime/watching
url: https://api.simkl.com/sync/all-items/anime/
body: none
auth: none
}

View File

@ -1,6 +1,11 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true />
</dict>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleName</key>

View File

@ -23,7 +23,7 @@
"tailwindcss": "^3.4.10",
"tslib": "^2.7.0",
"typescript": "^5.0.0",
"vite": "^4.5.3"
"vite": "^4.5.5"
},
"dependencies": {
"@popperjs/core": "^2.11.8",

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,14 @@
<script lang="ts">
import {createTable, Render, Subscribe} from "svelte-headless-table";
import {
createRender,
createTable,
Render,
Subscribe,
} from "svelte-headless-table"
// @ts-ignore
import { addSortBy } from "svelte-headless-table/plugins";
import {tableItems} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte"
import { addSortBy } from "svelte-headless-table/plugins"
import { tableItems } from "../helperModules/GlobalVariablesAndHelperFunctions.svelte"
import WebsiteLink from "./WebsiteLink.svelte"
//when adding sort here is code { sort: addSortBy() }
const table = createTable(tableItems, { sort: addSortBy() })
@ -10,100 +16,98 @@
const columns = table.createColumns([
table.column({
header: "Service Id",
accessor: 'id',
cell: ({ value }) => createRender(WebsiteLink, {id: value}),
accessor: "id",
}),
table.column({
header: "Anime Title",
accessor: "title",
}),
table.column({
header: 'Service',
accessor: 'service',
header: "Service",
accessor: "service",
}),
table.column({
header: 'Episode Progress',
accessor: 'progress',
header: "Episode Progress",
accessor: "progress",
}),
table.column({
header: 'Status',
accessor: 'status',
header: "Status",
accessor: "status",
}),
table.column({
header: 'Started At',
accessor: 'startedAt',
header: "Started At",
accessor: "startedAt",
}),
table.column({
header: 'Completed At',
accessor: 'completedAt',
header: "Completed At",
accessor: "completedAt",
}),
table.column({
header: 'Rating',
accessor: 'score',
header: "Rating",
accessor: "score",
}),
table.column({
header: 'Repeat',
accessor: 'repeat',
header: "Repeat",
accessor: "repeat",
}),
table.column({
header: 'Notes',
accessor: 'notes',
header: "Notes",
accessor: "notes",
}),
])
//add pluginStates when add sort back
const {
headerRows,
rows,
tableAttrs,
tableBodyAttrs,
} = table.createViewModel(columns)
const { headerRows, rows, tableAttrs, tableBodyAttrs } =
table.createViewModel(columns)
</script>
<div class="relative overflow-x-auto rounded-lg mb-5">
<table
class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400"
{...$tableAttrs}
class="w-full text-sm text-left rtl:text-right text-gray-400"
{...$tableAttrs}
>
<thead
class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400"
>
{#each $headerRows as headerRow (headerRow.id)}
<Subscribe attrs={headerRow.attrs()} let:attrs>
<tr {...attrs}>
{#each headerRow.cells as cell (cell.id)}
<Subscribe attrs={cell.attrs()} let:attrs props={cell.props()} let:props>
<th
<thead class="text-xs uppercase bg-gray-700 text-gray-400">
{#each $headerRows as headerRow (headerRow.id)}
<Subscribe attrs={headerRow.attrs()} let:attrs>
<tr {...attrs}>
{#each headerRow.cells as cell (cell.id)}
<Subscribe
attrs={cell.attrs()}
let:attrs
props={cell.props()}
let:props
>
<th
{...attrs}
on:click={props.sort.toggle}
class:sorted={props.sort.order !== undefined}
class:sorted={props.sort.order !==
undefined}
class="px-6 py-3"
>
<div>
<Render of={cell.render()}/>
{#if props.sort.order === 'asc'}
⬇️
{:else if props.sort.order === 'desc'}
⬆️
{/if}
</div>
</th>
</Subscribe>
{/each}
</tr>
</Subscribe>
{/each}
>
<div>
<Render of={cell.render()} />
{#if props.sort.order === "asc"}
⬇️
{:else if props.sort.order === "desc"}
⬆️
{/if}
</div>
</th>
</Subscribe>
{/each}
</tr>
</Subscribe>
{/each}
</thead>
<tbody {...$tableBodyAttrs}>
{#each $rows as row (row.id)}
<Subscribe attrs={row.attrs()} let:attrs>
<tr
{...attrs}
class="bg-white border-b dark:bg-gray-800 dark:border-gray-700"
>
<tr {...attrs} class="bg-gray-800 border-gray-700">
{#each row.cells as cell (cell.id)}
<Subscribe attrs={cell.attrs()} let:attrs>
<td {...attrs} class="px-6 py-4">
<Render of={cell.render()}/>
<Render of={cell.render()} />
</td>
</Subscribe>
{/each}

View File

@ -1,74 +1,128 @@
<script lang="ts">
import {Avatar} from "flowbite-svelte";
import type {AniListUser} from "../anilist/types/AniListTypes";
import {aniListLoggedIn, aniListUser, malLoggedIn, simklLoggedIn, logoutOfAniList, logoutOfMAL, logoutOfSimkl} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte"
import { Avatar } from "flowbite-svelte";
import type { AniListUser } from "../anilist/types/AniListTypes";
import {
aniListLoggedIn,
aniListUser,
malUser,
simklUser,
malLoggedIn,
simklLoggedIn,
loginToAniList,
loginToMAL,
loginToSimkl,
logoutOfAniList,
logoutOfMAL,
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";
let currentAniListUser: AniListUser
let isAniListLoggedIn: boolean
let isSimklLoggedIn: boolean
let isMALLoggedIn: boolean
let currentAniListUser: AniListUser;
let currentMALUser: MyAnimeListUser;
let currentSimklUser: SimklUser;
let isAniListLoggedIn: boolean;
let isSimklLoggedIn: boolean;
let isMALLoggedIn: boolean;
aniListUser.subscribe((value) => currentAniListUser = value)
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
simklLoggedIn.subscribe((value) => isSimklLoggedIn = value)
malLoggedIn.subscribe((value) => isMALLoggedIn = value)
aniListUser.subscribe((value) => (currentAniListUser = value));
malUser.subscribe((value) => (currentMALUser = value))
simklUser.subscribe(value => currentSimklUser = value)
aniListLoggedIn.subscribe((value) => (isAniListLoggedIn = value));
simklLoggedIn.subscribe((value) => (isSimklLoggedIn = value));
malLoggedIn.subscribe((value) => (isMALLoggedIn = value));
function dropdownUser(): void {
let dropdown = document.querySelector("#userDropdown")
dropdown.classList.toggle("hidden")
let dropdown = document.querySelector("#userDropdown");
dropdown.classList.toggle("hidden");
}
</script>
<div class="relative">
<button id="userDropdownButton" on:click={dropdownUser}>
{#if isAniListLoggedIn}
<Avatar src="{currentAniListUser.data.Viewer.avatar.medium}" class="cursor-pointer"
dot={{ color: 'green' }}/>
<Avatar
src={currentAniListUser.data.Viewer.avatar.medium}
class="cursor-pointer"
dot={{ color: "green" }}
/>
{:else}
<Avatar class="cursor-pointer" dot={{ color: 'red' }}/>
<Avatar class="cursor-pointer" dot={{ color: "red" }} />
{/if}
</button>
<div id="userDropdown"
class="absolute hidden right-0 2xl:left-1/2 2xl:-translate-x-1/2 z-10 bg-white divide-y divide-gray-100 rounded-lg shadow w-44 dark:bg-gray-700 dark:divide-gray-600">
<div class="px-4 py-3 text-sm text-gray-900 dark:text-white">
<div
id="userDropdown"
class="absolute hidden right-0 2xl:left-1/2 2xl:-translate-x-1/2 z-10 divide-y rounded-lg shadow w-44 bg-gray-700 divide-gray-600"
>
<div class="px-4 py-3 text-sm text-white">
{#if isAniListLoggedIn}
<div>{currentAniListUser.data.Viewer.name}</div>
{:else}
<div>You are not logged into AniList</div>
{/if}
</div>
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200"
aria-labelledby="dropdownUserAvatarButton">
<ul
class="py-2 text-sm text-gray-200"
aria-labelledby="dropdownUserAvatarButton"
>
{#if isAniListLoggedIn}
<li>
<button on:click={logoutOfAniList}
class="block px-4 py-2 w-full hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
Logout Anilist
<button
on:click={logoutOfAniList}
class="block px-4 py-2 w-full hover:bg-gray-600 truncate bg-green-800 hover:text-white"
>
<span class="maple-font text-lg text-green-200 mr-4">A</span>Logout {currentAniListUser.data.Viewer.name}
</button>
</li>
{:else}
<li>
<button on:click={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>
</li>
{/if}
{#if isMALLoggedIn}
<li>
<button on:click={logoutOfMAL}
class="block px-4 py-2 w-full hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
Logout MAL
<button
on:click={logoutOfMAL}
class="block px-4 py-2 w-full hover:bg-gray-600 truncate bg-blue-800 hover:text-white"
>
<span class="maple-font text-lg text-blue-200 mr-4">M</span>Logout {currentMALUser.name}
</button>
</li>
{:else}
<li>
<button on:click={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>
</li>
{/if}
{#if isSimklLoggedIn}
<li>
<button on:click={logoutOfSimkl}
class="block px-4 py-2 w-full hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
Logout Simkl
<button
on:click={logoutOfSimkl}
class="block px-4 py-2 w-full hover:bg-gray-600 truncate bg-indigo-800 hover:text-white"
>
<span class="maple-font text-lg text-indigo-200 mr-4">S</span>Logout {currentSimklUser.user.name}
</button>
</li>
{:else}
<li>
<button on:click={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>
</li>
{/if}
</ul>
<div class="py-2">
<button on:click={() => runtime.Quit()}
class="block px-4 py-2 w-full text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">
<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"
>
Exit Application
</button>
</div>

View File

@ -2,41 +2,25 @@
import Search from "./Search.svelte"
import {
aniListLoggedIn,
aniListUser,
loginToAniList,
loginToMAL,
loginToSimkl,
malLoggedIn,
malUser,
simklLoggedIn,
simklUser,
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte"
import type {AniListUser} from "../anilist/types/AniListTypes";
import type {SimklUser} from "../simkl/types/simklTypes";
import type {MyAnimeListUser} from "../mal/types/MALTypes";
import AvatarMenu from "./AvatarMenu.svelte";
import logo from "../assets/images/AniTrackLogo.svg"
import {location} from "svelte-spa-router";
let isAniListLoggedIn: boolean
let isSimklLoggedIn: boolean
let isMALLoggedIn: boolean
let currentAniListUser: AniListUser
let currentSimklUser: SimklUser
let currentMALUser: MyAnimeListUser
aniListLoggedIn.subscribe((value) => isAniListLoggedIn = value)
simklLoggedIn.subscribe((value) => isSimklLoggedIn = value)
malLoggedIn.subscribe((value) => isMALLoggedIn = value)
aniListUser.subscribe((value) => currentAniListUser = value)
simklUser.subscribe((value) => currentSimklUser = value)
malUser.subscribe((value) => currentMALUser = value)
let currentLocation: any
location.subscribe(value => currentLocation = value)
</script>
<nav class="bg-white border-gray-200 dark:bg-gray-900">
<nav class="border-gray-200 bg-gray-900">
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
<div class="flex items-center space-x-3 rtl:space-x-reverse">
<a href="/"><img src={logo} class="h-8" alt="AniTrack Logo"/></a>
@ -50,7 +34,7 @@
let menu = document.querySelector("#navbar-user")
menu.classList.toggle("hidden")
}} type="button"
class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg min-[950px]:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"
class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm rounded-lg min-[950px]:hidden focus:outline-none focus:ring-2 text-gray-400 hover:bg-gray-700 focus:ring-gray-600"
aria-controls="navbar-user" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
@ -60,40 +44,26 @@
</svg>
</button>
</div>
<div class="hidden items-center justify-between w-full pb-4 min-[950px]:pb-0 min-[950px]:flex min-[950px]:w-auto min-[950px]:order-1 border border-gray-100 dark:border-gray-700 min-[950px]:border-0 bg-gray-50 dark:bg-gray-800 min-[950px]:bg-transparent min-[950px]:dark:bg-transparent rounded-lg" id="navbar-user">
<div class="hidden items-center justify-between w-full pb-4 min-[950px]:pb-0 min-[950px]:flex min-[950px]:w-auto min-[950px]:order-1 border border-gray-700 min-[950px]:border-0 bg-gray-800 min-[950px]:bg-transparent rounded-lg" id="navbar-user">
<ul class="flex flex-col font-medium pb-6 min-[950px]:p-0 mt-4 min-[950px]:space-x-8 rtl:space-x-reverse min-[950px]:flex-row min-[950px]:mt-0">
<li>
{#if isAniListLoggedIn}
<div class="flex justify-center py-2 px-3 rounded bg-transparent min-[950px]:p-0">
<span class="w-48 min-[950px]:w-auto bg-green-100 text-green-800 text-sm font-medium me-2 px-3 py-2 rounded dark:bg-green-800 dark:text-green-200 cursor-default">AniList: {currentAniListUser.data.Viewer.name}</span>
</div>
{:else}
<button on:click={loginToAniList}
class="block py-2 px-3 text-gray-900 w-full min-[950px]:w-auto rounded hover:bg-gray-100 min-[950px]:hover:bg-transparent min-[950px]:hover:text-blue-700 min-[950px]:p-0 dark:text-white min-[950px]:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white min-[950px]:dark:hover:bg-transparent dark:border-gray-700">
{#if !isAniListLoggedIn}
<button on:click={loginToAniList}>
<!-- class="block py-2 px-3 w-full min-[950px]:w-auto rounded text-gray-300 min-[950px]:hover:text-blue-500 hover:bg-gray-700 hover:text-white min-[950px]:hover:bg-transparent border-gray-700">-->
AniList Login
</button>
{/if}
</li>
<li>
{#if isMALLoggedIn}
<div class="flex justify-center py-2 px-3 rounded bg-transparent min-[950px]:p-0">
<span class="w-48 min-[950px]:w-auto bg-blue-100 text-blue-800 text-sm font-medium me-2 px-3 py-2 rounded dark:bg-blue-800 dark:text-blue-200 cursor-default">MyAnimeList: {currentMALUser.name}</span>
</div>
{:else}
<button on:click={loginToMAL}
class="block py-2 px-3 text-gray-900 w-full min-[950px]:w-auto rounded hover:bg-gray-100 min-[950px]:hover:bg-transparent min-[950px]:hover:text-blue-700 min-[950px]:p-0 dark:text-white min-[950px]:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white min-[950px]:dark:hover:bg-transparent dark:border-gray-700">
{#if !isMALLoggedIn}
<button on:click={loginToMAL}>
<!-- class="block py-2 px-3 w-full min-[950px]:w-auto rounded min-[950px]:p-0 text-gray-300 min-[950px]:hover:text-blue-500 hover:bg-gray-700 hover:text-white min-[950px]:hover:bg-transparent border-gray-700">-->
MyAnimeList Login
</button>
{/if}
</li>
<li>
{#if isSimklLoggedIn}
<div class="flex justify-center py-2 px-3 rounded bg-transparent min-[950px]:p-0">
<span class="w-48 min-[950px]:w-auto bg-indigo-100 text-indigo-800 text-sm font-medium me-2 px-3 py-2 rounded dark:bg-indigo-800 dark:text-indigo-200 cursor-default">Simkl: {currentSimklUser.user.name}</span>
</div>
{:else}
<button on:click={loginToSimkl}
class="block py-2 px-3 text-gray-900 w-full min-[950px]:w-auto rounded hover:bg-gray-100 min-[950px]:hover:bg-transparent min-[950px]:hover:text-blue-700 min-[950px]:p-0 dark:text-white min-[950px]:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white min-[950px]:dark:hover:bg-transparent dark:border-gray-700">
{#if !isSimklLoggedIn}
<button on:click={loginToSimkl}>
<!-- class="block py-2 px-3 w-full min-[950px]:w-auto rounded min-[950px]:p-0 text-gray-300 min-[950px]:hover:text-blue-500 hover:bg-gray-700 hover:text-white min-[950px]:hover:bg-transparent border-gray-700">-->
Simkl Login
</button>
{/if}

View File

@ -50,14 +50,14 @@
{#if page === 1}
<li>
<button disabled
class="flex items-center justify-center px-4 h-10 ms-0 leading-tight text-gray-500 bg-white border border-e-0 border-gray-300 rounded-s-lg dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 cursor-default">
class="flex items-center justify-center px-4 h-10 ms-0 leading-tight border border-e-0 rounded-s-lg border-gray-700 text-gray-400 cursor-default">
Previous
</button>
</li>
{:else}
<li>
<button on:click={() => ChangeWatchListPage(page-1)}
class="flex items-center justify-center px-4 h-10 ms-0 leading-tight text-gray-500 bg-white border border-e-0 border-gray-300 rounded-s-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
class="flex items-center justify-center px-4 h-10 ms-0 leading-tight border border-e-0 rounded-s-lg border-gray-700 text-gray-400 hover:bg-gray-700 hover:text-white">
Previous
</button>
</li>
@ -66,26 +66,26 @@
{#if i + 1 === page}
<li>
<button on:click={() => ChangeWatchListPage(i+1)}
class="flex items-center justify-center px-4 h-10 leading-tight border border-gray-300 bg-gray-100 dark:border-gray-700 dark:bg-gray-700 dark:text-white">{i + 1}</button>
class="flex items-center justify-center px-4 h-10 leading-tight border bg-gray-100 border-gray-700 bg-gray-700 text-white">{i + 1}</button>
</li>
{:else}
<li>
<button on:click={() => ChangeWatchListPage(i+1)}
class="flex items-center justify-center px-4 h-10 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">{i + 1}</button>
class="flex items-center justify-center px-4 h-10 leading-tight border dark border-gray-700 text-gray-400 hover:bg-gray-700 hover:text-white">{i + 1}</button>
</li>
{/if}
{/each}
{#if page === aniListWatchListLoaded.data.Page.pageInfo.lastPage}
<li>
<button disabled
class="flex items-center justify-center px-4 h-10 leading-tight text-gray-500 bg-white border border-gray-300 rounded-e-lg dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 cursor-default">
class="flex items-center justify-center px-4 h-10 leading-tight border rounded-e-lg dark border-gray-700 text-gray-400 cursor-default">
Next
</button>
</li>
{:else}
<li>
<button on:click={() => ChangeWatchListPage(page+1)}
class="flex items-center justify-center px-4 h-10 leading-tight text-gray-500 bg-white border border-gray-300 rounded-e-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
class="flex items-center justify-center px-4 h-10 leading-tight border rounded-e-lg dark border-gray-700 text-gray-400 hover:bg-gray-700 hover:text-white">
Next
</button>
</li>
@ -96,7 +96,7 @@
<div class="flex mt-5">
<div class="w-20 mx-auto">
<select bind:value={perPage} on:change={(e) => changeCountPerPage(e)} id="countPerPage"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
class="border text-sm rounded-lg block w-full p-2.5 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500">
{#each perPageOptions as option}
<option value={option}>
{option}
@ -117,8 +117,8 @@
<div class="max-w-xs mx-auto">
<div class="relative flex items-center max-w-[11rem]">
<button type="button" id="decrement-button" on:click={() => ChangeWatchListPage(page-1)}
class="bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 dark:border-gray-600 hover:bg-gray-200 border border-gray-300 rounded-s-lg p-3 h-11 focus:ring-gray-100 dark:focus:ring-gray-700 focus:ring-2 focus:outline-none">
<svg class="w-3 h-3 text-gray-900 dark:text-white" aria-hidden="true"
class="bg-gray-700 hover:bg-gray-600 border-gray-600 border rounded-s-lg p-3 h-11 focus:ring-gray-700 focus:ring-2 focus:outline-none">
<svg class="w-3 h-3 text-white" aria-hidden="true"
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 2">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M1 1h16"/>
@ -126,14 +126,14 @@
</button>
<input type="number" min="1" max="{aniListWatchListLoaded.data.Page.pageInfo.lastPage}"
on:keydown={changePage} id="page-counter"
class="[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none bg-gray-50 border-x-0 border-gray-300 h-11 font-medium text-center text-gray-900 text-sm focus:ring-blue-500 focus:border-blue-500 block w-full pb-6 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
class="[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none border-x-0 h-11 font-medium text-center text-sm block w-full pb-6 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500"
value={page} required/>
<div class="absolute bottom-1 start-1/2 -translate-x-1/2 rtl:translate-x-1/2 flex items-center text-xs text-gray-400 space-x-1 rtl:space-x-reverse">
<span>Page #</span>
</div>
<button type="button" id="increment-button" on:click={() => ChangeWatchListPage(page+1)}
class="bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 dark:border-gray-600 hover:bg-gray-200 border border-gray-300 rounded-e-lg p-3 h-11 focus:ring-gray-100 dark:focus:ring-gray-700 focus:ring-2 focus:outline-none">
<svg class="w-3 h-3 text-gray-900 dark:text-white" aria-hidden="true"
class="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">
<svg class="w-3 h-3 text-white" aria-hidden="true"
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 1v16M1 9h16"/>

View File

@ -25,11 +25,11 @@
<div id="searchDropdown" class="relative w-64 md:w-48">
<div class="flex">
<label for="anime-search" class="mb-2 text-sm font-medium text-gray-900 sr-only dark:text-white">Find
<label for="anime-search" class="mb-2 text-sm font-medium sr-only text-white">Find
Anime</label>
<div class="relative w-full">
<input type="search" id="anime-search" bind:value={aniSearch}
class="rounded-s-lg block p-2.5 w-full z-20 text-sm text-gray-900 bg-gray-50 rounded-e-lg border-s-gray-50 border-s-2 border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-s-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:border-blue-500"
class="rounded-s-lg block p-2.5 w-full z-20 text-sm rounded-e-lg bg-gray-700 border-s-gray-700 border-gray-600 placeholder-gray-400 text-white focus:border-blue-500"
placeholder="Search for Anime"
on:keypress={(e) => {
if (e.key === "Enter") {
@ -39,7 +39,7 @@
}}
required/>
<button id="aniListSearchButton"
class="absolute top-0 end-0 h-full p-2.5 text-sm font-medium text-white bg-blue-700 rounded-e-lg border border-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
class="absolute top-0 end-0 h-full p-2.5 text-sm font-medium rounded-e-lg border focus:ring-4 focus:outline-none bg-blue-600 hover:bg-blue-700 focus:ring-blue-800"
on:click={() => {
searchDropdown()
if(aniSearch.length > 0) runAniListSearch()
@ -60,7 +60,7 @@
aria-labelledby="aniListSearchButton">
{#each aniListSearch.data.Page.media as media}
<li class="w-full">
<div class="flex w-full items-start p-1 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white rounded-lg">
<div class="flex w-full items-start p-1 hover:bg-gray-600 hover:text-white rounded-lg">
<button on:click={() => {
searchDropdown()
push(`#/anime/${media.id}`)

View File

@ -0,0 +1,28 @@
<script lang="ts">
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]?-?(.*)/
if (id !== undefined && id.length > 0) {
isAniList = id.includes("a-")
isMAL = id.includes("m-")
isSimkl = id.includes("s-")
newId = id.match(re)[1]
}
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>
{:else}
{id}
{/if}

View File

@ -1,7 +1,7 @@
export type TableItems = TableItem[]
export type TableItem = {
id: number
id: string
title: string
service: string
progress: number
@ -11,4 +11,4 @@ export type TableItem = {
score: number
repeat: number
notes: string
}
}

View File

@ -16,6 +16,12 @@ body {
sans-serif;
}
.maple-font {
font-family: "Maple Mono NF", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
}
@font-face {
font-family: "Nunito";
font-style: normal;
@ -24,6 +30,14 @@ body {
url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2");
}
@font-face {
font-family: "Maple Mono NF";
font-style: normal;
font-weight: 800;
src: local(""),
url("assets/fonts/MapleMono-Bold.woff2") format("woff2");
}
#app {
height: 100vh;
text-align: center;

View File

@ -1,3 +1,4 @@
import flowbitePlugin from 'flowbite/plugin'
/** @type {import('tailwindcss').Config} */
export default {
content: [
@ -6,9 +7,7 @@ export default {
"./node_modules/flowbite/**/*.{html,js,svelte,ts}",
"./node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}",
],
plugins: [
require('flowbite/plugin')
],
plugins: [ flowbitePlugin ],
darkMode: 'media',

View File

@ -0,0 +1,10 @@
// vite.config.ts
import { defineConfig } from "file:///home/nymusicman/Code/AniTrack/frontend/node_modules/vite/dist/node/index.js";
import { svelte } from "file:///home/nymusicman/Code/AniTrack/frontend/node_modules/@sveltejs/vite-plugin-svelte/src/index.js";
var vite_config_default = defineConfig({
plugins: [svelte()]
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvaG9tZS9ueW11c2ljbWFuL0NvZGUvQW5pVHJhY2svZnJvbnRlbmRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9ob21lL255bXVzaWNtYW4vQ29kZS9BbmlUcmFjay9mcm9udGVuZC92aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vaG9tZS9ueW11c2ljbWFuL0NvZGUvQW5pVHJhY2svZnJvbnRlbmQvdml0ZS5jb25maWcudHNcIjtpbXBvcnQge2RlZmluZUNvbmZpZ30gZnJvbSAndml0ZSdcbmltcG9ydCB7c3ZlbHRlfSBmcm9tICdAc3ZlbHRlanMvdml0ZS1wbHVnaW4tc3ZlbHRlJ1xuXG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcbiAgcGx1Z2luczogW3N2ZWx0ZSgpXVxufSlcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBdVMsU0FBUSxvQkFBbUI7QUFDbFUsU0FBUSxjQUFhO0FBR3JCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxPQUFPLENBQUM7QUFDcEIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K

View File

@ -231,6 +231,8 @@ export namespace main {
background: background;
related_anime: relatedAnime;
recommendations: recommendations;
// Go type: struct { NumListUsers int "json:\"num_list_users\" ts_type:\"numListUsers\""; Status struct { Watching string "json:\"watching\" ts_type:\"watching\""; Completed string "json:\"completed\" ts_type:\"completed\""; OnHold string "json:\"on_hold\" ts_type:\"onHold\""; Dropped string "json:\"dropped\" ts_type:\"dropped\""; PlanToWatch string "json:\"plan_to_watch\" ts_type:\"planToWatch\"" } }
Statistics: any;
static createFrom(source: any = {}) {
return new MALAnime(source);
@ -268,6 +270,7 @@ export namespace main {
this.background = source["background"];
this.related_anime = source["related_anime"];
this.recommendations = source["recommendations"];
this.Statistics = this.convertValues(source["Statistics"], Object);
}
convertValues(a: any, classs: any, asMap: boolean = false): any {

23
go.mod
View File

@ -1,12 +1,11 @@
module AniTrack
go 1.21
toolchain go1.21.11
go 1.23
require (
github.com/99designs/keyring v1.2.2
github.com/wailsapp/wails/v2 v2.9.1
github.com/tidwall/gjson v1.18.0
github.com/wailsapp/wails/v2 v2.9.2
)
require (
@ -33,16 +32,18 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/samber/lo v1.47.0 // indirect
github.com/tkrajina/go-reflector v0.5.6 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tkrajina/go-reflector v0.5.8 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/wailsapp/go-webview2 v1.0.13 // indirect
github.com/wailsapp/go-webview2 v1.0.16 // indirect
github.com/wailsapp/mimetype v1.4.1 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/term v0.24.0 // indirect
golang.org/x/text v0.18.0 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/term v0.25.0 // indirect
golang.org/x/text v0.19.0 // indirect
)
// replace github.com/wailsapp/wails/v2 v2.9.1 => /home/nymusicman/go/pkg/mod

39
go.sum
View File

@ -66,37 +66,44 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE=
github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ=
github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/wailsapp/go-webview2 v1.0.13 h1:I17/44xQ5/SujBaAUS4KMkWJYIoWCp35YxCEFWsMLKA=
github.com/wailsapp/go-webview2 v1.0.13/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
github.com/wailsapp/go-webview2 v1.0.16 h1:wffnvnkkLvhRex/aOrA3R7FP7rkvOqL/bir1br7BekU=
github.com/wailsapp/go-webview2 v1.0.16/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
github.com/wailsapp/wails/v2 v2.9.1 h1:irsXnoQrCpeKzKTYZ2SUVlRRyeMR6I0vCO9Q1cvlEdc=
github.com/wailsapp/wails/v2 v2.9.1/go.mod h1:7maJV2h+Egl11Ak8QZN/jlGLj2wg05bsQS+ywJPT0gI=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
github.com/wailsapp/wails/v2 v2.9.2 h1:Xb5YRTos1w5N7DTMyYegWaGukCP2fIaX9WF21kPPF2k=
github.com/wailsapp/wails/v2 v2.9.2/go.mod h1:uehvlCwJSFcBq7rMCGfk4rxca67QQGsbg5Nm4m9UnBs=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
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=

View File

@ -9,5 +9,9 @@
"author": {
"name": "John O'Keefe",
"email": "jokeefe@fastmail.com"
},
"info": {
"productName": "AniTrack",
"productVersion": "0.1.4"
}
}