Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f92b1714e | |||
| cd142f7601 | |||
| fe48e6a8c4 | |||
| 24d4d24edf | |||
| b68abfc1c9 | |||
| eadc96fb4f | |||
| 6a662cdf6e | |||
| 2a9777872f | |||
| b03d4ab7e3 | |||
| ff1b8fb742 | |||
| cbd4c7cd01 | |||
| 335d757255 |
12
Makefile
Normal file
12
Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
TAGS := webkit2_41
|
||||
|
||||
.PHONY: dev build clean
|
||||
|
||||
dev:
|
||||
wails dev -tags $(TAGS)
|
||||
|
||||
build:
|
||||
wails build -tags $(TAGS)
|
||||
|
||||
clean:
|
||||
rm -rf build/bin/*
|
||||
@@ -1,166 +0,0 @@
|
||||
# 🎉 AniTrack v0.7.0 Release Notes
|
||||
|
||||
## 🚨 Major Feature: Comprehensive Error Handling
|
||||
|
||||
This release brings **massive improvements** to application stability and user experience. The app will **no longer crash** when API services are down or experiencing errors!
|
||||
|
||||
---
|
||||
|
||||
## ✨ What's New
|
||||
|
||||
### 🛡️ Graceful API Error Handling
|
||||
- **Application Stability**: App now remains running even when AniList, MAL, or Simkl APIs are down
|
||||
- **Visual Error Feedback**: Beautiful modal dialogs display error details instead of silent crashes
|
||||
- **Manual Retry**: Users can retry failed API connections with a single button click
|
||||
- **Continue Using App**: Dismiss error messages and continue with limited functionality
|
||||
|
||||
### 🔧 Backend Improvements
|
||||
|
||||
#### AniList Integration
|
||||
- Replaced all `log.Fatal()` calls with proper error returns
|
||||
- Added error handling for API failures, network issues, and authentication errors
|
||||
- `AniListSearch` now returns detailed error messages
|
||||
- `GetAniListUserWatchingList` gracefully handles 403/404 responses
|
||||
|
||||
#### MyAnimeList Integration
|
||||
- Updated `MALHelper` to return structured errors
|
||||
- All MAL API functions now return errors instead of crashing:
|
||||
- `GetMyAnimeList`
|
||||
- `MyAnimeListUpdate`
|
||||
- `GetMyAnimeListAnime`
|
||||
- `DeleteMyAnimeListEntry`
|
||||
- Fixed OAuth callback server to prevent shutdown on errors
|
||||
|
||||
#### Simkl Integration
|
||||
- Updated `SimklHelper` with status code validation (200-299 range)
|
||||
- All Simkl API functions now return errors:
|
||||
- `SimklGetUserWatchlist`
|
||||
- `SimklSyncEpisodes`
|
||||
- `SimklSyncRating`
|
||||
- `SimklSyncStatus`
|
||||
- `SimklSearch`
|
||||
- `SimklSyncRemove`
|
||||
- Replaced `log.Fatal()` with proper error logging
|
||||
|
||||
### 💻 Frontend Improvements
|
||||
|
||||
#### New Error Management System
|
||||
- **Centralized Error State**: New reactive stores for API errors
|
||||
- `apiError` - Tracks current error with service, message, and status
|
||||
- `isApiDown` - Quick flag for API availability
|
||||
- **Error Helper Functions**:
|
||||
- `setApiError()` - Set error state from any component
|
||||
- `clearApiError()` - Reset error state
|
||||
|
||||
#### New Error Modal Component
|
||||
- Auto-displays when API errors occur
|
||||
- Shows service name, error message, and HTTP status code
|
||||
- **"Retry Connection"** button - Attempts to reconnect to the failed service
|
||||
- **"Dismiss"** button - Close modal and continue using the app
|
||||
- Beautiful red-themed styling with Tailwind CSS
|
||||
- Supports all three services (AniList, MAL, Simkl)
|
||||
|
||||
#### Updated User Interface
|
||||
- Home page now displays "API Unavailable" state when services are down
|
||||
- Helpful warning messages guide users during outages
|
||||
- App structure remains visible and functional during errors
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
|
||||
- **Critical**: Fixed app crashes when AniList API returns 403 Forbidden errors
|
||||
- **Critical**: Fixed app crashes when AniList API is down or unreachable
|
||||
- **Critical**: Fixed MAL OAuth server crashing on connection errors
|
||||
- **Critical**: Fixed Simkl JSON marshaling errors crashing the app
|
||||
- **Improved**: Better error messages for all API failures
|
||||
|
||||
---
|
||||
|
||||
## 📊 Technical Details
|
||||
|
||||
### Go Backend Changes
|
||||
- **AniListFunctions.go**: Updated 3 functions with error handling
|
||||
- **MALFunctions.go**: Updated 5 functions with error handling
|
||||
- **MALUserFunctions.go**: Fixed server error handling
|
||||
- **SimklFunctions.go**: Updated 7 functions with error handling
|
||||
- **SimklUserFunctions.go**: Fixed 2 critical error handling issues
|
||||
|
||||
### Frontend Changes
|
||||
- **ErrorModal.svelte**: New component (73 lines)
|
||||
- **GlobalVariablesAndHelperFunctions.svelte**: Added error state system (27 lines)
|
||||
- **App.svelte**: Integrated ErrorModal into main layout
|
||||
- **CheckIfAniListLoggedInAndLoadWatchList.svelte**: Added error handling
|
||||
- **Home.svelte**: Added API down state display
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Impact
|
||||
|
||||
### Before (v0.6.5)
|
||||
- ❌ App crashes to desktop when AniList API is down
|
||||
- ❌ Users see only console error messages
|
||||
- ❌ Must restart app after API failures
|
||||
- ❌ No way to retry failed connections
|
||||
|
||||
### After (v0.7.0)
|
||||
- ✅ App stays open during any API failures
|
||||
- ✅ Beautiful modal dialogs explain what went wrong
|
||||
- ✅ One-click retry to reconnect services
|
||||
- ✅ Continue using app with limited functionality
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Upgrading
|
||||
|
||||
No migration needed! This release is fully backward compatible.
|
||||
|
||||
Simply run:
|
||||
```bash
|
||||
git pull
|
||||
wails build
|
||||
```
|
||||
|
||||
Or download the latest release from the releases page.
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
This release addresses a critical stability issue that was affecting users during API service outages. Special thanks to the community for reporting these crashes and providing detailed error logs.
|
||||
|
||||
---
|
||||
|
||||
## 📝 Full Changelog
|
||||
|
||||
### Added
|
||||
- Error modal component with retry/dismiss functionality
|
||||
- Centralized error state management system
|
||||
- API availability status tracking
|
||||
- Visual feedback for all API failures
|
||||
- Manual retry functionality for all services
|
||||
|
||||
### Changed
|
||||
- AniList API functions to return errors instead of crashing
|
||||
- MAL API functions to return errors instead of crashing
|
||||
- Simkl API functions to return errors instead of crashing
|
||||
- Error handling from console-only to UI modal dialogs
|
||||
- App behavior from crash-on-error to graceful-degradation
|
||||
|
||||
### Fixed
|
||||
- App crashes on AniList 403 errors
|
||||
- App crashes on network failures
|
||||
- MAL OAuth server shutdown on errors
|
||||
- Simkl JSON marshaling crashes
|
||||
- All `log.Fatal()` calls that terminated the app
|
||||
|
||||
### Removed
|
||||
- `alert()` calls in favor of modal system
|
||||
- Vite timestamp file (cleanup)
|
||||
|
||||
---
|
||||
|
||||
**Version**: 0.7.0
|
||||
**Release Date**: March 2026
|
||||
**Upgrade Difficulty**: ⭐ Easy (backward compatible)
|
||||
**Recommended**: ⭐⭐⭐⭐⭐ Highly recommended for all users
|
||||
@@ -118,7 +118,7 @@
|
||||
</ul>
|
||||
</nav>
|
||||
{/if}
|
||||
<div class="flex mt-5">
|
||||
<div class="flex">
|
||||
<div class="w-20 mx-auto">
|
||||
<select
|
||||
bind:value={perPage}
|
||||
|
||||
18
frontend/src/helperComponents/RefreshWatchListButton.svelte
Normal file
18
frontend/src/helperComponents/RefreshWatchListButton.svelte
Normal file
@@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { CheckIfAniListLoggedInAndLoadWatchList } from "../helperModules/CheckIfAniListLoggedInAndLoadWatchList.svelte";
|
||||
import { loading } from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
|
||||
</script>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<button
|
||||
type="button"
|
||||
class="py-2 px-4 mt-4 mr-4 bg-gray-700 rounded-lg"
|
||||
on:click={async () => {
|
||||
loading.set(true);
|
||||
await CheckIfAniListLoggedInAndLoadWatchList();
|
||||
loading.set(false);
|
||||
}}
|
||||
>
|
||||
Refresh WatchList
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,77 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
aniListSort,
|
||||
watchListPage,
|
||||
animePerPage,
|
||||
aniListWatchlist,
|
||||
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
|
||||
import { MediaListSort } from "../anilist/types/AniListTypes";
|
||||
import { GetAniListUserWatchingList } from "../../wailsjs/go/main/App";
|
||||
|
||||
const sortTypes = [
|
||||
{ value: MediaListSort.MediaId, name: "Media Id Asc" },
|
||||
{ value: MediaListSort.MediaIdDesc, name: "Media Id Desc" },
|
||||
{ value: MediaListSort.Score, name: "Score Asc" },
|
||||
{ value: MediaListSort.ScoreDesc, name: "Score Desc" },
|
||||
{ value: MediaListSort.Status, name: "Status Asc" },
|
||||
{ value: MediaListSort.StatusDesc, name: "Status Desc" },
|
||||
{ value: MediaListSort.Progress, name: "Progress Asc" },
|
||||
{ value: MediaListSort.ProgressDesc, name: "Progress Desc" },
|
||||
{ value: MediaListSort.ProgressVolumes, name: "Progress Valumes Asc" },
|
||||
{ value: MediaListSort.ProgressVolumesDesc, name: "Progress Valumes Desc" },
|
||||
{ value: MediaListSort.Repeat, name: "Repeat Asc" },
|
||||
{ value: MediaListSort.RepeatDesc, name: "Repeat Desc" },
|
||||
{ value: MediaListSort.Priority, name: "Priority Asc" },
|
||||
{ value: MediaListSort.PriorityDesc, name: "Priority Desc" },
|
||||
{ value: MediaListSort.StartedOn, name: "Started On Asc" },
|
||||
{ value: MediaListSort.StartedOnDesc, name: "Started On Desc" },
|
||||
{ value: MediaListSort.FinishedOn, name: "Finished On Asc" },
|
||||
{ value: MediaListSort.FinishedOnDesc, name: "Finished On Desc" },
|
||||
{ value: MediaListSort.AddedTime, name: "Added Time Asc" },
|
||||
{ value: MediaListSort.AddedTimeDesc, name: "Added Time Desc" },
|
||||
{ value: MediaListSort.UpdatedTime, name: "Updated Time Asc" },
|
||||
{ value: MediaListSort.UpdatedTimeDesc, name: "Updated Time Desc" },
|
||||
{ value: MediaListSort.MediaTitleRomaji, name: "Media Title Romaji Asc" },
|
||||
{
|
||||
value: MediaListSort.MediaTitleRomajiDesc,
|
||||
name: "Media Title Romaji Desc",
|
||||
},
|
||||
{ value: MediaListSort.MediaTitleEnglish, name: "Media Title English Asc" },
|
||||
{
|
||||
value: MediaListSort.MediaTitleEnglishDesc,
|
||||
name: "Media Title English Desc",
|
||||
},
|
||||
{ value: MediaListSort.MediaTitleNative, name: "Media Title Native Asc" },
|
||||
{
|
||||
value: MediaListSort.MediaTitleNativeDesc,
|
||||
name: "Media Title Native Desc",
|
||||
},
|
||||
{ value: MediaListSort.MediaPopularity, name: "Media Popularity Asc" },
|
||||
{ value: MediaListSort.MediaPopularityDesc, name: "Media Popularity Desc" },
|
||||
];
|
||||
|
||||
let sort: string;
|
||||
aniListSort.subscribe((value) => (sort = value));
|
||||
console.log(sort);
|
||||
|
||||
async function changeWatchListSort() {
|
||||
const result = await GetAniListUserWatchingList(
|
||||
$watchListPage,
|
||||
$animePerPage,
|
||||
$aniListSort,
|
||||
);
|
||||
aniListWatchlist.set(result);
|
||||
}
|
||||
</script>
|
||||
|
||||
<select
|
||||
id="sort"
|
||||
class="border rounded-lg block p-1.5 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500"
|
||||
bind:value={$aniListSort}
|
||||
on:change={() => changeWatchListSort()}
|
||||
>
|
||||
<option value="" disabled>Sort WatchList</option>
|
||||
{#each sortTypes as sort}
|
||||
<option value={sort.value}>{sort.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import { Rating } from "flowbite-svelte";
|
||||
import loader from "../helperFunctions/loader";
|
||||
import { CheckIfAniListLoggedInAndLoadWatchList } from "../helperModules/CheckIfAniListLoggedInAndLoadWatchList.svelte";
|
||||
import Sort from "../helperComponents/Sort.svelte";
|
||||
|
||||
let isAniListLoggedIn: boolean;
|
||||
let aniListWatchListLoaded: AniListCurrentUserWatchList;
|
||||
@@ -25,17 +26,7 @@
|
||||
>
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h1 class="text-left text-xl font-bold">Your AniList WatchList</h1>
|
||||
<button
|
||||
type="button"
|
||||
class="py-2 px-4 bg-gray-700 rounded-lg"
|
||||
on:click={async () => {
|
||||
loading.set(true);
|
||||
await CheckIfAniListLoggedInAndLoadWatchList();
|
||||
loading.set(false);
|
||||
}}
|
||||
>
|
||||
Refresh WatchList
|
||||
</button>
|
||||
<Sort />
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import Pagination from "../helperComponents/Pagination.svelte";
|
||||
import WatchList from "../helperComponents/WatchList.svelte";
|
||||
import RefreshWatchListButton from "../helperComponents/RefreshWatchListButton.svelte";
|
||||
import {
|
||||
aniListLoggedIn,
|
||||
aniListPrimary,
|
||||
@@ -45,6 +46,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{:else if isAniListLoggedIn && isAniListPrimary}
|
||||
<RefreshWatchListButton />
|
||||
<div class="container py-10">
|
||||
<Pagination />
|
||||
<WatchList />
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
"frontend:dev:serverUrl": "auto",
|
||||
"author": {
|
||||
"name": "John O'Keefe",
|
||||
"email": "jokeefe@fastmail.com"
|
||||
"email": "admin@linuxhg.com"
|
||||
},
|
||||
"info": {
|
||||
"productName": "AniTrack",
|
||||
"productVersion": "0.7.0"
|
||||
"productVersion": "1.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user