fix(anilist): decode array-shaped airingSchedule/relations and isolate per-service sync errors
The 1.6.1 fix exposed a latent decoding bug: AniList returns airingSchedule.nodes and relations.nodes as arrays, but the Go Media struct declared Nodes as single structs. Every full-media response failed json.Unmarshal partway through - the update path turned that into a rejected promise which skipped the MAL and Simkl syncs and all table updates, while page loads silently continued with partially decoded data (the reason the old tags/genres copy workaround existed). - Media.AiringSchedule.Nodes is now []AiringScheduleNode and Media.Relations is an exported []MediaRelation (previously an unexported field silently dropped by encoding/json); title and fuzzy-date sub-structs promoted to named types. - Regenerate wailsjs models for the new shapes. - Anime.svelte: handleSubmit and deleteEntries now wrap each service in its own try/catch surfaced via setApiError/ErrorModal, so one service failing can no longer skip the others; removed the obsolete tags/genres copy workaround. - AniListUpdateEntry/AniListDeleteEntry log HTTP status and response body on failure for terminal diagnostics. Bump productVersion to 1.6.2.
This commit is contained in:
+161
-15
@@ -1,5 +1,25 @@
|
||||
export namespace main {
|
||||
|
||||
export class AiringScheduleNode {
|
||||
id: number;
|
||||
airingAt: number;
|
||||
timeUntilAiring: number;
|
||||
episode: number;
|
||||
mediaId: number;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new AiringScheduleNode(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.id = source["id"];
|
||||
this.airingAt = source["airingAt"];
|
||||
this.timeUntilAiring = source["timeUntilAiring"];
|
||||
this.episode = source["episode"];
|
||||
this.mediaId = source["mediaId"];
|
||||
}
|
||||
}
|
||||
export class AniListCurrentUserWatchList {
|
||||
data: struct { Page struct { PageInfo struct { Total int "json:\"total\""; PerPage int "json:\"perPage\""; CurrentPage int "json:\"currentPage\""; LastPage int "json:\"lastPage\""; HasNextPage bool "json:\"hasNextPage\"" } "json:\"pageInfo\""; MediaList []main.;
|
||||
|
||||
@@ -381,11 +401,136 @@ export namespace main {
|
||||
this.isAdult = source["isAdult"];
|
||||
}
|
||||
}
|
||||
export class MediaAiringSchedule {
|
||||
nodes: AiringScheduleNode[];
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new MediaAiringSchedule(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.nodes = this.convertValues(source["nodes"], AiringScheduleNode);
|
||||
}
|
||||
|
||||
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 MediaFuzzyDate {
|
||||
year: number;
|
||||
month: number;
|
||||
day: number;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new MediaFuzzyDate(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.year = source["year"];
|
||||
this.month = source["month"];
|
||||
this.day = source["day"];
|
||||
}
|
||||
}
|
||||
export class MediaRelation {
|
||||
id: number;
|
||||
title: MediaTitle;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new MediaRelation(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.id = source["id"];
|
||||
this.title = this.convertValues(source["title"], MediaTitle);
|
||||
}
|
||||
|
||||
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 MediaRelations {
|
||||
nodes: MediaRelation[];
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new MediaRelations(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.nodes = this.convertValues(source["nodes"], MediaRelation);
|
||||
}
|
||||
|
||||
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 MediaTitle {
|
||||
userPreferred: string;
|
||||
romaji: string;
|
||||
english: string;
|
||||
native: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new MediaTitle(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.userPreferred = source["userPreferred"];
|
||||
this.romaji = source["romaji"];
|
||||
this.english = source["english"];
|
||||
this.native = source["native"];
|
||||
}
|
||||
}
|
||||
export class Media {
|
||||
id: number;
|
||||
idMal: number;
|
||||
// Go type: struct { UserPreferred string "json:\"userPreferred\""; Romaji string "json:\"romaji\""; English string "json:\"english\""; Native string "json:\"native\"" }
|
||||
title: any;
|
||||
title: MediaTitle;
|
||||
description: string;
|
||||
// Go type: struct { ExtraLarge string; Large string "json:\"large\""; Medium string; Color string }
|
||||
coverImage: any;
|
||||
@@ -404,16 +549,12 @@ export namespace main {
|
||||
Popularity: number;
|
||||
Trending: number;
|
||||
Favourites: number;
|
||||
// Go type: struct { nodes struct { id int; Title struct { UserPreferred string "json:\"userPreferred\""; Romaji string "json:\"romaji\""; English string "json:\"english\""; Native string "json:\"native\"" } "json:\"title\"" } }
|
||||
Relations: any;
|
||||
// Go type: struct { Year int; Month int; Day int }
|
||||
StartDate: any;
|
||||
// Go type: struct { Year int; Month int; Day int }
|
||||
EndDate: any;
|
||||
relations: MediaRelations;
|
||||
startDate: MediaFuzzyDate;
|
||||
endDate: MediaFuzzyDate;
|
||||
// Go type: struct { AiringAt int "json:\"airingAt\""; TimeUntilAiring int "json:\"timeUntilAiring\""; Episode int "json:\"episode\"" }
|
||||
nextAiringEpisode: any;
|
||||
// Go type: struct { Nodes struct { Id int; AiringAt int; TimeUntilAiring int; Episode int; MediaId int } }
|
||||
AiringSchedule: any;
|
||||
airingSchedule: MediaAiringSchedule;
|
||||
genres: string[];
|
||||
tags: [];
|
||||
isAdult: boolean;
|
||||
@@ -426,7 +567,7 @@ export namespace main {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.id = source["id"];
|
||||
this.idMal = source["idMal"];
|
||||
this.title = this.convertValues(source["title"], Object);
|
||||
this.title = this.convertValues(source["title"], MediaTitle);
|
||||
this.description = source["description"];
|
||||
this.coverImage = this.convertValues(source["coverImage"], Object);
|
||||
this.BannerImage = source["BannerImage"];
|
||||
@@ -444,11 +585,11 @@ export namespace main {
|
||||
this.Popularity = source["Popularity"];
|
||||
this.Trending = source["Trending"];
|
||||
this.Favourites = source["Favourites"];
|
||||
this.Relations = this.convertValues(source["Relations"], Object);
|
||||
this.StartDate = this.convertValues(source["StartDate"], Object);
|
||||
this.EndDate = this.convertValues(source["EndDate"], Object);
|
||||
this.relations = this.convertValues(source["relations"], MediaRelations);
|
||||
this.startDate = this.convertValues(source["startDate"], MediaFuzzyDate);
|
||||
this.endDate = this.convertValues(source["endDate"], MediaFuzzyDate);
|
||||
this.nextAiringEpisode = this.convertValues(source["nextAiringEpisode"], Object);
|
||||
this.AiringSchedule = this.convertValues(source["AiringSchedule"], Object);
|
||||
this.airingSchedule = this.convertValues(source["airingSchedule"], MediaAiringSchedule);
|
||||
this.genres = source["genres"];
|
||||
this.tags = this.convertValues(source["tags"], );
|
||||
this.isAdult = source["isAdult"];
|
||||
@@ -472,6 +613,8 @@ export namespace main {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class MediaList {
|
||||
id: number;
|
||||
mediaId: number;
|
||||
@@ -527,6 +670,9 @@ export namespace main {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class MyAnimeListUser {
|
||||
id: id;
|
||||
name: name;
|
||||
|
||||
Reference in New Issue
Block a user