13 Commits

18 changed files with 720 additions and 223 deletions

View File

@ -17,14 +17,14 @@ func AniListQuery(body interface{}, login bool) (json.RawMessage, string) {
if login && (AniListJWT{}) != aniListJwt { if login && (AniListJWT{}) != aniListJwt {
response.Header.Add("Authorization", "Bearer "+aniListJwt.AccessToken) response.Header.Add("Authorization", "Bearer "+aniListJwt.AccessToken)
} else if login { } else if login {
return nil, "Please login to anilist to make this request" return nil, "Please login to AniList to make this request"
} }
response.Header.Add("Content-Type", "application/json") response.Header.Add("Content-Type", "application/json")
response.Header.Add("Accept", "application/json") response.Header.Add("Accept", "application/json")
client := &http.Client{} client := &http.Client{}
res, reserr := client.Do(response) res, resErr := client.Do(response)
if reserr != nil { if resErr != nil {
log.Printf("Failed at res, %s\n", err) log.Printf("Failed at res, %s\n", err)
} }
@ -148,7 +148,7 @@ func (a *App) GetAniListItem(aniId int, login bool) AniListGetSingleAnime {
return post return post
} }
if status == "404 Not Found" && login { if status == "404 Not Found" {
post = a.GetAniListItem(aniId, false) post = a.GetAniListItem(aniId, false)
} }

View File

