From c5f3a60660553ef909297ad10e5db574737a49d9 Mon Sep 17 00:00:00 2001 From: oPisiti Date: Mon, 24 Jun 2024 19:30:49 -0300 Subject: [PATCH 1/9] Initial implementation of ryot import process --- src/routes/(app)/import/+page.svelte | 118 +++++++++++++++++++ src/routes/(app)/import/process/+page.svelte | 13 ++ src/store.ts | 2 +- 3 files changed, 132 insertions(+), 1 deletion(-) diff --git a/src/routes/(app)/import/+page.svelte b/src/routes/(app)/import/+page.svelte index 889d9c5e..751433c0 100644 --- a/src/routes/(app)/import/+page.svelte +++ b/src/routes/(app)/import/+page.svelte @@ -369,6 +369,119 @@ } } + async function processRyotFile(files?: FileList | null) { + try { + console.log("processRyotFile", files); + if (!files || files?.length <= 0) { + console.error("processRyotFile", "No files to process!"); + notify({ + type: "error", + text: "File not found in dropped items. Please try again or refresh.", + time: 6000 + }); + isDragOver = false; + return; + } + isLoading = true; + if (files.length > 1) { + notify({ + type: "error", + text: "Only one file at a time is supported. Continuing with the first.", + time: 6000 + }); + } + + // Currently only support for importing one file at a time + const file = files[0]; + if (file.type !== "application/json") { + notify({ + type: "error", + text: "Must be a Ryot JSON export file" + }); + isLoading = false; + isDragOver = false; + return; + } + + // Build toImport array + const toImport: ImportedList[] = []; + const fileText = await readFile(new FileReader(), file); + const jsonData = JSON.parse(fileText)["media"] as Watched[]; + for (const v of jsonData) { + if (!v.source_id || !v.identifier) { + notify({ + type: "error", + text: "Item in export has no title or TMDB identifier! Look in console for more details." + }); + console.error( + "Can't add export item to import table! It has no source_id or identifier! Item:", + v + ); + continue; + } + + // Create t + let t; + if(v.lot === "movie"){ + // WatchedStatus = "PLANNED" | "WATCHING" | "FINISHED" | "HOLD" | "DROPPED"; + // TODO: Make better + // Translate status - May have multiple + // Main Ryot statuses: "Watchlist", "In Progress", "Completed", "Monitoring" + // There is no data equivalent to HOLD or DROPPED in the Ryot export + let mainStatus = null; + for(const s of v.collections){ + if(s === "Completed"){ + mainStatus = "FINISHED"; + break; + } + else if(s === "Watchlist") mainStatus = "PLANNED"; + else if(s === "In Progress") mainStatus = "WATCHING"; + else if(s === "Monitoring") mainStatus = "PLANNED"; + } + + const tmp: ImportedList = { + name: v.source_id, + tmdbId: Number(v.identifier), + type: v.lot, + status: mainStatus, + thoughts: "", + datesWatched: v.seen_history.map(seen => new Date(seen.ended_on)) + }; + t = tmp; + } + else if(v.lot === "show"){ + const tmp: ImportedList = { + name: v.source_id, + tmdbId: Number(v.identifier), + type: v.lot, + status: v.collections.includes("Completed") ? "FINISHED":"WATCHING", + thoughts: "", + watchedEpisodes: v.seen_history.map(h => ({ + status: h.progress === "100" ? "FINISHED":"WATCHING", + seasonNumber: h.show_season_number, + episodeNumber: h.show_episode_number + } + )) + }; + t = tmp; + } + + console.log(t); + toImport.push(t); + } + console.log("toImport:", toImport); + importedList.set({ + data: JSON.stringify(toImport), + type: "ryot" + }); + goto("/import/process"); + } catch (err) { + isLoading = false; + notify({ type: "error", text: "Failed to read file!" }); + console.error("import: Failed to read file!", err); + } + } + onMount(() => { if (!localStorage.getItem("token")) { goto("/login"); @@ -407,6 +520,11 @@ text="MyAnimeList Export" filesSelected={(f) => processFilesMyAnimeList(f)} /> + + processRyotFile(f)} + /> {/if} diff --git a/src/routes/(app)/import/process/+page.svelte b/src/routes/(app)/import/process/+page.svelte index 792a431b..7d4a1d4b 100644 --- a/src/routes/(app)/import/process/+page.svelte +++ b/src/routes/(app)/import/process/+page.svelte @@ -253,6 +253,19 @@ text: "Failed to process import data!" }); } + } else if (list?.type === "ryot") { + importText = "Ryot"; + try { + const s = JSON.parse(list.data); + // Builds imported list in previous step for ease. + rList = s; + } catch (err) { + console.error("Ryot import processing failed!", err); + notify({ + type: "error", + text: "Processing failed!. Please report this issue if it persists." + }); + } } // TODO: remove duplicate names in list return list; diff --git a/src/store.ts b/src/store.ts index f812332b..62718f8f 100644 --- a/src/store.ts +++ b/src/store.ts @@ -24,7 +24,7 @@ export const activeSort = writable(defaultSort); export const activeFilters = writable({ type: [], status: [] }); export const appTheme = writable(); export const importedList = writable< - { data: string; type: "text-list" | "tmdb" | "movary" | "watcharr" | "myanimelist" } | undefined + { data: string; type: "text-list" | "tmdb" | "movary" | "watcharr" | "myanimelist" | "ryot" } | undefined >(); export const parsedImportedList = writable(); export const searchQuery = writable(""); From 859c4a21f592b880456aae7485bd826749bad66a Mon Sep 17 00:00:00 2001 From: oPisiti Date: Tue, 25 Jun 2024 14:42:47 -0300 Subject: [PATCH 2/9] Bug fixes for movie imports and show ratings --- src/routes/(app)/import/+page.svelte | 82 +++++++++++++--------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/src/routes/(app)/import/+page.svelte b/src/routes/(app)/import/+page.svelte index 751433c0..c7b10205 100644 --- a/src/routes/(app)/import/+page.svelte +++ b/src/routes/(app)/import/+page.svelte @@ -370,6 +370,7 @@ } async function processRyotFile(files?: FileList | null) { + // TODO: Bugfix: Always ask for correct match try { console.log("processRyotFile", files); if (!files || files?.length <= 0) { @@ -419,51 +420,46 @@ ); continue; } - - // Create t - let t; - if(v.lot === "movie"){ - // WatchedStatus = "PLANNED" | "WATCHING" | "FINISHED" | "HOLD" | "DROPPED"; - // TODO: Make better - // Translate status - May have multiple - // Main Ryot statuses: "Watchlist", "In Progress", "Completed", "Monitoring" - // There is no data equivalent to HOLD or DROPPED in the Ryot export - let mainStatus = null; - for(const s of v.collections){ - if(s === "Completed"){ - mainStatus = "FINISHED"; - break; - } - else if(s === "Watchlist") mainStatus = "PLANNED"; - else if(s === "In Progress") mainStatus = "WATCHING"; - else if(s === "Monitoring") mainStatus = "PLANNED"; - } - const tmp: ImportedList = { - name: v.source_id, - tmdbId: Number(v.identifier), - type: v.lot, - status: mainStatus, - thoughts: "", - datesWatched: v.seen_history.map(seen => new Date(seen.ended_on)) - }; - t = tmp; + // Define the main general status of the movie/show + // In Ryot, it can be marked as multiple of the following + const ryotStatusRanks: string[] = ["Watchlist", "Monitoring", "In Progress", "Completed"] + const ryotToWatcharr: string[] = ["PLANNED", "PLANNED", "WATCHING", "FINISHED"] + let rank = 0; + for(const s of v.collections){ + rank = Math.max(rank, ryotStatusRanks.indexOf(s)) } - else if(v.lot === "show"){ - const tmp: ImportedList = { - name: v.source_id, - tmdbId: Number(v.identifier), - type: v.lot, - status: v.collections.includes("Completed") ? "FINISHED":"WATCHING", - thoughts: "", - watchedEpisodes: v.seen_history.map(h => ({ - status: h.progress === "100" ? "FINISHED":"WATCHING", - seasonNumber: h.show_season_number, - episodeNumber: h.show_episode_number - } - )) - }; - t = tmp; + + let mainStatus = ryotToWatcharr[rank]; + + const t: ImportedList = { + tmdbId: Number(v.identifier), + name: v.source_id, + type: v.lot === "show" ? "tv" : v.lot, + status: mainStatus, + + // In Ryot, shows can have one review for each episode - Not supported in Watcharr + // Will ignore the episodes' reviews + thoughts: v.lot === "movie" && v.reviews.length ? v.reviews[0].review.text : "", + + // Ryot does not support overall rating for shows + rating: v.lot === "movie" && v.reviews.length ? Number(v.reviews[0].rating) : null, + + datesWatched: v.lot === "movie" && v.seen_history.length ? v.seen_history.map(seen => new Date(seen.ended_on)) : [], + + // Episode ratings are on a separate field: "reviews" + watchedEpisodes: v.seen_history.map(episode => ({ + status: episode.progress === "100" ? "FINISHED" : "WATCHING", + + // Linear :( search the reviews for a match + rating: Number((v.reviews.find(review => + review.show_season_number === episode.show_season_number && + review.show_episode_number === episode.show_episode_number + ) || {}).rating) || null, + + seasonNumber: episode.show_season_number, + episodeNumber: episode.show_episode_number + })) } console.log(t); From 752964aea7f240e31827dbf745e05640001e99cc Mon Sep 17 00:00:00 2001 From: oPisiti Date: Tue, 25 Jun 2024 15:38:23 -0300 Subject: [PATCH 3/9] Cleanup --- src/routes/(app)/import/+page.svelte | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/routes/(app)/import/+page.svelte b/src/routes/(app)/import/+page.svelte index c7b10205..936bd130 100644 --- a/src/routes/(app)/import/+page.svelte +++ b/src/routes/(app)/import/+page.svelte @@ -370,7 +370,6 @@ } async function processRyotFile(files?: FileList | null) { - // TODO: Bugfix: Always ask for correct match try { console.log("processRyotFile", files); if (!files || files?.length <= 0) { @@ -423,20 +422,22 @@ // Define the main general status of the movie/show // In Ryot, it can be marked as multiple of the following - const ryotStatusRanks: string[] = ["Watchlist", "Monitoring", "In Progress", "Completed"] - const ryotToWatcharr: string[] = ["PLANNED", "PLANNED", "WATCHING", "FINISHED"] + const statusRanks = [ + ["Watchlist", "PLANNED"], + ["Monitoring", "PLANNED"], + ["In Progress", "WATCHING"], + ["Completed", "FINISHED"] + ]; let rank = 0; for(const s of v.collections){ - rank = Math.max(rank, ryotStatusRanks.indexOf(s)) + rank = Math.max(rank, statusRanks.findIndex(pair => pair[0] == s)) } - - let mainStatus = ryotToWatcharr[rank]; const t: ImportedList = { tmdbId: Number(v.identifier), - name: v.source_id, - type: v.lot === "show" ? "tv" : v.lot, - status: mainStatus, + name: v.source_id, + type: v.lot === "show" ? "tv" : v.lot, + status: statusRanks[rank][1], // In Ryot, shows can have one review for each episode - Not supported in Watcharr // Will ignore the episodes' reviews From ef247e1a1e7fa20f498a8032dae7dddb466335c6 Mon Sep 17 00:00:00 2001 From: oPisiti Date: Tue, 25 Jun 2024 16:48:48 -0300 Subject: [PATCH 4/9] Added Ryot's logo to import button --- src/lib/Icon.svelte | 37 ++++++++++++++++++++++++++++ src/routes/(app)/import/+page.svelte | 1 + 2 files changed, 38 insertions(+) diff --git a/src/lib/Icon.svelte b/src/lib/Icon.svelte index 349c4e83..0c63d809 100644 --- a/src/lib/Icon.svelte +++ b/src/lib/Icon.svelte @@ -295,6 +295,43 @@ /> +{:else if i === "ryot"} + + + + + {:else if i === "gamepad"} processRyotFile(f)} /> From e97a197237378f051e771d163714f804cfc5c2a8 Mon Sep 17 00:00:00 2001 From: oPisiti Date: Tue, 25 Jun 2024 17:47:41 -0300 Subject: [PATCH 5/9] Ryot import now supports the DROPPED flag for shows --- src/routes/(app)/import/+page.svelte | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/(app)/import/+page.svelte b/src/routes/(app)/import/+page.svelte index 2e1d86c7..df90d486 100644 --- a/src/routes/(app)/import/+page.svelte +++ b/src/routes/(app)/import/+page.svelte @@ -421,8 +421,9 @@ } // Define the main general status of the movie/show - // In Ryot, it can be marked as multiple of the following + // In Ryot, it can be marked as multiple of the following, so choose the most relevant const statusRanks = [ + ["", "DROPPED"], ["Watchlist", "PLANNED"], ["Monitoring", "PLANNED"], ["In Progress", "WATCHING"], From f831f1e04a4840cb7fd7b7d19d01fdc48fadcfe6 Mon Sep 17 00:00:00 2001 From: oPisiti Date: Thu, 27 Jun 2024 20:07:55 -0300 Subject: [PATCH 6/9] Formatted the code and added restrictions for tv shows and movies only --- src/routes/(app)/import/+page.svelte | 64 ++++++++++++++++------------ src/store.ts | 3 +- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/routes/(app)/import/+page.svelte b/src/routes/(app)/import/+page.svelte index df90d486..f420eb85 100644 --- a/src/routes/(app)/import/+page.svelte +++ b/src/routes/(app)/import/+page.svelte @@ -408,13 +408,13 @@ const fileText = await readFile(new FileReader(), file); const jsonData = JSON.parse(fileText)["media"] as Watched[]; for (const v of jsonData) { - if (!v.source_id || !v.identifier) { + if (!v.source_id || !v.identifier || !(v.lot == "show" || v.lot == "movie")) { notify({ type: "error", - text: "Item in export has no title or TMDB identifier! Look in console for more details." + text: "Item in export either has no title, TMDB identifier or is not a movie/tv show! Look in console for more details." }); console.error( - "Can't add export item to import table! It has no source_id or identifier! Item:", + "Can't add export item to import table! It has title, TMDB identifier or is not a movie/tv show! Item:", v ); continue; @@ -423,21 +423,24 @@ // Define the main general status of the movie/show // In Ryot, it can be marked as multiple of the following, so choose the most relevant const statusRanks = [ - ["", "DROPPED"], - ["Watchlist", "PLANNED"], - ["Monitoring", "PLANNED"], - ["In Progress", "WATCHING"], - ["Completed", "FINISHED"] + ["", "DROPPED"], + ["Watchlist", "PLANNED"], + ["Monitoring", "PLANNED"], + ["In Progress", "WATCHING"], + ["Completed", "FINISHED"] ]; - let rank = 0; - for(const s of v.collections){ - rank = Math.max(rank, statusRanks.findIndex(pair => pair[0] == s)) + let rank = 0; + for (const s of v.collections) { + rank = Math.max( + rank, + statusRanks.findIndex((pair) => pair[0] == s) + ); } const t: ImportedList = { tmdbId: Number(v.identifier), - name: v.source_id, - type: v.lot === "show" ? "tv" : v.lot, + name: v.source_id, + type: v.lot === "show" ? "tv" : v.lot, status: statusRanks[rank][1], // In Ryot, shows can have one review for each episode - Not supported in Watcharr @@ -446,23 +449,32 @@ // Ryot does not support overall rating for shows rating: v.lot === "movie" && v.reviews.length ? Number(v.reviews[0].rating) : null, - - datesWatched: v.lot === "movie" && v.seen_history.length ? v.seen_history.map(seen => new Date(seen.ended_on)) : [], + + datesWatched: + v.lot === "movie" && v.seen_history.length + ? v.seen_history.map((seen) => new Date(seen.ended_on)) + : [], // Episode ratings are on a separate field: "reviews" - watchedEpisodes: v.seen_history.map(episode => ({ + watchedEpisodes: v.seen_history.map((episode) => ({ status: episode.progress === "100" ? "FINISHED" : "WATCHING", - + // Linear :( search the reviews for a match - rating: Number((v.reviews.find(review => - review.show_season_number === episode.show_season_number && - review.show_episode_number === episode.show_episode_number - ) || {}).rating) || null, + rating: + Number( + ( + v.reviews.find( + (review) => + review.show_season_number === episode.show_season_number && + review.show_episode_number === episode.show_episode_number + ) || {} + ).rating + ) || null, - seasonNumber: episode.show_season_number, + seasonNumber: episode.show_season_number, episodeNumber: episode.show_episode_number })) - } + }; console.log(t); toImport.push(t); @@ -519,11 +531,7 @@ filesSelected={(f) => processFilesMyAnimeList(f)} /> - processRyotFile(f)} - /> + processRyotFile(f)} /> {/if} diff --git a/src/store.ts b/src/store.ts index 62718f8f..e188fa9d 100644 --- a/src/store.ts +++ b/src/store.ts @@ -24,7 +24,8 @@ export const activeSort = writable(defaultSort); export const activeFilters = writable({ type: [], status: [] }); export const appTheme = writable(); export const importedList = writable< - { data: string; type: "text-list" | "tmdb" | "movary" | "watcharr" | "myanimelist" | "ryot" } | undefined + | { data: string; type: "text-list" | "tmdb" | "movary" | "watcharr" | "myanimelist" | "ryot" } + | undefined >(); export const parsedImportedList = writable(); export const searchQuery = writable(""); From 81d506c19ae616e4024ff6cf277f56fecea28eb4 Mon Sep 17 00:00:00 2001 From: oPisiti Date: Thu, 27 Jun 2024 21:10:05 -0300 Subject: [PATCH 7/9] Better units --- src/routes/(app)/movie/[id]/+page.svelte | 2 +- src/routes/(app)/profile/+page.svelte | 32 ++++++++++++++++++------ src/routes/(app)/tv/[id]/+page.svelte | 2 +- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/routes/(app)/movie/[id]/+page.svelte b/src/routes/(app)/movie/[id]/+page.svelte index 5d8cf5d0..fe61509c 100644 --- a/src/routes/(app)/movie/[id]/+page.svelte +++ b/src/routes/(app)/movie/[id]/+page.svelte @@ -146,7 +146,7 @@ /> - {movie.runtime}m + {movie.runtime} min
{#each movie.genres as g, i} diff --git a/src/routes/(app)/profile/+page.svelte b/src/routes/(app)/profile/+page.svelte index 58bc47da..14c9c494 100644 --- a/src/routes/(app)/profile/+page.svelte +++ b/src/routes/(app)/profile/+page.svelte @@ -134,12 +134,28 @@ /** * Takes in number of minutes and converts to readable. - * eg into hours and minutes. - */ - function toFormattedMinutes(m: number) { - const hours = Math.floor(m / 60); - const minutes = m % 60; - return `${hours ? `${hours}h ` : ""}${minutes}m`; + * eg into months, weeks, days, hours and minutes. + */ + function toFormattedTimeLong(m: number) { + // Considers a 30 days long month + const countInMinutes = [ + ["month", 43200], + ["week", 10080], + ["day", 1440], + ["hour", 60], + ] + + let ansString: String = ""; + let tmp; + for(const c of countInMinutes){ + tmp = Math.floor(m / c[1]); + + // Ignore fields with fewer than 1 unit + if(tmp) ansString += `${tmp} ${c[0]}${tmp >= 2 ? "s, " : ", "}`; + m -= tmp * c[1]; + } + + return ansString.slice(0, -2); } @@ -163,10 +179,10 @@ - + {:catch err} diff --git a/src/routes/(app)/tv/[id]/+page.svelte b/src/routes/(app)/tv/[id]/+page.svelte index d7f53986..d927bbf5 100644 --- a/src/routes/(app)/tv/[id]/+page.svelte +++ b/src/routes/(app)/tv/[id]/+page.svelte @@ -145,7 +145,7 @@ {#if show?.episode_run_time?.length > 0} - {show.episode_run_time.join(",")}m + {show.episode_run_time.join(",")} min {/if}
From b6354db3df16bf4aff4e8e5e504fabcfd6091a7f Mon Sep 17 00:00:00 2001 From: oPisiti Date: Thu, 27 Jun 2024 21:11:36 -0300 Subject: [PATCH 8/9] Prettier format --- src/routes/(app)/profile/+page.svelte | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/routes/(app)/profile/+page.svelte b/src/routes/(app)/profile/+page.svelte index 14c9c494..54f66c24 100644 --- a/src/routes/(app)/profile/+page.svelte +++ b/src/routes/(app)/profile/+page.svelte @@ -135,23 +135,23 @@ /** * Takes in number of minutes and converts to readable. * eg into months, weeks, days, hours and minutes. - */ + */ function toFormattedTimeLong(m: number) { // Considers a 30 days long month const countInMinutes = [ ["month", 43200], ["week", 10080], ["day", 1440], - ["hour", 60], - ] + ["hour", 60] + ]; let ansString: String = ""; let tmp; - for(const c of countInMinutes){ + for (const c of countInMinutes) { tmp = Math.floor(m / c[1]); // Ignore fields with fewer than 1 unit - if(tmp) ansString += `${tmp} ${c[0]}${tmp >= 2 ? "s, " : ", "}`; + if (tmp) ansString += `${tmp} ${c[0]}${tmp >= 2 ? "s, " : ", "}`; m -= tmp * c[1]; } From b0750ccf56c13641aa03c84669372a9df54343c8 Mon Sep 17 00:00:00 2001 From: IRHM <37304121+IRHM@users.noreply.github.com> Date: Fri, 28 Jun 2024 02:03:08 +0100 Subject: [PATCH 9/9] Fix type errors, change stat styling to push value down --- src/lib/stats/Stat.svelte | 5 +---- src/routes/(app)/import/+page.svelte | 17 ++++++++--------- src/routes/(app)/profile/+page.svelte | 6 +++--- src/types.ts | 1 + 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/lib/stats/Stat.svelte b/src/lib/stats/Stat.svelte index 4a8b8b2d..f502bdf8 100644 --- a/src/lib/stats/Stat.svelte +++ b/src/lib/stats/Stat.svelte @@ -30,16 +30,13 @@ > span:first-of-type { font-weight: bold; font-size: 20px; + margin-top: auto; &.large { font-size: 32px; } } - > span:last-child { - margin-top: auto; - } - .disclaimer { position: absolute; top: 5px; diff --git a/src/routes/(app)/import/+page.svelte b/src/routes/(app)/import/+page.svelte index f420eb85..4257f596 100644 --- a/src/routes/(app)/import/+page.svelte +++ b/src/routes/(app)/import/+page.svelte @@ -18,7 +18,8 @@ MovaryHistory, MovaryRatings, MovaryWatchlist, - Watched + Watched, + WatchedStatus } from "@/types"; let isDragOver = false; @@ -406,7 +407,7 @@ // Build toImport array const toImport: ImportedList[] = []; const fileText = await readFile(new FileReader(), file); - const jsonData = JSON.parse(fileText)["media"] as Watched[]; + const jsonData = JSON.parse(fileText)["media"] as any[]; for (const v of jsonData) { if (!v.source_id || !v.identifier || !(v.lot == "show" || v.lot == "movie")) { notify({ @@ -422,7 +423,7 @@ // Define the main general status of the movie/show // In Ryot, it can be marked as multiple of the following, so choose the most relevant - const statusRanks = [ + const statusRanks: [string, WatchedStatus][] = [ ["", "DROPPED"], ["Watchlist", "PLANNED"], ["Monitoring", "PLANNED"], @@ -448,15 +449,15 @@ thoughts: v.lot === "movie" && v.reviews.length ? v.reviews[0].review.text : "", // Ryot does not support overall rating for shows - rating: v.lot === "movie" && v.reviews.length ? Number(v.reviews[0].rating) : null, + rating: v.lot === "movie" && v.reviews.length ? Number(v.reviews[0].rating) : undefined, datesWatched: v.lot === "movie" && v.seen_history.length - ? v.seen_history.map((seen) => new Date(seen.ended_on)) + ? v.seen_history.map((seen: any) => new Date(seen.ended_on)) : [], // Episode ratings are on a separate field: "reviews" - watchedEpisodes: v.seen_history.map((episode) => ({ + watchedEpisodes: v.seen_history.map((episode: any) => ({ status: episode.progress === "100" ? "FINISHED" : "WATCHING", // Linear :( search the reviews for a match @@ -464,7 +465,7 @@ Number( ( v.reviews.find( - (review) => + (review: any) => review.show_season_number === episode.show_season_number && review.show_episode_number === episode.show_episode_number ) || {} @@ -475,8 +476,6 @@ episodeNumber: episode.show_episode_number })) }; - - console.log(t); toImport.push(t); } console.log("toImport:", toImport); diff --git a/src/routes/(app)/profile/+page.svelte b/src/routes/(app)/profile/+page.svelte index 54f66c24..4d83b570 100644 --- a/src/routes/(app)/profile/+page.svelte +++ b/src/routes/(app)/profile/+page.svelte @@ -145,14 +145,14 @@ ["hour", 60] ]; - let ansString: String = ""; + let ansString = ""; let tmp; for (const c of countInMinutes) { - tmp = Math.floor(m / c[1]); + tmp = Math.floor(m / (c[1] as number)); // Ignore fields with fewer than 1 unit if (tmp) ansString += `${tmp} ${c[0]}${tmp >= 2 ? "s, " : ", "}`; - m -= tmp * c[1]; + m -= tmp * (c[1] as number); } return ansString.slice(0, -2); diff --git a/src/types.ts b/src/types.ts index 2548b0e0..7c046896 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,6 +34,7 @@ export type Icon = | "eye" | "star" | "movary" + | "ryot" | "refresh" | "gamepad" | "film"