@ -3,6 +3,7 @@ package main
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -123,7 +124,7 @@ func (a *App) handleAniListCallback(wg *sync.WaitGroup) {
go func() { go func() {
defer wg.Done() defer wg.Done()
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("listen: %s\n", err) log.Fatalf("listen: %s\n", err)
} }
fmt.Println("Shutting down...") fmt.Println("Shutting down...")
@ -152,8 +153,8 @@ func getAniListAuthorizationToken(content string) AniListJWT {
response.Header.Add("Accept", "application/json") response.Header.Add("Accept", "application/json")
client := &http.Client{} client := &http.Client{}
res, reserr := client.Do(response) res, resErr := client.Do(response)
if reserr != nil { if resErr != nil {
log.Printf("Failed at res, %s\n", err) log.Printf("Failed at res, %s\n", err)
} }

View File

@ -5,6 +5,7 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -70,7 +71,6 @@ func (v *CodeVerifier) CodeChallengeS256() string {
} }
func (a *App) CheckIfMyAnimeListLoggedIn() bool { func (a *App) CheckIfMyAnimeListLoggedIn() bool {
fmt.Println("check function reached")
if (MyAnimeListJWT{} == myAnimeListJwt) { if (MyAnimeListJWT{} == myAnimeListJwt) {
tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType") tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType")
expiresIn, expiresInErr := myAnimeListRing.Get("MyAnimeListExpiresIn") expiresIn, expiresInErr := myAnimeListRing.Get("MyAnimeListExpiresIn")
@ -79,10 +79,10 @@ func (a *App) CheckIfMyAnimeListLoggedIn() bool {
if (tokenErr != nil || expiresInErr != nil || refreshTokenErr != nil || accessTokenErr != nil) || len(accessToken.Data) == 0 { if (tokenErr != nil || expiresInErr != nil || refreshTokenErr != nil || accessTokenErr != nil) || len(accessToken.Data) == 0 {
return false return false
} else { } else {
var expresInConvertErr error var expiresInConvertErr error
myAnimeListJwt.TokenType = string(tokenType.Data) myAnimeListJwt.TokenType = string(tokenType.Data)
myAnimeListJwt.ExpiresIn, expresInConvertErr = strconv.Atoi(string(expiresIn.Data)) myAnimeListJwt.ExpiresIn, expiresInConvertErr = strconv.Atoi(string(expiresIn.Data))
if expresInConvertErr != nil { if expiresInConvertErr != nil {
fmt.Println("unable to convert string to int") fmt.Println("unable to convert string to int")
} }
myAnimeListJwt.AccessToken = string(accessToken.Data) myAnimeListJwt.AccessToken = string(accessToken.Data)
@ -95,7 +95,6 @@ func (a *App) CheckIfMyAnimeListLoggedIn() bool {
} }
func (a *App) MyAnimeListLogin() { func (a *App) MyAnimeListLogin() {
fmt.Println("login function reached")
if !a.CheckIfMyAnimeListLoggedIn() { if !a.CheckIfMyAnimeListLoggedIn() {
fmt.Println("check logged in function failed") fmt.Println("check logged in function failed")
tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType") tokenType, tokenErr := myAnimeListRing.Get("MyAnimeListTokenType")
@ -111,10 +110,10 @@ func (a *App) MyAnimeListLogin() {
a.handleMyAnimeListCallback(serverDone, verifier) a.handleMyAnimeListCallback(serverDone, verifier)
serverDone.Wait() serverDone.Wait()
} else { } else {
var expresInConvertErr error var expiresInConvertErr error
myAnimeListJwt.TokenType = string(tokenType.Data) myAnimeListJwt.TokenType = string(tokenType.Data)
myAnimeListJwt.ExpiresIn, expresInConvertErr = strconv.Atoi(string(expiresIn.Data)) myAnimeListJwt.ExpiresIn, expiresInConvertErr = strconv.Atoi(string(expiresIn.Data))
if expresInConvertErr != nil { if expiresInConvertErr != nil {
fmt.Println("unable to convert string to int in Login function") fmt.Println("unable to convert string to int in Login function")
} }
myAnimeListJwt.AccessToken = string(accessToken.Data) myAnimeListJwt.AccessToken = string(accessToken.Data)
@ -176,7 +175,7 @@ func (a *App) handleMyAnimeListCallback(wg *sync.WaitGroup, verifier *CodeVerifi
go func() { go func() {
defer wg.Done() defer wg.Done()
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("listen: %s\n", err) log.Fatalf("listen: %s\n", err)
} }
fmt.Println("Shutting down...") fmt.Println("Shutting down...")
@ -215,8 +214,8 @@ func getMyAnimeListAuthorizationToken(content string, verifier *CodeVerifier) My
response.Header.Add("Content-Type", "application/x-www-form-urlencoded") response.Header.Add("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{} client := &http.Client{}
res, reserr := client.Do(response) res, resErr := client.Do(response)
if reserr != nil { if resErr != nil {
log.Printf("Failed at res, %s\n", err) log.Printf("Failed at res, %s\n", err)
} }
@ -265,8 +264,8 @@ func refreshMyAnimeListAuthorizationToken() {
response.Header.Add("Content-Type", "application/x-www-form-urlencoded") response.Header.Add("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{} client := &http.Client{}
res, reserr := client.Do(response) res, resErr := client.Do(response)
if reserr != nil { if resErr != nil {
log.Printf("Failed at res, %s\n", err) log.Printf("Failed at res, %s\n", err)
} }

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -114,7 +115,7 @@ func (a *App) handleSimklCallback(wg *sync.WaitGroup) {
go func() { go func() {
defer wg.Done() defer wg.Done()
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("listen: %s\n", err) log.Fatalf("listen: %s\n", err)
} }
fmt.Println("Shutting down...") fmt.Println("Shutting down...")
@ -147,8 +148,8 @@ func getSimklAuthorizationToken(content string) SimklJWT {
response.Header.Add("Content-Type", "application/json") response.Header.Add("Content-Type", "application/json")
client := &http.Client{} client := &http.Client{}
res, reserr := client.Do(response) res, resErr := client.Do(response)
if reserr != nil { if resErr != nil {
log.Printf("Failed at res, %s\n", err) log.Printf("Failed at res, %s\n", err)
} }

11
build/AniTrack.desktop Executable file
View File

@ -0,0 +1,11 @@
[Desktop Entry]
Name=AniTrack
Comment=A manual synchronizer for various Anime trackers.
Exec=/home/nymusicman/Applications/AniTrack
Icon=AniTrack
Terminal=false
Type=Application
StartupNotify=true
Categories=Internet
Keywords=anitrack;anilist;simkl;mal;myanimelist;anime;sync
Path=

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -1,13 +1,16 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"/> <meta charset="UTF-8" />
<meta content="width=device-width, initial-scale=1.0" name="viewport"/> <meta content="width=device-width, initial-scale=1.0" name="viewport" />
<title>AniTrack</title> <title>AniTrack</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
<script src="./src/main.ts" type="module"></script> <script src="./src/main.ts" type="module"></script>
<script src="./node_modules/flowbite/dist/flowbite.js"></script> <script
</body> src="./node_modules/flowbite/dist/flowbite.js"
type="module"
></script>
</body>
</html> </html>

View File

@ -11,7 +11,10 @@
import { Button } from "flowbite-svelte"; import { Button } from "flowbite-svelte";
import type { AniListGetSingleAnime } from "../anilist/types/AniListCurrentUserWatchListType"; import type { AniListGetSingleAnime } from "../anilist/types/AniListCurrentUserWatchListType";
import Rating from "./Rating.svelte"; import Rating from "./Rating.svelte";
import convertAniListDateToString from "../helperFunctions/convertAniListDateToString"; import {
convertAniListDateToString,
convertAniListDateToDate,
} from "../helperFunctions/convertAniListDateIn";
import AnimeTable from "./AnimeTable.svelte"; import AnimeTable from "./AnimeTable.svelte";
import type { import type {
MALAnime, MALAnime,
@ -25,7 +28,10 @@
StatusOptions, StatusOptions,
} from "../helperTypes/StatusTypes"; } from "../helperTypes/StatusTypes";
import type { AniListUpdateVariables } from "../anilist/types/AniListTypes"; import type { AniListUpdateVariables } from "../anilist/types/AniListTypes";
import convertDateStringToAniList from "../helperFunctions/convertDateStringToAniList"; import {
convertDateStringToAniList,
convertDateToAniList,
} from "../helperFunctions/convertDateToAniList";
import { import {
AniListDeleteEntry, AniListDeleteEntry,
AniListUpdateEntry, AniListUpdateEntry,
@ -38,6 +44,8 @@
} from "../../wailsjs/go/main/App"; } from "../../wailsjs/go/main/App";
import { AddAnimeServiceToTable } from "../helperModules/AddAnimeServiceToTable.svelte"; import { AddAnimeServiceToTable } from "../helperModules/AddAnimeServiceToTable.svelte";
import { CheckIfAniListLoggedInAndLoadWatchList } from "../helperModules/CheckIfAniListLoggedInAndLoadWatchList.svelte"; import { CheckIfAniListLoggedInAndLoadWatchList } from "../helperModules/CheckIfAniListLoggedInAndLoadWatchList.svelte";
import Datepicker from "./Datepicker.svelte";
const re = /^([0-9]{4})-([0-9]{2})-([0-9]{2})/;
let isAniListLoggedIn: boolean; let isAniListLoggedIn: boolean;
let isMalLoggedIn: boolean; let isMalLoggedIn: boolean;
@ -78,10 +86,10 @@
(option) => (option) =>
currentAniListAnime.data.MediaList.status === option.aniList, currentAniListAnime.data.MediaList.status === option.aniList,
)[0]; )[0];
const startedAtDate = convertAniListDateToString( let startedAtDate: Date | null = convertAniListDateToDate(
currentAniListAnime.data.MediaList.startedAt, currentAniListAnime.data.MediaList.startedAt,
); );
const completedAtDate = convertAniListDateToString( let completedAtDate: Date | null = convertAniListDateToDate(
currentAniListAnime.data.MediaList.completedAt, currentAniListAnime.data.MediaList.completedAt,
); );
@ -103,19 +111,34 @@
notes: currentAniListAnime.data.MediaList.notes, notes: currentAniListAnime.data.MediaList.notes,
}); });
if (isMalLoggedIn) if (isMalLoggedIn) {
let startDate = "";
let finishDate = "";
if (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,
);
finishDate = `${finishArray[2]}-${finishArray[3]}-${finishArray[1]}`;
}
AddAnimeServiceToTable({ AddAnimeServiceToTable({
id: `m-${currentMalAnime.id}`, id: `m-${currentMalAnime.id}`,
title: currentMalAnime.title, title: currentMalAnime.title,
service: "MyAnimeList", service: "MyAnimeList",
progress: currentMalAnime.my_list_status.num_episodes_watched, progress: currentMalAnime.my_list_status.num_episodes_watched,
status: currentMalAnime.my_list_status.status, status: currentMalAnime.my_list_status.status,
startedAt: currentMalAnime.my_list_status.start_date, startedAt: startDate,
completedAt: currentMalAnime.my_list_status.finish_date, completedAt: finishDate,
score: currentMalAnime.my_list_status.score, 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, notes: currentMalAnime.my_list_status.comments,
}); });
}
if (isSimklLoggedIn && Object.keys(currentSimklAnime).length > 0) if (isSimklLoggedIn && Object.keys(currentSimklAnime).length > 0)
AddAnimeServiceToTable({ AddAnimeServiceToTable({
@ -137,8 +160,8 @@
rating: number; rating: number;
episodes: number; episodes: number;
status: StatusOption; status: StatusOption;
startedAt: string; startedAt: Date | null;
completedAt: string; completedAt: Date | null;
repeat: number; repeat: number;
notes: string; notes: string;
} = { } = {
@ -150,8 +173,8 @@
mal: "", mal: "",
simkl: "", simkl: "",
}, },
startedAt: "", startedAt: null,
completedAt: "", completedAt: null,
repeat: 0, repeat: 0,
notes: "", notes: "",
}; };
@ -188,8 +211,8 @@
score: submitData.rating, score: submitData.rating,
repeat: submitData.repeat, repeat: submitData.repeat,
notes: submitData.notes, notes: submitData.notes,
startedAt: convertDateStringToAniList(submitData.startedAt), startedAt: convertDateToAniList(startedAtDate),
completedAt: convertDateStringToAniList(submitData.completedAt), completedAt: convertDateToAniList(completedAtDate),
}; };
await AniListUpdateEntry(body).then( await AniListUpdateEntry(body).then(
(value: AniListGetSingleAnime) => { (value: AniListGetSingleAnime) => {
@ -244,6 +267,20 @@
value.my_list_status.comments = malAnimeReturn.comments; value.my_list_status.comments = malAnimeReturn.comments;
return value; return value;
}); });
let startDate = "";
let finishDate = "";
if (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,
);
finishDate = `${finishArray[2]}-${finishArray[3]}-${finishArray[1]}`;
}
AddAnimeServiceToTable({ AddAnimeServiceToTable({
id: `m-${currentMalAnime.id}`, id: `m-${currentMalAnime.id}`,
title: currentMalAnime.title, title: currentMalAnime.title,
@ -251,8 +288,8 @@
progress: progress:
currentMalAnime.my_list_status.num_episodes_watched, currentMalAnime.my_list_status.num_episodes_watched,
status: currentMalAnime.my_list_status.status, status: currentMalAnime.my_list_status.status,
startedAt: currentMalAnime.my_list_status.start_date, startedAt: startDate,
completedAt: currentMalAnime.my_list_status.finish_date, completedAt: finishDate,
score: currentMalAnime.my_list_status.score, score: currentMalAnime.my_list_status.score,
repeat: currentMalAnime.my_list_status repeat: currentMalAnime.my_list_status
.num_times_rewatched, .num_times_rewatched,
@ -483,8 +520,9 @@
1) 1)
? 'border-red-500 border-[2px] text-rose-300 focus:ring-red-500 focus:border-red-500' ? '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" : '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 bind:value={
.progress} currentAniListAnime.data.MediaList.progress
}
required required
/> />
<button <button
@ -556,33 +594,16 @@
class="text-left block mb-2 text-sm font-medium text-white" class="text-left block mb-2 text-sm font-medium text-white"
>Date Started</label >Date Started</label
> >
<div class="relative max-w-sm"> <Datepicker
<div bind:value={startedAtDate}
class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none" color="slate"
> dateFormat={{
<svg year: "numeric",
class="w-4 h-4 text-gray-400" month: "2-digit",
aria-hidden="true" day: "2-digit",
xmlns="http://www.w3.org/2000/svg" }}
fill="currentColor" showActionButtons
viewBox="0 0 20 20"
>
<path
d="M20 4a2 2 0 0 0-2-2h-2V1a1 1 0 0 0-2 0v1h-3V1a1 1 0 0 0-2 0v1H6V1a1 1 0 0 0-2 0v1H2a2 2 0 0 0-2 2v2h20V4ZM0 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8H0v10Zm5-8h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z"
/> />
</svg>
</div>
<input
id="startedAt"
type="date"
name="startedAt"
class="border text-sm rounded-lg
focus:ring-blue-500 focus:border-blue-500 block w-full ps-10 p-2.5 bg-gray-700 border-gray-600
placeholder-gray-400 text-white"
value={startedAtDate}
placeholder="Date Started"
/>
</div>
</div> </div>
<div> <div>
<label <label
@ -590,33 +611,16 @@
class="text-left block mb-2 text-sm font-medium text-white" class="text-left block mb-2 text-sm font-medium text-white"
>Date Completed</label >Date Completed</label
> >
<div class="relative max-w-sm"> <Datepicker
<div bind:value={completedAtDate}
class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none" color="slate"
> dateFormat={{
<svg year: "numeric",
class="w-4 h-4 text-gray-400" month: "2-digit",
aria-hidden="true" day: "2-digit",
xmlns="http://www.w3.org/2000/svg" }}
fill="currentColor" showActionButtons
viewBox="0 0 20 20"
>
<path
d="M20 4a2 2 0 0 0-2-2h-2V1a1 1 0 0 0-2 0v1h-3V1a1 1 0 0 0-2 0v1H6V1a1 1 0 0 0-2 0v1H2a2 2 0 0 0-2 2v2h20V4ZM0 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8H0v10Zm5-8h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z"
/> />
</svg>
</div>
<input
id="completedAt"
type="date"
name="completedAt"
class="border text-sm rounded-lg
block w-full ps-10 p-2.5 bg-gray-700 border-gray-600
placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500"
value={completedAtDate}
placeholder="Date Completed"
/>
</div>
</div> </div>
<div> <div>
<label <label

View File

@ -0,0 +1,481 @@
<script lang="ts">
import { createEventDispatcher, onMount } from "svelte";
import { fade } from "svelte/transition";
import { Button } from "flowbite-svelte";
export let value: Date | null = null;
export let defaultDate: Date | null = null;
export let range: boolean = false;
export let rangeFrom: Date | null = null;
export let rangeTo: Date | null = null;
export let locale: string = "default";
export let firstDayOfWeek: number = 0; // 0 = Monday, 6 = Sunday
export let dateFormat: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "long",
day: "numeric",
};
export let placeholder: string = "Select date";
export let disabled: boolean = false;
export let required: boolean = false;
export let inputClass: string = "";
export let color: Button["color"] = "primary";
export let inline: boolean = false;
export let autohide: boolean = true;
export let showActionButtons: boolean = false;
export let title: string = "";
// Internal state
const dispatch = createEventDispatcher();
let isOpen: boolean = inline;
let inputElement: HTMLInputElement;
let datepickerContainerElement: HTMLDivElement;
let currentMonth: Date = value || defaultDate || new Date();
let focusedDate: Date | null = null;
let calendarRef: HTMLDivElement;
$: daysInMonth = getDaysInMonth(currentMonth);
$: weekdays = getWeekdays();
onMount(() => {
if (!inline) {
document.addEventListener("click", handleClickOutside);
return () => {
document.removeEventListener("click", handleClickOutside);
};
}
});
// Color handling functions
function getFocusRingClass(color: Button["color"]): string {
switch (color) {
case "primary":
return "focus:ring-2 focus:ring-primary-500 dark:focus:ring-primary-400";
case "blue":
return "focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400";
case "red":
return "focus:ring-2 focus:ring-red-500 dark:focus:ring-red-400";
case "green":
return "focus:ring-2 focus:ring-green-500 dark:focus:ring-green-400";
case "yellow":
return "focus:ring-2 focus:ring-yellow-500 dark:focus:ring-yellow-400";
case "purple":
return "focus:ring-2 focus:ring-purple-500 dark:focus:ring-purple-400";
case "slate":
return "focus:ring-2 focus:ring-slate-500 dark:focus:ring-slate-400";
default:
return "";
}
}
function getRangeBackgroundClass(color: Button["color"]): string {
switch (color) {
case "primary":
return "bg-primary-100 dark:bg-primary-900";
case "blue":
return "bg-blue-100 dark:bg-blue-900";
case "red":
return "bg-red-100 dark:bg-red-900";
case "green":
return "bg-green-100 dark:bg-green-900";
case "yellow":
return "bg-yellow-100 dark:bg-yellow-900";
case "purple":
return "bg-purple-100 dark:bg-purple-900";
case "slate":
return "bg-slate-100 dark:bg-slate-900";
default:
return "";
}
}
function getDaysInMonth(date: Date): Date[] {
const year = date.getFullYear();
const month = date.getMonth();
const firstDay = new Date(year, month, 0);
const lastDay = new Date(year, month + 1, 0);
const daysArray: Date[] = [];
// Add days from previous month to fill the first week
let start = firstDay.getDay() - firstDayOfWeek;
if (start < 0) start += 7;
for (let i = 0; i < start; i++) {
daysArray.unshift(new Date(year, month, -i));
}
// Add days of the current month
for (let i = 1; i <= lastDay.getDate(); i++) {
daysArray.push(new Date(year, month, i));
}
// Add days from next month to fill the last week
const remainingDays = 7 - (daysArray.length % 7);
if (remainingDays < 7) {
for (let i = 1; i <= remainingDays; i++) {
daysArray.push(new Date(year, month + 1, i));
}
}
return daysArray;
}
function getWeekdays(): string[] {
const weekdays = [];
for (let i = 0; i < 7; i++) {
const day = new Date(2021, 5, i + firstDayOfWeek);
weekdays.push(day.toLocaleString(locale, { weekday: "short" }));
}
return weekdays;
}
function changeMonth(increment: number) {
currentMonth = new Date(
currentMonth.getFullYear(),
currentMonth.getMonth() + increment,
1,
);
}
function handleDaySelect(day: Date) {
if (range) {
if (!rangeFrom || (rangeFrom && rangeTo)) {
rangeFrom = day;
rangeTo = null;
} else if (day < rangeFrom) {
rangeTo = rangeFrom;
rangeFrom = day;
} else {
rangeTo = day;
}
dispatch("select", { from: rangeFrom, to: rangeTo });
} else {
value = day;
dispatch("select", value);
if (autohide && !inline) isOpen = false;
}
}
function handleInputChange() {
const date = new Date(inputElement.value);
if (!isNaN(date.getTime())) {
handleDaySelect(date);
}
}
function handleClickOutside(event: MouseEvent) {
if (
isOpen &&
datepickerContainerElement &&
!datepickerContainerElement.contains(event.target as Node)
) {
isOpen = false;
}
}
function formatDate(date: Date | null): string {
if (!date) return "";
return date.toLocaleDateString(locale, dateFormat);
}
function isSameDate(date1: Date | null, date2: Date | null): boolean {
if (!date1 || !date2) return false;
return date1.toDateString() === date2.toDateString();
}
$: isSelected = (day: Date): boolean => {
if (range) {
return isSameDate(day, rangeFrom) || isSameDate(day, rangeTo);
}
return isSameDate(day, value);
};
function isInRange(day: Date): boolean {
if (!range || !rangeFrom || !rangeTo) return false;
return day > rangeFrom && day < rangeTo;
}
function isToday(day: Date): boolean {
const today = new Date();
return day.toDateString() === today.toDateString();
}
function handleCalendarKeydown(event: KeyboardEvent) {
if (!isOpen) return;
if (!focusedDate) {
focusedDate = value || new Date();
}
switch (event.key) {
case "ArrowLeft":
focusedDate = new Date(
focusedDate.getFullYear(),
focusedDate.getMonth(),
focusedDate.getDate() - 1,
);
break;
case "ArrowRight":
focusedDate = new Date(
focusedDate.getFullYear(),
focusedDate.getMonth(),
focusedDate.getDate() + 1,
);
break;
case "ArrowUp":
focusedDate = new Date(
focusedDate.getFullYear(),
focusedDate.getMonth(),
focusedDate.getDate() - 7,
);
break;
case "ArrowDown":
focusedDate = new Date(
focusedDate.getFullYear(),
focusedDate.getMonth(),
focusedDate.getDate() + 7,
);
break;
case "Enter":
handleDaySelect(focusedDate);
break;
case "Escape":
isOpen = false;
inputElement.focus();
break;
default:
return;
}
event.preventDefault();
if (focusedDate.getMonth() !== currentMonth.getMonth()) {
currentMonth = new Date(
focusedDate.getFullYear(),
focusedDate.getMonth(),
1,
);
}
// Focus the button for the focused date
setTimeout(() => {
const focusedButton = calendarRef.querySelector(
`button[aria-label="${focusedDate!.toLocaleDateString(locale, { weekday: "long", year: "numeric", month: "long", day: "numeric" })}"]`,
) as HTMLButtonElement | null;
focusedButton?.focus();
}, 0);
}
function handleInputKeydown(event: KeyboardEvent) {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
isOpen = !isOpen;
}
}
function handleToday() {
handleDaySelect(new Date());
}
function handleClear() {
value = null;
rangeFrom = null;
rangeTo = null;
dispatch("clear");
}
function handleApply() {
dispatch("apply", range ? { from: rangeFrom, to: rangeTo } : value);
if (!inline) isOpen = false;
}
</script>
<div
bind:this={datepickerContainerElement}
class="relative {inline ? 'inline-block' : ''}"
>
{#if !inline}
<div class="relative">
<input
bind:this={inputElement}
type="text"
class="w-full px-4 py-3 text-sm border rounded-md focus:outline-none dark:bg-gray-700 dark:text-white dark:border-gray-600 {getFocusRingClass(
color,
)} {inputClass}"
{placeholder}
value={range
? `${formatDate(rangeFrom)} - ${formatDate(rangeTo)}`
: formatDate(value)}
on:focus={() => (isOpen = true)}
on:input={handleInputChange}
on:keydown={handleInputKeydown}
{disabled}
{required}
aria-haspopup="dialog"
/>
<button
type="button"
class="absolute inset-y-0 right-0 flex items-center px-3 text-gray-500 dark:text-gray-400 focus:outline-none"
on:click={() => (isOpen = !isOpen)}
{disabled}
aria-label={isOpen ? "Close date picker" : "Open date picker"}
>
<svg
class="w-4 h-4 text-gray-500 dark:text-gray-400"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
d="M20 4a2 2 0 0 0-2-2h-2V1a1 1 0 0 0-2 0v1h-3V1a1 1 0 0 0-2 0v1H6V1a1 1 0 0 0-2 0v1H2a2 2 0 0 0-2 2v2h20V4ZM0 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8H0v10Zm5-8h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z"
></path>
</svg>
</button>
</div>
{/if}
{#if isOpen || inline}
<div
bind:this={calendarRef}
id="datepicker-dropdown"
class="
{inline ? '' : 'absolute z-10 mt-1'}
bg-white dark:bg-gray-800 rounded-md shadow-lg"
transition:fade={{ duration: 100 }}
role="dialog"
aria-label="Calendar"
>
<div class="p-4" role="application">
{#if title}
<h2 class="text-lg font-semibold mb-4 dark:text-white">
{title}
</h2>
{/if}
<div class="flex items-center justify-between mb-4">
<Button
on:click={() => changeMonth(-1)}
{color}
size="sm"
aria-label="Previous month"
>
<svg
class="w-3 h-3 rtl:rotate-180 text-white dark:text-white"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 14 10"
><path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 5H1m0 0 4 4M1 5l4-4"
></path></svg
>
</Button>
<h3
class="text-lg font-semibold dark:text-white"
aria-live="polite"
>
{currentMonth.toLocaleString(locale, {
month: "long",
year: "numeric",
})}
</h3>
<Button
on:click={() => changeMonth(1)}
{color}
size="sm"
aria-label="Next month"
>
<svg
class="w-3 h-3 rtl:rotate-180 text-white dark:text-white"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 14 10"
><path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M1 5h12m0 0L9 1m4 4L9 9"
></path></svg
>
</Button>
</div>
<div class="grid grid-cols-7 gap-1" role="grid">
{#each weekdays as day}
<div
class="text-center text-sm font-medium text-gray-500 dark:text-gray-400"
role="columnheader"
>
{day}
</div>
{/each}
{#each daysInMonth as day}
<Button
color={isSelected(day) ? color : "alternative"}
size="sm"
class="w-full h-8 {day.getMonth() !==
currentMonth.getMonth()
? 'text-gray-300 dark:text-gray-600'
: ''} {isToday(day)
? 'font-bold'
: ''} {isInRange(day)
? getRangeBackgroundClass(color)
: ''}"
on:click={() => handleDaySelect(day)}
on:keydown={handleCalendarKeydown}
aria-label={day.toLocaleDateString(locale, {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
})}
aria-selected={isSelected(day)}
role="gridcell"
>
{day.getDate()}
</Button>
{/each}
</div>
{#if showActionButtons}
<div class="mt-4 flex justify-between">
<Button on:click={handleToday} {color} size="sm"
>Today</Button
>
<Button on:click={handleClear} color="red" size="sm"
>Clear</Button
>
<Button on:click={handleApply} {color} size="sm"
>Apply</Button
>
</div>
{/if}
</div>
</div>
{/if}
</div>
<!--
@component
[Go to docs](https://flowbite-svelte.com/)
## Props
@prop export let value: Date | null = null;
@prop export let defaultDate: Date | null = null;
@prop export let range: boolean = false;
@prop export let rangeFrom: Date | null = null;
@prop export let rangeTo: Date | null = null;
@prop export let locale: string = 'default';
@prop export let firstDayOfWeek: number = 0;
@prop export let dateFormat: Intl.DateTimeFormatOptions = { year: 'numeric', month: 'long', day: 'numeric' };
@prop export let placeholder: string = 'Select date';
@prop export let disabled: boolean = false;
@prop export let required: boolean = false;
@prop export let inputClass: string = '';
@prop export let color: Button['color'] = 'primary';
@prop export let inline: boolean = false;
@prop export let autohide: boolean = true;
@prop export let showActionButtons: boolean = false;
@prop export let title: string = '';
-->

View File

@ -0,0 +1,37 @@
import moment from "moment";
const convertAniListDateToString = (date: {
year?: number;
month?: number;
day?: number;
}): string => {
if (
date.year === undefined ||
(date.year === 0 && date.month === undefined) ||
(date.month === 0 && date.day === undefined) ||
date.day === 0
) {
return "";
}
const newISODate = new Date(date.year, date.month - 1, date.day);
const newMoment = moment(newISODate);
return newMoment.format("MM-DD-YYYY");
};
const convertAniListDateToDate = (date: {
year?: number;
month?: number;
day?: number;
}): Date | null => {
if (
date.year === undefined ||
(date.year === 0 && date.month === undefined) ||
(date.month === 0 && date.day === undefined) ||
date.day === 0
) {
return null;
}
return new Date(date.year, date.month - 1, date.day);
};
export { convertAniListDateToString, convertAniListDateToDate };

View File

@ -1,17 +0,0 @@
import moment from "moment";
export default (date: {
year?: number,
month?: number,
day?: number,
}): string => {
if (date.year === undefined || date.year === 0
&& date.month === undefined || date.month === 0
&& date.day === undefined || date.day === 0
) {
return ""
}
const newISODate = new Date(date.year, date.month - 1, date.day)
const newMoment = moment(newISODate)
return newMoment.format('YYYY-MM-DD')
}

View File

@ -1,22 +0,0 @@
type Date = {
year: number,
month: number,
day: number,
}
export default (date: string): Date => {
if (date === "") {
return {
year: 0,
month: 0,
day: 0,
}
}
const re = /^([0-9]{4})-([0-9]{2})-([0-9]{2})/
const newDate = re.exec(date)
return {
year: Number(newDate[1]),
month: Number(newDate[2]),
day: Number(newDate[3])
}
}

View File

@ -0,0 +1,39 @@
type AnilistDate = {
year: number;
month: number;
day: number;
};
const convertDateStringToAniList = (date: string): AnilistDate => {
if (date === "") {
return {
year: 0,
month: 0,
day: 0,
};
}
const re = /^([0-9]{4})-([0-9]{2})-([0-9]{2})/;
const newDate = re.exec(date);
return {
year: Number(newDate[1]),
month: Number(newDate[2]),
day: Number(newDate[3]),
};
};
const convertDateToAniList = (date: Date | null): AnilistDate => {
if (date === null) {
return {
year: 0,
month: 0,
day: 0,
};
}
return {
year: Number(date.getFullYear()),
month: Number(date.getMonth()) + 1,
day: Number(date.getDate()),
};
};
export { convertDateStringToAniList, convertDateToAniList };

View File

@ -202,8 +202,7 @@ export namespace main {
export class MALAnime { export class MALAnime {
id: id; id: id;
title: title; title: title;
// Go type: struct { Large string "json:\"large\" json:\"large\""; Medium string "json:\"medium\" json:\"medium\"" } main_picture: mainPicture;
main_picture: any;
alternative_titles: alternativeTitles; alternative_titles: alternativeTitles;
start_date: startDate; start_date: startDate;
end_date: endDate; end_date: endDate;
@ -242,7 +241,7 @@ export namespace main {
if ('string' === typeof source) source = JSON.parse(source); if ('string' === typeof source) source = JSON.parse(source);
this.id = source["id"]; this.id = source["id"];
this.title = source["title"]; this.title = source["title"];
this.main_picture = this.convertValues(source["main_picture"], Object); this.main_picture = source["main_picture"];
this.alternative_titles = source["alternative_titles"]; this.alternative_titles = source["alternative_titles"];
this.start_date = source["start_date"]; this.start_date = source["start_date"];
this.end_date = source["end_date"]; this.end_date = source["end_date"];
@ -314,7 +313,7 @@ export namespace main {
} }
} }
export class MALWatchlist { export class MALWatchlist {
data: struct { Node struct { Id int "json:\"id\" ts_type:\"id\""; Title string "json:\"title\" ts_type:\"title\""; MainPicture struct { Medium string "json:\"medium\" json:\"medium\""; Large string "json:\"large\" json:\"large\"" } "json:\"main_picture\" json:\"mainPicture\"" } "json:\"node\" json:\"node\""; ListStatus struct { Status string "json:\"status\" ts_type:\"status\""; Score int "json:\"score\" ts_type:\"score\""; NumEpisodesWatched int "json:\"num_episodes_watched\" ts_type:\"numEpisodesWatched\""; IsRewatching bool "json:\"is_rewatching\" ts_type:\"isRewatching\""; UpdatedAt time.Time "json:\"updated_at\" ts_type:\"updatedAt\""; StartDate string "json:\"start_date\" ts_type:\"startDate\""; FinishDate string "json:\"finish_date\" ts_type:\"finishDate\"" } "json:\"list_status\" ts_type:\"listStatus\"" }[]; data: data;
paging: paging; paging: paging;
static createFrom(source: any = {}) { static createFrom(source: any = {}) {
@ -323,27 +322,9 @@ export namespace main {
constructor(source: any = {}) { constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source); if ('string' === typeof source) source = JSON.parse(source);
this.data = this.convertValues(source["data"], struct { Node struct { Id int "json:\"id\" ts_type:\"id\""; Title string "json:\"title\" ts_type:\"title\""; MainPicture struct { Medium string "json:\"medium\" json:\"medium\""; Large string "json:\"large\" json:\"large\"" } "json:\"main_picture\" json:\"mainPicture\"" } "json:\"node\" json:\"node\""; ListStatus struct { Status string "json:\"status\" ts_type:\"status\""; Score int "json:\"score\" ts_type:\"score\""; NumEpisodesWatched int "json:\"num_episodes_watched\" ts_type:\"numEpisodesWatched\""; IsRewatching bool "json:\"is_rewatching\" ts_type:\"isRewatching\""; UpdatedAt time.Time "json:\"updated_at\" ts_type:\"updatedAt\""; StartDate string "json:\"start_date\" ts_type:\"startDate\""; FinishDate string "json:\"finish_date\" ts_type:\"finishDate\"" } "json:\"list_status\" ts_type:\"listStatus\"" }); this.data = source["data"];
this.paging = source["paging"]; this.paging = source["paging"];
} }
convertValues(a: any, classs: any, asMap: boolean = false): any {
if (!a) {
return a;
}
if (a.slice && a.map) {
return (a as any[]).map(elem => this.convertValues(elem, classs));
} else if ("object" === typeof a) {
if (asMap) {
for (const key of Object.keys(a)) {
a[key] = new classs(a[key]);
}
return a;
}
return new classs(a);
}
return a;
}
} }
export class MalListStatus { export class MalListStatus {
status: status; status: status;
@ -624,11 +605,10 @@ export namespace struct { Node main {
} }
export namespace struct { Node struct { Id int "json:\"id\" ts_type:\"id\""; Title string "json:\"title\" ts_type:\"title\""; MainPicture struct { Medium string "json:\"medium\" json:\"medium\""; Large string "json:\"large\" json:\"large\"" } "json:\"main_picture\" json:\"mainPicture\"" } "json:\"node\" json:\"node\""; ListStatus struct { Status string "json:\"status\" ts_type:\"status\""; Score int "json:\"score\" ts_type:\"score\""; NumEpisodesWatched int "json:\"num_episodes_watched\" ts_type:\"numEpisodesWatched\""; IsRewatching bool "json:\"is_rewatching\" ts_type:\"isRewatching\""; UpdatedAt time { export namespace struct { Node struct { Id int "json:\"id\" ts_type:\"id\""; Title string "json:\"title\" ts_type:\"title\""; MainPicture struct { Medium string "json:\"medium\" ts_type:\"medium\""; Large string "json:\"large\" ts_type:\"large\"" } "json:\"main_picture\" ts_type:\"mainPicture\"" } "json:\"node\" ts_type:\"node\""; ListStatus struct { Status string "json:\"status\" ts_type:\"status\""; Score int "json:\"score\" ts_type:\"score\""; NumEpisodesWatched int "json:\"num_episodes_watched\" ts_type:\"numEpisodesWatched\""; IsRewatching bool "json:\"is_rewatching\" ts_type:\"isRewatching\""; UpdatedAt time {
export class { export class {
// Go type: struct { Id int "json:\"id\" ts_type:\"id\""; Title string "json:\"title\" ts_type:\"title\""; MainPicture struct { Medium string "json:\"medium\" json:\"medium\""; Large string "json:\"large\" json:\"large\"" } "json:\"main_picture\" json:\"mainPicture\"" } node: node;
node: any;
list_status: listStatus; list_status: listStatus;
static createFrom(source: any = {}) { static createFrom(source: any = {}) {
@ -637,27 +617,9 @@ export namespace struct { Node struct { Id int "json:\"id\" ts_type:\"id\""; Tit
constructor(source: any = {}) { constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source); if ('string' === typeof source) source = JSON.parse(source);
this.node = this.convertValues(source["node"], Object); this.node = source["node"];
this.list_status = source["list_status"]; this.list_status = source["list_status"];
} }
convertValues(a: any, classs: any, asMap: boolean = false): any {
if (!a) {
return a;
}
if (a.slice && a.map) {
return (a as any[]).map(elem => this.convertValues(elem, classs));
} else if ("object" === typeof a) {
if (asMap) {
for (const key of Object.keys(a)) {
a[key] = new classs(a[key]);
}
return a;
}
return new classs(a);
}
return a;
}
} }
} }

18
go.mod
View File

@ -12,20 +12,20 @@ require (
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/bep/debounce v1.2.1 // indirect github.com/bep/debounce v1.2.1 // indirect
github.com/danieljoos/wincred v1.2.2 // indirect github.com/danieljoos/wincred v1.2.2 // indirect
github.com/dvsekhvalnov/jose2go v1.7.0 // indirect github.com/dvsekhvalnov/jose2go v1.8.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/labstack/echo/v4 v4.12.0 // indirect github.com/labstack/echo/v4 v4.13.3 // indirect
github.com/labstack/gommon v0.4.2 // indirect github.com/labstack/gommon v0.4.2 // indirect
github.com/leaanthony/go-ansi-parser v1.6.1 // indirect github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
github.com/leaanthony/gosod v1.0.4 // indirect github.com/leaanthony/gosod v1.0.4 // indirect
github.com/leaanthony/slicer v1.6.0 // indirect github.com/leaanthony/slicer v1.6.0 // indirect
github.com/leaanthony/u v1.1.1 // indirect github.com/leaanthony/u v1.1.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mtibben/percent v0.2.1 // indirect github.com/mtibben/percent v0.2.1 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
@ -37,13 +37,13 @@ require (
github.com/tkrajina/go-reflector v0.5.8 // indirect github.com/tkrajina/go-reflector v0.5.8 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/wailsapp/go-webview2 v1.0.16 // indirect github.com/wailsapp/go-webview2 v1.0.19 // indirect
github.com/wailsapp/mimetype v1.4.1 // indirect github.com/wailsapp/mimetype v1.4.1 // indirect
golang.org/x/crypto v0.28.0 // indirect golang.org/x/crypto v0.32.0 // indirect
golang.org/x/net v0.30.0 // indirect golang.org/x/net v0.34.0 // indirect
golang.org/x/sys v0.26.0 // indirect golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.25.0 // indirect golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.19.0 // indirect golang.org/x/text v0.21.0 // indirect
) )
// replace github.com/wailsapp/wails/v2 v2.9.1 => /home/nymusicman/go/pkg/mod // replace github.com/wailsapp/wails/v2 v2.9.1 => /home/nymusicman/go/pkg/mod

42
go.sum
View File

@ -8,8 +8,8 @@ github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ
github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8= github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo= github.com/dvsekhvalnov/jose2go v1.8.0 h1:LqkkVKAlHFfH9LOEl5fe4p/zL02OhWE7pCufMBG2jLA=
github.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/dvsekhvalnov/jose2go v1.8.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
@ -25,8 +25,8 @@ github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEE
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
@ -42,9 +42,8 @@ github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQc
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
@ -64,8 +63,8 @@ github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= 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/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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= 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 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
@ -79,31 +78,30 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 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 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/wailsapp/go-webview2 v1.0.16 h1:wffnvnkkLvhRex/aOrA3R7FP7rkvOqL/bir1br7BekU= github.com/wailsapp/go-webview2 v1.0.19 h1:7U3QcDj1PrBPaxJNCui2k1SkWml+Q5kvFUFyTImA6NU=
github.com/wailsapp/go-webview2 v1.0.16/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= 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/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
github.com/wailsapp/wails/v2 v2.9.2 h1:Xb5YRTos1w5N7DTMyYegWaGukCP2fIaX9WF21kPPF2k= github.com/wailsapp/wails/v2 v2.9.2 h1:Xb5YRTos1w5N7DTMyYegWaGukCP2fIaX9WF21kPPF2k=
github.com/wailsapp/wails/v2 v2.9.2/go.mod h1:uehvlCwJSFcBq7rMCGfk4rxca67QQGsbg5Nm4m9UnBs= 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.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-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-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.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.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.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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 h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -34,9 +34,9 @@ func main() {
app, app,
}, },
Linux: &linux.Options{ Linux: &linux.Options{
Icon: []byte("./build/appicon.png"), Icon: []byte("./build/AniTrack.png"),
WindowIsTranslucent: false, WindowIsTranslucent: false,
WebviewGpuPolicy: linux.WebviewGpuPolicyAlways, WebviewGpuPolicy: linux.WebviewGpuPolicyNever,
ProgramName: "AniTrack", ProgramName: "AniTrack",
}, },
}) })

View File

@ -12,6 +12,6 @@
}, },
"info": { "info": {
"productName": "AniTrack", "productName": "AniTrack",
"productVersion": "0.1.4" "productVersion": "0.1.6"
} }
} }