From 8a403d59e5f1fb4188a4b52324b46a341ab80189 Mon Sep 17 00:00:00 2001 From: Bogdan Stefan Date: Sun, 5 Jul 2026 15:04:49 +0100 Subject: [PATCH] v2.2.0: New features, performance improvements --- CHANGELOG.md | 38 ++ eslint.config.mts | 24 +- main.js | 90 ++-- manifest.json | 2 +- package.json | 2 +- src/AddFromUrlModal.ts | 3 + src/AddReadingModal.ts | 13 +- src/AddTitleModal.ts | 87 +++- src/ApiService.ts | 210 ++++++++- src/ColorPicker.ts | 169 +++++++ src/CustomListsTab.ts | 779 ++++++++++++++++++++++++++++--- src/DataManager.ts | 198 +++++++- src/EditTitleModal.ts | 174 ++++++- src/ListTab.ts | 303 ++++++++++-- src/PosterService.ts | 119 ++++- src/ReadingDataManager.ts | 22 + src/ReadingDetailModal.ts | 48 +- src/ReadingManageColumnsModal.ts | 41 +- src/SearchThumbnail.ts | 28 ++ src/SettingsTab.ts | 103 +++- src/StatusDropdown.ts | 82 ++++ src/TitleDetailModal.ts | 283 +++++++++-- src/WatchLogView.ts | 83 ++-- src/main.ts | 28 +- src/types.ts | 125 ++++- styles.css | 598 +++++++++++++++++++++++- versions.json | 1 + 27 files changed, 3287 insertions(+), 366 deletions(-) create mode 100644 src/ColorPicker.ts create mode 100644 src/SearchThumbnail.ts create mode 100644 src/StatusDropdown.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 03e9c32..9964bcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,44 @@ # Changelog All notable changes to WatchLog are documented here. +## [2.2.0] - 2026-07-05 + +##### Added +- **Per-list tab color** - each custom list tab can now be assigned a color, applied to its tab name. Set it via a color picker in Table settings (renamed from "Edit columns"). +- **Per-option colors for select columns** - each option of a select-type column can be given its own color, defined per table; the colored badge reflects the option's color in both the cell and the selection dropdown. +- **Custom colors everywhere** - the color picker now offers the 8 presets plus a full-spectrum custom color, with a built-in reset-to-default. Available for Custom Lists tab/option colors and Reading field colors alike. +- **Column resizing** - Columns now can be resized +- **TSV export** - Export now offers a format chooser: copy as TSV (pastes cleanly into Google Sheets / Excel as columns) or as Markdown (for pasting into notes). +- **Import rows** - a new Import button lets you paste tab-separated data copied from a spreadsheet to append rows to the current list +- **Select-all tick** - a tick in the table header checks or unchecks all visible rows at once. +- Now you can select default content type for adding titles - pick a fixed type or `* Last type used` (remembers your last choice) in Settings → Watchlist. +- Richer note frontmatter — Watchlist notes now carry review, dates, episode duration, IDs, community rating, a single resolved poster, and more; Reading notes add cover, external link, and modified date. Makes notes portable and `.base`-friendly. +- "Rewrite frontmatter on all notes" button (Settings → General) to apply the enriched frontmatter to existing notes - chunked, cancelable, preserves note bodies. +- Cover thumbnails in search results when adding titles, books, and manga, so you can tell same-named entries apart. +- **Director & cast fields** on Watchlist titles (`director`, `cast` — both `string[]`). Cast is hardcoded-capped at 4 across every source, so a title looks identical regardless of which API supplied it. +- **Lazy backfill on modal open**: opening `TitleDetailModal` for an older title missing the fields triggers a one-time fetch keyed off the IMDb id in its external link (prefers active API, falls back to the other keyed one). Persists through a new `DataManager.updateCredits()` that writes both `data.json` and the note frontmatter in one operation — not the silent poster path. +- **UI**: shared `renderCreditsRows` renders Director/Cast in the modal (below the stats box) and in the List view expanded row (under the "Not started" line). Names render as clickable chips (theme-variable CSS). +- **Click-to-filter**: clicking a name routes it into the existing search bar — visible, clearable, and matching typed-search behaviour. +- **YouTube trailers** — auto-fetched at add-time (TMDB, Jikan, AniList; OMDb has none), stored per title, shown as a red YouTube icon on the detail row and saved to note frontmatter. Manual override field in Edit. Existing titles get a refresh button to fetch on demand. +- Added the cover image to the left of the title detail modal (Movie/Series), with the full header block (title + badges + stats) moved to its right, mirroring the Reading modal layout. Letter-placeholder fallback when no poster exists. + +##### Improved +- Add-title form compacted (Episodes/Duration and Status/Priority paired onto single rows), giving the search results more room. +- Dashboard grid now adapts to panel width on mobile (3→2→1 columns); desktop unchanged. +- Mobile tab bar switched to icons so all tabs fit on one row without scrolling. +##### Changed +- Switching a column to **select** now populates its options from the distinct values already present in that column's cells (in order of first appearance), preserving existing cell values instead of resurrecting stale options. +- **Dashboard** — default card style is now rectangles for new installs. +- **Edit modal** — Status/Priority, Total episodes/Ep. duration, and Date started/Date finished now share rows; added the "Add to group / create new group" section. + +##### Fixed +- **Cover art accuracy** - posters are now matched by media type (Movie vs TV Show), preferring the correct release year, and resolved directly via IMDb id when available, instead of blindly taking the first multi-search result. Fixes cases where the wrong image was pulled (e.g. a film getting its TV series' poster). Applies to both TMDB and OMDb. +- Watchlist notes no longer overwrite content you wrote by hand directly in the `.md` file. +- Title frontmatter now escapes special characters - titles or links containing `:` no longer break the YAML. +- Dashboard no longer overflows off-screen on mobile. +- Fixed the whole view dragging sideways like a loose sheet on mobile. +- **Cards view** — selection now works (click a card to select, 3px purple border on selected); fixed the flicker when entering/exiting selection mode (no more full tab rebuild). +- Fixed the progressively-climbing CLS on scroll in Cards View. ## [2.1.0] - 2026-06-17 diff --git a/eslint.config.mts b/eslint.config.mts index c665539..a563ccc 100644 --- a/eslint.config.mts +++ b/eslint.config.mts @@ -26,9 +26,31 @@ export default tseslint.config( ...obsidianmd.configs.recommended, { // Cosmetic-only: keep UI sentence-case visible without failing the lint. + // ignoreWords/ignoreRegex teach the rule this plugin's proper nouns + // (tab, modal and feature names) and format-mask placeholders; genuine + // sentence-case violations are still reported. plugins: { obsidianmd }, rules: { - 'obsidianmd/ui/sentence-case': 'warn', + 'obsidianmd/ui/sentence-case': ['warn', { + ignoreWords: [ + // Plugin / feature names + 'WatchLog', 'Watchlist', 'Upcoming', 'Reading', 'Cards', + 'Drafts', 'Custom', 'Lists', 'Books', 'Manga', + 'Notes', 'Quotes', 'Regenerate', 'Settings', 'Add', 'Last', + // External services / acronyms not in the rule defaults + 'Google', 'MAL', 'TSV', 'URLs', 'APIs', + ], + ignoreRegex: [ + '^DD/MM/YYYY$', // date format mask + '^https://', // URL placeholder + '^Season \\d', // season-spec example placeholder + '^p\\. 123', // quote-location example placeholder + '^APIs & Services', // Google Cloud console path + '"N due"', // N is a number placeholder + '^\\* Last type used$', // sentinel option; * confuses sentence-start detection + '"Last type used"', // quotes that sentinel option's label + ], + }], }, }, globalIgnores([ diff --git a/main.js b/main.js index 5591365..83f4209 100644 --- a/main.js +++ b/main.js @@ -3,23 +3,24 @@ THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ -var ti=Object.defineProperty;var Os=Object.getOwnPropertyDescriptor;var Hs=Object.getOwnPropertyNames;var Ns=Object.prototype.hasOwnProperty;var _s=(g,i)=>{for(var t in i)ti(g,t,{get:i[t],enumerable:!0})},Us=(g,i,t,e)=>{if(i&&typeof i=="object"||typeof i=="function")for(let s of Hs(i))!Ns.call(g,s)&&s!==t&&ti(g,s,{get:()=>i[s],enumerable:!(e=Os(i,s))||e.enumerable});return g};var Vs=g=>Us(ti({},"__esModule",{value:!0}),g);var En={};_s(En,{default:()=>Xe});module.exports=Vs(En);var X=require("obsidian");var wt=["Reading","Completed","Plan to Read","To be released","Dropped"],lt=wt.filter(g=>g!=="To be released"),ei=[{color600:"#534AB7",color50:"#EEEDFE"},{color600:"#1D9E75",color50:"#E1F5EE"},{color600:"#EF9F27",color50:"#FAEEDA"},{color600:"#378ADD",color50:"#E6F1FB"},{color600:"#D85A30",color50:"#FAECE7"},{color600:"#993556",color50:"#FBEAF0"},{color600:"#639922",color50:"#EAF3DE"},{color600:"#5F5E5A",color50:"#F1EFE8"}],_i=Object.fromEntries(ei.map(({color600:g,color50:i})=>[g,i])),Bt="#5F5E5A",ii={defaultFolder:"WatchLog/Reading",defaultStatus:"Plan to Read",bookCustomFieldStyle:"fill",mangaCustomFieldStyle:"fill"};function Ui(g){var s,a,n;let i=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],t=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],e=g.releaseTime?` \xB7 ${g.releaseTime}`:"";if(g.recurrence==="once"){if(!g.releaseDate)return"No date set";let r=new Date(g.releaseDate+"T12:00:00");return`Release date \xB7 ${r.getDate()} ${(s=t[r.getMonth()])!=null?s:""} ${r.getFullYear()}${e}`}return g.recurrence==="daily"?`Every day${e}`:g.recurrence==="weekly"?`Every ${g.dayOfWeek!==void 0&&(a=i[g.dayOfWeek])!=null?a:"Unknown"}${e}`:g.recurrence==="monthly"?`Monthly on day ${(n=g.dayOfMonth)!=null?n:"?"}${e}`:"\u2014"}var dt={colorTheme:"default",defaultWatchlistView:"cards",autoCompleteOnLastEpisode:!0,setFinishDateAutomatically:!1,omdbApiKey:"",tmdbApiKey:"",googleBooksApiKey:"",activeApi:"OMDb",animeApiSource:"jikan",typeApiMapping:{},types:[{name:"Anime",color:"#1D9E75"},{name:"Movie",color:"#378ADD"},{name:"TV Show",color:"#BA7517"},{name:"Korean TV Show",color:"#7F77DD"},{name:"Animation",color:"#D85A30"}],statuses:[{name:"Watching",color:"#1D9E75"},{name:"Plan to watch",color:"#00A9A5"},{name:"Completed",color:"#378ADD"},{name:"To be released",color:"#E8873A"},{name:"Dropped",color:"#E24B4A"}],reviews:[{name:"Nah",color:"#E24B4A"},{name:"Awesome",color:"#1D9E75"},{name:"Marvelous",color:"#7F77DD"}],priorities:[{name:"Low",color:"#888780"},{name:"Medium",color:"#3b82f6"},{name:"High",color:"#E24B4A"}],rootFolder:"WatchLog",autoCreateFolders:!0,coloredTypeBadges:!0,dashboardCardStyle:"circles",episodeNumbering:"absolute",readingTypeColors:{manga:"#D4537E",book:"#D85A30"},customListsFolder:"WatchLog/CustomLists",defaultCustomColumns:[],draftsVaultTag:"#watchlog",draftsAfterAdding:"keep",customListTabOrder:[],showHintBanners:!0,showUpcomingStatusBar:!0,listFilters:{typeExclude:[],statusExclude:[],groupExclude:[],ratingExclude:[],priorityExclude:[],sort:"dateAdded",sortDir:"desc",secondSort:"none",secondSortDir:"asc"},seasonPalette:["#1D9E75","#BA7517","#378ADD","#7F77DD","#D85A30","#D4537E","#639922","#888780"]};function H(g,i,t){return i}function me(g,i){var e;let t=(e=i.readingTypeColors)!=null?e:dt.readingTypeColors;return g==="manga"?t.manga:t.book}function Q(g){if(!g)return"";let i=g.match(/^(\d{4})-(\d{2})-(\d{2})$/);return i?`${i[3]}/${i[2]}/${i[1]}`:g}function j(g){let i=g.trim();if(!i)return null;let t=i.split("/");if(t.length!==3)return null;let[e,s,a]=t;if(!e||!s||!a||a.length!==4)return null;let n=parseInt(e,10),r=parseInt(s,10),o=parseInt(a,10);if(isNaN(n)||isNaN(r)||isNaN(o)||r<1||r>12||n<1||n>31)return null;let l=new Date(o,r-1,n);return l.getFullYear()!==o||l.getMonth()!==r-1||l.getDate()!==n?null:`${a}-${s.padStart(2,"0")}-${e.padStart(2,"0")}`}function Pt(g){let i=g.trim();if(!i)return null;if(/^\d{4}-\d{2}-\d{2}$/.test(i))return i;let t=i.match(/^(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})$/);if(t){let e=t[1].padStart(2,"0"),s=t[2].padStart(2,"0"),a=t[3],n=parseInt(e,10),r=parseInt(s,10);return r<1||r>12||n<1||n>31?null:`${a}-${s}-${e}`}return null}function yt(g){if(!g||!/^\d{4}-\d{2}-\d{2}$/.test(g))return!1;let i=new Date;return i.setHours(0,0,0,0),new Date(g+"T12:00:00").getTime()>i.getTime()}function at(g,i){var t;return g==="Anime"?"anime":g==="Movie"||g==="TV Show"||g==="TvShow"?"movie":(t=i==null?void 0:i[g])!=null?t:""}function zt(g){var i;return g.manualPosterUrl&&g.manualPosterUrl.trim()!==""?g.manualPosterUrl:(i=g.posterUrl)!=null?i:""}function Vi(g){return!g||g<0?"0":g>=1e6?(g/1e6).toFixed(1)+"M":g>=1e3?(g/1e3).toFixed(1)+"K":g.toString()}function z(g){if(g<=0)return"0m";let i=Math.floor(g/60),t=g%60,e=i>=1e3?String(i).replace(/\B(?=(\d{3})+(?!\d))/g,"."):String(i);return i===0?`${t}m`:t===0?`${e}h`:`${e}h ${t}m`}var ct=require("obsidian");var Gs=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];function nt(g){var o;let i=new Date(g),t=(o=Gs[i.getDay()])!=null?o:"",e=String(i.getDate()).padStart(2,"0"),s=String(i.getMonth()+1).padStart(2,"0"),a=i.getFullYear(),n=String(i.getHours()).padStart(2,"0"),r=String(i.getMinutes()).padStart(2,"0");return`${t} ${e}/${s}/${a} at ${n}:${r}`}var jt=class{constructor(i){this.entries=[];this.MAX_ENTRIES=1e3;this.plugin=i}async load(){let i=this.plugin.dataManager.getData(),t=i.history;this.entries=Array.isArray(t)?t:[],this.entries.length>this.MAX_ENTRIES&&(this.entries=this.entries.slice(-this.MAX_ENTRIES)),i.history=this.entries}adoptExternalChange(){let i=this.plugin.dataManager.getData(),t=i.history;this.entries=Array.isArray(t)?t:[],this.entries.length>this.MAX_ENTRIES&&(this.entries=this.entries.slice(-this.MAX_ENTRIES)),i.history=this.entries}async log(i,t){let e={id:`${Date.now()}-${Math.random().toString(36).slice(2,7)}`,timestamp:new Date().toISOString(),message:i,source:t==null?void 0:t.source,action:t==null?void 0:t.action,titleName:t==null?void 0:t.titleName};this.entries.push(e),this.entries.length>this.MAX_ENTRIES&&(this.entries=this.entries.slice(-this.MAX_ENTRIES)),await this.save()}getEntries(){return[...this.entries].reverse()}exportEntries(){return[...this.entries]}async restore(i){let t=Array.isArray(i)?i:[];this.entries=t.length>this.MAX_ENTRIES?t.slice(-this.MAX_ENTRIES):t,await this.save()}async save(){try{this.plugin.dataManager.getData().history=this.entries,await this.plugin.dataManager.persist()}catch(i){}}};function Ks(g){return g!==null&&typeof g=="object"&&Array.isArray(g.titles)}var qt=class{constructor(i){this.changeListeners=[];this.historyManager=null;this.pendingSaveTimer=null;this.pendingMdTitleIds=new Set;this.EPISODE_SAVE_DEBOUNCE_MS=500;this.lastSelfSaveTime=0;this.SELF_SAVE_ECHO_WINDOW_MS=2e3;this.posterSaveTimer=null;this.POSTER_SAVE_DEBOUNCE_MS=5e3;this.queuedSaveTimer=null;this.QUEUED_SAVE_DEBOUNCE_MS=100;this.lastMarkdownPathById=new Map;this.plugin=i,this.app=i.app,this.data={titles:[],groups:[],settings:{}}}setHistoryManager(i){this.historyManager=i}async load(){let i=await this.plugin.loadData();this.data=Ks(i)?i:{titles:[],groups:[],settings:{}},this.migrateData()&&await this.saveOnly()}migrateData(){var t;let i=!1;Array.isArray(this.data.titles)||(this.data.titles=[],i=!0),Array.isArray(this.data.groups)||(this.data.groups=[],i=!0),Array.isArray(this.data.airtime)||(this.data.airtime=[],i=!0);for(let e of this.data.titles){if(e.dateAdded?e.dateAdded.includes("T")||(e.dateAdded=new Date(e.dateAdded).toISOString(),i=!0):(e.dateAdded=new Date().toISOString(),i=!0),!e.dateModified){let a=e.lastInteracted;typeof a=="string"&&a?e.dateModified=a:e.dateModified=e.dateAdded,i=!0}for(let s of(t=e.seasons)!=null?t:[])Array.isArray(s.skippedEpisodes)||(s.skippedEpisodes=[],i=!0);e.posterUrl===void 0&&(e.posterUrl="",i=!0),e.manualPosterUrl===void 0&&(e.manualPosterUrl="",i=!0),e.anilistId===void 0&&(e.anilistId=0,i=!0),e.communityRating===void 0&&(e.communityRating=0,i=!0),e.communityVotes===void 0&&(e.communityVotes=0,i=!0),e.communitySource===void 0&&(e.communitySource="",i=!0),e.communityRatingLastFetched===void 0&&(e.communityRatingLastFetched="",i=!0)}if(!this.data.posterRetryDone){for(let e of this.data.titles)e.posterUrl==="none"&&(e.posterUrl="");this.data.posterRetryDone=!0,i=!0}return i}updatePosterUrl(i,t){let e=this.data.titles.find(s=>s.id===i);e&&(e.posterUrl=t,this.schedulePosterSave())}updateCommunityRating(i,t,e,s){let a=this.data.titles.find(n=>n.id===i);a&&(a.communityRating=t,a.communityVotes=e,a.communitySource=s,a.communityRatingLastFetched=new Date().toISOString(),this.saveOnly())}schedulePosterSave(){this.posterSaveTimer===null&&(this.posterSaveTimer=window.setTimeout(()=>{this.posterSaveTimer=null,this.saveOnly()},this.POSTER_SAVE_DEBOUNCE_MS))}flushPosterSave(){this.posterSaveTimer!==null&&(window.clearTimeout(this.posterSaveTimer),this.posterSaveTimer=null,this.saveOnly())}flushPosterSaveSync(){this.posterSaveTimer!==null&&(window.clearTimeout(this.posterSaveTimer),this.posterSaveTimer=null,this.lastSelfSaveTime=Date.now(),this.plugin.saveData(this.data))}getData(){return this.data}queueSave(){this.queuedSaveTimer!==null&&window.clearTimeout(this.queuedSaveTimer),this.queuedSaveTimer=window.setTimeout(()=>{this.queuedSaveTimer=null,this.saveOnly()},this.QUEUED_SAVE_DEBOUNCE_MS)}flushQueuedSaveSync(){this.queuedSaveTimer!==null&&(window.clearTimeout(this.queuedSaveTimer),this.queuedSaveTimer=null,this.lastSelfSaveTime=Date.now(),this.plugin.saveData(this.data))}async saveSettings(i){this.data.settings=i,await this.saveOnly()}async saveOnly(){this.lastSelfSaveTime=Date.now(),await this.plugin.saveData(this.data),this.lastSelfSaveTime=Date.now()}async persist(){await this.saveOnly()}async save(){this.pendingSaveTimer!==null&&(window.clearTimeout(this.pendingSaveTimer),this.pendingSaveTimer=null,this.pendingMdTitleIds.clear()),await this.saveOnly(),this.notifyListeners()}scheduleEpisodeSave(i){this.pendingMdTitleIds.add(i),this.pendingSaveTimer!==null&&window.clearTimeout(this.pendingSaveTimer),this.pendingSaveTimer=window.setTimeout(()=>{this.flushPendingSave()},this.EPISODE_SAVE_DEBOUNCE_MS)}async flushPendingSave(){if(this.pendingSaveTimer!==null&&(window.clearTimeout(this.pendingSaveTimer),this.pendingSaveTimer=null),this.pendingMdTitleIds.size===0)return;let i=Array.from(this.pendingMdTitleIds);this.pendingMdTitleIds.clear(),await this.saveOnly();for(let t of i){let e=this.getTitle(t);e&&await this.updateMarkdownFile(e)}}flushPendingSaveSync(){if(this.pendingSaveTimer!==null&&(window.clearTimeout(this.pendingSaveTimer),this.pendingSaveTimer=null),this.pendingMdTitleIds.size===0)return;let i=Array.from(this.pendingMdTitleIds);this.pendingMdTitleIds.clear(),this.lastSelfSaveTime=Date.now(),this.plugin.saveData(this.data);for(let t of i){let e=this.getTitle(t);e&&this.updateMarkdownFile(e)}}getTitles(){var i;return(i=this.data.titles)!=null?i:[]}getTitle(i){var t;return((t=this.data.titles)!=null?t:[]).find(e=>e.id===i)}async addTitle(i){var s;let t=this.canAutoAddToUpcoming(i);t&&(i.status="To be released"),this.data.titles.push(i),await this.save(),t&&await this.autoAddToUpcoming(i),await this.updateMarkdownFile(i);let e=new Date().toISOString();(s=this.historyManager)==null||s.log(`${i.title} (${i.type}) was added on ${nt(e)}`,{source:"Watchlist",action:"added",titleName:i.title})}async addTitleSilent(i){let t=this.canAutoAddToUpcoming(i);t&&(i.status="To be released"),this.data.titles.push(i),await this.saveOnly(),t&&await this.autoAddToUpcoming(i),await this.updateMarkdownFile(i)}async addTitleBatch(i){let t=[];for(let e of i)this.canAutoAddToUpcoming(e)&&(e.status="To be released",t.push(e)),this.data.titles.push(e);await this.saveOnly();for(let e of t)await this.autoAddToUpcoming(e);for(let e of i)await this.updateMarkdownFile(e)}async batchUpdate(i,t){let e=[];for(let s of i){let a=this.getTitle(s);a&&(t(a),a.dateModified=new Date().toISOString(),e.push(a))}if(e.length!==0){await this.save();for(let s of e)await this.updateMarkdownFile(s)}}async removeTitlesBatch(i){let e=[];for(let s of i){let a=this.getTitle(s);a&&e.push(a),this.data.titles=this.data.titles.filter(r=>r.id!==s);for(let r of this.data.groups)r.titleIds=r.titleIds.filter(o=>o!==s);this.data.airtime&&(this.data.airtime=this.data.airtime.filter(r=>r.titleId!==s||r.source==="reading"));let n=this.data;n.collapsedSeasons&&delete n.collapsedSeasons[s]}await this.save();for(let s=0;sthis.deleteMarkdownFile(n)))}}canAutoAddToUpcoming(i){if(!i.releaseDate||!/^\d{4}-\d{2}-\d{2}$/.test(i.releaseDate))return!1;let t=new Date(i.releaseDate+"T12:00:00"),e=new Date;return e.setHours(0,0,0,0),t>e}async autoAddToUpcoming(i){var e;if(this.data.airtime||(this.data.airtime=[]),this.data.airtime.some(s=>s.titleId===i.id))return;let t={id:this.generateAirtimeId(i.id),titleId:i.id,schedule:{recurrence:"once",releaseDate:(e=i.releaseDate)!=null?e:void 0},dateAdded:new Date().toISOString()};this.data.airtime.push(t),await this.plugin.saveData(this.data)}async removeAirtimeEntriesForTitle(i){var e,s,a;let t=((e=this.data.airtime)!=null?e:[]).length;this.data.airtime=((s=this.data.airtime)!=null?s:[]).filter(n=>n.titleId!==i||n.source==="reading"),((a=this.data.airtime)!=null?a:[]).length!==t&&await this.save()}async autoAddReadingToUpcoming(i,t){var s;if(this.data.airtime||(this.data.airtime=[]),this.data.airtime.some(a=>a.source==="reading"&&a.titleId===i.id))return;let e={id:this.generateReadingAirtimeId(i.id),titleId:i.id,source:"reading",readingKind:t,schedule:{recurrence:"once",releaseDate:(s=i.releaseDate)!=null?s:void 0},dateAdded:new Date().toISOString()};this.data.airtime.push(e),await this.plugin.saveData(this.data)}async removeReadingAirtimeEntries(i){var e,s,a;let t=((e=this.data.airtime)!=null?e:[]).length;this.data.airtime=((s=this.data.airtime)!=null?s:[]).filter(n=>!(n.source==="reading"&&n.titleId===i)),((a=this.data.airtime)!=null?a:[]).length!==t&&await this.save()}generateReadingAirtimeId(i){var a;let t=`airtime-reading-${i}`,e=((a=this.data.airtime)!=null?a:[]).map(n=>n.id);if(!e.includes(t))return t;let s=2;for(;e.includes(`${t}-${s}`);)s++;return`${t}-${s}`}async updateTitle(i){var e,s;i.dateModified=new Date().toISOString(),i.status==="Completed"&&(i.priority="");let t=this.data.titles.findIndex(a=>a.id===i.id);if(t>=0){let a=this.data.titles[t],n=new Date().toISOString();a.rating!==i.rating&&((e=this.historyManager)==null||e.log(`${i.title} (${i.type}) was reviewed on ${nt(n)}`,{source:"Watchlist",action:"rating",titleName:i.title})),a.status!==i.status&&i.status==="Completed"&&((s=this.historyManager)==null||s.log(`${i.title} (${i.type}) was marked as watched on ${nt(n)}`,{source:"Watchlist",action:"completed",titleName:i.title})),this.data.titles[t]=i,await this.save(),await this.updateMarkdownFile(i)}}updateTitleSilent(i){var e,s;i.dateModified=new Date().toISOString(),i.status==="Completed"&&(i.priority="");let t=this.data.titles.findIndex(a=>a.id===i.id);if(t>=0){let a=this.data.titles[t],n=new Date().toISOString();a.rating!==i.rating&&((e=this.historyManager)==null||e.log(`${i.title} (${i.type}) was reviewed on ${nt(n)}`,{source:"Watchlist",action:"rating",titleName:i.title})),a.status!==i.status&&i.status==="Completed"&&((s=this.historyManager)==null||s.log(`${i.title} (${i.type}) was marked as watched on ${nt(n)}`,{source:"Watchlist",action:"completed",titleName:i.title})),this.data.titles[t]=i}}async removeTitle(i){var s;let t=this.getTitle(i);if(t){let a=new Date().toISOString();(s=this.historyManager)==null||s.log(`${t.title} (${t.type}) was deleted on ${nt(a)}`,{source:"Watchlist",action:"deleted",titleName:t.title})}this.data.titles=this.data.titles.filter(a=>a.id!==i);for(let a of this.data.groups)a.titleIds=a.titleIds.filter(n=>n!==i);this.data.airtime&&(this.data.airtime=this.data.airtime.filter(a=>a.titleId!==i||a.source==="reading"));let e=this.data;e.collapsedSeasons&&delete e.collapsedSeasons[i],await this.save(),t&&await this.deleteMarkdownFile(t)}getGroups(){var i;return(i=this.data.groups)!=null?i:[]}getGroup(i){var t;return((t=this.data.groups)!=null?t:[]).find(e=>e.id===i)}async addGroup(i){this.data.groups.push(i),await this.save()}async updateGroup(i){let t=this.data.groups.findIndex(e=>e.id===i.id);t>=0&&(this.data.groups[t]=i,await this.save())}async removeGroup(i){this.data.groups=this.data.groups.filter(t=>t.id!==i),await this.save()}async addTitleToGroup(i,t){let e=this.getGroup(i);e&&(e.titleIds.includes(t)||(e.titleIds.push(t),await this.updateGroup(e)))}getGroupedTitleIds(){var t;let i=new Set;for(let e of(t=this.data.groups)!=null?t:[])for(let s of e.titleIds)i.add(s);return i}generateGroupId(i){var a;let t="group-"+i.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),e=((a=this.data.groups)!=null?a:[]).map(n=>n.id);if(!e.includes(t))return t;let s=2;for(;e.includes(`${t}-${s}`);)s++;return`${t}-${s}`}getPinnedGroupId(){var i;return(i=this.data.pinnedGroupId)!=null?i:null}async setPinnedGroupId(i){this.data.pinnedGroupId=i,await this.save()}getSavedFilterPreset(){var i;return(i=this.data.savedFilterPreset)!=null?i:null}async setSavedFilterPreset(i){this.data.savedFilterPreset=i,await this.save()}getAirtimeEntries(){var i;return(i=this.data.airtime)!=null?i:[]}async addAirtimeEntry(i){this.data.airtime||(this.data.airtime=[]),this.data.airtime.push(i),await this.save()}async updateAirtimeEntry(i){if(!this.data.airtime)return;let t=this.data.airtime.findIndex(e=>e.id===i.id);t>=0&&(this.data.airtime[t]=i,await this.save())}async removeAirtimeEntry(i){var t;this.data.airtime=((t=this.data.airtime)!=null?t:[]).filter(e=>e.id!==i),await this.save()}async removeAirtimeEntriesBatch(i){var e;if(i.length===0)return;let t=new Set(i);this.data.airtime=((e=this.data.airtime)!=null?e:[]).filter(s=>!t.has(s.id)),await this.save()}getMaybeTitles(){var i;return(i=this.data.maybe)!=null?i:[]}async addMaybeTitle(i){this.data.maybe||(this.data.maybe=[]),this.data.maybe.push(i),await this.save()}async removeMaybeTitle(i){var t;this.data.maybe=((t=this.data.maybe)!=null?t:[]).filter(e=>e.id!==i),await this.save()}generateMaybeId(i){var a;let t="maybe-"+i.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),e=((a=this.data.maybe)!=null?a:[]).map(n=>n.id);if(!e.includes(t))return t;let s=2;for(;e.includes(`${t}-${s}`);)s++;return`${t}-${s}`}generateAirtimeId(i){var a;let t=`airtime-${i}`,e=((a=this.data.airtime)!=null?a:[]).map(n=>n.id);if(!e.includes(t))return t;let s=2;for(;e.includes(`${t}-${s}`);)s++;return`${t}-${s}`}calcTimeWatched(i){return i.episodeDuration<=0||i.status==="To be released"?0:i.type==="Movie"?i.watchedEpisodes.includes(1)?i.episodeDuration:0:i.status==="Completed"?this.getEffectiveTotal(i)*i.episodeDuration:i.watchedEpisodes.length*i.episodeDuration}calcTimeRemaining(i){if(i.episodeDuration<=0||i.status==="Dropped"||i.status==="To be released")return 0;if(i.type==="Movie")return i.watchedEpisodes.includes(1)?0:i.episodeDuration;let t=this.getEffectiveTotal(i);return i.status==="Plan to watch"||i.status==="Watching"?Math.max(0,t-i.watchedEpisodes.length)*i.episodeDuration:0}calcTimeRemainingForModal(i){if(i.episodeDuration<=0||i.status==="To be released")return 0;if(i.type==="Movie")return i.watchedEpisodes.includes(1)?0:i.episodeDuration;let t=this.getEffectiveTotal(i);return i.status==="Dropped"||i.status==="Plan to watch"||i.status==="Watching"?Math.max(0,t-i.watchedEpisodes.length)*i.episodeDuration:0}getTotalTimeWatched(){var i;return((i=this.data.titles)!=null?i:[]).reduce((t,e)=>t+this.calcTimeWatched(e),0)}getTotalTimeRemaining(){var i;return((i=this.data.titles)!=null?i:[]).reduce((t,e)=>t+this.calcTimeRemaining(e),0)}startWatchingExternalChanges(){let i=this.app.vault.on("raw",t=>{if(t.endsWith("watchlog/data.json")){if(Date.now()-this.lastSelfSaveTime{var e,s;await this.load(),this.notifyListeners(),await((e=this.plugin.readingDataManager)==null?void 0:e.adoptExternalChange()),(s=this.plugin.historyManager)==null||s.adoptExternalChange()})()}});this.plugin.registerEvent(i)}onChange(i){this.changeListeners.push(i)}offChange(i){this.changeListeners=this.changeListeners.filter(t=>t!==i)}notifyChange(){this.notifyListeners()}notifyListeners(){for(let i of this.changeListeners)i();activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed"))}getCollapsedSeasonsForTitle(i){var e;let t=this.data.collapsedSeasons;return new Set((e=t==null?void 0:t[i])!=null?e:[])}async persistCollapsedSeasons(i,t){let e=this.data;e.collapsedSeasons||(e.collapsedSeasons={}),e.collapsedSeasons[i]=Array.from(t),await this.save()}getTotalSkippedCount(i){return i.seasons.reduce((t,e)=>{var s,a;return t+((a=(s=e.skippedEpisodes)==null?void 0:s.length)!=null?a:0)},0)}getEffectiveTotal(i){return Math.max(0,i.totalEpisodes-this.getTotalSkippedCount(i))}isEpisodeSkipped(i,t){var e;for(let s of i.seasons){let a=t-s.offset;if(a>=1&&a<=s.episodes&&((e=s.skippedEpisodes)!=null?e:[]).includes(a))return!0}return!1}applyEpisodeWatchedToggle(i,t,e){var a,n;let s=this.getTitle(i);if(!s)return null;if(e){s.watchedEpisodes.includes(t)||(s.watchedEpisodes.push(t),s.watchedEpisodes.sort((o,l)=>o-l));let r=new Date().toISOString();s.totalEpisodes>1?(a=this.historyManager)==null||a.log(`${s.title} (${s.type}) episode ${t} was marked as watched on ${nt(r)}`,{source:"Watchlist",action:"watched",titleName:s.title}):(n=this.historyManager)==null||n.log(`${s.title} (${s.type}) was marked as watched on ${nt(r)}`,{source:"Watchlist",action:"watched",titleName:s.title})}else s.watchedEpisodes=s.watchedEpisodes.filter(r=>r!==t);return s.dateModified=new Date().toISOString(),this.applyAutoCompleteRules(s),this.scheduleEpisodeSave(i),s}applyAutoCompleteRules(i){var e;let t=this.getEffectiveTotal(i);this.plugin.settings.autoCompleteOnLastEpisode&&t>0&&i.watchedEpisodes.length>=t?(i.status!=="Completed"&&(i.status="Completed",i.priority=""),this.plugin.settings.setFinishDateAutomatically&&!i.dateFinished&&(i.dateFinished=(e=new Date().toISOString().split("T")[0])!=null?e:null)):i.status==="Completed"&&i.watchedEpisodes.lengthc-d));let l=new Date().toISOString();s.totalEpisodes>1?(n=this.historyManager)==null||n.log(`${s.title} (${s.type}) episode ${t} was marked as watched on ${nt(l)}`,{source:"Watchlist",action:"watched",titleName:s.title}):(r=this.historyManager)==null||r.log(`${s.title} (${s.type}) was marked as watched on ${nt(l)}`,{source:"Watchlist",action:"watched",titleName:s.title})}else s.watchedEpisodes=s.watchedEpisodes.filter(l=>l!==t);let a=this.getEffectiveTotal(s);this.plugin.settings.autoCompleteOnLastEpisode&&a>0&&s.watchedEpisodes.length>=a?(s.status="Completed",this.plugin.settings.setFinishDateAutomatically&&!s.dateFinished&&(s.dateFinished=(o=new Date().toISOString().split("T")[0])!=null?o:null)):s.status==="Completed"&&s.watchedEpisodes.length0&&t.every(d=>n.has(d));if(e){let d=new Set(a.watchedEpisodes);for(let u of t)d.add(u);a.watchedEpisodes=Array.from(d).sort((u,h)=>u-h)}else{let d=new Set(t);a.watchedEpisodes=a.watchedEpisodes.filter(u=>!d.has(u))}if(e&&s){let d=new Set(a.watchedEpisodes),u=t.length>0&&t.every(h=>d.has(h));if(!r&&u){let h=new Date().toISOString();(l=this.historyManager)==null||l.log(`${a.title} (${a.type}) ${s} was fully watched on ${nt(h)}`,{source:"Watchlist",action:"watched",titleName:a.title})}}let o=this.getEffectiveTotal(a);this.plugin.settings.autoCompleteOnLastEpisode&&o>0&&a.watchedEpisodes.length>=o?(a.status="Completed",this.plugin.settings.setFinishDateAutomatically&&!a.dateFinished&&(a.dateFinished=(c=new Date().toISOString().split("T")[0])!=null?c:null)):a.status==="Completed"&&a.watchedEpisodes.length:|?]/g,"-");return(0,ct.normalizePath)(`${t}/${i.type}/${e}.md`)}async updateMarkdownFile(i){let t=this.plugin.settings.rootFolder,e=(0,ct.normalizePath)(`${t}/${i.type}`);await this.ensureFolder(e);let s=this.getNoteFilePath(i),a=this.getProgress(i),n=this.buildMarkdownContent(i,a),r=this.lastMarkdownPathById.get(i.id);if(r&&r!==s)try{let l=this.app.vault.getAbstractFileByPath(r);l instanceof ct.TFile&&await this.app.fileManager.trashFile(l)}catch(l){}let o=this.app.vault.getAbstractFileByPath(s);o instanceof ct.TFile?await this.app.vault.modify(o,n):await this.app.vault.create(s,n),this.lastMarkdownPathById.set(i.id,s)}async createMarkdownFileIfMissing(i){let t=this.plugin.settings.rootFolder,e=(0,ct.normalizePath)(`${t}/${i.type}`),s=this.getNoteFilePath(i);if(this.app.vault.getAbstractFileByPath(s)instanceof ct.TFile)return!1;await this.ensureFolder((0,ct.normalizePath)(t)),await this.ensureFolder(e);let a=this.buildMarkdownContent(i,this.getProgress(i));return await this.app.vault.create(s,a),!0}buildMarkdownContent(i,t){var e,s;return`--- -title: ${i.title.replace(/[*"\\/<>:|?]/g,"-")} -type: ${i.type} -status: ${i.status} -priority: ${i.priority} -rating: ${i.rating} -dateStarted: ${(e=i.dateStarted)!=null?e:"null"} -dateFinished: ${(s=i.dateFinished)!=null?s:"null"} -progress: ${t}% -totalEpisodes: ${i.totalEpisodes} -externalLink: ${i.externalLink} ---- +var Ei=Object.defineProperty;var wa=Object.getOwnPropertyDescriptor;var ya=Object.getOwnPropertyNames;var ba=Object.prototype.hasOwnProperty;var Ea=(g,i)=>{for(var t in i)Ei(g,t,{get:i[t],enumerable:!0})},Sa=(g,i,t,e)=>{if(i&&typeof i=="object"||typeof i=="function")for(let s of ya(i))!ba.call(g,s)&&s!==t&&Ei(g,s,{get:()=>i[s],enumerable:!(e=wa(i,s))||e.enumerable});return g};var Da=g=>Sa(Ei({},"__esModule",{value:!0}),g);var ir={};Ea(ir,{default:()=>wi});module.exports=Da(ir);var Z=require("obsidian");var oe="none";function Ta(g){return(g==null?void 0:g.length)===1&&g[0]===oe}function zt(g){return!g||g.length===0}function ws(g){return zt(g.director)||zt(g.cast)}function kt(g){return!g||Ta(g)?[]:g}function le(g){let i=g.map(t=>t.trim()).filter(t=>t!==""&&t!=="N/A");return i.length>0?i.slice(0,4):[oe]}var Mt=["Reading","Completed","Plan to Read","To be released","Dropped"],ct=Mt.filter(g=>g!=="To be released"),Ie=[{color600:"#534AB7",color50:"#EEEDFE"},{color600:"#1D9E75",color50:"#E1F5EE"},{color600:"#EF9F27",color50:"#FAEEDA"},{color600:"#378ADD",color50:"#E6F1FB"},{color600:"#D85A30",color50:"#FAECE7"},{color600:"#993556",color50:"#FBEAF0"},{color600:"#639922",color50:"#EAF3DE"},{color600:"#5F5E5A",color50:"#F1EFE8"}],cr=Object.fromEntries(Ie.map(({color600:g,color50:i})=>[g,i])),dt="#5F5E5A",Si={defaultFolder:"WatchLog/Reading",defaultStatus:"Plan to Read",bookCustomFieldStyle:"fill",mangaCustomFieldStyle:"fill"};function ys(g){var s,a,n;let i=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],t=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],e=g.releaseTime?` \xB7 ${g.releaseTime}`:"";if(g.recurrence==="once"){if(!g.releaseDate)return"No date set";let r=new Date(g.releaseDate+"T12:00:00");return`Release date \xB7 ${r.getDate()} ${(s=t[r.getMonth()])!=null?s:""} ${r.getFullYear()}${e}`}return g.recurrence==="daily"?`Every day${e}`:g.recurrence==="weekly"?`Every ${g.dayOfWeek!==void 0&&(a=i[g.dayOfWeek])!=null?a:"Unknown"}${e}`:g.recurrence==="monthly"?`Monthly on day ${(n=g.dayOfMonth)!=null?n:"?"}${e}`:"\u2014"}var xt="__wl_last_used__",ht={colorTheme:"default",defaultWatchlistView:"cards",autoCompleteOnLastEpisode:!0,setFinishDateAutomatically:!1,omdbApiKey:"",tmdbApiKey:"",googleBooksApiKey:"",activeApi:"OMDb",animeApiSource:"jikan",typeApiMapping:{},types:[{name:"Anime",color:"#1D9E75"},{name:"Movie",color:"#378ADD"},{name:"TV Show",color:"#BA7517"},{name:"Korean TV Show",color:"#7F77DD"},{name:"Animation",color:"#D85A30"}],statuses:[{name:"Watching",color:"#1D9E75"},{name:"Plan to watch",color:"#00A9A5"},{name:"Completed",color:"#378ADD"},{name:"To be released",color:"#E8873A"},{name:"Dropped",color:"#E24B4A"}],reviews:[{name:"Nah",color:"#E24B4A"},{name:"Awesome",color:"#1D9E75"},{name:"Marvelous",color:"#7F77DD"}],priorities:[{name:"Low",color:"#888780"},{name:"Medium",color:"#3b82f6"},{name:"High",color:"#E24B4A"}],rootFolder:"WatchLog",autoCreateFolders:!0,coloredTypeBadges:!0,dashboardCardStyle:"rectangles",episodeNumbering:"absolute",defaultAddType:xt,lastAddedType:"",readingTypeColors:{manga:"#D4537E",book:"#D85A30"},customListsFolder:"WatchLog/CustomLists",defaultCustomColumns:[],draftsVaultTag:"#watchlog",draftsAfterAdding:"keep",customListTabOrder:[],showHintBanners:!0,showUpcomingStatusBar:!0,listFilters:{typeExclude:[],statusExclude:[],groupExclude:[],ratingExclude:[],priorityExclude:[],sort:"dateAdded",sortDir:"desc",secondSort:"none",secondSortDir:"asc"},seasonPalette:["#1D9E75","#BA7517","#378ADD","#7F77DD","#D85A30","#D4537E","#639922","#888780"]};function N(g,i,t){return i}function Pe(g,i){var e;let t=(e=i.readingTypeColors)!=null?e:ht.readingTypeColors;return g==="manga"?t.manga:t.book}function Q(g){if(!g)return"";let i=g.match(/^(\d{4})-(\d{2})-(\d{2})$/);return i?`${i[3]}/${i[2]}/${i[1]}`:g}function q(g){let i=g.trim();if(!i)return null;let t=i.split("/");if(t.length!==3)return null;let[e,s,a]=t;if(!e||!s||!a||a.length!==4)return null;let n=parseInt(e,10),r=parseInt(s,10),o=parseInt(a,10);if(isNaN(n)||isNaN(r)||isNaN(o)||r<1||r>12||n<1||n>31)return null;let l=new Date(o,r-1,n);return l.getFullYear()!==o||l.getMonth()!==r-1||l.getDate()!==n?null:`${a}-${s.padStart(2,"0")}-${e.padStart(2,"0")}`}function jt(g){let i=g.trim();if(!i)return null;if(/^\d{4}-\d{2}-\d{2}$/.test(i))return i;let t=i.match(/^(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})$/);if(t){let e=t[1].padStart(2,"0"),s=t[2].padStart(2,"0"),a=t[3],n=parseInt(e,10),r=parseInt(s,10);return r<1||r>12||n<1||n>31?null:`${a}-${s}-${e}`}return null}function Lt(g){if(!g||!/^\d{4}-\d{2}-\d{2}$/.test(g))return!1;let i=new Date;return i.setHours(0,0,0,0),new Date(g+"T12:00:00").getTime()>i.getTime()}function tt(g,i){var t;return g==="Anime"?"anime":g==="Movie"||g==="TV Show"||g==="TvShow"?"movie":(t=i==null?void 0:i[g])!=null?t:""}function Rt(g){var i;return g.manualPosterUrl&&g.manualPosterUrl.trim()!==""?g.manualPosterUrl:(i=g.posterUrl)!=null?i:""}function Be(g){return g.manualTrailerUrl&&g.manualTrailerUrl.trim()!==""?g.manualTrailerUrl:g.trailerUrl&&g.trailerUrl!=="none"?g.trailerUrl:""}function bs(g){return!g||g<0?"0":g>=1e6?(g/1e6).toFixed(1)+"M":g>=1e3?(g/1e3).toFixed(1)+"K":g.toString()}function j(g){if(g<=0)return"0m";let i=Math.floor(g/60),t=g%60,e=i>=1e3?String(i).replace(/\B(?=(\d{3})+(?!\d))/g,"."):String(i);return i===0?`${t}m`:t===0?`${e}h`:`${e}h ${t}m`}var it=require("obsidian");var Ca=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];function ot(g){var o;let i=new Date(g),t=(o=Ca[i.getDay()])!=null?o:"",e=String(i.getDate()).padStart(2,"0"),s=String(i.getMonth()+1).padStart(2,"0"),a=i.getFullYear(),n=String(i.getHours()).padStart(2,"0"),r=String(i.getMinutes()).padStart(2,"0");return`${t} ${e}/${s}/${a} at ${n}:${r}`}var ce=class{constructor(i){this.entries=[];this.MAX_ENTRIES=1e3;this.plugin=i}async load(){let i=this.plugin.dataManager.getData(),t=i.history;this.entries=Array.isArray(t)?t:[],this.entries.length>this.MAX_ENTRIES&&(this.entries=this.entries.slice(-this.MAX_ENTRIES)),i.history=this.entries}adoptExternalChange(){let i=this.plugin.dataManager.getData(),t=i.history;this.entries=Array.isArray(t)?t:[],this.entries.length>this.MAX_ENTRIES&&(this.entries=this.entries.slice(-this.MAX_ENTRIES)),i.history=this.entries}async log(i,t){let e={id:`${Date.now()}-${Math.random().toString(36).slice(2,7)}`,timestamp:new Date().toISOString(),message:i,source:t==null?void 0:t.source,action:t==null?void 0:t.action,titleName:t==null?void 0:t.titleName};this.entries.push(e),this.entries.length>this.MAX_ENTRIES&&(this.entries=this.entries.slice(-this.MAX_ENTRIES)),await this.save()}getEntries(){return[...this.entries].reverse()}exportEntries(){return[...this.entries]}async restore(i){let t=Array.isArray(i)?i:[];this.entries=t.length>this.MAX_ENTRIES?t.slice(-this.MAX_ENTRIES):t,await this.save()}async save(){try{this.plugin.dataManager.getData().history=this.entries,await this.plugin.dataManager.persist()}catch(i){}}};function ka(g){return g!==null&&typeof g=="object"&&Array.isArray(g.titles)}var de=class{constructor(i){this.changeListeners=[];this.historyManager=null;this.pendingSaveTimer=null;this.pendingMdTitleIds=new Set;this.EPISODE_SAVE_DEBOUNCE_MS=500;this.lastSelfSaveTime=0;this.SELF_SAVE_ECHO_WINDOW_MS=2e3;this.posterSaveTimer=null;this.POSTER_SAVE_DEBOUNCE_MS=5e3;this.queuedSaveTimer=null;this.QUEUED_SAVE_DEBOUNCE_MS=100;this.lastMarkdownPathById=new Map;this.plugin=i,this.app=i.app,this.data={titles:[],groups:[],settings:{}}}setHistoryManager(i){this.historyManager=i}async load(){let i=await this.plugin.loadData();this.data=ka(i)?i:{titles:[],groups:[],settings:{}},this.migrateData()&&await this.saveOnly()}migrateData(){var t;let i=!1;Array.isArray(this.data.titles)||(this.data.titles=[],i=!0),Array.isArray(this.data.groups)||(this.data.groups=[],i=!0),Array.isArray(this.data.airtime)||(this.data.airtime=[],i=!0);for(let e of this.data.titles){if(e.dateAdded?e.dateAdded.includes("T")||(e.dateAdded=new Date(e.dateAdded).toISOString(),i=!0):(e.dateAdded=new Date().toISOString(),i=!0),!e.dateModified){let a=e.lastInteracted;typeof a=="string"&&a?e.dateModified=a:e.dateModified=e.dateAdded,i=!0}for(let s of(t=e.seasons)!=null?t:[])Array.isArray(s.skippedEpisodes)||(s.skippedEpisodes=[],i=!0);e.posterUrl===void 0&&(e.posterUrl="",i=!0),e.manualPosterUrl===void 0&&(e.manualPosterUrl="",i=!0),e.trailerUrl===void 0&&(e.trailerUrl="",i=!0),e.manualTrailerUrl===void 0&&(e.manualTrailerUrl="",i=!0),e.anilistId===void 0&&(e.anilistId=0,i=!0),e.communityRating===void 0&&(e.communityRating=0,i=!0),e.communityVotes===void 0&&(e.communityVotes=0,i=!0),e.communitySource===void 0&&(e.communitySource="",i=!0),e.communityRatingLastFetched===void 0&&(e.communityRatingLastFetched="",i=!0)}if(!this.data.posterRetryDone){for(let e of this.data.titles)e.posterUrl==="none"&&(e.posterUrl="");this.data.posterRetryDone=!0,i=!0}return i}updatePosterUrl(i,t){let e=this.data.titles.find(s=>s.id===i);e&&(e.posterUrl=t,this.schedulePosterSave())}updateCommunityRating(i,t,e,s){let a=this.data.titles.find(n=>n.id===i);a&&(a.communityRating=t,a.communityVotes=e,a.communitySource=s,a.communityRatingLastFetched=new Date().toISOString(),this.saveOnly())}updateTrailerUrl(i,t){let e=this.data.titles.find(s=>s.id===i);e&&(e.trailerUrl=t,this.saveOnly())}async updateCredits(i,t,e){let s=this.getTitle(i);s&&(s.director=t,s.cast=e,await this.save(),await this.updateMarkdownFile(s))}schedulePosterSave(){this.posterSaveTimer===null&&(this.posterSaveTimer=window.setTimeout(()=>{this.posterSaveTimer=null,this.saveOnly()},this.POSTER_SAVE_DEBOUNCE_MS))}flushPosterSave(){this.posterSaveTimer!==null&&(window.clearTimeout(this.posterSaveTimer),this.posterSaveTimer=null,this.saveOnly())}flushPosterSaveSync(){this.posterSaveTimer!==null&&(window.clearTimeout(this.posterSaveTimer),this.posterSaveTimer=null,this.lastSelfSaveTime=Date.now(),this.plugin.saveData(this.data))}getData(){return this.data}queueSave(){this.queuedSaveTimer!==null&&window.clearTimeout(this.queuedSaveTimer),this.queuedSaveTimer=window.setTimeout(()=>{this.queuedSaveTimer=null,this.saveOnly()},this.QUEUED_SAVE_DEBOUNCE_MS)}flushQueuedSaveSync(){this.queuedSaveTimer!==null&&(window.clearTimeout(this.queuedSaveTimer),this.queuedSaveTimer=null,this.lastSelfSaveTime=Date.now(),this.plugin.saveData(this.data))}async saveSettings(i){this.data.settings=i,await this.saveOnly()}async saveOnly(){this.lastSelfSaveTime=Date.now(),await this.plugin.saveData(this.data),this.lastSelfSaveTime=Date.now()}async persist(){await this.saveOnly()}async save(){this.pendingSaveTimer!==null&&(window.clearTimeout(this.pendingSaveTimer),this.pendingSaveTimer=null,this.pendingMdTitleIds.clear()),await this.saveOnly(),this.notifyListeners()}scheduleEpisodeSave(i){this.pendingMdTitleIds.add(i),this.pendingSaveTimer!==null&&window.clearTimeout(this.pendingSaveTimer),this.pendingSaveTimer=window.setTimeout(()=>{this.flushPendingSave()},this.EPISODE_SAVE_DEBOUNCE_MS)}async flushPendingSave(){if(this.pendingSaveTimer!==null&&(window.clearTimeout(this.pendingSaveTimer),this.pendingSaveTimer=null),this.pendingMdTitleIds.size===0)return;let i=Array.from(this.pendingMdTitleIds);this.pendingMdTitleIds.clear(),await this.saveOnly();for(let t of i){let e=this.getTitle(t);e&&await this.updateMarkdownFile(e)}}flushPendingSaveSync(){if(this.pendingSaveTimer!==null&&(window.clearTimeout(this.pendingSaveTimer),this.pendingSaveTimer=null),this.pendingMdTitleIds.size===0)return;let i=Array.from(this.pendingMdTitleIds);this.pendingMdTitleIds.clear(),this.lastSelfSaveTime=Date.now(),this.plugin.saveData(this.data);for(let t of i){let e=this.getTitle(t);e&&this.updateMarkdownFile(e)}}getTitles(){var i;return(i=this.data.titles)!=null?i:[]}getTitle(i){var t;return((t=this.data.titles)!=null?t:[]).find(e=>e.id===i)}async addTitle(i){var s;i.posterUrl===void 0&&(i.posterUrl=""),i.trailerUrl===void 0&&(i.trailerUrl=""),i.manualTrailerUrl===void 0&&(i.manualTrailerUrl="");let t=this.canAutoAddToUpcoming(i);t&&(i.status="To be released"),this.data.titles.push(i),await this.save(),t&&await this.autoAddToUpcoming(i),await this.updateMarkdownFile(i);let e=new Date().toISOString();(s=this.historyManager)==null||s.log(`${i.title} (${i.type}) was added on ${ot(e)}`,{source:"Watchlist",action:"added",titleName:i.title})}async addTitleSilent(i){let t=this.canAutoAddToUpcoming(i);t&&(i.status="To be released"),this.data.titles.push(i),await this.saveOnly(),t&&await this.autoAddToUpcoming(i),await this.updateMarkdownFile(i)}async addTitleBatch(i){let t=[];for(let e of i)this.canAutoAddToUpcoming(e)&&(e.status="To be released",t.push(e)),this.data.titles.push(e);await this.saveOnly();for(let e of t)await this.autoAddToUpcoming(e);for(let e of i)await this.updateMarkdownFile(e)}async batchUpdate(i,t){let e=[];for(let s of i){let a=this.getTitle(s);a&&(t(a),a.dateModified=new Date().toISOString(),e.push(a))}if(e.length!==0){await this.save();for(let s of e)await this.updateMarkdownFile(s)}}async removeTitlesBatch(i){let e=[];for(let s of i){let a=this.getTitle(s);a&&e.push(a),this.data.titles=this.data.titles.filter(r=>r.id!==s);for(let r of this.data.groups)r.titleIds=r.titleIds.filter(o=>o!==s);this.data.airtime&&(this.data.airtime=this.data.airtime.filter(r=>r.titleId!==s||r.source==="reading"));let n=this.data;n.collapsedSeasons&&delete n.collapsedSeasons[s]}await this.save();for(let s=0;sthis.deleteMarkdownFile(n)))}}canAutoAddToUpcoming(i){if(!i.releaseDate||!/^\d{4}-\d{2}-\d{2}$/.test(i.releaseDate))return!1;let t=new Date(i.releaseDate+"T12:00:00"),e=new Date;return e.setHours(0,0,0,0),t>e}async autoAddToUpcoming(i){var e;if(this.data.airtime||(this.data.airtime=[]),this.data.airtime.some(s=>s.titleId===i.id))return;let t={id:this.generateAirtimeId(i.id),titleId:i.id,schedule:{recurrence:"once",releaseDate:(e=i.releaseDate)!=null?e:void 0},dateAdded:new Date().toISOString()};this.data.airtime.push(t),await this.plugin.saveData(this.data)}async removeAirtimeEntriesForTitle(i){var e,s,a;let t=((e=this.data.airtime)!=null?e:[]).length;this.data.airtime=((s=this.data.airtime)!=null?s:[]).filter(n=>n.titleId!==i||n.source==="reading"),((a=this.data.airtime)!=null?a:[]).length!==t&&await this.save()}async autoAddReadingToUpcoming(i,t){var s;if(this.data.airtime||(this.data.airtime=[]),this.data.airtime.some(a=>a.source==="reading"&&a.titleId===i.id))return;let e={id:this.generateReadingAirtimeId(i.id),titleId:i.id,source:"reading",readingKind:t,schedule:{recurrence:"once",releaseDate:(s=i.releaseDate)!=null?s:void 0},dateAdded:new Date().toISOString()};this.data.airtime.push(e),await this.plugin.saveData(this.data)}async removeReadingAirtimeEntries(i){var e,s,a;let t=((e=this.data.airtime)!=null?e:[]).length;this.data.airtime=((s=this.data.airtime)!=null?s:[]).filter(n=>!(n.source==="reading"&&n.titleId===i)),((a=this.data.airtime)!=null?a:[]).length!==t&&await this.save()}generateReadingAirtimeId(i){var a;let t=`airtime-reading-${i}`,e=((a=this.data.airtime)!=null?a:[]).map(n=>n.id);if(!e.includes(t))return t;let s=2;for(;e.includes(`${t}-${s}`);)s++;return`${t}-${s}`}async updateTitle(i){var e,s;i.dateModified=new Date().toISOString(),i.status==="Completed"&&(i.priority="");let t=this.data.titles.findIndex(a=>a.id===i.id);if(t>=0){let a=this.data.titles[t],n=new Date().toISOString();a.rating!==i.rating&&((e=this.historyManager)==null||e.log(`${i.title} (${i.type}) was reviewed on ${ot(n)}`,{source:"Watchlist",action:"rating",titleName:i.title})),a.status!==i.status&&i.status==="Completed"&&((s=this.historyManager)==null||s.log(`${i.title} (${i.type}) was marked as watched on ${ot(n)}`,{source:"Watchlist",action:"completed",titleName:i.title})),this.data.titles[t]=i,await this.save(),await this.updateMarkdownFile(i)}}updateTitleSilent(i){var e,s;i.dateModified=new Date().toISOString(),i.status==="Completed"&&(i.priority="");let t=this.data.titles.findIndex(a=>a.id===i.id);if(t>=0){let a=this.data.titles[t],n=new Date().toISOString();a.rating!==i.rating&&((e=this.historyManager)==null||e.log(`${i.title} (${i.type}) was reviewed on ${ot(n)}`,{source:"Watchlist",action:"rating",titleName:i.title})),a.status!==i.status&&i.status==="Completed"&&((s=this.historyManager)==null||s.log(`${i.title} (${i.type}) was marked as watched on ${ot(n)}`,{source:"Watchlist",action:"completed",titleName:i.title})),this.data.titles[t]=i}}async removeTitle(i){var s;let t=this.getTitle(i);if(t){let a=new Date().toISOString();(s=this.historyManager)==null||s.log(`${t.title} (${t.type}) was deleted on ${ot(a)}`,{source:"Watchlist",action:"deleted",titleName:t.title})}this.data.titles=this.data.titles.filter(a=>a.id!==i);for(let a of this.data.groups)a.titleIds=a.titleIds.filter(n=>n!==i);this.data.airtime&&(this.data.airtime=this.data.airtime.filter(a=>a.titleId!==i||a.source==="reading"));let e=this.data;e.collapsedSeasons&&delete e.collapsedSeasons[i],await this.save(),t&&await this.deleteMarkdownFile(t)}getGroups(){var i;return(i=this.data.groups)!=null?i:[]}getGroup(i){var t;return((t=this.data.groups)!=null?t:[]).find(e=>e.id===i)}async addGroup(i){this.data.groups.push(i),await this.save()}async updateGroup(i){let t=this.data.groups.findIndex(e=>e.id===i.id);t>=0&&(this.data.groups[t]=i,await this.save())}async removeGroup(i){this.data.groups=this.data.groups.filter(t=>t.id!==i),await this.save()}async addTitleToGroup(i,t){let e=this.getGroup(i);e&&(e.titleIds.includes(t)||(e.titleIds.push(t),await this.updateGroup(e)))}getGroupedTitleIds(){var t;let i=new Set;for(let e of(t=this.data.groups)!=null?t:[])for(let s of e.titleIds)i.add(s);return i}generateGroupId(i){var a;let t="group-"+i.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),e=((a=this.data.groups)!=null?a:[]).map(n=>n.id);if(!e.includes(t))return t;let s=2;for(;e.includes(`${t}-${s}`);)s++;return`${t}-${s}`}getPinnedGroupId(){var i;return(i=this.data.pinnedGroupId)!=null?i:null}async setPinnedGroupId(i){this.data.pinnedGroupId=i,await this.save()}getSavedFilterPreset(){var i;return(i=this.data.savedFilterPreset)!=null?i:null}async setSavedFilterPreset(i){this.data.savedFilterPreset=i,await this.save()}getAirtimeEntries(){var i;return(i=this.data.airtime)!=null?i:[]}async addAirtimeEntry(i){this.data.airtime||(this.data.airtime=[]),this.data.airtime.push(i),await this.save()}async updateAirtimeEntry(i){if(!this.data.airtime)return;let t=this.data.airtime.findIndex(e=>e.id===i.id);t>=0&&(this.data.airtime[t]=i,await this.save())}async removeAirtimeEntry(i){var t;this.data.airtime=((t=this.data.airtime)!=null?t:[]).filter(e=>e.id!==i),await this.save()}async removeAirtimeEntriesBatch(i){var e;if(i.length===0)return;let t=new Set(i);this.data.airtime=((e=this.data.airtime)!=null?e:[]).filter(s=>!t.has(s.id)),await this.save()}getMaybeTitles(){var i;return(i=this.data.maybe)!=null?i:[]}async addMaybeTitle(i){this.data.maybe||(this.data.maybe=[]),this.data.maybe.push(i),await this.save()}async removeMaybeTitle(i){var t;this.data.maybe=((t=this.data.maybe)!=null?t:[]).filter(e=>e.id!==i),await this.save()}generateMaybeId(i){var a;let t="maybe-"+i.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),e=((a=this.data.maybe)!=null?a:[]).map(n=>n.id);if(!e.includes(t))return t;let s=2;for(;e.includes(`${t}-${s}`);)s++;return`${t}-${s}`}generateAirtimeId(i){var a;let t=`airtime-${i}`,e=((a=this.data.airtime)!=null?a:[]).map(n=>n.id);if(!e.includes(t))return t;let s=2;for(;e.includes(`${t}-${s}`);)s++;return`${t}-${s}`}calcTimeWatched(i){return i.episodeDuration<=0||i.status==="To be released"?0:i.type==="Movie"?i.watchedEpisodes.includes(1)?i.episodeDuration:0:i.status==="Completed"?this.getEffectiveTotal(i)*i.episodeDuration:i.watchedEpisodes.length*i.episodeDuration}calcTimeRemaining(i){if(i.episodeDuration<=0||i.status==="Dropped"||i.status==="To be released")return 0;if(i.type==="Movie")return i.watchedEpisodes.includes(1)?0:i.episodeDuration;let t=this.getEffectiveTotal(i);return i.status==="Plan to watch"||i.status==="Watching"?Math.max(0,t-i.watchedEpisodes.length)*i.episodeDuration:0}calcTimeRemainingForModal(i){if(i.episodeDuration<=0||i.status==="To be released")return 0;if(i.type==="Movie")return i.watchedEpisodes.includes(1)?0:i.episodeDuration;let t=this.getEffectiveTotal(i);return i.status==="Dropped"||i.status==="Plan to watch"||i.status==="Watching"?Math.max(0,t-i.watchedEpisodes.length)*i.episodeDuration:0}getTotalTimeWatched(){var i;return((i=this.data.titles)!=null?i:[]).reduce((t,e)=>t+this.calcTimeWatched(e),0)}getTotalTimeRemaining(){var i;return((i=this.data.titles)!=null?i:[]).reduce((t,e)=>t+this.calcTimeRemaining(e),0)}startWatchingExternalChanges(){let i=this.app.vault.on("raw",t=>{if(t.endsWith("watchlog/data.json")){if(Date.now()-this.lastSelfSaveTime{var e,s;await this.load(),this.notifyListeners(),await((e=this.plugin.readingDataManager)==null?void 0:e.adoptExternalChange()),(s=this.plugin.historyManager)==null||s.adoptExternalChange()})()}});this.plugin.registerEvent(i)}onChange(i){this.changeListeners.push(i)}offChange(i){this.changeListeners=this.changeListeners.filter(t=>t!==i)}notifyChange(){this.notifyListeners()}notifyListeners(){for(let i of this.changeListeners)i();activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed"))}getCollapsedSeasonsForTitle(i){var e;let t=this.data.collapsedSeasons;return new Set((e=t==null?void 0:t[i])!=null?e:[])}async persistCollapsedSeasons(i,t){let e=this.data;e.collapsedSeasons||(e.collapsedSeasons={}),e.collapsedSeasons[i]=Array.from(t),await this.save()}getTotalSkippedCount(i){return i.seasons.reduce((t,e)=>{var s,a;return t+((a=(s=e.skippedEpisodes)==null?void 0:s.length)!=null?a:0)},0)}getEffectiveTotal(i){return Math.max(0,i.totalEpisodes-this.getTotalSkippedCount(i))}isEpisodeSkipped(i,t){var e;for(let s of i.seasons){let a=t-s.offset;if(a>=1&&a<=s.episodes&&((e=s.skippedEpisodes)!=null?e:[]).includes(a))return!0}return!1}applyEpisodeWatchedToggle(i,t,e){var a,n;let s=this.getTitle(i);if(!s)return null;if(e){s.watchedEpisodes.includes(t)||(s.watchedEpisodes.push(t),s.watchedEpisodes.sort((o,l)=>o-l));let r=new Date().toISOString();s.totalEpisodes>1?(a=this.historyManager)==null||a.log(`${s.title} (${s.type}) episode ${t} was marked as watched on ${ot(r)}`,{source:"Watchlist",action:"watched",titleName:s.title}):(n=this.historyManager)==null||n.log(`${s.title} (${s.type}) was marked as watched on ${ot(r)}`,{source:"Watchlist",action:"watched",titleName:s.title})}else s.watchedEpisodes=s.watchedEpisodes.filter(r=>r!==t);return s.dateModified=new Date().toISOString(),this.applyAutoCompleteRules(s),this.scheduleEpisodeSave(i),s}applyAutoCompleteRules(i){var e;let t=this.getEffectiveTotal(i);this.plugin.settings.autoCompleteOnLastEpisode&&t>0&&i.watchedEpisodes.length>=t?(i.status!=="Completed"&&(i.status="Completed",i.priority=""),this.plugin.settings.setFinishDateAutomatically&&!i.dateFinished&&(i.dateFinished=(e=new Date().toISOString().split("T")[0])!=null?e:null)):i.status==="Completed"&&i.watchedEpisodes.lengthc-d));let l=new Date().toISOString();s.totalEpisodes>1?(n=this.historyManager)==null||n.log(`${s.title} (${s.type}) episode ${t} was marked as watched on ${ot(l)}`,{source:"Watchlist",action:"watched",titleName:s.title}):(r=this.historyManager)==null||r.log(`${s.title} (${s.type}) was marked as watched on ${ot(l)}`,{source:"Watchlist",action:"watched",titleName:s.title})}else s.watchedEpisodes=s.watchedEpisodes.filter(l=>l!==t);let a=this.getEffectiveTotal(s);this.plugin.settings.autoCompleteOnLastEpisode&&a>0&&s.watchedEpisodes.length>=a?(s.status="Completed",this.plugin.settings.setFinishDateAutomatically&&!s.dateFinished&&(s.dateFinished=(o=new Date().toISOString().split("T")[0])!=null?o:null)):s.status==="Completed"&&s.watchedEpisodes.length0&&t.every(d=>n.has(d));if(e){let d=new Set(a.watchedEpisodes);for(let u of t)d.add(u);a.watchedEpisodes=Array.from(d).sort((u,h)=>u-h)}else{let d=new Set(t);a.watchedEpisodes=a.watchedEpisodes.filter(u=>!d.has(u))}if(e&&s){let d=new Set(a.watchedEpisodes),u=t.length>0&&t.every(h=>d.has(h));if(!r&&u){let h=new Date().toISOString();(l=this.historyManager)==null||l.log(`${a.title} (${a.type}) ${s} was fully watched on ${ot(h)}`,{source:"Watchlist",action:"watched",titleName:a.title})}}let o=this.getEffectiveTotal(a);this.plugin.settings.autoCompleteOnLastEpisode&&o>0&&a.watchedEpisodes.length>=o?(a.status="Completed",this.plugin.settings.setFinishDateAutomatically&&!a.dateFinished&&(a.dateFinished=(c=new Date().toISOString().split("T")[0])!=null?c:null)):a.status==="Completed"&&a.watchedEpisodes.length:|?]/g,"-");return(0,it.normalizePath)(`${t}/${i.type}/${e}.md`)}async updateMarkdownFile(i){let t=this.plugin.settings.rootFolder,e=(0,it.normalizePath)(`${t}/${i.type}`);await this.ensureFolder(e);let s=this.getNoteFilePath(i),a=this.getProgress(i),n=this.buildMarkdownContent(i,a),r=this.lastMarkdownPathById.get(i.id);if(r&&r!==s)try{let l=this.app.vault.getAbstractFileByPath(r);l instanceof it.TFile&&await this.app.fileManager.trashFile(l)}catch(l){}let o=this.app.vault.getAbstractFileByPath(s);if(o instanceof it.TFile){let l=await this.app.vault.read(o),c=this.rebuildWithFrontmatter(l,this.buildFrontmatter(i,a));c=this.replaceNotesSection(c,i.notes),c!==l&&await this.app.vault.modify(o,c)}else await this.app.vault.create(s,n);this.lastMarkdownPathById.set(i.id,s)}rebuildWithFrontmatter(i,t){let e=i.match(/^---\n[\s\S]*?\n---\n?/);return e?t+` +`+i.slice(e[0].length):t+` + +`+i}async readNotesFromFile(i){var n;let t=this.getNoteFilePath(i),e=this.app.vault.getAbstractFileByPath(t);if(!(e instanceof it.TFile))return console.warn(`[WatchLog] Notes read: no note file at resolved path "${t}" for title "${i.title}"`),null;let a=(await this.app.vault.read(e)).match(/(^|\n)## Notes[ \t]*\r?\n([\s\S]*?)(?=\n## |\n# |$)/);return a?((n=a[2])!=null?n:"").replace(/^\n+/,"").replace(/\s+$/,""):null}replaceNotesSection(i,t){let e=i.match(/(^|\n)## Notes[ \t]*\r?\n/);if(!e||e.index===void 0){let c=i.length===0||i.endsWith(` +`)?"":` +`;return`${i}${c} +## Notes + +${t} +`}let s=e.index+e[0].length,n=i.slice(s).match(/\n(?:## |# )/),r=n&&n.index!==void 0?s+n.index:i.length,o=i.slice(0,s),l=i.slice(r);return`${o} +${t} +${l}`}async createMarkdownFileIfMissing(i){let t=this.plugin.settings.rootFolder,e=(0,it.normalizePath)(`${t}/${i.type}`),s=this.getNoteFilePath(i);if(this.app.vault.getAbstractFileByPath(s)instanceof it.TFile)return!1;await this.ensureFolder((0,it.normalizePath)(t)),await this.ensureFolder(e);let a=this.buildMarkdownContent(i,this.getProgress(i));return await this.app.vault.create(s,a),!0}async rewriteFrontmatterIfExists(i){let t=this.getNoteFilePath(i),e=this.app.vault.getAbstractFileByPath(t);if(!(e instanceof it.TFile))return!1;let s=await this.app.vault.read(e),a=this.rebuildWithFrontmatter(s,this.buildFrontmatter(i,this.getProgress(i)));return a!==s&&await this.app.vault.modify(e,a),this.lastMarkdownPathById.set(i.id,t),!0}yamlEscape(i){return i===""?'""':`"${i.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}buildFrontmatter(i,t){var l,c;let e=d=>this.yamlEscape(d),s=["---"];s.push(`title: ${e(i.title)}`),s.push(`type: ${e(i.type)}`),s.push(`status: ${e(i.status)}`),s.push(`priority: ${e(i.priority)}`),i.review&&s.push(`review: ${e(i.review)}`),s.push(`rating: ${i.rating}`),s.push(`progress: ${t}%`),s.push(`totalEpisodes: ${i.totalEpisodes}`),s.push(`episodeDuration: ${i.episodeDuration}`),s.push(`dateStarted: ${(l=i.dateStarted)!=null?l:"null"}`),s.push(`dateFinished: ${(c=i.dateFinished)!=null?c:"null"}`),s.push(`dateAdded: ${e(i.dateAdded)}`),s.push(`dateModified: ${e(i.dateModified)}`),i.releaseDate&&s.push(`releaseDate: ${i.releaseDate}`),i.malId!==void 0&&s.push(`malId: ${i.malId}`),i.anilistId!==void 0&&s.push(`anilistId: ${i.anilistId}`),i.communityRating!==void 0&&s.push(`communityRating: ${i.communityRating}`),i.communityVotes!==void 0&&s.push(`communityVotes: ${i.communityVotes}`),i.communitySource&&s.push(`communitySource: ${e(i.communitySource)}`);let a=kt(i.director);a.length>0&&s.push(`director: [${a.map(e).join(", ")}]`);let n=kt(i.cast);n.length>0&&s.push(`cast: [${n.map(e).join(", ")}]`);let r=Rt(i);r&&r!=="none"&&s.push(`poster: ${e(r)}`);let o=Be(i);return o&&s.push(`trailer: ${e(o)}`),i.externalLink&&s.push(`externalLink: ${e(i.externalLink)}`),i.pinned&&s.push("pinned: true"),s.push("---"),s.join(` +`)}buildMarkdownContent(i,t){return`${this.buildFrontmatter(i,t)} ## Notes ${i.notes} -`}async deleteMarkdownFile(i){let t=this.getNoteFilePath(i),e=this.app.vault.getAbstractFileByPath(t);e instanceof ct.TFile&&await this.app.fileManager.trashFile(e)}getRecentlyWatched(i){var t;return[...(t=this.data.titles)!=null?t:[]].filter(e=>e.watchedEpisodes.length>0||e.status==="Completed").sort((e,s)=>s.dateModified.localeCompare(e.dateModified)).slice(0,i)}getRecentlyAdded(i){var t;return[...(t=this.data.titles)!=null?t:[]].sort((e,s)=>s.dateAdded.localeCompare(e.dateAdded)).slice(0,i)}getStatsByType(i){var r;let t=["Dropped","To be released"],e=(r=this.data.titles)!=null?r:[],s=(i==="All"?e:e.filter(o=>o.type===i)).filter(o=>!t.includes(o.status)),a=s.length;return{watched:s.filter(o=>o.status==="Completed").length,total:a}}getCompletedCount(){var i;return((i=this.data.titles)!=null?i:[]).filter(t=>t.status==="Completed").length}generateId(i){var a;let t=i.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),e=((a=this.data.titles)!=null?a:[]).map(n=>n.id);if(!e.includes(t))return t;let s=2;for(;e.includes(`${t}-${s}`);)s++;return`${t}-${s}`}};var rt=require("obsidian");function Gi(g){return g.replace(/[*"\\/<>:|?]/g,"-").trim()}function Ft(g){return g===""?'""':`"${g.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function si(g){return g.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}var Qt=class{constructor(i){this.changeListeners=[];this.historyManager=null;this.coverSaveTimer=null;this.COVER_SAVE_DEBOUNCE_MS=5e3;this.lastNotePathById=new Map;this.plugin=i,this.data=this.emptyData()}setHistoryManager(i){this.historyManager=i}emptyData(){return{books:[],manga:[],bookColumns:[],mangaColumns:[],settings:{...ii}}}get master(){return this.plugin.dataManager.getData()}bindFromMaster(){var t;let i=this.master.reading;i&&typeof i=="object"?this.data={books:Array.isArray(i.books)?i.books:[],manga:Array.isArray(i.manga)?i.manga:[],bookColumns:Array.isArray(i.bookColumns)?i.bookColumns:[],mangaColumns:Array.isArray(i.mangaColumns)?i.mangaColumns:[],settings:{...ii,...(t=i.settings)!=null?t:{}}}:this.data=this.emptyData(),this.master.reading=this.data}async load(){this.bindFromMaster(),this.migrate()&&await this.saveOnly();let t=this.plugin.dataManager;if(t){for(let e of this.data.books)yt(e.releaseDate)&&await t.autoAddReadingToUpcoming(e,"book");for(let e of this.data.manga)yt(e.releaseDate)&&await t.autoAddReadingToUpcoming(e,"manga")}}migrate(){let i=!1;this.data.settings.defaultStatus==="On Hold"&&(this.data.settings.defaultStatus="Plan to Read",i=!0);for(let t of this.data.books)typeof t.author!="string"&&(t.author="",i=!0),typeof t.rating!="number"&&(t.rating=0,i=!0),typeof t.pagesRead!="number"&&(t.pagesRead=0,i=!0),typeof t.totalPages!="number"&&(t.totalPages=0,i=!0),typeof t.chaptersRead!="number"&&(t.chaptersRead=0,i=!0),typeof t.totalChapters!="number"&&(t.totalChapters=0,i=!0),typeof t.coverUrl!="string"&&(t.coverUrl="",i=!0),typeof t.googleBooksId!="string"&&(t.googleBooksId="",i=!0),typeof t.vaultPage!="string"&&(t.vaultPage="",i=!0),t.dateStarted===void 0&&(t.dateStarted=null,i=!0),t.dateFinished===void 0&&(t.dateFinished=null,i=!0),t.releaseDate===void 0&&(t.releaseDate=null,i=!0),t.status==="On Hold"&&(t.status="Plan to Read",i=!0),t.dateAdded||(t.dateAdded=new Date().toISOString(),i=!0),t.dateModified||(t.dateModified=t.dateAdded,i=!0),(!t.customFields||typeof t.customFields!="object")&&(t.customFields={},i=!0);for(let t of this.data.manga)typeof t.author!="string"&&(t.author="",i=!0),typeof t.rating!="number"&&(t.rating=0,i=!0),typeof t.chaptersRead!="number"&&(t.chaptersRead=0,i=!0),typeof t.totalChapters!="number"&&(t.totalChapters=0,i=!0),typeof t.volumesRead!="number"&&(t.volumesRead=0,i=!0),typeof t.totalVolumes!="number"&&(t.totalVolumes=0,i=!0),typeof t.coverUrl!="string"&&(t.coverUrl="",i=!0),typeof t.malId!="string"&&(t.malId="",i=!0),typeof t.vaultPage!="string"&&(t.vaultPage="",i=!0),t.dateStarted===void 0&&(t.dateStarted=null,i=!0),t.dateFinished===void 0&&(t.dateFinished=null,i=!0),t.releaseDate===void 0&&(t.releaseDate=null,i=!0),t.status==="On Hold"&&(t.status="Plan to Read",i=!0),t.dateAdded||(t.dateAdded=new Date().toISOString(),i=!0),t.dateModified||(t.dateModified=t.dateAdded,i=!0),(!t.customFields||typeof t.customFields!="object")&&(t.customFields={},i=!0);for(let t of this.data.bookColumns)Array.isArray(t.options)||(t.options=[],i=!0),t.color||(t.color="#5F5E5A",i=!0);for(let t of this.data.mangaColumns)Array.isArray(t.options)||(t.options=[],i=!0),t.color||(t.color="#5F5E5A",i=!0);for(let t of this.data.books)this.applyReleaseStatus(t)&&(i=!0);for(let t of this.data.manga)this.applyReleaseStatus(t)&&(i=!0);return i}applyReleaseStatus(i){if(yt(i.releaseDate)){if(i.status!=="To be released")return i.status="To be released",!0}else if(i.status==="To be released")return i.status="Plan to Read",!0;return!1}async syncUpcoming(i,t){let e=this.plugin.dataManager;e&&(yt(i.releaseDate)?await e.autoAddReadingToUpcoming(i,t):await e.removeReadingAirtimeEntries(i.id))}getData(){return this.data}getSettings(){return this.data.settings}async updateSettings(i){this.data.settings={...this.data.settings,...i},await this.save()}async saveOnly(){try{this.master.reading=this.data,await this.plugin.dataManager.persist()}catch(i){console.warn("[WL] ReadingDataManager.save failed:",i)}}async adoptExternalChange(){this.bindFromMaster(),this.migrate()&&await this.saveOnly(),this.notifyListeners()}async save(){await this.saveOnly(),this.notifyListeners()}onChange(i){this.changeListeners.push(i)}offChange(i){this.changeListeners=this.changeListeners.filter(t=>t!==i)}notifyChange(){this.notifyListeners()}async saveAndNotify(){await this.saveOnly(),this.notifyListeners()}async restore(i){this.master.reading=i,await this.plugin.dataManager.persist(),await this.load(),this.notifyListeners()}notifyListeners(){for(let i of this.changeListeners)i()}updateCoverUrl(i,t,e){let s=i==="book"?this.getBook(t):this.getManga(t);s&&(s.coverUrl=e,this.coverSaveTimer===null&&(this.coverSaveTimer=window.setTimeout(()=>{this.coverSaveTimer=null,this.saveOnly()},this.COVER_SAVE_DEBOUNCE_MS)))}updateCoverAndSource(i,t,e,s){let a=i==="book"?this.getBook(t):this.getManga(t);a&&(a.coverUrl=e,i==="book"?a.googleBooksId=s:a.malId=s,this.coverSaveTimer===null&&(this.coverSaveTimer=window.setTimeout(()=>{this.coverSaveTimer=null,this.saveOnly()},this.COVER_SAVE_DEBOUNCE_MS)))}flushCoverSave(){this.coverSaveTimer!==null&&(window.clearTimeout(this.coverSaveTimer),this.coverSaveTimer=null,this.saveOnly())}getBooks(){return this.data.books}getBook(i){return this.data.books.find(t=>t.id===i)}async addBook(i){var t;this.applyReleaseStatus(i),this.data.books.push(i),await this.save(),await this.syncUpcoming(i,"book");try{await this.writeReadingNote("book",i)}catch(e){console.warn("[WL] writeReadingNote failed:",e)}(t=this.historyManager)==null||t.log(`${i.title} (Book) was added`,{source:"Reading",action:"added",titleName:i.title})}async addBookSilent(i){this.applyReleaseStatus(i),this.data.books.push(i),await this.saveOnly()}async updateBook(i){var e,s,a;i.dateModified=new Date().toISOString(),this.applyReleaseStatus(i);let t=this.data.books.findIndex(n=>n.id===i.id);if(t>=0){let n=this.data.books[t];if(n.status!==i.status){let r=i.status==="Completed"?"completed":"status";i.status==="Completed"&&this.plugin.settings.setFinishDateAutomatically&&!i.dateFinished&&(i.dateFinished=(e=new Date().toISOString().split("T")[0])!=null?e:null),(s=this.historyManager)==null||s.log(`${i.title} (Book) status changed to ${i.status}`,{source:"Reading",action:r,titleName:i.title})}n.rating!==i.rating&&((a=this.historyManager)==null||a.log(`${i.title} (Book) Rating \u2192 ${i.rating}/5`,{source:"Reading",action:"rating",titleName:i.title})),this.data.books[t]=i,await this.save(),n.releaseDate!==i.releaseDate&&await this.syncUpcoming(i,"book");try{await this.writeReadingNote("book",i)}catch(r){console.warn("[WL] writeReadingNote failed:",r)}}}updateBookSilent(i){i.dateModified=new Date().toISOString(),this.applyReleaseStatus(i);let t=this.data.books.findIndex(e=>e.id===i.id);t>=0&&(this.data.books[t]=i)}async removeBook(i){var e,s;let t=this.getBook(i);if(this.data.books=this.data.books.filter(a=>a.id!==i),await this.save(),await((e=this.plugin.dataManager)==null?void 0:e.removeReadingAirtimeEntries(i)),t){(s=this.historyManager)==null||s.log(`${t.title} (Book) was deleted`,{source:"Reading",action:"deleted",titleName:t.title});try{await this.deleteReadingNote("book",t)}catch(a){console.warn("[WL] deleteReadingNote failed:",a)}}}async addBookBatch(i){var t;for(let e of i)this.applyReleaseStatus(e),this.data.books.push(e);await this.saveOnly();for(let e of i){await this.syncUpcoming(e,"book");try{await this.writeReadingNote("book",e)}catch(s){console.warn("[WL] writeReadingNote failed:",s)}(t=this.historyManager)==null||t.log(`${e.title} (Book) was added`,{source:"Reading",action:"added",titleName:e.title})}}generateBookId(i){let t=si(i)||"book",e=new Set(this.data.books.map(a=>a.id));if(!e.has(t))return t;let s=2;for(;e.has(`${t}-${s}`);)s++;return`${t}-${s}`}getMangaList(){return this.data.manga}getManga(i){return this.data.manga.find(t=>t.id===i)}async addManga(i){var t;this.applyReleaseStatus(i),this.data.manga.push(i),await this.save(),await this.syncUpcoming(i,"manga");try{await this.writeReadingNote("manga",i)}catch(e){console.warn("[WL] writeReadingNote failed:",e)}(t=this.historyManager)==null||t.log(`${i.title} (Manga) was added`,{source:"Reading",action:"added",titleName:i.title})}async addMangaSilent(i){this.applyReleaseStatus(i),this.data.manga.push(i),await this.saveOnly()}async updateManga(i){var e,s,a;i.dateModified=new Date().toISOString(),this.applyReleaseStatus(i);let t=this.data.manga.findIndex(n=>n.id===i.id);if(t>=0){let n=this.data.manga[t];if(n.status!==i.status){let r=i.status==="Completed"?"completed":"status";i.status==="Completed"&&this.plugin.settings.setFinishDateAutomatically&&!i.dateFinished&&(i.dateFinished=(e=new Date().toISOString().split("T")[0])!=null?e:null),(s=this.historyManager)==null||s.log(`${i.title} (Manga) status changed to ${i.status}`,{source:"Reading",action:r,titleName:i.title})}n.rating!==i.rating&&((a=this.historyManager)==null||a.log(`${i.title} (Manga) Rating \u2192 ${i.rating}/5`,{source:"Reading",action:"rating",titleName:i.title})),this.data.manga[t]=i,await this.save(),n.releaseDate!==i.releaseDate&&await this.syncUpcoming(i,"manga");try{await this.writeReadingNote("manga",i)}catch(r){console.warn("[WL] writeReadingNote failed:",r)}}}updateMangaSilent(i){i.dateModified=new Date().toISOString(),this.applyReleaseStatus(i);let t=this.data.manga.findIndex(e=>e.id===i.id);t>=0&&(this.data.manga[t]=i)}async removeManga(i){var e,s;let t=this.getManga(i);if(this.data.manga=this.data.manga.filter(a=>a.id!==i),await this.save(),await((e=this.plugin.dataManager)==null?void 0:e.removeReadingAirtimeEntries(i)),t){(s=this.historyManager)==null||s.log(`${t.title} (Manga) was deleted`,{source:"Reading",action:"deleted",titleName:t.title});try{await this.deleteReadingNote("manga",t)}catch(a){console.warn("[WL] deleteReadingNote failed:",a)}}}async removeBooksBatch(i){var s,a;let e=[];for(let n of i){let r=this.getBook(n);r&&e.push(r)}this.data.books=this.data.books.filter(n=>!i.includes(n.id)),await this.save();for(let n of i)await((s=this.plugin.dataManager)==null?void 0:s.removeReadingAirtimeEntries(n));for(let n of e)(a=this.historyManager)==null||a.log(`${n.title} (Book) was deleted`,{source:"Reading",action:"deleted",titleName:n.title});for(let n=0;nthis.deleteReadingNote("book",o).catch(()=>{})))}}async removeMangaBatch(i){var s,a;let e=[];for(let n of i){let r=this.getManga(n);r&&e.push(r)}this.data.manga=this.data.manga.filter(n=>!i.includes(n.id)),await this.save();for(let n of i)await((s=this.plugin.dataManager)==null?void 0:s.removeReadingAirtimeEntries(n));for(let n of e)(a=this.historyManager)==null||a.log(`${n.title} (Manga) was deleted`,{source:"Reading",action:"deleted",titleName:n.title});for(let n=0;nthis.deleteReadingNote("manga",o).catch(()=>{})))}}async addMangaBatch(i){var t;for(let e of i)this.applyReleaseStatus(e),this.data.manga.push(e);await this.saveOnly();for(let e of i){await this.syncUpcoming(e,"manga");try{await this.writeReadingNote("manga",e)}catch(s){console.warn("[WL] writeReadingNote failed:",s)}(t=this.historyManager)==null||t.log(`${e.title} (Manga) was added`,{source:"Reading",action:"added",titleName:e.title})}}generateMangaId(i){let t=si(i)||"manga",e=new Set(this.data.manga.map(a=>a.id));if(!e.has(t))return t;let s=2;for(;e.has(`${t}-${s}`);)s++;return`${t}-${s}`}getBookColumns(){return this.data.bookColumns}getMangaColumns(){return this.data.mangaColumns}columnsFor(i){return i==="book"?this.data.bookColumns:this.data.mangaColumns}async addColumn(i,t){this.columnsFor(i).push(t),await this.save()}async updateColumn(i,t){let e=this.columnsFor(i),s=e.findIndex(a=>a.id===t.id);s>=0&&(e[s]=t,await this.save())}async removeColumn(i,t){if(i==="book"){this.data.bookColumns=this.data.bookColumns.filter(e=>e.id!==t);for(let e of this.data.books)e.customFields&&Object.prototype.hasOwnProperty.call(e.customFields,t)&&delete e.customFields[t]}else{this.data.mangaColumns=this.data.mangaColumns.filter(e=>e.id!==t);for(let e of this.data.manga)e.customFields&&Object.prototype.hasOwnProperty.call(e.customFields,t)&&delete e.customFields[t]}await this.save()}generateColumnId(i,t){let e=`col-${si(t)||"field"}`,s=new Set(this.columnsFor(i).map(n=>n.id));if(!s.has(e))return e;let a=2;for(;s.has(`${e}-${a}`);)a++;return`${e}-${a}`}async reorderColumns(i,t,e){let s=this.columnsFor(i);if(t<0||t>=s.length||e<0||e>=s.length)return;let[a]=s.splice(t,1);a&&(s.splice(e,0,a),await this.save())}async setCustomField(i,t,e,s){let a=i==="book"?this.getBook(t):this.getManga(t);a&&(a.customFields||(a.customFields={}),s===null||s===""?delete a.customFields[e]:a.customFields[e]=s,a.dateModified=new Date().toISOString(),await this.save())}kindFolder(i){let t=this.data.settings.defaultFolder||"WatchLog/Reading";return(0,rt.normalizePath)(`${t}/${i==="book"?"Books":"Manga"}`)}noteFilePath(i,t){let e=Gi(t)||(i==="book"?"book":"manga");return(0,rt.normalizePath)(`${this.kindFolder(i)}/${e}.md`)}async ensureFolder(i){let t=(0,rt.normalizePath)(i);if(!this.plugin.app.vault.getAbstractFileByPath(t))try{await this.plugin.app.vault.createFolder(t)}catch(e){}}buildFrontmatter(i,t){var s,a,n,r;let e=["---"];if(e.push(`title: ${Ft(Gi(t.title))}`),e.push(`author: ${Ft((s=t.author)!=null?s:"")}`),e.push(`status: ${Ft(t.status)}`),e.push(`rating: ${t.rating|0}`),i==="book"){let o=t;e.push(`pagesRead: ${o.pagesRead|0}`),e.push(`totalPages: ${o.totalPages|0}`),e.push(`chaptersRead: ${o.chaptersRead|0}`),e.push(`totalChapters: ${o.totalChapters|0}`),o.googleBooksId&&e.push(`googleBooksId: ${Ft(o.googleBooksId)}`)}else{let o=t;e.push(`chaptersRead: ${o.chaptersRead|0}`),e.push(`totalChapters: ${o.totalChapters|0}`),e.push(`volumesRead: ${o.volumesRead|0}`),e.push(`totalVolumes: ${o.totalVolumes|0}`),o.malId&&e.push(`malId: ${Ft(o.malId)}`)}return e.push(`dateStarted: ${(a=t.dateStarted)!=null?a:"null"}`),e.push(`dateFinished: ${(n=t.dateFinished)!=null?n:"null"}`),e.push(`releaseDate: ${(r=t.releaseDate)!=null?r:"null"}`),e.push(`dateAdded: ${Ft(t.dateAdded)}`),e.push(`type: ${i==="book"?"book":"manga"}`),e.push("---"),e.join(` +`}async deleteMarkdownFile(i){let t=this.getNoteFilePath(i),e=this.app.vault.getAbstractFileByPath(t);e instanceof it.TFile&&await this.app.fileManager.trashFile(e)}getRecentlyWatched(i){var t;return[...(t=this.data.titles)!=null?t:[]].filter(e=>e.watchedEpisodes.length>0||e.status==="Completed").sort((e,s)=>s.dateModified.localeCompare(e.dateModified)).slice(0,i)}getRecentlyAdded(i){var t;return[...(t=this.data.titles)!=null?t:[]].sort((e,s)=>s.dateAdded.localeCompare(e.dateAdded)).slice(0,i)}getStatsByType(i){var r;let t=["Dropped","To be released"],e=(r=this.data.titles)!=null?r:[],s=(i==="All"?e:e.filter(o=>o.type===i)).filter(o=>!t.includes(o.status)),a=s.length;return{watched:s.filter(o=>o.status==="Completed").length,total:a}}getCompletedCount(){var i;return((i=this.data.titles)!=null?i:[]).filter(t=>t.status==="Completed").length}generateId(i){var a;let t=i.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),e=((a=this.data.titles)!=null?a:[]).map(n=>n.id);if(!e.includes(t))return t;let s=2;for(;e.includes(`${t}-${s}`);)s++;return`${t}-${s}`}};var st=require("obsidian");function Es(g){return g.replace(/[*"\\/<>:|?]/g,"-").trim()}function Et(g){return g===""?'""':`"${g.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function Di(g){return g.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}var ue=class{constructor(i){this.changeListeners=[];this.historyManager=null;this.coverSaveTimer=null;this.COVER_SAVE_DEBOUNCE_MS=5e3;this.lastNotePathById=new Map;this.plugin=i,this.data=this.emptyData()}setHistoryManager(i){this.historyManager=i}emptyData(){return{books:[],manga:[],bookColumns:[],mangaColumns:[],settings:{...Si}}}get master(){return this.plugin.dataManager.getData()}bindFromMaster(){var t;let i=this.master.reading;i&&typeof i=="object"?this.data={books:Array.isArray(i.books)?i.books:[],manga:Array.isArray(i.manga)?i.manga:[],bookColumns:Array.isArray(i.bookColumns)?i.bookColumns:[],mangaColumns:Array.isArray(i.mangaColumns)?i.mangaColumns:[],settings:{...Si,...(t=i.settings)!=null?t:{}}}:this.data=this.emptyData(),this.master.reading=this.data}async load(){this.bindFromMaster(),this.migrate()&&await this.saveOnly();let t=this.plugin.dataManager;if(t){for(let e of this.data.books)Lt(e.releaseDate)&&await t.autoAddReadingToUpcoming(e,"book");for(let e of this.data.manga)Lt(e.releaseDate)&&await t.autoAddReadingToUpcoming(e,"manga")}}migrate(){let i=!1;this.data.settings.defaultStatus==="On Hold"&&(this.data.settings.defaultStatus="Plan to Read",i=!0);for(let t of this.data.books)typeof t.author!="string"&&(t.author="",i=!0),typeof t.rating!="number"&&(t.rating=0,i=!0),typeof t.pagesRead!="number"&&(t.pagesRead=0,i=!0),typeof t.totalPages!="number"&&(t.totalPages=0,i=!0),typeof t.chaptersRead!="number"&&(t.chaptersRead=0,i=!0),typeof t.totalChapters!="number"&&(t.totalChapters=0,i=!0),typeof t.coverUrl!="string"&&(t.coverUrl="",i=!0),typeof t.googleBooksId!="string"&&(t.googleBooksId="",i=!0),typeof t.vaultPage!="string"&&(t.vaultPage="",i=!0),t.dateStarted===void 0&&(t.dateStarted=null,i=!0),t.dateFinished===void 0&&(t.dateFinished=null,i=!0),t.releaseDate===void 0&&(t.releaseDate=null,i=!0),t.status==="On Hold"&&(t.status="Plan to Read",i=!0),t.dateAdded||(t.dateAdded=new Date().toISOString(),i=!0),t.dateModified||(t.dateModified=t.dateAdded,i=!0),(!t.customFields||typeof t.customFields!="object")&&(t.customFields={},i=!0);for(let t of this.data.manga)typeof t.author!="string"&&(t.author="",i=!0),typeof t.rating!="number"&&(t.rating=0,i=!0),typeof t.chaptersRead!="number"&&(t.chaptersRead=0,i=!0),typeof t.totalChapters!="number"&&(t.totalChapters=0,i=!0),typeof t.volumesRead!="number"&&(t.volumesRead=0,i=!0),typeof t.totalVolumes!="number"&&(t.totalVolumes=0,i=!0),typeof t.coverUrl!="string"&&(t.coverUrl="",i=!0),typeof t.malId!="string"&&(t.malId="",i=!0),typeof t.vaultPage!="string"&&(t.vaultPage="",i=!0),t.dateStarted===void 0&&(t.dateStarted=null,i=!0),t.dateFinished===void 0&&(t.dateFinished=null,i=!0),t.releaseDate===void 0&&(t.releaseDate=null,i=!0),t.status==="On Hold"&&(t.status="Plan to Read",i=!0),t.dateAdded||(t.dateAdded=new Date().toISOString(),i=!0),t.dateModified||(t.dateModified=t.dateAdded,i=!0),(!t.customFields||typeof t.customFields!="object")&&(t.customFields={},i=!0);for(let t of this.data.bookColumns)Array.isArray(t.options)||(t.options=[],i=!0),t.color||(t.color="#5F5E5A",i=!0);for(let t of this.data.mangaColumns)Array.isArray(t.options)||(t.options=[],i=!0),t.color||(t.color="#5F5E5A",i=!0);for(let t of this.data.books)this.applyReleaseStatus(t)&&(i=!0);for(let t of this.data.manga)this.applyReleaseStatus(t)&&(i=!0);return i}applyReleaseStatus(i){if(Lt(i.releaseDate)){if(i.status!=="To be released")return i.status="To be released",!0}else if(i.status==="To be released")return i.status="Plan to Read",!0;return!1}async syncUpcoming(i,t){let e=this.plugin.dataManager;e&&(Lt(i.releaseDate)?await e.autoAddReadingToUpcoming(i,t):await e.removeReadingAirtimeEntries(i.id))}getData(){return this.data}getSettings(){return this.data.settings}async updateSettings(i){this.data.settings={...this.data.settings,...i},await this.save()}async saveOnly(){try{this.master.reading=this.data,await this.plugin.dataManager.persist()}catch(i){console.warn("[WL] ReadingDataManager.save failed:",i)}}async adoptExternalChange(){this.bindFromMaster(),this.migrate()&&await this.saveOnly(),this.notifyListeners()}async save(){await this.saveOnly(),this.notifyListeners()}onChange(i){this.changeListeners.push(i)}offChange(i){this.changeListeners=this.changeListeners.filter(t=>t!==i)}notifyChange(){this.notifyListeners()}async saveAndNotify(){await this.saveOnly(),this.notifyListeners()}async restore(i){this.master.reading=i,await this.plugin.dataManager.persist(),await this.load(),this.notifyListeners()}notifyListeners(){for(let i of this.changeListeners)i()}updateCoverUrl(i,t,e){let s=i==="book"?this.getBook(t):this.getManga(t);s&&(s.coverUrl=e,this.coverSaveTimer===null&&(this.coverSaveTimer=window.setTimeout(()=>{this.coverSaveTimer=null,this.saveOnly()},this.COVER_SAVE_DEBOUNCE_MS)))}updateCoverAndSource(i,t,e,s){let a=i==="book"?this.getBook(t):this.getManga(t);a&&(a.coverUrl=e,i==="book"?a.googleBooksId=s:a.malId=s,this.coverSaveTimer===null&&(this.coverSaveTimer=window.setTimeout(()=>{this.coverSaveTimer=null,this.saveOnly()},this.COVER_SAVE_DEBOUNCE_MS)))}flushCoverSave(){this.coverSaveTimer!==null&&(window.clearTimeout(this.coverSaveTimer),this.coverSaveTimer=null,this.saveOnly())}getBooks(){return this.data.books}getBook(i){return this.data.books.find(t=>t.id===i)}async addBook(i){var t;this.applyReleaseStatus(i),this.data.books.push(i),await this.save(),await this.syncUpcoming(i,"book");try{await this.writeReadingNote("book",i)}catch(e){console.warn("[WL] writeReadingNote failed:",e)}(t=this.historyManager)==null||t.log(`${i.title} (Book) was added`,{source:"Reading",action:"added",titleName:i.title})}async addBookSilent(i){this.applyReleaseStatus(i),this.data.books.push(i),await this.saveOnly()}async updateBook(i){var e,s,a;i.dateModified=new Date().toISOString(),this.applyReleaseStatus(i);let t=this.data.books.findIndex(n=>n.id===i.id);if(t>=0){let n=this.data.books[t];if(n.status!==i.status){let r=i.status==="Completed"?"completed":"status";i.status==="Completed"&&this.plugin.settings.setFinishDateAutomatically&&!i.dateFinished&&(i.dateFinished=(e=new Date().toISOString().split("T")[0])!=null?e:null),(s=this.historyManager)==null||s.log(`${i.title} (Book) status changed to ${i.status}`,{source:"Reading",action:r,titleName:i.title})}n.rating!==i.rating&&((a=this.historyManager)==null||a.log(`${i.title} (Book) Rating \u2192 ${i.rating}/5`,{source:"Reading",action:"rating",titleName:i.title})),this.data.books[t]=i,await this.save(),n.releaseDate!==i.releaseDate&&await this.syncUpcoming(i,"book");try{await this.writeReadingNote("book",i)}catch(r){console.warn("[WL] writeReadingNote failed:",r)}}}updateBookSilent(i){i.dateModified=new Date().toISOString(),this.applyReleaseStatus(i);let t=this.data.books.findIndex(e=>e.id===i.id);t>=0&&(this.data.books[t]=i)}async removeBook(i){var e,s;let t=this.getBook(i);if(this.data.books=this.data.books.filter(a=>a.id!==i),await this.save(),await((e=this.plugin.dataManager)==null?void 0:e.removeReadingAirtimeEntries(i)),t){(s=this.historyManager)==null||s.log(`${t.title} (Book) was deleted`,{source:"Reading",action:"deleted",titleName:t.title});try{await this.deleteReadingNote("book",t)}catch(a){console.warn("[WL] deleteReadingNote failed:",a)}}}async addBookBatch(i){var t;for(let e of i)this.applyReleaseStatus(e),this.data.books.push(e);await this.saveOnly();for(let e of i){await this.syncUpcoming(e,"book");try{await this.writeReadingNote("book",e)}catch(s){console.warn("[WL] writeReadingNote failed:",s)}(t=this.historyManager)==null||t.log(`${e.title} (Book) was added`,{source:"Reading",action:"added",titleName:e.title})}}generateBookId(i){let t=Di(i)||"book",e=new Set(this.data.books.map(a=>a.id));if(!e.has(t))return t;let s=2;for(;e.has(`${t}-${s}`);)s++;return`${t}-${s}`}getMangaList(){return this.data.manga}getManga(i){return this.data.manga.find(t=>t.id===i)}async addManga(i){var t;this.applyReleaseStatus(i),this.data.manga.push(i),await this.save(),await this.syncUpcoming(i,"manga");try{await this.writeReadingNote("manga",i)}catch(e){console.warn("[WL] writeReadingNote failed:",e)}(t=this.historyManager)==null||t.log(`${i.title} (Manga) was added`,{source:"Reading",action:"added",titleName:i.title})}async addMangaSilent(i){this.applyReleaseStatus(i),this.data.manga.push(i),await this.saveOnly()}async updateManga(i){var e,s,a;i.dateModified=new Date().toISOString(),this.applyReleaseStatus(i);let t=this.data.manga.findIndex(n=>n.id===i.id);if(t>=0){let n=this.data.manga[t];if(n.status!==i.status){let r=i.status==="Completed"?"completed":"status";i.status==="Completed"&&this.plugin.settings.setFinishDateAutomatically&&!i.dateFinished&&(i.dateFinished=(e=new Date().toISOString().split("T")[0])!=null?e:null),(s=this.historyManager)==null||s.log(`${i.title} (Manga) status changed to ${i.status}`,{source:"Reading",action:r,titleName:i.title})}n.rating!==i.rating&&((a=this.historyManager)==null||a.log(`${i.title} (Manga) Rating \u2192 ${i.rating}/5`,{source:"Reading",action:"rating",titleName:i.title})),this.data.manga[t]=i,await this.save(),n.releaseDate!==i.releaseDate&&await this.syncUpcoming(i,"manga");try{await this.writeReadingNote("manga",i)}catch(r){console.warn("[WL] writeReadingNote failed:",r)}}}updateMangaSilent(i){i.dateModified=new Date().toISOString(),this.applyReleaseStatus(i);let t=this.data.manga.findIndex(e=>e.id===i.id);t>=0&&(this.data.manga[t]=i)}async removeManga(i){var e,s;let t=this.getManga(i);if(this.data.manga=this.data.manga.filter(a=>a.id!==i),await this.save(),await((e=this.plugin.dataManager)==null?void 0:e.removeReadingAirtimeEntries(i)),t){(s=this.historyManager)==null||s.log(`${t.title} (Manga) was deleted`,{source:"Reading",action:"deleted",titleName:t.title});try{await this.deleteReadingNote("manga",t)}catch(a){console.warn("[WL] deleteReadingNote failed:",a)}}}async removeBooksBatch(i){var s,a;let e=[];for(let n of i){let r=this.getBook(n);r&&e.push(r)}this.data.books=this.data.books.filter(n=>!i.includes(n.id)),await this.save();for(let n of i)await((s=this.plugin.dataManager)==null?void 0:s.removeReadingAirtimeEntries(n));for(let n of e)(a=this.historyManager)==null||a.log(`${n.title} (Book) was deleted`,{source:"Reading",action:"deleted",titleName:n.title});for(let n=0;nthis.deleteReadingNote("book",o).catch(()=>{})))}}async removeMangaBatch(i){var s,a;let e=[];for(let n of i){let r=this.getManga(n);r&&e.push(r)}this.data.manga=this.data.manga.filter(n=>!i.includes(n.id)),await this.save();for(let n of i)await((s=this.plugin.dataManager)==null?void 0:s.removeReadingAirtimeEntries(n));for(let n of e)(a=this.historyManager)==null||a.log(`${n.title} (Manga) was deleted`,{source:"Reading",action:"deleted",titleName:n.title});for(let n=0;nthis.deleteReadingNote("manga",o).catch(()=>{})))}}async addMangaBatch(i){var t;for(let e of i)this.applyReleaseStatus(e),this.data.manga.push(e);await this.saveOnly();for(let e of i){await this.syncUpcoming(e,"manga");try{await this.writeReadingNote("manga",e)}catch(s){console.warn("[WL] writeReadingNote failed:",s)}(t=this.historyManager)==null||t.log(`${e.title} (Manga) was added`,{source:"Reading",action:"added",titleName:e.title})}}generateMangaId(i){let t=Di(i)||"manga",e=new Set(this.data.manga.map(a=>a.id));if(!e.has(t))return t;let s=2;for(;e.has(`${t}-${s}`);)s++;return`${t}-${s}`}getBookColumns(){return this.data.bookColumns}getMangaColumns(){return this.data.mangaColumns}columnsFor(i){return i==="book"?this.data.bookColumns:this.data.mangaColumns}async addColumn(i,t){this.columnsFor(i).push(t),await this.save()}async updateColumn(i,t){let e=this.columnsFor(i),s=e.findIndex(a=>a.id===t.id);s>=0&&(e[s]=t,await this.save())}async removeColumn(i,t){if(i==="book"){this.data.bookColumns=this.data.bookColumns.filter(e=>e.id!==t);for(let e of this.data.books)e.customFields&&Object.prototype.hasOwnProperty.call(e.customFields,t)&&delete e.customFields[t]}else{this.data.mangaColumns=this.data.mangaColumns.filter(e=>e.id!==t);for(let e of this.data.manga)e.customFields&&Object.prototype.hasOwnProperty.call(e.customFields,t)&&delete e.customFields[t]}await this.save()}generateColumnId(i,t){let e=`col-${Di(t)||"field"}`,s=new Set(this.columnsFor(i).map(n=>n.id));if(!s.has(e))return e;let a=2;for(;s.has(`${e}-${a}`);)a++;return`${e}-${a}`}async reorderColumns(i,t,e){let s=this.columnsFor(i);if(t<0||t>=s.length||e<0||e>=s.length)return;let[a]=s.splice(t,1);a&&(s.splice(e,0,a),await this.save())}async setCustomField(i,t,e,s){let a=i==="book"?this.getBook(t):this.getManga(t);a&&(a.customFields||(a.customFields={}),s===null||s===""?delete a.customFields[e]:a.customFields[e]=s,a.dateModified=new Date().toISOString(),await this.save())}kindFolder(i){let t=this.data.settings.defaultFolder||"WatchLog/Reading";return(0,st.normalizePath)(`${t}/${i==="book"?"Books":"Manga"}`)}noteFilePath(i,t){let e=Es(t)||(i==="book"?"book":"manga");return(0,st.normalizePath)(`${this.kindFolder(i)}/${e}.md`)}async ensureFolder(i){let t=(0,st.normalizePath)(i);if(!this.plugin.app.vault.getAbstractFileByPath(t))try{await this.plugin.app.vault.createFolder(t)}catch(e){}}buildFrontmatter(i,t){var s,a,n,r;let e=["---"];if(e.push(`title: ${Et(Es(t.title))}`),e.push(`author: ${Et((s=t.author)!=null?s:"")}`),e.push(`status: ${Et(t.status)}`),e.push(`rating: ${t.rating|0}`),i==="book"){let o=t;e.push(`pagesRead: ${o.pagesRead|0}`),e.push(`totalPages: ${o.totalPages|0}`),e.push(`chaptersRead: ${o.chaptersRead|0}`),e.push(`totalChapters: ${o.totalChapters|0}`),o.googleBooksId&&e.push(`googleBooksId: ${Et(o.googleBooksId)}`)}else{let o=t;e.push(`chaptersRead: ${o.chaptersRead|0}`),e.push(`totalChapters: ${o.totalChapters|0}`),e.push(`volumesRead: ${o.volumesRead|0}`),e.push(`totalVolumes: ${o.totalVolumes|0}`),o.malId&&e.push(`malId: ${Et(o.malId)}`)}return e.push(`dateStarted: ${(a=t.dateStarted)!=null?a:"null"}`),e.push(`dateFinished: ${(n=t.dateFinished)!=null?n:"null"}`),e.push(`releaseDate: ${(r=t.releaseDate)!=null?r:"null"}`),e.push(`dateAdded: ${Et(t.dateAdded)}`),e.push(`dateModified: ${Et(t.dateModified)}`),t.coverUrl&&e.push(`coverUrl: ${Et(t.coverUrl)}`),t.externalLink&&e.push(`externalLink: ${Et(t.externalLink)}`),e.push(`type: ${i==="book"?"book":"manga"}`),e.push("---"),e.join(` `)}buildInitialNoteContent(i,t){return`${this.buildFrontmatter(i,t)} ## Notes @@ -29,22 +30,22 @@ ${i.notes} `}rebuildWithFrontmatter(i,t){let e=i.match(/^---\n[\s\S]*?\n---\n?/);return e?t+` `+i.slice(e[0].length):t+` -`+i}async writeReadingNote(i,t){await this.ensureFolder(this.kindFolder(i));let e=this.noteFilePath(i,t.title),s=this.buildFrontmatter(i,t),a=`${i}:${t.id}`,n=this.lastNotePathById.get(a);if(n&&n!==e){let o=this.plugin.app.vault.getAbstractFileByPath(n);if(o instanceof rt.TFile)try{await this.plugin.app.fileManager.trashFile(o)}catch(l){}}let r=this.plugin.app.vault.getAbstractFileByPath(e);if(r instanceof rt.TFile){let o=await this.plugin.app.vault.read(r),l=this.rebuildWithFrontmatter(o,s);l!==o&&await this.plugin.app.vault.modify(r,l)}else await this.plugin.app.vault.create(e,this.buildInitialNoteContent(i,t));return this.lastNotePathById.set(a,e),e}async ensureReadingNote(i,t){let e=this.noteFilePath(i,t.title);return this.plugin.app.vault.getAbstractFileByPath(e)instanceof rt.TFile?(this.lastNotePathById.set(`${i}:${t.id}`,e),e):this.writeReadingNote(i,t)}async createReadingNoteIfMissing(i,t){let e=this.noteFilePath(i,t.title);return this.plugin.app.vault.getAbstractFileByPath(e)instanceof rt.TFile?!1:(await this.writeReadingNote(i,t),!0)}async readReadingNote(i,t){let e=this.noteFilePath(i,t.title),s=this.plugin.app.vault.getAbstractFileByPath(e);return s instanceof rt.TFile?this.plugin.app.vault.read(s):null}async appendQuote(i,t,e,s){await this.ensureReadingNote(i,t);let a=this.noteFilePath(i,t.title),n=this.plugin.app.vault.getAbstractFileByPath(a);if(!(n instanceof rt.TFile))return;let r=await this.plugin.app.vault.read(n),o=s.trim(),l=o?` ${o}`:"",c=e.split(/\r?\n/).map(p=>`> ${p}`).join(` +`+i}async writeReadingNote(i,t){await this.ensureFolder(this.kindFolder(i));let e=this.noteFilePath(i,t.title),s=this.buildFrontmatter(i,t),a=`${i}:${t.id}`,n=this.lastNotePathById.get(a);if(n&&n!==e){let o=this.plugin.app.vault.getAbstractFileByPath(n);if(o instanceof st.TFile)try{await this.plugin.app.fileManager.trashFile(o)}catch(l){}}let r=this.plugin.app.vault.getAbstractFileByPath(e);if(r instanceof st.TFile){let o=await this.plugin.app.vault.read(r),l=this.rebuildWithFrontmatter(o,s);l!==o&&await this.plugin.app.vault.modify(r,l)}else await this.plugin.app.vault.create(e,this.buildInitialNoteContent(i,t));return this.lastNotePathById.set(a,e),e}async ensureReadingNote(i,t){let e=this.noteFilePath(i,t.title);return this.plugin.app.vault.getAbstractFileByPath(e)instanceof st.TFile?(this.lastNotePathById.set(`${i}:${t.id}`,e),e):this.writeReadingNote(i,t)}async createReadingNoteIfMissing(i,t){let e=this.noteFilePath(i,t.title);return this.plugin.app.vault.getAbstractFileByPath(e)instanceof st.TFile?!1:(await this.writeReadingNote(i,t),!0)}async rewriteFrontmatterIfExists(i,t){let e=this.noteFilePath(i,t.title),s=this.plugin.app.vault.getAbstractFileByPath(e);if(!(s instanceof st.TFile))return!1;let a=await this.plugin.app.vault.read(s),n=this.rebuildWithFrontmatter(a,this.buildFrontmatter(i,t));return n!==a&&await this.plugin.app.vault.modify(s,n),this.lastNotePathById.set(`${i}:${t.id}`,e),!0}async readReadingNote(i,t){let e=this.noteFilePath(i,t.title),s=this.plugin.app.vault.getAbstractFileByPath(e);return s instanceof st.TFile?this.plugin.app.vault.read(s):null}async appendQuote(i,t,e,s){await this.ensureReadingNote(i,t);let a=this.noteFilePath(i,t.title),n=this.plugin.app.vault.getAbstractFileByPath(a);if(!(n instanceof st.TFile))return;let r=await this.plugin.app.vault.read(n),o=s.trim(),l=o?` ${o}`:"",c=e.split(/\r?\n/).map(p=>`> ${p}`).join(` `),d=`> [!quote]${l} -${c}`,u,h=r.match(/(^|\n)## Quotes[ \t]*\r?\n/);if(h&&h.index!==void 0){let p=h.index+h[0].length,m=r.slice(0,p),v=r.slice(p),f=m.length>0&&!m.endsWith(` +${c}`,u,h=r.match(/(^|\n)## Quotes[ \t]*\r?\n/);if(h&&h.index!==void 0){let p=h.index+h[0].length,m=r.slice(0,p),f=r.slice(p),y=m.length>0&&!m.endsWith(` -`);u=`${m}${f?` +`);u=`${m}${y?` `:""}${d} -${v.startsWith(` +${f.startsWith(` `)?"":` -`}${v}`}else{let p=r.endsWith(` +`}${f}`}else{let p=r.endsWith(` `)?"":` `;u=`${r}${p} ## Quotes ${d} -`}await this.plugin.app.vault.modify(n,u)}async deleteReadingNote(i,t){let e=this.noteFilePath(i,t.title),s=this.plugin.app.vault.getAbstractFileByPath(e);if(s instanceof rt.TFile)try{await this.plugin.app.fileManager.trashFile(s)}catch(a){}this.lastNotePathById.delete(`${i}:${t.id}`)}};var ve=require("obsidian"),Yt="https://api.jikan.moe/v4",Lt="https://www.omdbapi.com",bt="https://api.themoviedb.org/3",Ki="https://graphql.anilist.co",zi=700,zs="https://www.googleapis.com/books/v1",ji=400,ai=8e3,ut=class extends Error{constructor(i,t,e){super(t),this.name="GoogleBooksError",this.reason=i,this.status=e}};function Et(g){var i;if(g instanceof ut)switch(g.reason){case"no-key":return"Google Books API key required \u2014 add one in Settings \u2192 API \u2192 Books.";case"rate-limited":return"Google Books rate limit reached \u2014 your API key is missing or over quota.";case"http":return`Google Books request failed (HTTP ${(i=g.status)!=null?i:"?"}).`;case"parse":return"Google Books returned an unreadable response.";default:return"Google Books request failed \u2014 check your connection."}return"Google Books request failed \u2014 check your connection."}var Jt=class{constructor(i,t="",e=""){this.anilistLastRequest=0;this.anilistQueue=Promise.resolve();this.jikanLastRequest=0;this.jikanQueue=Promise.resolve();this.omdbApiKey=i,this.tmdbApiKey=t,this.googleBooksApiKey=e}throttleJikan(i){let t=async()=>{let a=Date.now()-this.jikanLastRequest;return awindow.setTimeout(n,ji-a)),this.jikanLastRequest=Date.now(),i()},e=this.jikanQueue.then(t,t);return this.jikanQueue=e.then(()=>{},()=>{}),e}setOmdbKey(i){this.omdbApiKey=i}setTmdbKey(i){this.tmdbApiKey=i}setGoogleBooksKey(i){this.googleBooksApiKey=i}hasGoogleBooksKey(){return this.googleBooksApiKey.trim().length>0}tmdbHeaders(){return{Authorization:`Bearer ${this.tmdbApiKey}`}}async fetchWithTimeout(i,t){let e=null,s=new Promise((a,n)=>{e=window.setTimeout(()=>n(new Error("Request timed out")),ai)});try{let a=(0,ve.requestUrl)({url:i,headers:t}).then(n=>n.json);return await Promise.race([a,s])}finally{e!==null&&window.clearTimeout(e)}}async postJsonWithTimeout(i,t,e){let s=null,a=new Promise((n,r)=>{s=window.setTimeout(()=>r(new Error("Request timed out")),ai)});try{let n=(0,ve.requestUrl)({url:i,method:"POST",headers:{"Content-Type":"application/json",...e!=null?e:{}},body:JSON.stringify(t)}).then(r=>r.json);return await Promise.race([n,a])}finally{s!==null&&window.clearTimeout(s)}}throttleAniList(i){let t=async()=>{let a=Date.now()-this.anilistLastRequest;return awindow.setTimeout(n,zi-a)),this.anilistLastRequest=Date.now(),i()},e=this.anilistQueue.then(t,t);return this.anilistQueue=e.then(()=>{},()=>{}),e}stripHtml(i){return i.replace(//gi,` -`).replace(/<[^>]+>/g,"").replace(/ /g," ").replace(/&/g,"&").replace(/"/g,'"').replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").trim()}formatAniListDate(i){var a,n;if(!(i!=null&&i.year))return"";let t=String(i.year),e=String((a=i.month)!=null?a:1).padStart(2,"0"),s=String((n=i.day)!=null?n:1).padStart(2,"0");return`${t}-${e}-${s}`}mapAniListMedia(i){var r,o,l,c,d,u,h,p,m,v,f;let t=((r=i.title)==null?void 0:r.english)||((o=i.title)==null?void 0:o.romaji)||((l=i.title)==null?void 0:l.native)||"",e=(c=i.episodes)!=null?c:0,s=(d=i.duration)!=null?d:24,a=e>0?[{name:"Season 1",episodes:e,offset:0}]:[],n=i.description?this.stripHtml(i.description):"";return{malId:0,anilistId:i.id,title:t,episodes:e,duration:s,releaseDate:this.formatAniListDate(i.startDate),url:`https://anilist.co/anime/${i.id}`,seasons:a,description:n,averageScore:(u=i.averageScore)!=null?u:void 0,genres:(h=i.genres)!=null?h:void 0,posterUrl:(f=(v=(p=i.coverImage)==null?void 0:p.large)!=null?v:(m=i.coverImage)==null?void 0:m.medium)!=null?f:void 0}}async searchAniList(i){var e,s,a;let t=` +`}await this.plugin.app.vault.modify(n,u)}async deleteReadingNote(i,t){let e=this.noteFilePath(i,t.title),s=this.plugin.app.vault.getAbstractFileByPath(e);if(s instanceof st.TFile)try{await this.plugin.app.fileManager.trashFile(s)}catch(a){}this.lastNotePathById.delete(`${i}:${t.id}`)}};var $e=require("obsidian");var qt="https://api.jikan.moe/v4",At="https://www.omdbapi.com",pt="https://api.themoviedb.org/3",Ss="https://graphql.anilist.co",Ds=700,Ma="https://www.googleapis.com/books/v1",Ts=400,Ti=8e3;function Fe(g){return`https://www.youtube.com/watch?v=${g}`}function Cs(g){var t;if(!g)return"";let i=g.match(/(?:[?&]v=|\/embed\/|youtu\.be\/)([A-Za-z0-9_-]{6,})/);return(t=i==null?void 0:i[1])!=null?t:""}function Qt(g){return!g||g==="N/A"?le([]):le(g.split(","))}function Ci(g){var e,s;let i=((e=g==null?void 0:g.crew)!=null?e:[]).filter(a=>a.job==="Director"&&a.name).map(a=>a.name),t=((s=g==null?void 0:g.cast)!=null?s:[]).map(a=>{var n;return(n=a.name)!=null?n:""});return{director:le(i),cast:le(t)}}var gt=class extends Error{constructor(i,t,e){super(t),this.name="GoogleBooksError",this.reason=i,this.status=e}};function It(g){var i;if(g instanceof gt)switch(g.reason){case"no-key":return"Google Books API key required \u2014 add one in Settings \u2192 API \u2192 Books.";case"rate-limited":return"Google Books rate limit reached \u2014 your API key is missing or over quota.";case"http":return`Google Books request failed (HTTP ${(i=g.status)!=null?i:"?"}).`;case"parse":return"Google Books returned an unreadable response.";default:return"Google Books request failed \u2014 check your connection."}return"Google Books request failed \u2014 check your connection."}var he=class{constructor(i,t="",e=""){this.anilistLastRequest=0;this.anilistQueue=Promise.resolve();this.jikanLastRequest=0;this.jikanQueue=Promise.resolve();this.omdbApiKey=i,this.tmdbApiKey=t,this.googleBooksApiKey=e}throttleJikan(i){let t=async()=>{let a=Date.now()-this.jikanLastRequest;return awindow.setTimeout(n,Ts-a)),this.jikanLastRequest=Date.now(),i()},e=this.jikanQueue.then(t,t);return this.jikanQueue=e.then(()=>{},()=>{}),e}setOmdbKey(i){this.omdbApiKey=i}setTmdbKey(i){this.tmdbApiKey=i}setGoogleBooksKey(i){this.googleBooksApiKey=i}hasGoogleBooksKey(){return this.googleBooksApiKey.trim().length>0}tmdbHeaders(){return{Authorization:`Bearer ${this.tmdbApiKey}`}}async fetchWithTimeout(i,t){let e=null,s=new Promise((a,n)=>{e=window.setTimeout(()=>n(new Error("Request timed out")),Ti)});try{let a=(0,$e.requestUrl)({url:i,headers:t}).then(n=>n.json);return await Promise.race([a,s])}finally{e!==null&&window.clearTimeout(e)}}async postJsonWithTimeout(i,t,e){let s=null,a=new Promise((n,r)=>{s=window.setTimeout(()=>r(new Error("Request timed out")),Ti)});try{let n=(0,$e.requestUrl)({url:i,method:"POST",headers:{"Content-Type":"application/json",...e!=null?e:{}},body:JSON.stringify(t)}).then(r=>r.json);return await Promise.race([n,a])}finally{s!==null&&window.clearTimeout(s)}}throttleAniList(i){let t=async()=>{let a=Date.now()-this.anilistLastRequest;return awindow.setTimeout(n,Ds-a)),this.anilistLastRequest=Date.now(),i()},e=this.anilistQueue.then(t,t);return this.anilistQueue=e.then(()=>{},()=>{}),e}stripHtml(i){return i.replace(//gi,` +`).replace(/<[^>]+>/g,"").replace(/ /g," ").replace(/&/g,"&").replace(/"/g,'"').replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").trim()}formatAniListDate(i){var a,n;if(!(i!=null&&i.year))return"";let t=String(i.year),e=String((a=i.month)!=null?a:1).padStart(2,"0"),s=String((n=i.day)!=null?n:1).padStart(2,"0");return`${t}-${e}-${s}`}mapAniListMedia(i){var r,o,l,c,d,u,h,p,m,f,y,v;let t=((r=i.title)==null?void 0:r.english)||((o=i.title)==null?void 0:o.romaji)||((l=i.title)==null?void 0:l.native)||"",e=(c=i.episodes)!=null?c:0,s=(d=i.duration)!=null?d:24,a=e>0?[{name:"Season 1",episodes:e,offset:0}]:[],n=i.description?this.stripHtml(i.description):"";return{malId:0,anilistId:i.id,title:t,episodes:e,duration:s,releaseDate:this.formatAniListDate(i.startDate),url:`https://anilist.co/anime/${i.id}`,seasons:a,description:n,averageScore:(u=i.averageScore)!=null?u:void 0,genres:(h=i.genres)!=null?h:void 0,posterUrl:(y=(f=(p=i.coverImage)==null?void 0:p.large)!=null?f:(m=i.coverImage)==null?void 0:m.medium)!=null?y:void 0,trailerUrl:((v=i.trailer)==null?void 0:v.site)==="youtube"&&i.trailer.id?Fe(i.trailer.id):"none"}}async searchAniList(i){var e,s,a;let t=` query ($search: String) { Page(page: 1, perPage: 10) { media(search: $search, type: ANIME) { @@ -61,10 +62,11 @@ ${d} coverImage { large medium } description genres + trailer { id site } } } } - `;try{return((a=(s=(e=(await this.throttleAniList(()=>this.postJsonWithTimeout(Ki,{query:t,variables:{search:i}}))).data)==null?void 0:e.Page)==null?void 0:s.media)!=null?a:[]).map(l=>this.mapAniListMedia(l))}catch(n){return[]}}async getAniListById(i){var e,s;let t=` + `;try{return((a=(s=(e=(await this.throttleAniList(()=>this.postJsonWithTimeout(Ss,{query:t,variables:{search:i}}))).data)==null?void 0:e.Page)==null?void 0:s.media)!=null?a:[]).map(l=>this.mapAniListMedia(l))}catch(n){return[]}}async getAniListById(i){var e,s;let t=` query ($id: Int) { Media(id: $id, type: ANIME) { id @@ -75,6 +77,7 @@ ${d} averageScore popularity coverImage { large } + trailer { id site } nextAiringEpisode { airingAt episode @@ -82,17 +85,17 @@ ${d} } } } - `;try{return(s=(e=(await this.throttleAniList(()=>this.postJsonWithTimeout(Ki,{query:t,variables:{id:i}}))).data)==null?void 0:e.Media)!=null?s:null}catch(a){return null}}async searchAnime(i){var e;let t=`${Yt}/anime?q=${encodeURIComponent(i)}&limit=10&sfw=false`;try{return((e=(await this.fetchWithTimeout(t)).data)!=null?e:[]).map(a=>this.mapJikanAnime(a))}catch(s){return[]}}mapJikanAnime(i){var r,o,l,c,d;let e=((r=i.duration)!=null?r:"24 min per ep").match(/(\d+)\s*min/),s=e&&e[1]?parseInt(e[1]):24,a=(o=i.episodes)!=null?o:0,n=a>0?[{name:"Season 1",episodes:a,offset:0}]:[];return{malId:i.mal_id,title:(l=i.title_english)!=null?l:i.title,episodes:a,duration:s,releaseDate:(c=i.aired)!=null&&c.from&&(d=i.aired.from.split("T")[0])!=null?d:"",url:i.url,seasons:n}}async searchOmdb(i,t){var s;if(!this.omdbApiKey)return[];let e=`${Lt}/?s=${encodeURIComponent(i)}&type=${t}&apikey=${encodeURIComponent(this.omdbApiKey)}`;try{let a=await this.fetchWithTimeout(e);return a.Response==="False"?[]:((s=a.Search)!=null?s:[]).slice(0,10).map(n=>({imdbId:n.imdbID,title:n.Title,mediaType:t==="movie"?"movie":"tv",episodes:t==="movie"?1:0,episodeDuration:0,releaseDate:n.Year?`${n.Year}-01-01`:"",url:`https://www.imdb.com/title/${n.imdbID}`,seasons:[]}))}catch(a){return[]}}async getOmdbMovieDetails(i){var e;if(!this.omdbApiKey)return null;let t=`${Lt}/?i=${encodeURIComponent(i)}&apikey=${encodeURIComponent(this.omdbApiKey)}`;try{let s=await this.fetchWithTimeout(t);if(s.Response==="False"||!s.imdbID)return null;let a=s.Runtime?parseInt(s.Runtime.replace(/[^0-9]/g,"")):120;return{imdbId:s.imdbID,title:s.Title,mediaType:"movie",episodes:1,episodeDuration:isNaN(a)?120:a,releaseDate:this.parseOmdbDate((e=s.Released)!=null?e:s.Year),url:`https://www.imdb.com/title/${s.imdbID}`,seasons:[{name:"Movie",episodes:1,offset:0}]}}catch(s){return null}}async getOmdbTvDetails(i){var e,s;if(!this.omdbApiKey)return null;let t=`${Lt}/?i=${encodeURIComponent(i)}&apikey=${encodeURIComponent(this.omdbApiKey)}`;try{let a=await this.fetchWithTimeout(t);if(a.Response==="False"||!a.imdbID)return null;let n=parseInt((e=a.totalSeasons)!=null?e:"1")||1,r=[],o=0;for(let c=1;c<=n;c++){let d=await this.getOmdbSeasonEpisodeCount(i,c);if(d===null)break;r.push({name:`Season ${c}`,episodes:d,offset:o}),o+=d}let l=r.reduce((c,d)=>c+d.episodes,0);return{imdbId:a.imdbID,title:a.Title,mediaType:"tv",episodes:l,episodeDuration:45,releaseDate:this.parseOmdbDate((s=a.Released)!=null?s:a.Year),url:`https://www.imdb.com/title/${a.imdbID}`,seasons:r}}catch(a){return null}}async getOmdbSeasonEpisodeCount(i,t){var s;let e=`${Lt}/?i=${encodeURIComponent(i)}&Season=${t}&apikey=${encodeURIComponent(this.omdbApiKey)}`;try{let a=await this.fetchWithTimeout(e);return a.Response==="False"?null:((s=a.Episodes)!=null?s:[]).length}catch(a){return null}}async getAnimeScheduleByMalId(i){var t;try{let e=`${Yt}/anime/${i}`,a=(t=(await this.fetchWithTimeout(e)).data)==null?void 0:t.broadcast;if(!(a!=null&&a.day)||!a.time)return null;let r={Mondays:1,Tuesdays:2,Wednesdays:3,Thursdays:4,Fridays:5,Saturdays:6,Sundays:0}[a.day];return r===void 0?null:{dayOfWeek:r,time:a.time}}catch(e){return null}}parseOmdbDate(i){let t={Jan:"01",Feb:"02",Mar:"03",Apr:"04",May:"05",Jun:"06",Jul:"07",Aug:"08",Sep:"09",Oct:"10",Nov:"11",Dec:"12"},e=i.match(/^(\d{2})\s+([A-Za-z]{3})\s+(\d{4})$/);if(e&&e[1]&&e[2]&&e[3]){let s=t[e[2]];if(s)return`${e[3]}-${s}-${e[1]}`}return i}async getOmdbByImdbId(i){if(!this.omdbApiKey)return null;let t=`${Lt}/?i=${encodeURIComponent(i)}&apikey=${encodeURIComponent(this.omdbApiKey)}`;try{let e=await this.fetchWithTimeout(t);return e.Response==="False"||!e.imdbID?null:e.Type==="movie"?this.getOmdbMovieDetails(i):this.getOmdbTvDetails(i)}catch(e){return null}}async searchTmdb(i,t){var a;if(!this.tmdbApiKey)return[];let s=`${bt}/search/${t==="movie"?"movie":"tv"}?query=${encodeURIComponent(i)}&page=1`;try{return((a=(await this.fetchWithTimeout(s,this.tmdbHeaders())).results)!=null?a:[]).slice(0,10).map(r=>{var o,l,c,d;return{imdbId:String(r.id),title:(l=(o=r.title)!=null?o:r.name)!=null?l:"",mediaType:t==="movie"?"movie":"tv",episodes:0,episodeDuration:0,releaseDate:(d=(c=r.release_date)!=null?c:r.first_air_date)!=null?d:"",url:"",seasons:[]}})}catch(n){return[]}}async getTmdbMovieDetails(i){var t,e,s,a;if(!this.tmdbApiKey)return null;try{let[n,r]=await Promise.all([this.fetchWithTimeout(`${bt}/movie/${i}`,this.tmdbHeaders()),this.fetchWithTimeout(`${bt}/movie/${i}/external_ids`,this.tmdbHeaders())]),o=n,c=(e=(t=r.imdb_id)!=null?t:o.imdb_id)!=null?e:"";return{imdbId:String(o.id),title:o.title,mediaType:"movie",episodes:1,episodeDuration:(s=o.runtime)!=null?s:120,releaseDate:(a=o.release_date)!=null?a:"",url:c?`https://www.imdb.com/title/${c}`:"",seasons:[{name:"Movie",episodes:1,offset:0}]}}catch(n){return null}}async getTmdbTvDetails(i){var t,e,s,a,n,r;if(!this.tmdbApiKey)return null;try{let[o,l]=await Promise.all([this.fetchWithTimeout(`${bt}/tv/${i}`,this.tmdbHeaders()),this.fetchWithTimeout(`${bt}/tv/${i}/external_ids`,this.tmdbHeaders())]),c=o,u=(t=l.imdb_id)!=null?t:"",h=((e=c.seasons)!=null?e:[]).filter(f=>f.season_number!==0),p=0,m=h.map(f=>{let y={name:f.name,episodes:f.episode_count,offset:p};return p+=f.episode_count,y}),v=m.reduce((f,y)=>f+y.episodes,0)||((s=c.number_of_episodes)!=null?s:0);return{imdbId:String(c.id),title:c.name,mediaType:"tv",episodes:v,episodeDuration:(n=((a=c.episode_run_time)!=null?a:[])[0])!=null?n:45,releaseDate:(r=c.first_air_date)!=null?r:"",url:u?`https://www.imdb.com/title/${u}`:"",seasons:m}}catch(o){return null}}async getTmdbByImdbId(i){if(!this.tmdbApiKey)return null;let t=`${bt}/find/${encodeURIComponent(i)}?external_source=imdb_id`;try{let e=await this.fetchWithTimeout(t,this.tmdbHeaders());return e.movie_results&&e.movie_results.length>0?this.getTmdbMovieDetails(String(e.movie_results[0].id)):e.tv_results&&e.tv_results.length>0?this.getTmdbTvDetails(String(e.tv_results[0].id)):null}catch(e){return null}}parseOmdbVotes(i){if(!i||i==="N/A")return 0;let t=parseInt(i.replace(/,/g,""),10);return isNaN(t)?0:t}parseOmdbRating(i){if(!i||i==="N/A")return 0;let t=parseFloat(i);return isNaN(t)?0:t}extractImdbId(i){let t=i.match(/tt\d+/);return t?t[0]:""}async fetchMalRating(i){var t,e,s,a;try{let n=`${Yt}/anime/${i}`,r=await this.fetchWithTimeout(n),o=(e=(t=r.data)==null?void 0:t.score)!=null?e:0,l=(a=(s=r.data)==null?void 0:s.scored_by)!=null?a:0;return!o&&!l?null:{rating:o,votes:l}}catch(n){return null}}async fetchAniListRating(i){var a,n;let t=await this.getAniListById(i);if(!t)return null;let e=(a=t.averageScore)!=null?a:0,s=(n=t.popularity)!=null?n:0;return!e&&!s?null:{rating:e,votes:s}}async fetchOmdbRating(i){if(!this.omdbApiKey)return null;try{let t=`${Lt}/?i=${encodeURIComponent(i)}&apikey=${encodeURIComponent(this.omdbApiKey)}`,e=await this.fetchWithTimeout(t);if(e.Response==="False")return null;let s=this.parseOmdbRating(e.imdbRating),a=this.parseOmdbVotes(e.imdbVotes);return!s&&!a?null:{rating:s,votes:a}}catch(t){return null}}async fetchTmdbRatingByImdb(i){var t,e;if(!this.tmdbApiKey)return null;try{let s=`${bt}/find/${encodeURIComponent(i)}?external_source=imdb_id`,a=await this.fetchWithTimeout(s,this.tmdbHeaders()),n=a.movie_results&&a.movie_results[0]||a.tv_results&&a.tv_results[0]||null;if(!n)return null;let r=(t=n.vote_average)!=null?t:0,o=(e=n.vote_count)!=null?e:0;return!r&&!o?null:{rating:r,votes:o}}catch(s){return null}}async fetchCommunityRating(i,t="jikan",e=""){var o,l,c;let s=((o=i.malId)!=null?o:0)>0,a=((l=i.anilistId)!=null?l:0)>0,n=e||(i.type==="Anime"?"anime":i.type==="Movie"||i.type==="TV Show"||i.type==="TvShow"?"movie":"");if(n==="")return null;if(n==="anime")if(t==="anilist"){if(a){let d=await this.fetchAniListRating(i.anilistId);if(d)return{...d,source:"anilist"}}if(s){let d=await this.fetchMalRating(i.malId);if(d)return{...d,source:"mal"}}}else{if(s){let d=await this.fetchMalRating(i.malId);if(d)return{...d,source:"mal"}}if(a){let d=await this.fetchAniListRating(i.anilistId);if(d)return{...d,source:"anilist"}}}let r=this.extractImdbId((c=i.externalLink)!=null?c:"");if(r){if(this.omdbApiKey){let d=await this.fetchOmdbRating(r);if(d)return{...d,source:"imdb"}}if(this.tmdbApiKey){let d=await this.fetchTmdbRatingByImdb(r);if(d)return{...d,source:"tmdb"}}}return null}googleCoverUrl(i){var s,a,n,r,o,l;let t=i.imageLinks;if(!t)return"";let e=(l=(o=(r=(n=(a=(s=t.extraLarge)!=null?s:t.large)!=null?a:t.medium)!=null?n:t.small)!=null?r:t.thumbnail)!=null?o:t.smallThumbnail)!=null?l:"";return e?e.replace(/^http:/,"https:").replace(/&edge=curl/g,""):""}googleReleaseDate(i){return i?/^\d{4}-\d{2}-\d{2}$/.test(i)?i:/^\d{4}-\d{2}$/.test(i)?`${i}-01`:/^\d{4}$/.test(i)?`${i}-01-01`:i:""}mapGoogleVolume(i){var n,r,o,l,c,d,u,h,p;let t=(n=i.volumeInfo)!=null?n:{},e=(r=t.publishedDate)!=null?r:"",s=e&&parseInt(e.slice(0,4),10)||0;return{title:t.subtitle?`${(o=t.title)!=null?o:""}: ${t.subtitle}`:(l=t.title)!=null?l:"",author:((c=t.authors)!=null?c:[]).join(", "),year:s,totalPages:(d=t.pageCount)!=null?d:0,coverUrl:this.googleCoverUrl(t),googleBooksId:(u=i.id)!=null?u:"",releaseDate:this.googleReleaseDate(e),url:(p=(h=t.infoLink)!=null?h:t.canonicalVolumeLink)!=null?p:""}}async googleBooksFetch(i){var r;let t=this.googleBooksApiKey.trim();if(!t)throw new ut("no-key","Google Books API key not set");let e=i.includes("?")?"&":"?",s=`${zs}${i}${e}key=${encodeURIComponent(t)}`,a=null,n=new Promise((o,l)=>{a=window.setTimeout(()=>l(new ut("network","Request timed out")),ai)});try{let o=(0,ve.requestUrl)({url:s,throw:!1}).then(l=>{if(l.status===429||l.status===403)throw new ut("rate-limited",`Google Books returned ${l.status}`,l.status);if(l.status<200||l.status>=300)throw new ut("http",`Google Books returned ${l.status}`,l.status);try{return l.json}catch(c){throw new ut("parse","Failed to parse Google Books response")}});return await Promise.race([o,n])}catch(o){throw o instanceof ut?o:new ut("network",(r=o==null?void 0:o.message)!=null?r:"Network error")}finally{a!==null&&window.clearTimeout(a)}}async searchGoogleBooks(i){var e;return((e=(await this.googleBooksFetch(`/volumes?q=${encodeURIComponent(i)}&maxResults=10`)).items)!=null?e:[]).slice(0,10).map(s=>this.mapGoogleVolume(s))}async checkGoogleBooksConnection(){let i=await this.googleBooksFetch("/volumes?q=tolkien&maxResults=1");return Array.isArray(i.items)}mapJikanManga(i){var s,a,n,r,o,l,c,d,u,h,p,m;let t=(a=(s=i.published)==null?void 0:s.from)!=null?a:"",e=t&&parseInt(t.slice(0,4),10)||0;return{malId:i.mal_id,title:(n=i.title_english)!=null?n:i.title,author:((r=i.authors)!=null?r:[]).map(v=>v.name).join(", "),year:e,totalChapters:(o=i.chapters)!=null?o:0,totalVolumes:(l=i.volumes)!=null?l:0,coverUrl:(u=(d=(c=i.images)==null?void 0:c.jpg)==null?void 0:d.image_url)!=null?u:"",releaseDate:(h=i.published)!=null&&h.from&&(p=i.published.from.split("T")[0])!=null?p:"",url:(m=i.url)!=null?m:`https://myanimelist.net/manga/${i.mal_id}`}}async searchManga(i){var e;let t=`${Yt}/manga?q=${encodeURIComponent(i)}&limit=10`;try{return((e=(await this.throttleJikan(()=>this.fetchWithTimeout(t))).data)!=null?e:[]).map(a=>this.mapJikanManga(a))}catch(s){return[]}}async getMangaByMalId(i){let t=`${Yt}/manga/${i}`;try{let e=await this.throttleJikan(()=>this.fetchWithTimeout(t));return e.data?this.mapJikanManga(e.data):null}catch(e){return null}}async getGoogleBookById(i){if(!i)return null;let t=await this.googleBooksFetch(`/volumes/${encodeURIComponent(i)}`);return!t||!t.id?null:this.mapGoogleVolume(t)}async checkTmdbConnection(){if(!this.tmdbApiKey)return!1;try{let i=`${bt}/movie/550`;return(await this.fetchWithTimeout(i,this.tmdbHeaders())).id!==void 0}catch(i){return!1}}async checkOmdbConnection(){if(!this.omdbApiKey)return!1;try{let i=`${Lt}/?i=tt0111161&apikey=${encodeURIComponent(this.omdbApiKey)}`;return(await this.fetchWithTimeout(i)).Response==="True"}catch(i){return!1}}};var ni=require("obsidian");var qi="https://api.jikan.moe/v4",js="https://www.omdbapi.com",qs="https://api.themoviedb.org/3",Qs="https://image.tmdb.org/t/p/w300",Ys="https://graphql.anilist.co",Qi=8e3,Js=400,Xs=700,Zs=30,ta=100,fe=class{constructor(i,t){this.queue=[];this.isProcessing=!1;this.disposed=!1;this.dataManager=i,this.getSettings=t}destroy(){this.disposed=!0,this.clearQueue()}enqueue(i){return new Promise(t=>{if(this.disposed){t(null);return}this.queue.push({title:i,resolve:t}),this.processQueue()})}clearQueue(){let i=this.queue.splice(0);for(let t of i)t.resolve(null)}async processQueue(){if(!this.isProcessing){for(this.isProcessing=!0;this.queue.length>0&&!this.disposed;){let i=this.queue.shift();if(!i)break;if(i.title.manualPosterUrl&&i.title.manualPosterUrl.trim()!==""){i.resolve(i.title.manualPosterUrl);continue}try{let e=await this.fetchPosterForTitle(i.title);if(this.disposed){i.resolve(null);break}let s=e||"none";this.dataManager.updatePosterUrl(i.title.id,s),i.resolve(e)}catch(e){this.disposed||this.dataManager.updatePosterUrl(i.title.id,"none"),i.resolve(null)}let t=this.getDelayForTitle(i.title);t>0&&await new Promise(e=>window.setTimeout(e,t))}this.isProcessing=!1}}getDelayForTitle(i){let t=this.getSettings();return at(i.type,t.typeApiMapping)==="anime"?i.anilistId&&i.anilistId>0?Xs:Js:t.tmdbApiKey?Zs:t.omdbApiKey?ta:0}async fetchPosterForTitle(i){if(i.posterUrl&&i.posterUrl.startsWith("http"))return i.posterUrl;if(i.posterUrl==="none")return null;let t=this.getSettings(),e=at(i.type,t.typeApiMapping);return e==="anime"?this.fetchAnimePoster(i):e==="movie"?this.fetchMediaPoster(i):null}cleanTitleForSearch(i){return i.replace(/\s*-?\s*[Ss]eason\s*\d+/gi,"").replace(/\s*-?\s*[Ss]eries\s*\d+/gi,"").replace(/\s*-?\s*[Pp]art\s*\d+/gi,"").replace(/\s*-?\s*[Vv]ol(ume)?\.?\s*\d+/gi,"").replace(/\s*\(\d{4}\)/g,"").replace(/\s*-?\s*[Ss]\d+/gi,"").replace(/\s+/g," ").trim()||i}async fetchAnimePoster(i){var r,o,l,c,d,u,h,p,m,v,f,y;if(i.anilistId&&i.anilistId>0){let b=await this.postJson(Ys,{query:"query ($id: Int) { Media(id: $id, type: ANIME) { coverImage { large medium } } }",variables:{id:i.anilistId}}),S=(o=(r=b==null?void 0:b.data)==null?void 0:r.Media)==null?void 0:o.coverImage;return(c=(l=S==null?void 0:S.large)!=null?l:S==null?void 0:S.medium)!=null?c:null}if(i.malId){let w=`${qi}/anime/${i.malId}`,b=await this.fetchJson(w),S=(u=(d=b==null?void 0:b.data)==null?void 0:d.images)==null?void 0:u.jpg;return(p=(h=S==null?void 0:S.large_image_url)!=null?h:S==null?void 0:S.image_url)!=null?p:null}let t=encodeURIComponent(this.cleanTitleForSearch(i.title)),e=`${qi}/anime?q=${t}&limit=1`,s=await this.fetchJson(e),a=(m=s==null?void 0:s.data)==null?void 0:m[0],n=(v=a==null?void 0:a.images)==null?void 0:v.jpg;return(y=(f=n==null?void 0:n.large_image_url)!=null?f:n==null?void 0:n.image_url)!=null?y:null}async fetchMediaPoster(i){var s,a;let t=this.getSettings(),e=this.cleanTitleForSearch(i.title);if(t.tmdbApiKey){let n=encodeURIComponent(e),r=`${qs}/search/multi?query=${n}&page=1`,o=await this.fetchJson(r,{Authorization:`Bearer ${t.tmdbApiKey}`}),l=(a=(s=o==null?void 0:o.results)==null?void 0:s[0])==null?void 0:a.poster_path;return l?`${Qs}${l}`:null}if(t.omdbApiKey){let n=encodeURIComponent(e),r=`${js}/?t=${n}&apikey=${encodeURIComponent(t.omdbApiKey)}`,o=await this.fetchJson(r),l=o==null?void 0:o.Poster;return l&&l!=="N/A"?l:null}return null}async fetchJson(i,t){let e=null,s=new Promise((a,n)=>{e=window.setTimeout(()=>n(new Error("Request timed out")),Qi)});try{let a=(0,ni.requestUrl)({url:i,headers:t}).then(n=>n.json);return await Promise.race([a,s])}finally{e!==null&&window.clearTimeout(e)}}async postJson(i,t,e){let s=null,a=new Promise((n,r)=>{s=window.setTimeout(()=>r(new Error("Request timed out")),Qi)});try{let n=(0,ni.requestUrl)({url:i,method:"POST",headers:{"Content-Type":"application/json",...e!=null?e:{}},body:JSON.stringify(t)}).then(r=>r.json);return await Promise.race([n,a])}finally{s!==null&&window.clearTimeout(s)}}};var _t=require("obsidian");var Yi=2*Math.PI*45,we=class{constructor(i,t,e,s){this.container=i,this.plugin=t,this.dataManager=e,this.readingData=s}render(){this.container.empty(),this.container.addClass("wl-dashboard");let i=this.dataManager.getTitles(),t=new Map;for(let c of i){let d=t.get(c.type);d?d.push(c):t.set(c.type,[c])}let e=i.filter(c=>c.status==="Plan to watch"),s=this.readingData.getBooks(),a=this.readingData.getMangaList(),n=i.length+s.length+a.length,r=i.reduce((c,d)=>c+(d.status==="Completed"?1:0),0)+s.reduce((c,d)=>c+(d.status==="Completed"?1:0),0)+a.reduce((c,d)=>c+(d.status==="Completed"?1:0),0),o=this.aggregateBooks(s),l=this.aggregateManga(a);this.renderCards(i,t,o,l),this.renderSummaryMetrics(n,r),this.renderSuggestions(e),this.renderRecentlyWatched(),this.renderRecentlyAdded()}statsFor(i){let t=new Set(["Dropped","To be released"]),e=0,s=0;for(let a of i)t.has(a.status)||(e++,a.status==="Completed"&&s++);return{watched:s,total:e}}renderCards(i,t,e,s){var d;let a=this.plugin.settings.dashboardCardStyle==="rectangles",n=this.container.createDiv({cls:"wl-rings-grid"}),r=this.statsFor(i),o=r.total===0?0:Math.round(r.watched/r.total*100),l=this.dataManager.getTotalTimeWatched(),c=this.dataManager.getTotalTimeRemaining();this.renderUnifiedCard(n,a,o,r,z(l),z(c));for(let u of this.plugin.settings.types){let h=this.statsFor((d=t.get(u.name))!=null?d:[]),p=h.total===0?0:Math.round(h.watched/h.total*100);if(a){let m=n.createDiv({cls:"wl-rect-item"});this.fillRect(m,u.name,u.color,p,h),m.createDiv({cls:"wl-rect-subline",text:"\xA0"})}else{let m=n.createDiv({cls:"wl-ring-item"});this.fillRing(m,u.name,u.color,p,h),m.createDiv({cls:"wl-ring-subtitle wl-ring-subline",text:"\xA0"})}}this.renderReadingCard(n,a,"Books",e),this.renderReadingCard(n,a,"Manga",s)}renderUnifiedCard(i,t,e,s,a,n){let r=i.createDiv({cls:t?"wl-dash-unified wl-dash-unified-bordered":"wl-dash-unified"}),o=r.createDiv({cls:t?"wl-dash-seg":"wl-dash-seg wl-dash-seg-center"});t?this.fillRect(o,"Total","#7F77DD",e,s):this.fillRing(o.createDiv({cls:"wl-ring-item"}),"Total","#7F77DD",e,s),this.renderTimeSegment(r,"Time Watched",a),this.renderTimeSegment(r,"Time Remaining",n)}renderTimeSegment(i,t,e){let s=i.createDiv({cls:"wl-dash-seg wl-dash-seg-center"});s.createDiv({cls:"wl-dash-seg-label",text:t}),s.createDiv({cls:"wl-dash-seg-value",text:e})}aggregateBooks(i){let t={left:0,read:0,total:0,volumesRead:0,totalVolumes:0};for(let e of i)e.status!=="To be released"&&((e.status==="Reading"||e.status==="Plan to Read")&&t.left++,t.read+=e.pagesRead,t.total+=e.totalPages);return t}aggregateManga(i){let t={left:0,read:0,total:0,volumesRead:0,totalVolumes:0};for(let e of i)e.status!=="To be released"&&((e.status==="Reading"||e.status==="Plan to Read")&&t.left++,t.read+=e.chaptersRead,t.total+=e.totalChapters,t.volumesRead+=e.volumesRead,t.totalVolumes+=e.totalVolumes);return t}renderReadingCard(i,t,e,s){let a=s.total>0?Math.round(s.read/s.total*100):0,n=me(e==="Books"?"book":"manga",this.plugin.settings),r=e==="Books"?`${s.read} / ${s.total} pages`:`${s.read} / ${s.total} chapters \xB7 ${s.volumesRead} / ${s.totalVolumes} vol`;if(t){let o=i.createDiv({cls:"wl-rect-item"}),l=o.createDiv({cls:"wl-rect-top"});l.createSpan({cls:"wl-rect-label",text:e}),l.createSpan({cls:"wl-rect-unwatched",text:`${s.left} left`}),o.createDiv({cls:"wl-rect-value",text:`${a}%`});let d=o.createDiv({cls:"wl-rect-bar-wrap"}).createDiv({cls:"wl-rect-bar"});d.style.width=`${a}%`,d.style.backgroundColor=n,o.createDiv({cls:"wl-rect-subline",text:r})}else{let o=i.createDiv({cls:"wl-ring-item"}),l=this.makeRingSvg(a,n,`${a}%`,"",!0);o.appendChild(l),o.createDiv({cls:"wl-ring-label",text:e}),o.createDiv({cls:"wl-ring-subtitle",text:`${s.left} left`}),o.createDiv({cls:"wl-ring-subtitle wl-ring-subline",text:r})}}makeRingSvg(i,t,e,s,a=!1){let n="http://www.w3.org/2000/svg",r=activeDocument.createElementNS(n,"svg");r.setAttribute("viewBox","0 0 120 120"),r.setAttribute("width","110"),r.setAttribute("height","110"),r.addClass("wl-ring-svg");let o=activeDocument.createElementNS(n,"circle");o.setAttribute("cx","60"),o.setAttribute("cy","60"),o.setAttribute("r","45"),o.setAttribute("fill","none"),o.setAttribute("stroke-width","10"),o.addClass("wl-ring-track"),r.appendChild(o);let l=activeDocument.createElementNS(n,"circle");l.setAttribute("cx","60"),l.setAttribute("cy","60"),l.setAttribute("r","45"),l.setAttribute("fill","none"),a?l.style.stroke=t:l.setAttribute("stroke",t),l.setAttribute("stroke-width","10"),l.setAttribute("stroke-linecap","round"),l.setAttribute("stroke-dasharray",String(Yi)),l.setAttribute("stroke-dashoffset",String(Yi*(1-i/100))),l.setAttribute("transform","rotate(-90 60 60)"),l.addClass("wl-ring-arc"),r.appendChild(l);let c=activeDocument.createElementNS(n,"text");if(c.setAttribute("x","60"),c.setAttribute("y",s?"55":"60"),c.setAttribute("text-anchor","middle"),c.setAttribute("dominant-baseline","middle"),c.addClass("wl-ring-percent-text"),c.textContent=e,r.appendChild(c),s){let d=activeDocument.createElementNS(n,"text");d.setAttribute("x","60"),d.setAttribute("y","72"),d.setAttribute("text-anchor","middle"),d.addClass("wl-ring-sub-text"),d.textContent=s,r.appendChild(d)}return r}fillRing(i,t,e,s,a){let n=this.makeRingSvg(s,e,`${s}%`,`${a.watched}/${a.total}`);i.appendChild(n),i.createDiv({cls:"wl-ring-label",text:t});let r=a.total-a.watched;i.createDiv({cls:"wl-ring-subtitle",text:`${r} unwatched`})}fillRect(i,t,e,s,a){let n=i.createDiv({cls:"wl-rect-top"});n.createSpan({cls:"wl-rect-label",text:t});let r=a.total-a.watched;n.createSpan({cls:"wl-rect-unwatched",text:`${r} left`}),i.createDiv({cls:"wl-rect-value",text:`${s}%`});let l=i.createDiv({cls:"wl-rect-bar-wrap"}).createDiv({cls:"wl-rect-bar"});l.style.width=`${s}%`,l.style.backgroundColor=e}renderSummaryMetrics(i,t){let e=this.container.createDiv({cls:"wl-summary-metrics"});this.renderMetricRow(e,"Titles in library",String(i)),this.renderMetricRow(e,"Completed",String(t))}renderMetricRow(i,t,e){let s=i.createDiv({cls:"wl-metric-row"});s.createSpan({cls:"wl-metric-label",text:t}),s.createSpan({cls:"wl-metric-value",text:e})}renderSuggestions(i){if(i.length===0)return;let t=this.container.createDiv({cls:"wl-suggestions"});t.createDiv({cls:"wl-section-title",text:"Don't know what to watch next?"});let e=t.createDiv({cls:"wl-suggestions-grid"}),s=d=>{var h,p,m,v;let u=i.filter(f=>f.type===d).filter(f=>f.totalEpisodes>0||f.episodeDuration>0);return u.length===0?(p=(h=i.filter(y=>y.type===d)[0])==null?void 0:h.title)!=null?p:null:(u.sort((f,y)=>{let w=f.totalEpisodes>0?f.totalEpisodes*(f.episodeDuration||24):f.episodeDuration,b=y.totalEpisodes>0?y.totalEpisodes*(y.episodeDuration||24):y.episodeDuration;return w-b}),(v=(m=u[0])==null?void 0:m.title)!=null?v:null)},a=["Anime","Movie","TV Show"];for(let d of a){let u=s(d),h=e.createDiv({cls:"wl-suggestion-card"});h.createDiv({cls:"wl-suggestion-label",text:`Shortest ${d}`}),h.createDiv({cls:`wl-suggestion-title${u?"":" wl-suggestion-empty"}`,text:u!=null?u:"Nothing planned"})}let n=e.createDiv({cls:"wl-suggestion-card"}),r=n.createDiv({cls:"wl-suggestion-random-header"});r.createDiv({cls:"wl-suggestion-label",text:"Random"});let o=r.createEl("button",{cls:"wl-suggestion-shuffle",text:"\u{1F500}"});o.title="Pick another";let l=()=>{var d,u;return(u=(d=i[Math.floor(Math.random()*i.length)])==null?void 0:d.title)!=null?u:""},c=n.createDiv({cls:"wl-suggestion-title",text:l()});o.addEventListener("click",()=>{c.textContent=l()})}renderRecentlyWatched(){let i=this.container.createDiv({cls:"wl-recently-watched"});i.createDiv({cls:"wl-section-title",text:"Recently watched"});let t=this.dataManager.getRecentlyWatched(3);if(t.length===0){i.createDiv({cls:"wl-empty-state",text:"No titles watched yet."});return}for(let e of t){let s=i.createDiv({cls:"wl-rw-item"});s.createDiv({cls:"wl-rw-title",text:e.title});let a=this.getTagDef(e.type,this.plugin.settings.types),n=this.plugin.settings.coloredTypeBadges,o=s.createDiv({cls:"wl-rw-col-badge"}).createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:e.type});n&&a&&(o.style.backgroundColor=H(e.type,a.color,this.plugin.settings.colorTheme));let l=s.createDiv({cls:"wl-rw-col-ep"}),c=e.type==="Movie";if(!c){let u=this.dataManager.getNextUnwatchedEpisode(e);l.textContent=u!==null?`Ep ${u}`:"\u2713"}let d=s.createDiv({cls:"wl-rw-col-pct"});c?d.textContent=e.watchedEpisodes.includes(1)?"100%":"0%":d.textContent=`${this.dataManager.getProgress(e)}%`}}renderRecentlyAdded(){let i=this.container.createDiv({cls:"wl-recently-watched"});i.createDiv({cls:"wl-section-title",text:"Recently added"});let t=this.dataManager.getRecentlyAdded(3);if(t.length===0){i.createDiv({cls:"wl-empty-state",text:"No titles in your library yet."});return}for(let e of t){let s=i.createDiv({cls:"wl-rw-item"});s.createDiv({cls:"wl-rw-title",text:e.title});let a=this.getTagDef(e.type,this.plugin.settings.types),n=this.plugin.settings.coloredTypeBadges,o=s.createDiv({cls:"wl-rw-col-badge"}).createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:e.type});n&&a&&(o.style.backgroundColor=H(e.type,a.color,this.plugin.settings.colorTheme));let l=s.createDiv({cls:"wl-rw-col-ep"}),c=e.type==="Movie";if(!c){let u=this.dataManager.getNextUnwatchedEpisode(e);l.textContent=u!==null?`Ep ${u}`:"\u2713"}let d=s.createDiv({cls:"wl-rw-col-pct"});c?d.textContent=e.watchedEpisodes.includes(1)?"100%":"0%":d.textContent=`${this.dataManager.getProgress(e)}%`}}getTagDef(i,t){return t.find(e=>e.name===i)}};var as=require("obsidian");var Xt=require("obsidian");var ea=30*24*60*60*1e3,Zi={imdb:"IMDb",mal:"MAL",anilist:"AniList",tmdb:"TMDB"};function ia(g,i){return i==="anilist"?`${Math.round(g)}%`:g.toFixed(g>=10?0:1)}function $t(g,i,t,e){var o,l,c,d,u,h;let s=i.dataManager.getTitle(t);if(!s)return;g.createSpan({cls:"wl-rating-divider"});let a=g.createDiv({cls:"wl-community-badge"});if(!!s.communitySource&&((o=s.communityRating)!=null?o:0)>0){let p=(l=s.communitySource)!=null?l:"",m=(c=Zi[p])!=null?c:p.toUpperCase();a.createSpan({cls:`wl-community-source wl-community-source--${p}`,text:m}),a.createSpan({cls:"wl-community-score",text:ia((d=s.communityRating)!=null?d:0,p)}),((u=s.communityVotes)!=null?u:0)>0&&a.createSpan({cls:"wl-community-votes",text:`(${Vi((h=s.communityVotes)!=null?h:0)})`})}else a.createSpan({cls:"wl-community-empty",text:"No community rating"});let r=a.createEl("button",{cls:"wl-community-refresh",text:"\u27F3",attr:{title:"Refresh community rating",type:"button"}});r.addEventListener("click",p=>{p.stopPropagation(),oi(i,t,r,!0).then(()=>{e&&e()})})}var ri=new Set;function ye(g,i,t){var a,n;let e=g.dataManager.getTitle(i);if(!e)return;let s=(a=e.communityRatingLastFetched)!=null?a:"";if(s){let r=Date.parse(s);if(!isNaN(r)&&Date.now()-r{r&&t&&t()}).finally(()=>{ri.delete(i)})))}function sa(g,i,t){var s,a,n;let e=at(g.type,t);return e===""?!1:e==="anime"?i==="anilist"?((s=g.anilistId)!=null?s:0)>0:((a=g.malId)!=null?a:0)>0:!!((n=g.externalLink)!=null?n:"").match(/tt\d+/)}async function aa(g,i){var n;let t=g.dataManager.getTitle(i);if(!t)return!1;let e=(n=g.settings.animeApiSource)!=null?n:"jikan",s=at(t.type,g.settings.typeApiMapping),a=await g.apiService.fetchCommunityRating(t,e,s);return a?(g.dataManager.updateCommunityRating(i,a.rating,a.votes,a.source),!0):!1}async function oi(g,i,t,e){var a,n,r,o,l;let s=g.dataManager.getTitle(i);if(!s)return!1;t&&t.addClass("is-loading");try{let c=(a=g.settings.animeApiSource)!=null?a:"jikan",d=at(s.type,g.settings.typeApiMapping);if(d==="")return e&&new Xt.Notice(`No API configured for type "${s.type}". Configure it in Settings \u2192 API.`),!1;if(d==="anime"){let h=c==="anilist";if(h?((n=s.anilistId)!=null?n:0)>0:((r=s.malId)!=null?r:0)>0){let m=h?`https://anilist.co/anime/${s.anilistId}`:`https://myanimelist.net/anime/${s.malId}`;s.externalLink!==m&&(s.externalLink=m,await g.dataManager.updateTitle(s))}else{let m=await na(g,s,h);if(!m)return e&&new Xt.Notice(`Could not find matching title on ${h?"AniList":"MAL"}.`),!1;let v=g.dataManager.getTitle(i);if(!v)return!1;h?(v.anilistId=(o=m.anilistId)!=null?o:0,v.externalLink=`https://anilist.co/anime/${v.anilistId}`):(v.malId=m.malId,v.externalLink=`https://myanimelist.net/anime/${v.malId}`),await g.dataManager.updateTitle(v),s=v}}let u=await g.apiService.fetchCommunityRating(s,c,d);if(!u)return e&&new Xt.Notice("Could not fetch community rating."),!1;if(g.dataManager.updateCommunityRating(i,u.rating,u.votes,u.source),e){let h=(l=Zi[u.source])!=null?l:u.source;new Xt.Notice(`Rating updated from ${h}.`)}return!0}finally{t&&t.removeClass("is-loading")}}function Ji(g){return g.toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function Xi(g,i){let t=Ji(g),e=Ji(i);if(!t||!e)return!1;if(t===e||t.includes(e)||e.includes(t))return!0;let s=new Set(t.split(" ").filter(o=>o.length>2)),a=new Set(e.split(" ").filter(o=>o.length>2));if(s.size===0||a.size===0)return!1;let n=0;for(let o of s)a.has(o)&&n++;let r=Math.min(s.size,a.size);return n/r>=.5}async function na(g,i,t){let e=t?await g.apiService.searchAniList(i.title):await g.apiService.searchAnime(i.title);if(!e.length)return null;let s=e[0];if(Xi(i.title,s.title))return s;for(let a=1;a{this.selectedType=s.value,this.searchResults=[],this.noApiMessage="",this.renderResults(),this.renderForm()});let a=t.createDiv({cls:"wl-modal-row"});a.createSpan({cls:"wl-modal-label",text:"Search"});let n=a.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Search for a title..."}});n.value=this.searchQuery,n.addEventListener("input",()=>{this.searchQuery=n.value,this.searchDebounce&&window.clearTimeout(this.searchDebounce),this.searchDebounce=window.setTimeout(()=>void this.performSearch(),600)}),a.createEl("button",{cls:"wl-btn",text:"Search"}).addEventListener("click",()=>void this.performSearch()),this.resultsEl=t.createDiv({cls:"wl-modal-results"}),this.formEl=t.createDiv({cls:"wl-modal-form"}),this.renderForm()}async performSearch(){var e,s;if(!this.searchQuery.trim())return;let t=++this.searchGeneration;this.isSearching=!0,this.renderResults();try{let a=this.plugin.apiService,n=(e=this.plugin.settings.activeApi)!=null?e:"OMDb",r=at(this.selectedType,this.plugin.settings.typeApiMapping),o=this.selectedType==="Movie",l=[],c="";if(r===""?c=`No API configured for type "${this.selectedType}". Go to Settings \u2192 API to set one up.`:r==="anime"?l=((s=this.plugin.settings.animeApiSource)!=null?s:"jikan")==="anilist"?await a.searchAniList(this.searchQuery):await a.searchAnime(this.searchQuery):n==="TMDB"?l=await a.searchTmdb(this.searchQuery,o?"movie":"series"):l=await a.searchOmdb(this.searchQuery,o?"movie":"series"),t!==this.searchGeneration)return;this.noApiMessage=c,this.searchResults=l}catch(a){if(t!==this.searchGeneration)return;new Wt.Notice("Search failed. Check your connection and API settings."),this.searchResults=[]}finally{t===this.searchGeneration&&(this.isSearching=!1,this.renderResults())}}renderResults(){if(this.resultsEl){if(this.resultsEl.empty(),this.isSearching){this.resultsEl.createDiv({cls:"wl-modal-loading",text:"Searching..."});return}if(this.noApiMessage){let t=this.resultsEl.createDiv({cls:"wl-modal-no-api"});t.createSpan({cls:"wl-modal-no-api-icon",text:"\u2139"}),t.createSpan({cls:"wl-modal-no-api-text",text:this.noApiMessage});return}this.searchResults.length!==0&&this.searchResults.forEach((t,e)=>{let s=this.resultsEl.createDiv({cls:"wl-result-item"}),a=Zt(t)?`${t.episodes} eps`:t.episodes>0?`${t.episodes} eps`:t.mediaType;s.createDiv({cls:"wl-result-title",text:t.title}),s.createDiv({cls:"wl-result-meta",text:`${a} \xB7 ${t.releaseDate}`}),s.dataset.idx=String(e),s.addEventListener("click",()=>void this.selectResult(t,s))})}}async selectResult(t,e){var r;if(this.resultsEl)for(let o of Array.from(this.resultsEl.children))o.removeClass("is-selected");e.addClass("is-selected");let s=++this.searchGeneration,a=this.plugin.apiService,n=(r=this.plugin.settings.activeApi)!=null?r:"OMDb";try{if(!Zt(t)&&t.mediaType==="tv"){let o=n==="TMDB"?await a.getTmdbTvDetails(t.imdbId):await a.getOmdbTvDetails(t.imdbId);if(s!==this.searchGeneration)return;o&&(this.fieldTitle=o.title,this.fieldEpisodes=o.episodes,this.fieldDuration=o.episodeDuration,this.fieldReleaseDate=o.releaseDate,this.fieldLink=o.url,this.fieldSeasons=o.seasons)}else if(!Zt(t)&&t.mediaType==="movie"){let o=n==="TMDB"?await a.getTmdbMovieDetails(t.imdbId):await a.getOmdbMovieDetails(t.imdbId);if(s!==this.searchGeneration)return;o&&(this.fieldTitle=o.title,this.fieldEpisodes=o.episodes,this.fieldDuration=o.episodeDuration,this.fieldReleaseDate=o.releaseDate,this.fieldLink=o.url,this.fieldSeasons=o.seasons)}else{let o=t;this.fieldTitle=o.title,this.fieldEpisodes=o.episodes,this.fieldDuration=o.duration,this.fieldReleaseDate=o.releaseDate,this.fieldLink=o.url,this.fieldSeasons=o.seasons,o.anilistId&&o.anilistId>0?(this.fieldAnilistId=o.anilistId,this.fieldMalId=null):(this.fieldMalId=o.malId,this.fieldAnilistId=null)}}catch(o){this.fieldTitle=t.title,this.fieldEpisodes=(Zt(t),t.episodes),this.fieldDuration=Zt(t)?t.duration:t.episodeDuration,this.fieldReleaseDate=t.releaseDate,this.fieldLink=t.url,this.fieldSeasons=t.seasons}this.renderForm()}renderForm(){if(!this.formEl)return;this.formEl.empty();let t=M=>{let L=this.formEl.createDiv({cls:"wl-modal-row"});return L.createSpan({cls:"wl-modal-label",text:M}),L},s=t("Title").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Title name"}});s.value=this.fieldTitle,s.addEventListener("input",()=>{this.fieldTitle=s.value});let n=t("Episodes").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0",placeholder:"0"}});n.value=String(this.fieldEpisodes),n.addEventListener("input",()=>{this.fieldEpisodes=parseInt(n.value)||0});let o=t("Ep. duration (min)").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0",placeholder:"24"}});o.value=String(this.fieldDuration),o.addEventListener("input",()=>{this.fieldDuration=parseInt(o.value)||0});let c=t("Release date").createDiv({cls:"wl-modal-input-stack"}),d=c.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Date (dd-mm-yyyy or yyyy-mm-dd)"}});d.value=this.fieldReleaseDate;let u=c.createDiv({cls:"wl-modal-error wl-hidden"});d.addEventListener("change",()=>{let M=d.value.trim();if(!M){this.fieldReleaseDate="",u.addClass("wl-hidden");return}let L=Pt(M);L?(this.fieldReleaseDate=L,d.value=L,u.addClass("wl-hidden")):(this.fieldReleaseDate=M,u.textContent="Unrecognised format. Expected dd/mm/yyyy or yyyy-mm-dd.",u.removeClass("wl-hidden"))});let p=t("External link").createEl("input",{cls:"wl-modal-input",attr:{type:"url",placeholder:"https://example.com"}});p.value=this.fieldLink,p.addEventListener("input",()=>{this.fieldLink=p.value});let v=t("Status").createEl("select",{cls:"wl-select"});for(let M of this.plugin.settings.statuses.filter(L=>L.name!=="To be released")){let L=v.createEl("option",{text:M.name,value:M.name});M.name===this.fieldStatus&&(L.selected=!0)}v.addEventListener("change",()=>{this.fieldStatus=v.value});let y=t("Priority").createEl("select",{cls:"wl-select"});for(let M of this.plugin.settings.priorities){let L=y.createEl("option",{text:M.name,value:M.name});M.name===this.fieldPriority&&(L.selected=!0)}y.addEventListener("change",()=>{this.fieldPriority=y.value});let b=t("Date started").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"15/01/2024",maxlength:"10"}});b.value=this.fieldDateStarted?Q(this.fieldDateStarted):"",b.addEventListener("change",()=>{let M=j(b.value);b.value.trim()&&!M?b.addClass("wl-input-error"):(b.removeClass("wl-input-error"),this.fieldDateStarted=M!=null?M:"")});let S=this.dataManager.getGroups(),E=t("Add to group").createEl("select",{cls:"wl-select"});E.createEl("option",{text:"\u2014 none \u2014",value:""});for(let M of S){let L=E.createEl("option",{text:M.name,value:M.id});M.id===this.selectedGroupId&&(L.selected=!0)}let C=t("Or create new group").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"New group name..."}});C.value=this.newGroupName,E.addEventListener("change",()=>{this.selectedGroupId=E.value,this.selectedGroupId?(this.newGroupName="",C.value="",C.disabled=!0):C.disabled=!1}),C.addEventListener("input",()=>{this.newGroupName=C.value,this.newGroupName.trim()?(this.selectedGroupId="",E.value="",E.disabled=!0):E.disabled=!1}),this.selectedGroupId&&(C.disabled=!0),this.newGroupName.trim()&&(E.disabled=!0),this.fieldSeasons.length>0&&t("Seasons").createSpan({cls:"wl-modal-info",text:this.fieldSeasons.map(L=>`${L.name} (${L.episodes} eps)`).join(", ")}),this.formEl.createDiv({cls:"wl-modal-btn-row"}).createEl("button",{cls:"wl-btn wl-btn-primary",text:"Add to watchlog"}).addEventListener("click",()=>void this.addTitle())}showDuplicateWarning(t,e){if(this.duplicateWarningEl)return;let s=e.createDiv({cls:"wl-duplicate-warning"});this.duplicateWarningEl=s,s.createSpan({text:`"${t}" already exists. Add anyway?`});let a=s.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Continue"}),n=s.createEl("button",{cls:"wl-btn",text:"Cancel"});a.addEventListener("click",()=>{this.skipDuplicateCheck=!0,s.remove(),this.duplicateWarningEl=null,this.addTitle()}),n.addEventListener("click",()=>{s.remove(),this.duplicateWarningEl=null,this.skipDuplicateCheck=!1})}async addTitle(){var s;let t=this.fieldTitle.trim();if(!t){new Wt.Notice("Please enter a title name.");return}if(!this.skipDuplicateCheck&&this.dataManager.getTitles().find(n=>n.title.toLowerCase()===t.toLowerCase())){let n=this.contentEl.querySelector(".wl-modal-btn-row");n&&this.showDuplicateWarning(t,n);return}this.skipDuplicateCheck=!1;let e={id:this.dataManager.generateId(t),title:t,type:this.selectedType,status:this.fieldStatus,priority:this.fieldPriority,review:"",rating:0,notes:"",dateStarted:this.fieldDateStarted||null,dateFinished:null,dateAdded:new Date().toISOString(),dateModified:new Date().toISOString(),totalEpisodes:this.fieldEpisodes,episodeDuration:this.fieldDuration,releaseDate:this.fieldReleaseDate||null,externalLink:this.fieldLink,seasons:this.fieldSeasons,watchedEpisodes:[],...this.fieldMalId!==null?{malId:this.fieldMalId}:{},...this.fieldAnilistId!==null?{anilistId:this.fieldAnilistId}:{}};if(e.status==="Completed"&&e.totalEpisodes>0&&(e.watchedEpisodes=Array.from({length:e.totalEpisodes},(a,n)=>n+1),this.plugin.settings.setFinishDateAutomatically&&(e.dateFinished=(s=new Date().toISOString().split("T")[0])!=null?s:null)),await this.dataManager.addTitle(e),(async()=>{var o;let a=(o=this.plugin.settings.animeApiSource)!=null?o:"jikan",n=at(e.type,this.plugin.settings.typeApiMapping);if(n==="")return;let r=await this.plugin.apiService.fetchCommunityRating(e,a,n);r&&this.dataManager.updateCommunityRating(e.id,r.rating,r.votes,r.source)})(),this.selectedGroupId)await this.dataManager.addTitleToGroup(this.selectedGroupId,e.id);else if(this.newGroupName.trim()){let a=this.newGroupName.trim(),n={id:this.dataManager.generateGroupId(a),name:a,titleIds:[e.id],dateAdded:new Date().toISOString()};await this.dataManager.addGroup(n)}new Wt.Notice(`"${t}" added to WatchLog.`),this.close(),this.onAdded()}};var ts=require("obsidian");var be=class extends ts.Modal{constructor(t,e,s,a){super(t);this.urlInput=null;this.errorEl=null;this.addBtn=null;this.plugin=e,this.dataManager=s,this.onAdded=a}onOpen(){this.titleEl.setText("Add from URL");let t=this.contentEl;t.addClass("wl-add-modal"),t.createDiv({cls:"wl-modal-info",text:"Please enter an IMDb URL (e.g. https://www.imdb.com/title/tt1375666/)"});let e=t.createDiv({cls:"wl-modal-row"});this.urlInput=e.createEl("input",{cls:"wl-modal-input",attr:{type:"url",placeholder:"https://www.imdb.com/title/ttXXXXXXX/"}}),this.urlInput.addEventListener("keydown",a=>{a.key==="Enter"&&this.handleAdd()}),this.errorEl=t.createDiv({cls:"wl-modal-error"}),this.errorEl.hide();let s=t.createDiv({cls:"wl-modal-btn-row"});this.addBtn=s.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Add"}),this.addBtn.addEventListener("click",()=>void this.handleAdd()),window.setTimeout(()=>{var a;return(a=this.urlInput)==null?void 0:a.focus()},50)}onClose(){this.contentEl.empty()}async handleAdd(){var a,n;let e=((n=(a=this.urlInput)==null?void 0:a.value.trim())!=null?n:"").match(/tt\d+/);if(!e){this.showError("Title not found. Please check the URL and try again.");return}let s=e[0];this.addBtn&&(this.addBtn.disabled=!0,this.addBtn.textContent="Loading\u2026"),this.errorEl&&this.errorEl.hide();try{let r=this.plugin.settings.activeApi==="TMDB"?await this.plugin.apiService.getTmdbByImdbId(s):await this.plugin.apiService.getOmdbByImdbId(s);if(!r){this.showError("Title not found. Please check the URL and try again.");return}this.close();let o=r.mediaType==="movie"?"Movie":"TV Show";new ht(this.app,this.plugin,this.dataManager,this.onAdded,{title:r.title,type:o,episodes:r.episodes,duration:r.episodeDuration,releaseDate:r.releaseDate,link:r.url,seasons:r.seasons}).open()}finally{this.addBtn&&(this.addBtn.disabled=!1,this.addBtn.textContent="Add")}}showError(t){this.errorEl&&(this.errorEl.textContent=t,this.errorEl.show())}};var es=require("obsidian"),Ee=class extends es.Modal{constructor(t,e){super(t);this.onChoice=e}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("wl-draft-choice-modal"),this.titleEl.setText("Add title");let e=t.createDiv({cls:"wl-draft-choice-grid"}),s=(a,n)=>{let r=e.createEl("button",{cls:"wl-draft-choice-btn"});r.createDiv({cls:"wl-draft-choice-label",text:a}),r.addEventListener("click",()=>{this.close(),this.onChoice(n)})};s("Add from URL","url"),s("Add manually / via API","manual")}onClose(){this.contentEl.empty()}};var Se=require("obsidian");function De(g){let{controls:i,renderSearch:t,renderActions:e}=g;if(!Se.Platform.isMobile){t(i),e(i);return}let s=g.expanded,a=i.createDiv({cls:"wl-toolbar-slot"}),n=a.createDiv({cls:"wl-toolbar-slot-pane wl-toolbar-fade"});t(n);let r=a.createDiv({cls:"wl-toolbar-slot-pane wl-toolbar-fade"});e(r);let o=()=>{n.toggleClass("wl-toolbar-pane-hidden",s),r.toggleClass("wl-toolbar-pane-hidden",!s)};o();let l=i.createEl("button",{cls:"wl-btn wl-btn-sm wl-toolbar-toggle-btn"}),c=()=>{(0,Se.setIcon)(l,s?"chevron-right":"chevron-left"),l.setAttr("aria-label",s?"Show search":"Show actions")};c(),l.addEventListener("click",()=>{s=!s,g.onToggleChange(s),o(),c()})}var te=require("obsidian");function ra(g){var t,e;let i=[];for(let s of g.split(",").map(a=>a.trim()).filter(Boolean)){let a=s.split("-");if(a.length===2){let n=parseInt((t=a[0])!=null?t:"0",10),r=parseInt((e=a[1])!=null?e:"0",10);if(!isNaN(n)&&!isNaN(r)&&n<=r)for(let o=n;o<=r;o++)i.push(o)}else{let n=parseInt(s,10);isNaN(n)||i.push(n)}}return[...new Set(i)].sort((s,a)=>s-a)}function oa(g){if(g.length===0)return"";let i=[...new Set(g)].sort((s,a)=>s-a),t=[],e=0;for(;ee?t.push(`${i[e]}-${i[s]}`):t.push(String(i[e])),e=s+1}return t.join(",")}function li(g){let i=g.split(` -`).map(s=>s.trim()).filter(Boolean),t=[],e=0;for(let s of i){let a=s.match(/^(.+?):\s*(\d+)(?:\s*\(([^)]+)\))?/);if(a&&a[1]&&a[2]){let n=parseInt(a[2],10),r=a[3]?ra(a[3]):[];t.push({name:a[1].trim(),episodes:n,offset:e,skippedEpisodes:r}),e+=n}}return t}function la(g){return g.map(i=>{let t=`${i.name}: ${i.episodes}`;return i.skippedEpisodes&&i.skippedEpisodes.length>0?`${t} (${oa(i.skippedEpisodes)})`:t}).join(` -`)}var St=class extends te.Modal{constructor(t,e,s,a,n){var r,o,l,c,d;super(t);this.skipDuplicateCheck=!1;this.duplicateWarningEl=null;this.plugin=e,this.dataManager=s,this.original=a,this.onSaved=n,this.fieldTitle=a.title,this.fieldType=a.type,this.fieldEpisodes=a.totalEpisodes,this.fieldDuration=a.episodeDuration,this.fieldReleaseDate=(r=a.releaseDate)!=null?r:"",this.fieldLink=a.externalLink,this.fieldSeasonsText=la(a.seasons),this.fieldStatus=a.status,this.fieldPriority=a.priority,this.fieldReview=(o=a.review)!=null?o:"",this.fieldRating=a.rating,this.fieldNotes=a.notes,this.fieldDateStarted=(l=a.dateStarted)!=null?l:"",this.fieldDateFinished=(c=a.dateFinished)!=null?c:"",this.fieldPosterUrl=(d=a.manualPosterUrl)!=null?d:""}onOpen(){this.titleEl.setText(`Edit: ${this.original.title}`),this.contentEl.addClass("wl-add-modal"),this.buildUI()}onClose(){this.contentEl.empty()}buildUI(){let t=this.contentEl;t.empty();let e=$=>{let K=t.createDiv({cls:"wl-modal-row"});return K.createSpan({cls:"wl-modal-label",text:$}),K},a=e("Title").createEl("input",{cls:"wl-modal-input",attr:{type:"text"}});a.value=this.fieldTitle,a.addEventListener("input",()=>{this.fieldTitle=a.value});let r=e("Type").createEl("select",{cls:"wl-select"});for(let $ of this.plugin.settings.types){let K=r.createEl("option",{text:$.name,value:$.name});$.name===this.fieldType&&(K.selected=!0)}r.addEventListener("change",()=>{this.fieldType=r.value});let l=e("Status").createEl("select",{cls:"wl-select"}),c=this.fieldStatus==="To be released";for(let $ of this.plugin.settings.statuses){if($.name==="To be released"&&!c)continue;let K=l.createEl("option",{text:$.name,value:$.name});$.name===this.fieldStatus&&(K.selected=!0)}l.addEventListener("change",()=>{this.fieldStatus=l.value});let u=e("Priority").createEl("select",{cls:"wl-select"});for(let $ of this.plugin.settings.priorities){let K=u.createEl("option",{text:$.name,value:$.name});$.name===this.fieldPriority&&(K.selected=!0)}u.addEventListener("change",()=>{this.fieldPriority=u.value});let p=e("Rating").createDiv({cls:"wl-stars"}),m=()=>{p.empty();for(let $=1;$<=5;$++)p.createSpan({cls:`wl-star${this.fieldRating>=$?" is-active":""}`,text:"\u2605"}).addEventListener("click",()=>{this.fieldRating=this.fieldRating===$?0:$,m()})};m();let v=e("Total episodes"),f=v.createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0"}});f.value=String(this.fieldEpisodes);let y=v.createSpan({cls:"wl-modal-skip-inline"}),w=v.createSpan({cls:"wl-modal-skip-inline"}),b=()=>{let K=li(this.fieldSeasonsText).reduce((Ut,Vt)=>{var Gt,Kt;return Ut+((Kt=(Gt=Vt.skippedEpisodes)==null?void 0:Gt.length)!=null?Kt:0)},0);if(K===0){y.textContent="",w.textContent="";return}let ge=Math.max(0,this.fieldEpisodes-K);y.textContent=`\xB7 ${K} to skip`,w.textContent=`\xB7 ${ge} to watch`};f.addEventListener("input",()=>{this.fieldEpisodes=parseInt(f.value)||0,b()});let k=e("Ep. duration (min)").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0"}});k.value=String(this.fieldDuration),k.addEventListener("input",()=>{this.fieldDuration=parseInt(k.value)||0});let D=e("Release date").createDiv({cls:"wl-modal-input-stack"}),C=D.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Date (dd-mm-yyyy or yyyy-mm-dd)"}});C.value=this.fieldReleaseDate;let x=D.createDiv({cls:"wl-modal-error wl-hidden"});C.addEventListener("change",()=>{let $=C.value.trim();if(!$){this.fieldReleaseDate="",x.addClass("wl-hidden");return}let K=Pt($);K?(this.fieldReleaseDate=K,C.value=K,x.addClass("wl-hidden")):(this.fieldReleaseDate=$,x.textContent="Unrecognised format. Expected dd/mm/yyyy or yyyy-mm-dd.",x.removeClass("wl-hidden"))});let M=e("External link").createEl("input",{cls:"wl-modal-input",attr:{type:"url",placeholder:"HTTPS://..."}});M.value=this.fieldLink,M.addEventListener("input",()=>{this.fieldLink=M.value});let q=e("Poster URL").createDiv({cls:"wl-modal-input-stack"}),A=q.createEl("input",{cls:"wl-modal-input",attr:{type:"url",placeholder:"https://example.com/poster.jpg"}});A.value=this.fieldPosterUrl,A.addEventListener("input",()=>{this.fieldPosterUrl=A.value}),q.createDiv({cls:"wl-modal-info",text:"Override the auto-fetched cover. Leave blank to let WatchLog fetch one again."});let I=e("Date started").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});I.value=Q(this.fieldDateStarted),I.addEventListener("change",()=>{let $=j(I.value);I.value.trim()&&!$?I.addClass("wl-input-error"):(I.removeClass("wl-input-error"),this.fieldDateStarted=$!=null?$:"")});let _=e("Date finished").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});_.value=Q(this.fieldDateFinished),_.addEventListener("change",()=>{let $=j(_.value);_.value.trim()&&!$?_.addClass("wl-input-error"):(_.removeClass("wl-input-error"),this.fieldDateFinished=$!=null?$:"")});let G=e("Notes").createEl("textarea",{cls:"wl-modal-textarea",attr:{rows:"3",placeholder:"Your notes..."}});G.value=this.fieldNotes,G.addEventListener("input",()=>{this.fieldNotes=G.value});let ft=e("Seasons").createDiv({cls:"wl-modal-input-stack"}),xt=ft.createEl("textarea",{cls:"wl-modal-textarea",attr:{rows:"4",placeholder:`Season 1: 12 -Season 2: 13 (5,8,33-37)`}});xt.value=this.fieldSeasonsText;let U=ft.createDiv({cls:"wl-modal-season-total"}),O=()=>{let $=li(xt.value),K=$.reduce((Ut,Vt)=>Ut+Vt.episodes,0),ge=$.reduce((Ut,Vt)=>{var Gt,Kt;return Ut+((Kt=(Gt=Vt.skippedEpisodes)==null?void 0:Gt.length)!=null?Kt:0)},0);U.textContent=ge>0?`Total episodes: ${K} \xB7 ${ge} to skip`:`Total episodes: ${K}`};O(),b(),xt.addEventListener("input",()=>{this.fieldSeasonsText=xt.value,O(),b()}),ft.createDiv({cls:"wl-modal-info",text:'Format: "Season Name: N" (e.g. "Season 1: 12")'}),ft.createDiv({cls:"wl-modal-info",text:'Skip episodes: add "(1,3,5-10)" after count (e.g. "Season 1: 48 (33-37)")'}),ft.createDiv({cls:"wl-modal-info",text:'Note: when adding a new season, remember to update "Total Episodes" so progress calculates correctly.'});let Y=t.createDiv({cls:"wl-modal-btn-row"});Y.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),Y.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save changes"}).addEventListener("click",()=>void this.saveTitle())}showDuplicateWarning(t,e){if(this.duplicateWarningEl)return;let s=e.createDiv({cls:"wl-duplicate-warning"});this.duplicateWarningEl=s,s.createSpan({text:`"${t}" already exists. Save anyway?`});let a=s.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Continue"}),n=s.createEl("button",{cls:"wl-btn",text:"Cancel"});a.addEventListener("click",()=>{this.skipDuplicateCheck=!0,s.remove(),this.duplicateWarningEl=null,this.saveTitle()}),n.addEventListener("click",()=>{s.remove(),this.duplicateWarningEl=null,this.skipDuplicateCheck=!1})}async saveTitle(){let t=this.fieldTitle.trim();if(!t){new te.Notice("Title name cannot be empty.");return}if(!this.skipDuplicateCheck&&this.dataManager.getTitles().find(d=>d.id!==this.original.id&&d.title.toLowerCase()===t.toLowerCase())){let d=this.contentEl.querySelector(".wl-modal-btn-row");d&&this.showDuplicateWarning(t,d);return}this.skipDuplicateCheck=!1;let e=li(this.fieldSeasonsText),s=this.fieldReleaseDate||null,a={...this.original,title:t,type:this.fieldType,status:this.fieldStatus,priority:this.fieldPriority,review:this.fieldReview,rating:this.fieldRating,notes:this.fieldNotes,totalEpisodes:this.fieldEpisodes,episodeDuration:this.fieldDuration,releaseDate:s,externalLink:this.fieldLink,seasons:e,dateStarted:this.fieldDateStarted||null,dateFinished:this.fieldDateFinished||null,manualPosterUrl:this.fieldPosterUrl.trim()};a.status==="Completed"&&a.totalEpisodes>0&&(a.watchedEpisodes=Array.from({length:a.totalEpisodes},(c,d)=>d+1)),await this.dataManager.updateTitle(a);let r=this.dataManager.getAirtimeEntries().find(c=>c.titleId===a.id);if(r&&r.schedule.recurrence==="once"){let c=s!=null?s:void 0;r.schedule.releaseDate!==c&&(r.schedule.releaseDate=c,await this.dataManager.updateAirtimeEntry(r))}let o=new Date;o.setHours(0,0,0,0),(c=>c!==null&&/^\d{4}-\d{2}-\d{2}$/.test(c))(s)?new Date(s+"T12:00:00").getTime()>o.getTime()?(a.status!=="To be released"&&(a.status="To be released",await this.dataManager.updateTitle(a)),this.dataManager.getAirtimeEntries().some(p=>p.titleId===a.id)||await this.dataManager.autoAddToUpcoming(a)):a.status==="To be released"&&(a.status="Plan to watch",await this.dataManager.updateTitle(a),await this.dataManager.removeAirtimeEntriesForTitle(a.id)):!s&&a.status==="To be released"&&(a.status="Plan to watch",await this.dataManager.updateTitle(a),await this.dataManager.removeAirtimeEntriesForTitle(a.id)),new te.Notice(`"${t}" updated.`),this.close(),this.onSaved()}};var is=require("obsidian"),N=class extends is.Modal{constructor(i,t,e){super(i),this.message=t,this.onConfirm=e}onOpen(){let{contentEl:i}=this;i.createDiv({cls:"wl-confirm-msg",text:this.message});let t=i.createDiv({cls:"wl-modal-btn-row"});t.createEl("button",{cls:"wl-btn wl-btn-danger",text:"Confirm"}).addEventListener("click",()=>{this.close(),this.onConfirm()}),t.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close())}onClose(){this.contentEl.empty()}};var ci=require("obsidian");var Rt=require("obsidian");function ke(g,i,t,e){let s=i.createEl("span",{cls:"wl-acc-link-icon"});return(0,Rt.setIcon)(s,"file-text"),s.setAttr("aria-label","Open note"),s.title="Open note",s.addEventListener("click",a=>{a.stopPropagation();let n=t instanceof Rt.TFile?t:g.vault.getAbstractFileByPath(t);if(!(n instanceof Rt.TFile)){new Rt.Notice("Note file not found for this title.");return}g.workspace.getLeaf().openFile(n),e==null||e()}),s}var ee=class extends ci.Modal{constructor(t,e,s,a){super(t);this.changed=!1;this.collapsedSeasons=new Set;this.statsBoxEl=null;this.episodesSectionEl=null;this.starsWrapEl=null;this.plugin=e,this.dataManager=e.dataManager,this.title=s,this.onChanged=a,this.collapsedSeasons=this.dataManager.getCollapsedSeasonsForTitle(s.id)}onOpen(){var e;let t=(e=this.plugin.settings.colorTheme)!=null?e:"default";this.modalEl.setAttribute("data-theme",t),this.contentEl.setAttribute("data-theme",t),this.contentEl.addClass("wl-view"),this.contentEl.addClass("wl-detail-modal"),this.renderAll()}onClose(){this.contentEl.empty(),this.changed&&this.onChanged&&this.onChanged()}getTagDef(t,e){return e.find(s=>s.name===t)}refreshTitle(){let t=this.dataManager.getTitle(this.title.id);t&&(this.title=t)}markChanged(){this.changed=!0}renderAll(){this.contentEl.empty(),this.renderHeader(this.contentEl),this.renderEpisodesSection(this.contentEl),this.renderRatingSection(this.contentEl),this.renderNotesSection(this.contentEl),this.renderDateSection(this.contentEl),this.renderFooter(this.contentEl)}renderHeader(t){let e=t.createDiv({cls:"wl-detail-header"}),s=e.createDiv({cls:"wl-detail-header-left"});s.createEl("h2",{cls:"wl-detail-title",text:this.title.title});let a=s.createDiv({cls:"wl-detail-badge-row"}),n=this.getTagDef(this.title.type,this.plugin.settings.types),r=n?H(this.title.type,n.color,this.plugin.settings.colorTheme):"#888780",o=a.createSpan({cls:"wl-card-type-badge",text:this.title.type});if(o.style.backgroundColor=r,this.title.externalLink){let c=a.createEl("a",{cls:"wl-acc-link-icon",text:"\u{1F310}"});c.href=this.title.externalLink,c.title="Open external link",c.target="_blank",c.rel="noopener noreferrer"}ke(this.app,a,this.dataManager.getNoteFilePath(this.title),()=>this.close());let l=a.createSpan({cls:"wl-reading-detail-status-wrap"});this.renderStatusBadge(l),this.statsBoxEl=e.createDiv({cls:"wl-detail-stats-box"}),this.renderStatsBox()}renderStatsBox(){if(!this.statsBoxEl)return;this.statsBoxEl.empty();let t=this.title,e=this.dataManager.calcTimeRemainingForModal(t),s=this.dataManager.calcTimeWatched(t),a=t.watchedEpisodes.length,n=this.dataManager.getEffectiveTotal(t),r=this.dataManager.getProgress(t),o=(d,u)=>{let h=this.statsBoxEl.createDiv({cls:"wl-acc-stat-block"});h.createDiv({cls:"wl-acc-percent",text:d}),h.createDiv({cls:"wl-acc-progress-label",text:u})};o(z(e),"left"),o(z(s),"watched"),o(`${a} / ${n}`,"episodes");let l=this.statsBoxEl.createDiv({cls:"wl-acc-header-right"});l.createDiv({cls:"wl-acc-percent",text:`${r}%`}),l.createDiv({cls:"wl-acc-progress-label",text:"progress"});let c=l.createDiv({cls:"wl-acc-progress-wrap"});c.createDiv({cls:"wl-progress-bar"}).style.width=`${r}%`}renderEpisodesSection(t){this.episodesSectionEl=t.createDiv({cls:"wl-detail-episodes"}),this.renderEpisodesBody()}renderEpisodesBody(){if(!this.episodesSectionEl)return;this.episodesSectionEl.empty();let t=this.title;if(t.type==="Movie"){let e=this.episodesSectionEl.createDiv({cls:"wl-movie-row"}),s=e.createEl("input",{cls:"wl-movie-checkbox",attr:{type:"checkbox"}});s.checked=t.watchedEpisodes.includes(1),e.createSpan({cls:"wl-movie-label",text:"Watched"}),s.addEventListener("change",()=>{this.dataManager.markEpisodeWatched(t.id,1,s.checked).then(()=>{this.refreshTitle(),this.markChanged(),this.renderStatsBox()})});return}if(t.seasons.length===0){t.totalEpisodes>0&&this.renderEpisodeGrid(this.episodesSectionEl,null);return}t.seasons.forEach((e,s)=>{var h,p;let a=this.collapsedSeasons.has(s),n=this.episodesSectionEl.createDiv({cls:"wl-season-wrap"}),r=n.createDiv({cls:"wl-season-header"}),o=r.createSpan({cls:"wl-season-badge"});o.textContent=e.name;let l=this.plugin.settings.seasonPalette;o.style.backgroundColor=(h=l[s%l.length])!=null?h:"#888780";let c=((p=e.skippedEpisodes)!=null?p:[]).length,d=c>0?` (${c} to skip)`:"";r.createSpan({cls:"wl-season-ep-count",text:`${e.episodes} eps${d}`});let u=r.createSpan({cls:`wl-chevron${a?"":" is-open"}`,text:"\u203A"});a||this.renderEpisodeGrid(n,e),r.addEventListener("click",()=>{var m;a?(a=!1,this.collapsedSeasons.delete(s),u.classList.add("is-open"),this.renderEpisodeGrid(n,e)):(a=!0,this.collapsedSeasons.add(s),u.classList.remove("is-open"),(m=n.querySelector(".wl-episode-grid"))==null||m.remove()),this.dataManager.persistCollapsedSeasons(this.title.id,this.collapsedSeasons)})})}renderEpisodeGrid(t,e){let s=this.title,a=t.createDiv({cls:"wl-episode-grid"}),n=e?e.episodes:s.totalEpisodes,r=e?e.offset:0,o=Array.from({length:n},(u,h)=>r+h+1),l=a.createDiv({cls:"wl-season-fill-btn"}),c=()=>{let u=new Set(this.title.watchedEpisodes),h=o.length>0&&o.every(p=>u.has(p));l.classList.toggle("is-clear",h),l.classList.toggle("is-fill",!h),l.textContent=h?"\u2717":"\u2713",l.title=h?"Clear all episodes in this season":"Mark all episodes in this season as watched"};c(),l.addEventListener("click",()=>{let u=new Set(this.title.watchedEpisodes),h=o.length>0&&o.every(p=>u.has(p));this.dataManager.markSeasonWatched(this.title.id,o,!h,e==null?void 0:e.name).then(()=>{this.refreshTitle(),this.markChanged(),this.renderEpisodesBody(),this.renderStatsBox()})});let d=this.plugin.settings.episodeNumbering==="per-season";for(let u=0;u{var b;let y=this.title.watchedEpisodes.includes(h),w=e?((b=e.skippedEpisodes)!=null?b:[]).includes(p):!1;v.classList.toggle("is-watched",y),v.classList.toggle("is-skipped",w),v.textContent=w&&!y?"\u2014":y?"\u2713":String(m),v.title=`Episode ${h}${w?" (skipped)":""}`};f(),v.addEventListener("click",()=>{let y=this.title.watchedEpisodes.includes(h);this.dataManager.applyEpisodeWatchedToggle(this.title.id,h,!y),this.refreshTitle(),this.markChanged(),f(),c(),this.renderStatsBox()})}}renderRatingSection(t){let e=t.createDiv({cls:"wl-detail-rating"});e.createSpan({cls:"wl-stars-label",text:"Rating"}),this.starsWrapEl=e.createDiv({cls:"wl-stars wl-detail-stars"}),this.renderStars();let s=()=>{var r;let n=e.querySelector(".wl-rating-divider");for(;n;){let o=n;n=n.nextSibling,(r=o.parentNode)==null||r.removeChild(o)}$t(e,this.plugin,this.title.id,s),this.refreshTitle()};$t(e,this.plugin,this.title.id,s),ye(this.plugin,this.title.id,s)}renderStars(){if(this.starsWrapEl){this.starsWrapEl.empty();for(let t=1;t<=5;t++)this.starsWrapEl.createSpan({cls:`wl-star${this.title.rating>=t?" is-active":""}`,text:"\u2605"}).addEventListener("click",()=>{(async()=>{let s=this.dataManager.getTitle(this.title.id);s&&(s.rating=s.rating===t?0:t,await this.dataManager.updateTitle(s),this.refreshTitle(),this.markChanged(),this.renderStars())})()})}}renderNotesSection(t){let e=t.createDiv({cls:"wl-detail-notes"});e.createSpan({cls:"wl-stars-label",text:"Notes"});let s=e.createEl("textarea",{cls:"wl-detail-notes-input",attr:{placeholder:"Add notes...",rows:"3"}});s.value=this.title.notes;let a=()=>{s.setCssProps({height:"auto"}),s.setCssProps({height:`${s.scrollHeight}px`})};s.addEventListener("input",a),window.setTimeout(a,0),s.addEventListener("blur",()=>{s.value!==this.title.notes&&(async()=>{let n=this.dataManager.getTitle(this.title.id);n&&(n.notes=s.value,await this.dataManager.updateTitle(n),this.refreshTitle(),this.markChanged())})()})}renderDateSection(t){let e=t.createDiv({cls:"wl-detail-date"});e.createSpan({cls:"wl-stars-label",text:"Date watched"});let s=e.createEl("button",{cls:"wl-btn wl-btn-sm wl-footer-today-btn",text:"Today"}),a=e.createEl("input",{cls:"wl-footer-date",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});a.value=Q(this.title.dateFinished);let n=()=>{s.toggleClass("is-dimmed",!!a.value.trim())};n(),a.addEventListener("change",()=>{(async()=>{let r=this.dataManager.getTitle(this.title.id);if(!r)return;let o=j(a.value);if(a.value.trim()&&!o){a.addClass("wl-input-error");return}a.removeClass("wl-input-error"),r.dateFinished=o,await this.dataManager.updateTitle(r),this.refreshTitle(),this.markChanged(),n()})()}),s.addEventListener("click",()=>{if(a.value.trim())return;let r=new Date,o=String(r.getDate()).padStart(2,"0"),l=String(r.getMonth()+1).padStart(2,"0"),c=r.getFullYear();a.value=`${o}/${l}/${c}`,n(),a.dispatchEvent(new Event("change"))})}statusColor(t){let e=this.getTagDef(t,this.plugin.settings.statuses);return e?H(t,e.color,this.plugin.settings.colorTheme):"#888780"}renderStatusBadge(t){t.empty();let e=this.title.status,s=t.createSpan({cls:"wl-reading-detail-status",text:e});s.style.backgroundColor=this.statusColor(e),s.title="Click to change status",s.addEventListener("click",a=>{a.stopPropagation(),this.openStatusDropdown(s,t)})}openStatusDropdown(t,e){this.contentEl.querySelectorAll(".wl-reading-status-dropdown").forEach(o=>o.remove());let s=t.getBoundingClientRect(),a=this.contentEl.createDiv({cls:"wl-reading-status-dropdown"});a.style.top=`${s.bottom+4}px`,a.style.left=`${s.left}px`;let n=this.contentEl.ownerDocument;for(let o of this.plugin.settings.statuses){if(o.name==="To be released")continue;let l=a.createDiv({cls:"wl-reading-status-option"}),c=l.createSpan({cls:"wl-reading-status-option-dot"});c.style.backgroundColor=this.statusColor(o.name),l.createSpan({text:o.name}),l.addEventListener("click",()=>{a.remove(),n.removeEventListener("mousedown",r,!0),this.saveStatus(o.name).then(()=>this.renderStatusBadge(e))})}let r=o=>{a.contains(o.target)||(a.remove(),n.removeEventListener("mousedown",r,!0))};window.setTimeout(()=>n.addEventListener("mousedown",r,!0),0)}async saveStatus(t){let e=this.dataManager.getTitle(this.title.id);e&&(e.status=t,await this.dataManager.updateTitle(e),this.refreshTitle(),this.markChanged())}renderFooter(t){let e=t.createDiv({cls:"wl-detail-footer"});e.createEl("button",{cls:"wl-delete-btn wl-btn-danger wl-detail-remove",text:"Remove"}).addEventListener("click",()=>{new N(this.plugin.app,`Remove "${this.title.title}" from watchlog?`,()=>{this.dataManager.removeTitle(this.title.id).then(()=>{this.markChanged(),this.close()})}).open()}),e.createEl("button",{cls:"wl-edit-btn wl-detail-edit",text:"Edit"}).addEventListener("click",()=>{let n=this.dataManager.getTitle(this.title.id);n&&(this.close(),new St(this.plugin.app,this.plugin,this.dataManager,n,()=>{this.onChanged&&this.onChanged()}).open())})}},Te=class extends ci.Modal{constructor(t,e,s,a,n){super(t);this.changed=!1;this.plugin=e,this.dataManager=e.dataManager,this.group=s,this.members=a,this.onChanged=n}onOpen(){var e;let t=(e=this.plugin.settings.colorTheme)!=null?e:"default";this.modalEl.setAttribute("data-theme",t),this.contentEl.setAttribute("data-theme",t),this.contentEl.addClass("wl-view"),this.contentEl.addClass("wl-detail-modal"),this.renderAll()}onClose(){this.contentEl.empty(),this.changed&&this.onChanged&&this.onChanged()}renderAll(){this.contentEl.empty();let t=this.contentEl.createDiv({cls:"wl-detail-header"}),e=t.createDiv({cls:"wl-detail-header-left"});e.createEl("h2",{cls:"wl-detail-title",text:this.group.name}),e.createDiv({cls:"wl-detail-group-meta",text:`${this.members.length} title${this.members.length!==1?"s":""}`});let s=this.members.reduce((d,u)=>d+this.dataManager.getEffectiveTotal(u),0),a=this.members.reduce((d,u)=>d+u.watchedEpisodes.length,0),n=s>0?Math.round(a/s*100):0,o=t.createDiv({cls:"wl-detail-stats-box"}).createDiv({cls:"wl-acc-header-right"});o.createDiv({cls:"wl-acc-percent",text:`${n}%`}),o.createDiv({cls:"wl-acc-progress-label",text:"progress"});let l=o.createDiv({cls:"wl-acc-progress-wrap"});l.createDiv({cls:"wl-progress-bar"}).style.width=`${n}%`;let c=this.contentEl.createDiv({cls:"wl-cards-grid wl-detail-group-grid"});for(let d of this.members){let u=ca(this.plugin,d,{onOpenDetail:()=>{this.close(),new ee(this.plugin.app,this.plugin,d,()=>{this.changed=!0,this.onChanged&&this.onChanged()}).open()},onEdit:()=>{this.close(),new St(this.plugin.app,this.plugin,this.dataManager,d,()=>{this.changed=!0,this.onChanged&&this.onChanged()}).open()}});c.appendChild(u)}}};function ca(g,i,t){var b;let e=g.settings,s=e.types.find(S=>S.name===i.type),a=e.statuses.find(S=>S.name===i.status),n=s?H(i.type,s.color,e.colorTheme):"#888780",o=activeDocument.createElement("div").createDiv({cls:"wl-card"});o.dataset.titleId=i.id;let l=o.createDiv({cls:"wl-card-poster-placeholder"});l.style.backgroundColor=n;let c=(i.title.trim().charAt(0)||"?").toUpperCase();l.createSpan({text:c});let d=o.createEl("img",{cls:"wl-card-poster"});d.alt=i.title;let u=S=>{d.src=S,o.addClass("has-poster")},h=()=>{o.removeClass("has-poster")},p=zt(i),m=!!(i.manualPosterUrl&&i.manualPosterUrl.trim()!=="");if(p&&p.startsWith("http")?(u(p),d.onerror=()=>{h(),m||g.dataManager.updatePosterUrl(i.id,"none")}):!m&&i.posterUrl===""&&(l.addClass("is-loading"),(b=g.posterService)==null||b.enqueue(i).then(S=>{l.removeClass("is-loading"),S&&u(S)})),a){let S=o.createSpan({cls:"wl-card-status-badge",text:i.status});S.style.backgroundColor=H(i.status,a.color,e.colorTheme)}let v=o.createDiv({cls:"wl-card-overlay"});v.createSpan({cls:"wl-card-title",text:i.title});let f=v.createSpan({cls:"wl-card-type-badge",text:i.type});f.style.backgroundColor=n;let y=i.totalEpisodes;if(y&&y>0){let k=i.status==="Completed"?1:Math.max(0,Math.min(1,i.watchedEpisodes.length/y)),D=v.createDiv({cls:"wl-card-progress-bar"}).createDiv({cls:"wl-card-progress-fill"});D.style.width=`${k*100}%`}let w=o.createEl("button",{cls:"wl-card-menu-btn",text:"\u22EE"});return w.setAttr("aria-label","Edit"),w.addEventListener("click",S=>{S.stopPropagation(),t.onEdit()}),o.addEventListener("click",()=>t.onOpenDetail()),o}function ss(g,i,t,e){let s=[];for(let n of i){let r=t(n);if(r&&r!=="none"&&r.trim()!==""&&(s.push(r),s.length===3))break}if(s.length===0){let n=g.createDiv({cls:"wl-card-poster-placeholder"});return n.style.backgroundColor=e.color,n.createSpan({text:e.letter}),n}let a=g.createDiv({cls:"wl-card-collage"});for(let n of s){let r=a.createDiv({cls:"wl-card-collage-strip"});r.style.backgroundImage=`url("${n.replace(/"/g,"%22")}")`}return a}var ie=["High","Medium","Low"],tt=class tt{constructor(i,t,e){this.filterTypeExclude=new Set;this.filterStatusExclude=new Set;this.filterPriorityExclude=new Set;this.filterRatingExclude=new Set;this.filterGroupExclude=new Set;this.filterSort="dateAdded";this.filterSortDir="desc";this.filterSecondSort="none";this.filterSecondSortDir="asc";this.searchQuery="";this.expandedId=null;this.collapsedSeasons=new Set;this.expandedGroups=new Set;this.renamingGroupId=null;this.selectionMode=!1;this.selectedItems=new Set;this.pinnedGroupId=null;this.savedFilterActive=!1;this.savedFilterBtnEl=null;this.filterRatingEmptyOnly=!1;this.filterPriorityEmptyOnly=!1;this.filterRecentlyArrivedOnly=!1;this.filterGroupsOnly=!1;this.currentSubTab="list";this.toolbarExpanded=!1;this.scrollCleanup=null;this.cardsObserver=null;this.observedCards=new Set;this.cardsScrollContainer=null;this.cardsScrollSpacer=null;this.cardsGridEl=null;this.cardsDisplayItems=[];this.cardsScrollHandler=null;this.cardsScrollRAF=null;this.cardsResizeObserver=null;this.cardsLastFirst=-1;this.cardsLastLast=-1;this.cardsLastScrollTop=0;this._cardsPersistentScrollTop=0;this.cardsRowHeight=0;this._lastScrollTop=0;this.scrollPositionListener=null;this.activeCleanups=[];this.STATUS_ORDER=["Watching","Plan to watch","Completed","To be released","Dropped"];var n,r,o,l,c,d,u,h,p,m,v,f,y,w,b,S,k;this.container=i,this.plugin=t,this.dataManager=e,this.currentSubTab=t.settings.defaultWatchlistView==="list"?"list":"cards",this.scrollPositionListener=()=>{this._lastScrollTop=this.container.scrollTop},this.container.addEventListener("scroll",this.scrollPositionListener,{passive:!0}),this.pinnedGroupId=e.getPinnedGroupId();let s=t.settings.listFilters;if(s){this.filterTypeExclude=new Set((n=s.typeExclude)!=null?n:[]),this.filterStatusExclude=new Set((r=s.statusExclude)!=null?r:[]),this.filterGroupExclude=new Set((o=s.groupExclude)!=null?o:[]),this.filterRatingExclude=new Set((l=s.ratingExclude)!=null?l:[]),this.filterPriorityExclude=new Set((c=s.priorityExclude)!=null?c:[]);let E=tt.migrateSortKey((d=s.sort)!=null?d:"dateAdded-newest");this.filterSort=E.key,this.filterSortDir=(u=s.sortDir)!=null?u:E.dir;let D=tt.migrateSortKey((h=s.secondSort)!=null?h:"none");this.filterSecondSort=D.key,this.filterSecondSortDir=(p=s.secondSortDir)!=null?p:D.dir,this.filterRatingEmptyOnly=(m=s.ratingEmptyOnly)!=null?m:!1,this.filterPriorityEmptyOnly=(v=s.priorityEmptyOnly)!=null?v:!1,this.filterRecentlyArrivedOnly=(f=s.recentlyArrivedOnly)!=null?f:!1,this.filterGroupsOnly=(y=s.groupsOnly)!=null?y:!1}let a=e.getSavedFilterPreset();if(a){let E=(D,C)=>D.size===C.length&&C.every(x=>D.has(x));this.savedFilterActive=E(this.filterTypeExclude,a.typeExclude)&&E(this.filterStatusExclude,a.statusExclude)&&E(this.filterGroupExclude,a.groupExclude)&&E(this.filterRatingExclude,a.ratingExclude)&&E(this.filterPriorityExclude,a.priorityExclude)&&this.filterRatingEmptyOnly===((w=a.ratingEmptyOnly)!=null?w:!1)&&this.filterPriorityEmptyOnly===((b=a.priorityEmptyOnly)!=null?b:!1)&&this.filterRecentlyArrivedOnly===((S=a.recentlyArrivedOnly)!=null?S:!1)&&this.filterGroupsOnly===((k=a.groupsOnly)!=null?k:!1)}}saveFiltersToSettings(){this.plugin.settings.listFilters={typeExclude:Array.from(this.filterTypeExclude),statusExclude:Array.from(this.filterStatusExclude),groupExclude:Array.from(this.filterGroupExclude),ratingExclude:Array.from(this.filterRatingExclude),priorityExclude:Array.from(this.filterPriorityExclude),sort:this.filterSort,sortDir:this.filterSortDir,secondSort:this.filterSecondSort,secondSortDir:this.filterSecondSortDir,ratingEmptyOnly:this.filterRatingEmptyOnly,priorityEmptyOnly:this.filterPriorityEmptyOnly,recentlyArrivedOnly:this.filterRecentlyArrivedOnly,groupsOnly:this.filterGroupsOnly},this.plugin.saveSettings()}hasActiveFilter(){return this.filterTypeExclude.size>0||this.filterStatusExclude.size>0||this.filterPriorityExclude.size>0||this.filterRatingExclude.size>0||this.filterGroupExclude.size>0||this.filterRatingEmptyOnly||this.filterPriorityEmptyOnly||this.filterRecentlyArrivedOnly||this.filterGroupsOnly}clearAllFilters(){this.filterTypeExclude.clear(),this.filterStatusExclude.clear(),this.filterPriorityExclude.clear(),this.filterRatingExclude.clear(),this.filterGroupExclude.clear(),this.filterRatingEmptyOnly=!1,this.filterPriorityEmptyOnly=!1,this.filterRecentlyArrivedOnly=!1,this.filterGroupsOnly=!1}applyPreset(i){var t,e,s,a;this.filterTypeExclude=new Set(i.typeExclude),this.filterStatusExclude=new Set(i.statusExclude),this.filterGroupExclude=new Set(i.groupExclude),this.filterRatingExclude=new Set(i.ratingExclude),this.filterPriorityExclude=new Set(i.priorityExclude),this.filterRatingEmptyOnly=(t=i.ratingEmptyOnly)!=null?t:!1,this.filterPriorityEmptyOnly=(e=i.priorityEmptyOnly)!=null?e:!1,this.filterRecentlyArrivedOnly=(s=i.recentlyArrivedOnly)!=null?s:!1,this.filterGroupsOnly=(a=i.groupsOnly)!=null?a:!1}deactivateSavedFilter(){var i;this.savedFilterActive&&(this.savedFilterActive=!1,(i=this.savedFilterBtnEl)==null||i.removeClass("wl-btn-preset-active"))}static isRecentlyArrived(i){if(!i.releaseDate||!/^\d{4}-\d{2}-\d{2}$/.test(i.releaseDate))return!1;let t=new Date(i.releaseDate+"T00:00:00").getTime(),e=new Date;e.setHours(0,0,0,0);let s=(e.getTime()-t)/864e5;return s>=0&&s<=7}titlePassesFilters(i){if(this.filterTypeExclude.size>0&&this.filterTypeExclude.has(i.type))return!1;if(this.filterRecentlyArrivedOnly){if(!tt.isRecentlyArrived(i))return!1}else if(this.filterStatusExclude.size>0&&this.filterStatusExclude.has(i.status))return!1;if(this.filterRatingEmptyOnly){if(i.rating!==0)return!1}else if(this.filterRatingExclude.size>0&&this.filterRatingExclude.has(`${i.rating}\u2605`))return!1;if(this.filterPriorityEmptyOnly){if(i.priority)return!1}else if(this.filterPriorityExclude.size>0&&this.filterPriorityExclude.has(i.priority))return!1;return!0}destroy(){this.scrollPositionListener&&(this.container.removeEventListener("scroll",this.scrollPositionListener),this.scrollPositionListener=null),this.scrollCleanup&&(this.scrollCleanup(),this.scrollCleanup=null),this.destroyVirtualScroll(),this.dataManager.flushPendingSave()}render(){this._lastScrollTop=this.container.scrollTop||this._lastScrollTop,this.activeCleanups.forEach(i=>i()),this.activeCleanups=[],this.container.empty(),this.container.addClass("wl-list"),this.renderSubTabBar(),this.currentSubTab==="list"?this.renderListContent():this.renderCardsContent()}renderSubTabBar(){let i=this.container.createDiv({cls:"wl-inner-tab-bar"}),t=i.createEl("button",{cls:`wl-inner-tab-btn${this.currentSubTab==="cards"?" is-active":""}`,text:"Cards"});i.createEl("button",{cls:`wl-inner-tab-btn${this.currentSubTab==="list"?" is-active":""}`,text:"List"}).addEventListener("click",()=>{this.currentSubTab!=="list"&&(this.destroyVirtualScroll(),this.currentSubTab="list",this.render())}),t.addEventListener("click",()=>{this.currentSubTab!=="cards"&&(this.currentSubTab="cards",this.render())})}renderListContent(){this.renderHeader(),this.container.createDiv({cls:"wl-divider"}),this.renderTable(this._lastScrollTop)}renderCardsContent(){this.renderHeader(),this.container.createDiv({cls:"wl-divider"}),this.renderCardsView()}renderCardsView(){this.destroyVirtualScroll();let i=this.getDisplayItems();if(this.cardsDisplayItems=i,this.renderResultsCount(this.container,i),i.length===0){let a=this.container.createDiv({cls:"wl-cards-empty"});a.createSpan({cls:"wl-cards-empty-icon",text:"\u{1F3AC}"}),a.createEl("p",{cls:"wl-cards-empty-msg",text:"No titles match your filters"});return}let t=this.container.createDiv({cls:"wl-cards-scroll-container"}),e=t.createDiv({cls:"wl-cards-scroll-spacer"}),s=e.createDiv({cls:"wl-cards-grid wl-cards-grid-virtual"});this.cardsScrollContainer=t,this.cardsScrollSpacer=e,this.cardsGridEl=s,this.cardsLastFirst=-1,this.cardsLastLast=-1,this.cardsScrollHandler=()=>{let a=t.scrollTop;this._cardsPersistentScrollTop=a;let n=this.cardsRowHeight>0?this.cardsRowHeight/2:50;Math.abs(a-this.cardsLastScrollTop){this.cardsScrollRAF=null,this.renderVisibleCards()})))},t.addEventListener("scroll",this.cardsScrollHandler,{passive:!0}),this.cardsResizeObserver=new ResizeObserver(()=>{this.renderVisibleCards()}),this.cardsResizeObserver.observe(t),this._cardsPersistentScrollTop>0&&(this.renderVisibleCards(),t.scrollTop=this._cardsPersistentScrollTop,this.cardsLastScrollTop=this._cardsPersistentScrollTop,this.renderVisibleCards())}getCardsGridMetrics(i){let s=Math.max(1,Math.floor((i+12)/152)),a=(i-12*(s-1))/s,n=a*1.5,r=n+12;return{cols:s,cardWidth:a,cardHeight:n,rowHeight:r}}renderVisibleCards(){let i=this.cardsScrollContainer,t=this.cardsScrollSpacer,e=this.cardsGridEl;if(!i||!t||!e)return;let s=i.scrollTop,a=i.clientHeight,n=i.clientWidth;if(n<=0||a<=0)return;let{cols:r,cardWidth:o,cardHeight:l,rowHeight:c}=this.getCardsGridMetrics(n);this.cardsRowHeight=c;let d=this.cardsDisplayItems.length,u=Math.ceil(d/r),h=Math.max(0,Math.floor(s/c)-2),p=Math.min(u-1,Math.ceil((s+a)/c)+2),m=h*r,v=Math.min(d-1,(p+1)*r-1);t.style.height=`${u*c}px`,e.style.transform=`translateY(${h*c}px)`,e.style.setProperty("--wl-cards-cols",String(r)),e.style.setProperty("--wl-card-height",`${l}px`);let f=this.cardsLastFirst,y=this.cardsLastLast;if(m===f&&v===y)return;let w=f===-1||y===-1,b=!w&&m<=y&&v>=f;if(this.cardsLastFirst=m,this.cardsLastLast=v,w||!b){this.fullRenderCards(e,m,v,o,l),this.setupCardsObserver(i);return}if(m>f){let S=m-f;for(let k=0;ky){let S=Math.max(y+1,m),k=activeDocument.createDocumentFragment();for(let E=S;E<=v;E++){let D=this.buildCardElement(E,o,l);D&&k.appendChild(D)}e.appendChild(k)}this.setupCardsObserver(i)}fullRenderCards(i,t,e,s,a){this.observedCards.clear(),i.empty();let n=activeDocument.createDocumentFragment();for(let r=t;r<=e;r++){let o=this.buildCardElement(r,s,a);o&&n.appendChild(o)}i.appendChild(n)}buildCardElement(i,t,e){let s=this.cardsDisplayItems[i];if(!s)return null;let a=activeDocument.createElement("div");return s.kind==="title"?this.renderTitleCard(a,s.data,t,e):this.renderGroupCard(a,s.data,s.members,t,e),a.firstElementChild}unobserveAndRemove(i){this.cardsObserver&&this.observedCards.has(i)&&(this.cardsObserver.unobserve(i),this.observedCards.delete(i)),i.remove()}setupCardsObserver(i){var e;this.cardsObserver||(this.cardsObserver=new IntersectionObserver(s=>this.handleCardIntersection(s),{root:i,rootMargin:"0px",threshold:0})),((e=this.cardsGridEl)!=null?e:i).querySelectorAll('.wl-card[data-needs-poster="true"]').forEach(s=>{let a=s;this.observedCards.has(a)||(this.cardsObserver.observe(a),this.observedCards.add(a))})}handleCardIntersection(i){var t;for(let e of i){if(!e.isIntersecting)continue;let s=e.target,a=s.dataset.titleId;if(!a)continue;(t=this.cardsObserver)==null||t.unobserve(s);let n=this.dataManager.getTitles().find(o=>o.id===a);if(!n||n.manualPosterUrl&&n.manualPosterUrl.trim()!==""||n.posterUrl!=="")continue;let r=s.querySelector(".wl-card-poster-placeholder");r==null||r.addClass("is-loading"),this.plugin.posterService.enqueue(n).then(o=>{r==null||r.removeClass("is-loading"),o&&this.applyPosterToCard(s,o)})}}applyPosterToCard(i,t){let e=i.querySelector(".wl-card-poster");e&&(e.onload=()=>{i.addClass("has-poster")},e.onerror=()=>{let s=i.dataset.titleId;s&&this.dataManager.updatePosterUrl(s,"none")},e.src=t)}destroyCardsObserver(){var i;this.cardsObserver&&(this.cardsObserver.disconnect(),this.cardsObserver=null),this.observedCards.clear(),(i=this.plugin.posterService)==null||i.clearQueue()}destroyVirtualScroll(){this.cardsScrollRAF!==null&&(window.cancelAnimationFrame(this.cardsScrollRAF),this.cardsScrollRAF=null),this.cardsResizeObserver&&(this.cardsResizeObserver.disconnect(),this.cardsResizeObserver=null),this.cardsScrollContainer&&this.cardsScrollHandler&&this.cardsScrollContainer.removeEventListener("scroll",this.cardsScrollHandler),this.cardsScrollHandler=null,this.cardsScrollContainer=null,this.cardsScrollSpacer=null,this.cardsGridEl=null,this.cardsDisplayItems=[],this.cardsLastFirst=-1,this.cardsLastLast=-1,this.cardsLastScrollTop=0,this.cardsRowHeight=0,this.destroyCardsObserver()}renderTitleCard(i,t,e,s){let a=this.getTagDef(t.type,this.plugin.settings.types),n=this.getTagDef(t.status,this.plugin.settings.statuses),r=a?H(t.type,a.color,this.plugin.settings.colorTheme):"#888780",o=i.createDiv({cls:"wl-card"});o.dataset.titleId=t.id,s!==void 0&&(o.style.height=`${s}px`);let l=o.createDiv({cls:"wl-card-poster-placeholder"});l.style.backgroundColor=r;let c=(t.title.trim().charAt(0)||"?").toUpperCase();l.createSpan({text:c});let d=o.createEl("img",{cls:"wl-card-poster"});d.alt=t.title;let u=zt(t),h=!!(t.manualPosterUrl&&t.manualPosterUrl.trim()!=="");if(u&&u.startsWith("http")?(d.src=u,o.addClass("has-poster"),d.onerror=()=>{o.removeClass("has-poster"),h||this.dataManager.updatePosterUrl(t.id,"none")}):!h&&t.posterUrl===""&&(o.dataset.needsPoster="true"),n){let y=o.createSpan({cls:"wl-card-status-badge",text:t.status});y.style.backgroundColor=H(t.status,n.color,this.plugin.settings.colorTheme)}let p=o.createDiv({cls:"wl-card-overlay"});p.createSpan({cls:"wl-card-title",text:t.title});let m=p.createSpan({cls:"wl-card-type-badge",text:t.type});m.style.backgroundColor=r;let v=t.totalEpisodes;if(v&&v>0){let w=t.status==="Completed"?1:Math.max(0,Math.min(1,t.watchedEpisodes.length/v)),S=p.createDiv({cls:"wl-card-progress-bar"}).createDiv({cls:"wl-card-progress-fill"});S.style.width=`${w*100}%`}let f=o.createEl("button",{cls:"wl-card-menu-btn",text:"\u22EE"});f.setAttr("aria-label","More actions"),f.addEventListener("click",y=>{y.stopPropagation(),this.openCardContextMenu(o,f,t)}),o.addEventListener("click",()=>{this.openDetailModalForTitle(t.id)})}openCardContextMenu(i,t,e){this.container.querySelectorAll(".wl-card-context-menu").forEach(h=>h.remove());let s=i.createDiv({cls:"wl-card-context-menu"}),a=s.createDiv({cls:"wl-card-context-item",text:"Edit title"}),n=s.createDiv({cls:"wl-card-context-item",text:"Refresh poster"}),r=s.createDiv({cls:"wl-card-context-item",text:"Refresh rating"}),o=i.getBoundingClientRect(),l=this.container.getBoundingClientRect();o.right>l.right-180&&s.classList.add("is-right-aligned");let c=i.ownerDocument,d=()=>{s.remove(),c.removeEventListener("click",u,!0)},u=h=>{!s.contains(h.target)&&h.target!==t&&d()};window.setTimeout(()=>c.addEventListener("click",u,!0),0),this.activeCleanups.push(()=>c.removeEventListener("click",u,!0)),a.addEventListener("click",h=>{h.stopPropagation(),d(),this.openEditModalForTitle(e.id)}),n.addEventListener("click",h=>{h.stopPropagation(),d(),this.refreshPosterForCard(i,e.id)}),r.addEventListener("click",h=>{h.stopPropagation(),d(),oi(this.plugin,e.id,null,!0)})}refreshPosterForCard(i,t){let e=this.dataManager.getTitle(t);if(!e)return;this.dataManager.updatePosterUrl(t,""),i.dataset.needsPoster="true";let s=i.querySelector(".wl-card-poster"),a=i.querySelector(".wl-card-poster-placeholder");s&&s.removeAttribute("src"),i.removeClass("has-poster"),a&&a.addClass("is-loading"),this.plugin.posterService.enqueue(e).then(n=>{a==null||a.removeClass("is-loading"),n&&this.applyPosterToCard(i,n)})}renderGroupCard(i,t,e,s,a){var p,m;let n=(m=(p=e[0])==null?void 0:p.type)!=null?m:"",r=n?this.getTagDef(n,this.plugin.settings.types):void 0,o=r?H(n,r.color,this.plugin.settings.colorTheme):"#888780",l=i.createDiv({cls:"wl-card wl-card-group"});a!==void 0&&(l.style.height=`${a}px`);let c=(t.name.trim().charAt(0)||"?").toUpperCase();ss(l,e,zt,{letter:c,color:o});let d=l.createDiv({cls:"wl-card-overlay"});d.createSpan({cls:"wl-card-title",text:t.name});let u=d.createSpan({cls:"wl-card-type-badge"});u.style.backgroundColor=o,u.textContent=`${e.length} title${e.length!==1?"s":""}`;let h=l.createEl("button",{cls:"wl-card-menu-btn",text:"\u22EE"});h.setAttr("aria-label","Group actions"),h.addEventListener("click",v=>{v.stopPropagation(),this.openGroupCardContextMenu(l,h,t)}),l.addEventListener("click",()=>{new Te(this.plugin.app,this.plugin,t,e,()=>{this.render()}).open()})}openGroupCardContextMenu(i,t,e){this.container.querySelectorAll(".wl-card-context-menu").forEach(u=>u.remove());let s=i.createDiv({cls:"wl-card-context-menu"}),a=s.createDiv({cls:"wl-card-context-item",text:"Edit name"}),n=s.createDiv({cls:"wl-card-context-item",text:"Delete group"}),r=i.getBoundingClientRect(),o=this.container.getBoundingClientRect();r.right>o.right-180&&s.classList.add("is-right-aligned");let l=i.ownerDocument,c=()=>{s.remove(),l.removeEventListener("click",d,!0)},d=u=>{!s.contains(u.target)&&u.target!==t&&c()};window.setTimeout(()=>l.addEventListener("click",d,!0),0),this.activeCleanups.push(()=>l.removeEventListener("click",d,!0)),a.addEventListener("click",u=>{u.stopPropagation(),c(),this.openRenameGroupPrompt(e)}),n.addEventListener("click",u=>{u.stopPropagation(),c(),new N(this.plugin.app,`Delete group "${e.name}"? All titles inside will be returned to the main list.`,()=>{this.dataManager.removeGroup(e.id).then(()=>{this.expandedGroups.delete(e.id),this.render()})}).open()})}openRenameGroupPrompt(i){let t=new as.Modal(this.plugin.app);t.titleEl.setText("Rename group");let e=t.contentEl.createEl("input",{cls:"wl-input",attr:{type:"text",value:i.name,placeholder:"Group name"}}),s=t.contentEl.createDiv({cls:"wl-modal-btn-row"}),a=()=>{let n=e.value.trim();n&&n!==i.name&&this.dataManager.updateGroup({...i,name:n}).then(()=>this.render()),t.close()};s.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",a),s.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>t.close()),e.addEventListener("keydown",n=>{n.key==="Enter"?a():n.key==="Escape"&&t.close()}),t.open(),window.setTimeout(()=>{e.focus(),e.select()},0)}openEditModalForTitle(i){let t=this.dataManager.getTitle(i);t&&new St(this.plugin.app,this.plugin,this.dataManager,t,()=>{this.render()}).open()}openDetailModalForTitle(i){let t=this.dataManager.getTitle(i);t&&new ee(this.plugin.app,this.plugin,t,()=>{this.render()}).open()}renderHeader(){let i=this.container.createDiv({cls:"wl-list-header"});if(this.plugin.importProgress){let{current:e,total:s,cancel:a}=this.plugin.importProgress,n=i.createDiv({cls:"wl-header-import-progress"}),o=n.createDiv({cls:"wl-header-import-track"}).createDiv({cls:"wl-header-import-fill"});o.style.width=`${s>0?Math.round(e/s*100):0}%`,n.createSpan({cls:"wl-header-import-text",text:`${e} / ${s}`}),n.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Cancel import"}).addEventListener("click",()=>a())}let t=i.createDiv({cls:"wl-header-controls"});De({controls:t,renderSearch:e=>this.renderSearch(e),renderActions:e=>this.renderToolbarActions(e),expanded:this.toolbarExpanded,onToggleChange:e=>{this.toolbarExpanded=e}})}renderToolbarActions(i){let t=this.dataManager.getSavedFilterPreset();if(t){let r=i.createEl("button",{cls:`wl-btn wl-btn-sm${this.savedFilterActive?" wl-btn-preset-active":""}`,text:"Saved filter"});this.savedFilterBtnEl=r,r.addEventListener("click",()=>{this.applyPreset(t),this.savedFilterActive=!0,r.addClass("wl-btn-preset-active"),this.saveFiltersToSettings(),this.render()})}else this.savedFilterBtnEl=null;if(this.renderFiltersDropdown(i),this.renderSortingDropdown(i),this.selectionMode&&this.selectedItems.size>0&&this.renderActionBar(i),this.selectionMode){let r=this.selectedItems.size>0,o=i.createEl("button",{cls:"wl-btn wl-btn-sm",text:r?"None":"All"});o.title=r?"Deselect all":"Select all visible",o.addEventListener("click",()=>{if(this.selectedItems.size>0)this.selectedItems.clear();else for(let l of this.getDisplayItems())this.selectedItems.add(l.data.id);this.render()})}i.createEl("button",{cls:`wl-btn wl-btn-sm${this.selectionMode?" is-active":""}`,text:"Select"}).addEventListener("click",()=>{this.selectionMode=!this.selectionMode,this.selectedItems.clear(),this.render()}),i.createDiv({cls:"wl-header-controls-right"}).createDiv({cls:"wl-add-btn-wrap"}).createEl("button",{cls:"wl-add-btn wl-btn-success",text:"+ add"}).addEventListener("click",r=>{r.stopPropagation(),this.openAddTitleChooser()})}openAddTitleChooser(){new Ee(this.plugin.app,i=>{i==="url"?new be(this.plugin.app,this.plugin,this.dataManager,()=>{this.render()}).open():this.openAddTitleModal()}).open()}renderFiltersDropdown(i){let t=i.createDiv({cls:"wl-add-btn-wrap"}),e=t.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Filters \u25BC"}),s=e.createSpan({cls:"wl-filter-dot"});this.hasActiveFilter()?s.show():s.hide();let a=i.createEl("button",{cls:"wl-btn wl-btn-sm wl-btn-clear-filters",text:"\u2715 clear"});a.title="Clear all filters",this.hasActiveFilter()?a.show():a.hide(),a.addEventListener("click",()=>{this.clearAllFilters(),this.saveFiltersToSettings(),this.deactivateSavedFilter(),s.hide(),a.hide(),this.rerenderTable()}),e.addEventListener("click",n=>{n.stopPropagation();let r=activeDocument.querySelector(".wl-filters-panel");if(r){r.remove();return}let o=activeDocument.body.createDiv({cls:"wl-dropdown wl-filters-panel wl-filters-panel-popup"}),l=e.getBoundingClientRect();o.style.top=`${l.bottom+4}px`,o.style.left=`${l.left}px`;let c=this.plugin.settings.types.map(T=>T.name),d=this.plugin.settings.statuses.map(T=>T.name),u=["1\u2605","2\u2605","3\u2605","4\u2605","5\u2605"],h=this.plugin.settings.priorities.map(T=>T.name),p=this.dataManager.getGroups().map(T=>T.name),m={typeExclude:new Set(this.filterTypeExclude),statusExclude:new Set(this.filterStatusExclude),ratingExclude:new Set(this.filterRatingExclude),priorityExclude:new Set(this.filterPriorityExclude),groupExclude:new Set(this.filterGroupExclude),filterRatingEmptyOnly:this.filterRatingEmptyOnly,filterPriorityEmptyOnly:this.filterPriorityEmptyOnly,filterRecentlyArrivedOnly:this.filterRecentlyArrivedOnly,filterGroupsOnly:this.filterGroupsOnly},v=[{label:"Type",opts:c,excludeSet:m.typeExclude},{label:"Status",opts:d,excludeSet:m.statusExclude},{label:"Rating",opts:u,excludeSet:m.ratingExclude},{label:"Priority",opts:h,excludeSet:m.priorityExclude}];p.length>0&&v.push({label:"Group",opts:p,excludeSet:m.groupExclude});let f=[],y=o.createDiv({cls:"wl-filter-global-btns"}),w=null;y.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Select all"}).addEventListener("click",T=>{T.stopPropagation();for(let{excludeSet:M}of v)M.clear();for(let{cb:M}of f)M.checked=!0;m.filterRecentlyArrivedOnly=!1,w&&(w.checked=!1)}),y.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Deselect all"}).addEventListener("click",T=>{T.stopPropagation();for(let{opts:M,excludeSet:L}of v)for(let q of M)L.add(q);for(let{cb:M}of f)M.checked=!1;m.filterRecentlyArrivedOnly=!1,w&&(w.checked=!1)});let k=this.dataManager.getSavedFilterPreset(),E=y.createEl("button",{cls:"wl-btn wl-btn-sm",text:k?"Delete":"Save"});E.addEventListener("click",T=>{(async()=>(T.stopPropagation(),E.textContent==="Save"?await this.dataManager.setSavedFilterPreset({typeExclude:Array.from(m.typeExclude),statusExclude:Array.from(m.statusExclude),groupExclude:Array.from(m.groupExclude),ratingExclude:Array.from(m.ratingExclude),priorityExclude:Array.from(m.priorityExclude),ratingEmptyOnly:m.filterRatingEmptyOnly,priorityEmptyOnly:m.filterPriorityEmptyOnly,recentlyArrivedOnly:m.filterRecentlyArrivedOnly,groupsOnly:m.filterGroupsOnly}):(await this.dataManager.setSavedFilterPreset(null),this.savedFilterActive=!1),o.remove(),this.render()))()});let D={};for(let{label:T}of v)D[T]=!0;for(let{label:T,opts:M,excludeSet:L}of v){let q=o.createDiv({cls:"wl-filter-section"}),A=q.createDiv({cls:"wl-filter-section-header"});A.createSpan({cls:"wl-filter-label",text:T});let P=A.createSpan({cls:"wl-filter-chevron",text:"\u25BC"}),I=q.createDiv({cls:"wl-filter-section-content wl-hidden"});A.addEventListener("click",U=>{var Y;U.stopPropagation(),D[T]=!D[T];let O=(Y=D[T])!=null?Y:!0;I.toggleClass("wl-hidden",O),P.textContent=O?"\u25BC":"\u25B2"});let F=I.createDiv({cls:"wl-filter-checkbox-row"}),_=F.createEl("input",{attr:{type:"checkbox"}});if(F.createSpan({cls:"wl-filter-all-toggle",text:"\u25C6 All"}),T==="Status"){let U=I.createDiv({cls:"wl-filter-checkbox-row"}),O=U.createEl("input",{attr:{type:"checkbox"}});O.checked=m.filterRecentlyArrivedOnly,U.createSpan({cls:"wl-recently-arrived-filter",text:"\u2726 Recently arrived"}),w=O,O.addEventListener("change",()=>{if(m.filterRecentlyArrivedOnly=O.checked,O.checked){L.clear();for(let Y of Mt)Y.checked=!0}})}let V=null,G=[],Mt=[];if(T==="Rating"||T==="Priority"){let U=I.createDiv({cls:"wl-filter-checkbox-row"});V=U.createEl("input",{attr:{type:"checkbox"}}),V.checked=T==="Rating"?m.filterRatingEmptyOnly:m.filterPriorityEmptyOnly,U.createSpan({text:"Empty"});let O=V;V.addEventListener("change",()=>{if(T==="Rating"?m.filterRatingEmptyOnly=O.checked:m.filterPriorityEmptyOnly=O.checked,O.checked){for(let Y of G)Y.checked=!0;L.clear()}})}if(T==="Group"){let U=I.createDiv({cls:"wl-filter-checkbox-row"}),O=U.createEl("input",{attr:{type:"checkbox"}});O.checked=m.filterGroupsOnly,U.createSpan({cls:"wl-recently-arrived-filter",text:"\u25C7 Groups only"}),O.addEventListener("change",()=>{m.filterGroupsOnly=O.checked}),I.createDiv({cls:"wl-filter-section-divider"})}for(let U of M){let O=I.createDiv({cls:"wl-filter-checkbox-row"}),Y=O.createEl("input",{attr:{type:"checkbox"}});Y.checked=!L.has(U),O.createSpan({text:U}),G.push(Y),T==="Status"&&Mt.push(Y),f.push({cb:Y});let Ze=V;Y.addEventListener("change",()=>{Y.checked?L.delete(U):L.add(U),T==="Status"&&w&&(m.filterRecentlyArrivedOnly=!1,w.checked=!1),(T==="Rating"||T==="Priority")&&Ze&&(T==="Rating"?m.filterRatingEmptyOnly=!1:m.filterPriorityEmptyOnly=!1,Ze.checked=!1)})}let ft=()=>{_.checked=G.length>0&&G.every(U=>U.checked)};ft();let xt=()=>{if(G.length>0&&G.every(O=>O.checked)){for(let O of G)O.checked=!1;for(let O of M)L.add(O)}else{for(let O of G)O.checked=!0;L.clear()}ft()};_.addEventListener("click",U=>{U.stopPropagation(),xt()}),F.addEventListener("click",U=>{U.target!==_&&(U.stopPropagation(),xt())})}o.createEl("button",{cls:"wl-btn wl-btn-sm wl-filter-apply-btn",text:"Apply"}).addEventListener("click",T=>{T.stopPropagation(),this.filterTypeExclude=m.typeExclude,this.filterStatusExclude=m.statusExclude,this.filterRatingExclude=m.ratingExclude,this.filterPriorityExclude=m.priorityExclude,this.filterGroupExclude=m.groupExclude,this.filterRatingEmptyOnly=m.filterRatingEmptyOnly,this.filterPriorityEmptyOnly=m.filterPriorityEmptyOnly,this.filterRecentlyArrivedOnly=m.filterRecentlyArrivedOnly,this.filterGroupsOnly=m.filterGroupsOnly,this.saveFiltersToSettings(),this.deactivateSavedFilter(),this.hasActiveFilter()?(s.show(),a.show()):(s.hide(),a.hide()),this.rerenderTable(),o.remove(),activeDocument.removeEventListener("mousedown",x,!1)});let x=T=>{let M=T.target;o.contains(M)||t.contains(M)||(o.remove(),activeDocument.removeEventListener("mousedown",x,!1))};window.setTimeout(()=>activeDocument.addEventListener("mousedown",x,!1),0)})}renderSortingDropdown(i){let t=i.createDiv({cls:"wl-add-btn-wrap"}),e=t.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Sorting \u25BC"});e.addEventListener("click",s=>{s.stopPropagation();let a=t.querySelector(".wl-dropdown");if(a){a.remove();return}let n=t.createDiv({cls:"wl-dropdown wl-sorting-panel"});if(window.innerWidth<=600){let c=e.getBoundingClientRect();n.addClass("wl-sorting-panel-mobile"),n.style.top=`${c.bottom+4}px`}let r=["Title","Date added","Progress","Rating","Priority","Started","Status","Date watched","Time left","Time watched"],o=(c,d,u,h)=>{let p=n.createDiv({cls:"wl-filter-row"});p.createSpan({cls:"wl-filter-label",text:c});let m=p.createEl("select",{cls:"wl-select"});if(!h){let f=m.createEl("option",{text:"None",value:"none"});f.selected=d==="none"}for(let f of r){let y=m.createEl("option",{text:f,value:f});this.sortLabelToKey(f)===d&&(y.selected=!0)}let v=p.createEl("button",{cls:"wl-btn wl-btn-sm wl-sort-dir-btn",text:u==="asc"?"\u2191":"\u2193"});v.title=u==="asc"?"Ascending \u2014 click to switch to descending":"Descending \u2014 click to switch to ascending",m.addEventListener("change",()=>{var y,w;let f=m.value==="none"?"none":this.sortLabelToKey(m.value);h?(this.filterSort=f,this.filterSortDir=(y=tt.SORT_DEFAULT_DIR[f])!=null?y:"asc"):(this.filterSecondSort=f,this.filterSecondSortDir=(w=tt.SORT_DEFAULT_DIR[f])!=null?w:"asc"),n.remove(),activeDocument.removeEventListener("click",l,!0),this.saveFiltersToSettings(),this.render()}),v.addEventListener("click",f=>{f.stopPropagation(),h?this.filterSortDir=this.filterSortDir==="asc"?"desc":"asc":this.filterSecondSortDir=this.filterSecondSortDir==="asc"?"desc":"asc",n.remove(),activeDocument.removeEventListener("click",l,!0),this.saveFiltersToSettings(),this.render()})};o("Sort by",this.filterSort,this.filterSortDir,!0),o("Then by",this.filterSecondSort,this.filterSecondSortDir,!1);let l=c=>{t.contains(c.target)||(n.remove(),activeDocument.removeEventListener("click",l,!0))};window.setTimeout(()=>activeDocument.addEventListener("click",l,!0),0)})}renderActionBar(i){let t=i.createDiv({cls:"wl-action-bar"}),e=t.createEl("button",{cls:"wl-group-action-btn wl-group-action-btn-delete wl-btn-danger",text:"\u2715"});e.title="Delete selected",e.addEventListener("click",o=>{o.stopPropagation();let l=this.selectedItems.size;new N(this.plugin.app,`Delete ${l} selected item${l!==1?"s":""}? This cannot be undone.`,()=>{(async()=>{let c=new Set(this.dataManager.getGroups().map(u=>u.id)),d=[];for(let u of Array.from(this.selectedItems))c.has(u)?(await this.dataManager.removeGroup(u),this.expandedGroups.delete(u)):(d.push(u),this.expandedId===u&&(this.expandedId=null));d.length>0&&await this.dataManager.removeTitlesBatch(d),this.selectedItems.clear(),this.render()})()}).open()});let s=t.createEl("select",{cls:"wl-select wl-select-sm"});s.createEl("option",{text:"Status\u2026",value:""});for(let o of this.plugin.settings.statuses.filter(l=>l.name!=="To be released"))s.createEl("option",{text:o.name,value:o.name});s.addEventListener("change",()=>{(async()=>{let o=s.value;if(!o)return;let l=new Set(this.dataManager.getGroups().map(d=>d.id)),c=[];for(let d of this.selectedItems){if(l.has(d))continue;let u=this.dataManager.getTitle(d);u&&(u.status=o,this.dataManager.updateTitleSilent(u),c.push(u))}if(c.length>0){await this.dataManager.save();for(let d of c)await this.dataManager.updateMarkdownFile(d)}s.value="",this.render()})()});let a=this.dataManager.getGroups(),n=Array.from(this.selectedItems).some(o=>this.dataManager.getGroups().some(l=>l.id===o)),r=t.createEl("select",{cls:"wl-select wl-select-sm"});n&&(r.disabled=!0,r.title="A group is selected \u2014 cannot move groups into other groups"),r.createEl("option",{text:"Group\u2026",value:""});for(let o of a)r.createEl("option",{text:o.name,value:o.id});r.createEl("option",{text:"Create new group\u2026",value:"__new__"}),r.addEventListener("change",()=>{(async()=>{let o=r.value;if(!o)return;let l=new Set(a.map(d=>d.id)),c=Array.from(this.selectedItems).filter(d=>!l.has(d));if(o==="__new__"){r.value="",r.hide();let d=t.createEl("input",{cls:"wl-modal-input wl-group-name-input",attr:{type:"text",placeholder:"Group name\u2026",maxlength:"64"}}),u=t.createEl("button",{cls:"wl-group-action-btn",text:"\u2713"});u.title="Create group";let h=t.createEl("button",{cls:"wl-group-action-btn",text:"\u2715"});h.title="Cancel";let p=async()=>{let m=d.value.trim();if(!m)return;let v={id:this.dataManager.generateGroupId(m),name:m,titleIds:c,dateAdded:new Date().toISOString()};await this.dataManager.addGroup(v),this.selectedItems.clear(),this.selectionMode=!1,this.render()};u.addEventListener("click",m=>{m.stopPropagation(),p()}),h.addEventListener("click",m=>{m.stopPropagation(),this.render()}),d.addEventListener("keydown",m=>{m.stopPropagation(),m.key==="Enter"&&p(),m.key==="Escape"&&this.render()}),d.addEventListener("click",m=>m.stopPropagation()),window.setTimeout(()=>d.focus(),0);return}for(let d of c)await this.dataManager.addTitleToGroup(o,d);r.value="",this.selectedItems.clear(),this.selectionMode=!1,this.render()})()})}openAddTitleModal(){new ht(this.plugin.app,this.plugin,this.dataManager,()=>{this.render()}).open()}renderSearch(i){let e=i.createDiv({cls:"wl-reading-search-wrap"}).createEl("input",{cls:"wl-reading-search-input",attr:{type:"text",placeholder:"Search titles..."}});e.value=this.searchQuery;let s=0;e.addEventListener("input",()=>{this.searchQuery=e.value,window.clearTimeout(s),s=window.setTimeout(()=>{this.rerenderActiveSubTab()},250)})}sortLabelToKey(i){var e;return(e={Title:"title","Date added":"dateAdded",Progress:"progress",Rating:"rating",Priority:"priority",Started:"started",Status:"status","Date watched":"dateWatched","Time left":"timeLeft","Time watched":"timeWatched"}[i])!=null?e:"dateAdded"}static migrateSortKey(i){var e;return(e={"title-asc":{key:"title",dir:"asc"},"title-desc":{key:"title",dir:"desc"},"dateAdded-newest":{key:"dateAdded",dir:"desc"},"dateAdded-oldest":{key:"dateAdded",dir:"asc"},"progress-high":{key:"progress",dir:"desc"},"progress-low":{key:"progress",dir:"asc"},"rating-high":{key:"rating",dir:"desc"},"rating-low":{key:"rating",dir:"asc"},priority:{key:"priority",dir:"asc"},"started-asc":{key:"started",dir:"asc"},"started-desc":{key:"started",dir:"desc"},"status-asc":{key:"status",dir:"asc"},"status-desc":{key:"status",dir:"desc"},"dateWatched-newest":{key:"dateWatched",dir:"desc"},"dateWatched-oldest":{key:"dateWatched",dir:"asc"},"timeLeft-high":{key:"timeLeft",dir:"desc"},"timeLeft-low":{key:"timeLeft",dir:"asc"},"timeWatched-high":{key:"timeWatched",dir:"desc"},"timeWatched-low":{key:"timeWatched",dir:"asc"},none:{key:"none",dir:"asc"}}[i])!=null?e:{key:i,dir:"desc"}}static sortBaseAndDirToKey(i,t){var s,a;return(a=(s={title:{asc:"title-asc",desc:"title-desc"},dateAdded:{asc:"dateAdded-oldest",desc:"dateAdded-newest"},progress:{asc:"progress-low",desc:"progress-high"},rating:{asc:"rating-low",desc:"rating-high"},priority:{asc:"priority",desc:"priority"},started:{asc:"started-asc",desc:"started-desc"},status:{asc:"status-asc",desc:"status-desc"},dateWatched:{asc:"dateWatched-oldest",desc:"dateWatched-newest"},timeLeft:{asc:"timeLeft-low",desc:"timeLeft-high"},timeWatched:{asc:"timeWatched-low",desc:"timeWatched-high"}}[i])==null?void 0:s[t])!=null?a:"dateAdded-newest"}rerenderTable(){if(this.currentSubTab!=="list"){this.rerenderActiveSubTab();return}let i=this._lastScrollTop,t=this.container.querySelector(".wl-table-section");t&&t.remove(),this.renderTable(i)}rerenderActiveSubTab(){if(this.currentSubTab==="cards")this.destroyVirtualScroll(),this.container.querySelectorAll(".wl-cards-scroll-container, .wl-cards-empty, .wl-table-section, .wl-results-count").forEach(i=>i.remove()),this.renderCardsView();else{let i=this._lastScrollTop,t=this.container.querySelector(".wl-table-section");t&&t.remove(),this.renderTable(i)}}renderResultsCount(i,t){let e=t.reduce((r,o)=>r+(o.kind==="title"?1:0),0),s=t.reduce((r,o)=>r+(o.kind==="group"?1:0),0),a=i.createDiv({cls:"wl-results-count"}),n=[];e>0&&n.push(`${e} title${e!==1?"s":""}`),s>0&&n.push(`${s} group${s!==1?"s":""}`),a.textContent=n.length>0?n.join(", "):"0 titles"}renderTable(i){this.scrollCleanup&&(this.scrollCleanup(),this.scrollCleanup=null);let t=this.container.createDiv({cls:"wl-table-section"}),e=this.getDisplayItems();this.renderResultsCount(t,e);let s=this.selectionMode?"wl-table wl-selection-mode":"wl-table",a=t.createDiv({cls:s}),n=a.createDiv({cls:"wl-table-header-row"});if(this.selectionMode&&n.createDiv({cls:"wl-col-select-h"}),n.createDiv({cls:"wl-col-title-h",text:"Title"}),n.createDiv({cls:"wl-col-priority-h",text:"Priority"}),n.createDiv({cls:"wl-col-started-h",text:"Started"}),n.createDiv({cls:"wl-col-rating-h",text:"Rating"}),n.createDiv({cls:"wl-col-status-h",text:"Status"}),e.length===0){a.createDiv({cls:"wl-empty-state",text:"No titles match your filters."});return}this.mountVirtualRows(a,e,i)}mountVirtualRows(i,t,e){var w;let o=t.map(()=>68);if(this.expandedId!==null){let b=t.findIndex(S=>S.kind==="title"&&S.data.id===this.expandedId);if(b!==-1){let S=t[b];if((S==null?void 0:S.kind)==="title"){let k=activeDocument.body.createDiv();k.style.cssText=`position:absolute;left:-9999px;top:0;width:${i.clientWidth}px;visibility:hidden;`,this.renderRow(k,S.data);let E=k.offsetHeight;k.remove(),E>0&&(o[b]=E)}}}for(let b=0;b0&&(o[b]=E)}let l=[],c=0;for(let b=0;b{var q,A,P,I;let b=u.scrollTop,S=u.clientHeight||600,k=5*44,E=b-h,D=E-k,C=E+S+k,x=0,T=t.length-1;for(;x<=T;){let F=x+T>>>1;((q=l[F])!=null?q:0)+((A=o[F])!=null?A:44)<=D?x=F+1:T=F-1}let M=Math.max(0,x),L=M;for(let F=M;F=C);F++)L=F;if(!(M===m&&L===v)){m=M,v=L,d.empty();for(let F=M;F<=L;F++){let _=t[F];if(!_)continue;let V=d.createDiv({cls:"wl-virt-item"});V.style.top=`${(I=l[F])!=null?I:0}px`,_.kind==="title"?this.renderRow(V,_.data):this.renderGroupRow(V,_.data,_.members)}}};f();let y=()=>{p===0&&(p=window.requestAnimationFrame(()=>{p=0,f()}))};u.addEventListener("scroll",y,{passive:!0}),this.scrollCleanup=()=>{u.removeEventListener("scroll",y),p!==0&&(window.cancelAnimationFrame(p),p=0)}}getDisplayItems(){let i=this.dataManager.getGroups(),t=this.dataManager.getGroupedTitleIds(),e=this.dataManager.getTitles(),s=new Map(e.map(l=>[l.id,l])),a=this.searchQuery.trim().toLowerCase(),n=this.filterGroupsOnly?[]:this.getFilteredSortedTitles().filter(l=>!t.has(l.id)),r=[];for(let l of i){if(this.filterGroupExclude.size>0&&this.filterGroupExclude.has(l.name))continue;let c=l.titleIds.map(u=>s.get(u)).filter(u=>u!==void 0);if(a){let u=l.name.toLowerCase().includes(a),h=c.some(p=>p.title.toLowerCase().includes(a));if(!u&&!h)continue}(this.filterTypeExclude.size>0||this.filterStatusExclude.size>0||this.filterRatingExclude.size>0||this.filterPriorityExclude.size>0)&&!c.some(u=>this.titlePassesFilters(u))||r.push({kind:"group",data:l,members:c})}return[...r,...n.map(l=>({kind:"title",data:l}))].sort((l,c)=>{let d=l.kind==="title"&&l.data.pinned||l.kind==="group"&&l.data.id===this.pinnedGroupId,u=c.kind==="title"&&c.data.pinned||c.kind==="group"&&c.data.id===this.pinnedGroupId;return d&&!u?-1:!d&&u?1:this.compareDisplayItems(l,c)})}getStatusIndex(i){let t=this.STATUS_ORDER.indexOf(i);return t===-1?99:t}compareDisplayItemsByKey(i,t,e){let s=p=>p.kind==="title"?p.data.title:p.data.name,a=p=>p.kind==="title"?this.dataManager.getProgress(p.data):this.getGroupProgress(p.members),n=p=>{if(p.kind==="title"){let v=ie.indexOf(p.data.priority);return v===-1?99:v}let m=p.members.map(v=>ie.indexOf(v.priority)).filter(v=>v!==-1);return m.length>0?Math.min(...m):99},r=p=>{if(p.kind==="title")return new Date(p.data.dateAdded).getTime();let m=p.members.map(v=>new Date(v.dateAdded).getTime());return m.length>0?Math.max(...m):0},o=p=>{if(p.kind==="title")return p.data.dateStarted?new Date(p.data.dateStarted).getTime():null;let m=p.members.map(v=>v.dateStarted?new Date(v.dateStarted).getTime():null).filter(v=>v!==null);return m.length>0?Math.min(...m):null},l=p=>p.kind==="title"?this.getStatusIndex(p.data.status):this.getStatusIndex(this.getGroupStatus(p.members)),c=p=>{if(p.kind==="title")return p.data.rating;let m=p.members.filter(v=>v.rating>0);return m.length===0?0:m.reduce((v,f)=>v+f.rating,0)/m.length},d=p=>{if(p.kind==="title")return p.data.dateFinished?new Date(p.data.dateFinished).getTime():0;let m=p.members.map(v=>v.dateFinished?new Date(v.dateFinished).getTime():0).filter(v=>v>0);return m.length>0?Math.max(...m):0},u=p=>p.kind==="title"?this.dataManager.calcTimeRemaining(p.data):p.members.reduce((m,v)=>m+this.dataManager.calcTimeRemaining(v),0),h=p=>p.kind==="title"?this.dataManager.calcTimeWatched(p.data):p.members.reduce((m,v)=>m+this.dataManager.calcTimeWatched(v),0);switch(i){case"title-asc":return s(t).localeCompare(s(e));case"title-desc":return s(e).localeCompare(s(t));case"dateAdded-newest":return r(e)-r(t);case"dateAdded-oldest":return r(t)-r(e);case"progress-high":return a(e)-a(t);case"progress-low":return a(t)-a(e);case"rating-high":{let p=c(t),m=c(e);return p===0&&m===0?0:p===0?1:m===0?-1:m-p}case"rating-low":{let p=c(t),m=c(e);return p===0&&m===0?0:p===0?1:m===0?-1:p-m}case"priority":return n(t)-n(e);case"status-asc":return l(t)-l(e);case"status-desc":return l(e)-l(t);case"started-asc":{let p=o(t),m=o(e);return p==null&&m==null?0:p==null?1:m==null?-1:p-m}case"started-desc":{let p=o(t),m=o(e);return p==null&&m==null?0:p==null?1:m==null?-1:m-p}case"dateWatched-newest":return d(e)-d(t);case"dateWatched-oldest":{let p=d(t)||1/0,m=d(e)||1/0;return p-m}case"timeLeft-high":return u(e)-u(t);case"timeLeft-low":return u(t)-u(e);case"timeWatched-high":return h(e)-h(t);case"timeWatched-low":return h(t)-h(e);default:return 0}}compareDisplayItems(i,t){let e=tt.sortBaseAndDirToKey(this.filterSort,this.filterSortDir),s=this.compareDisplayItemsByKey(e,i,t);if(s!==0||this.filterSecondSort==="none")return s;let a=tt.sortBaseAndDirToKey(this.filterSecondSort,this.filterSecondSortDir);return this.compareDisplayItemsByKey(a,i,t)}renderRow(i,t,e=!1){let s=this.expandedId===t.id,a=this.selectedItems.has(t.id),n=["wl-row",s?"is-expanded":"",e?"wl-row-indented":"",a?"wl-row-selected":""].filter(Boolean).join(" "),r=i.createDiv({cls:n});if(r.dataset.titleId=t.id,this.selectionMode){let D=r.createDiv({cls:"wl-col-select"}).createEl("input",{attr:{type:"checkbox"}});D.checked=a,D.addEventListener("click",C=>C.stopPropagation()),D.addEventListener("change",()=>{D.checked?this.selectedItems.add(t.id):this.selectedItems.delete(t.id),this.render()})}let o=r.createDiv({cls:"wl-col-title"});o.createDiv({cls:"wl-row-title-text",text:t.title});let l=this.getTagDef(t.type,this.plugin.settings.types),c=this.plugin.settings.coloredTypeBadges,d=o.createDiv({cls:"wl-badge-row"}),u=d.createSpan({cls:c?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});c&&l&&(u.style.backgroundColor=H(t.type,l.color,this.plugin.settings.colorTheme)),tt.isRecentlyArrived(t)&&d.createSpan({cls:"wl-recently-arrived",text:"\xB7 Recently arrived"});let p=o.createDiv({cls:"wl-progress-wrap"}).createDiv({cls:"wl-progress-bar"});p.style.width=`${this.dataManager.getProgress(t)}%`;let m=r.createDiv({cls:"wl-col-priority"});if(t.priority){let E=this.getTagDef(t.priority,this.plugin.settings.priorities),D=m.createSpan({cls:"wl-priority-badge",text:t.priority});E&&(D.style.color=E.color)}let v=r.createDiv({cls:"wl-col-started"});v.textContent=t.dateStarted?Q(t.dateStarted):"\u2014";let f=r.createDiv({cls:"wl-col-rating"});t.rating>0?f.createSpan({cls:"wl-row-rating",text:`\u2605 ${t.rating}/5`}):f.createSpan({cls:"wl-row-rating wl-row-rating-empty",text:"\u2014"});let y=r.createDiv({cls:"wl-col-status"}),w=this.getTagDef(t.status,this.plugin.settings.statuses),b=y.createSpan({cls:c?"wl-badge":"wl-badge-plain",text:t.status});c&&w&&(b.style.backgroundColor=H(t.status,w.color,this.plugin.settings.colorTheme));let k=r.createDiv({cls:"wl-col-pin"}).createSpan({cls:`wl-pin-icon${t.pinned?" is-pinned":""}`,text:"\u{1F4CC}"});k.title=t.pinned?"Unpin":"Pin to top",k.addEventListener("click",E=>{E.stopPropagation(),(async()=>{let D=this.dataManager.getTitle(t.id);if(!D)return;let C=!D.pinned;if(C)for(let x of this.dataManager.getTitles())x.id!==D.id&&x.pinned&&(x.pinned=!1,await this.dataManager.updateTitle(x));D.pinned=C,await this.dataManager.updateTitle(D),this.rerenderTable()})()}),r.addEventListener("click",()=>{if(this.selectionMode){this.selectedItems.has(t.id)?this.selectedItems.delete(t.id):this.selectedItems.add(t.id),this.render();return}this.expandedId=s?null:t.id,s||(this.collapsedSeasons=this.dataManager.getCollapsedSeasonsForTitle(t.id)),this.rerenderTable()}),s&&!this.selectionMode&&this.renderAccordion(i,t)}renderGroupRow(i,t,e){var T,M,L,q,A;let s=this.expandedGroups.has(t.id),a=this.selectedItems.has(t.id),n=i.createDiv({cls:`wl-row wl-group-row${s?" is-expanded":""}${a?" wl-row-selected":""}`});if(n.dataset.type=(M=(T=e[0])==null?void 0:T.type)!=null?M:"",n.dataset.status=this.getGroupStatus(e),n.dataset.priority=(L=this.getGroupHighestPriority(e))!=null?L:"",n.dataset.rating=`${Math.round(this.getGroupRating(e))}\u2605`,n.dataset.group=t.name,this.selectionMode){let I=n.createDiv({cls:"wl-col-select"}).createEl("input",{attr:{type:"checkbox"}});I.checked=a,I.addEventListener("click",F=>F.stopPropagation()),I.addEventListener("change",()=>{I.checked?this.selectedItems.add(t.id):this.selectedItems.delete(t.id),this.render()})}let r=n.createDiv({cls:"wl-col-title"});if(this.renamingGroupId===t.id){let P=r.createDiv({cls:"wl-group-name-row"}),I=P.createEl("input",{cls:"wl-group-rename-input",attr:{type:"text",value:t.name}});I.addEventListener("click",V=>V.stopPropagation()),I.addEventListener("keydown",V=>{V.stopPropagation(),V.key==="Enter"?(async()=>{let G=I.value.trim();if(G&&G!==t.name){let Mt={...t,name:G};await this.dataManager.updateGroup(Mt)}this.renamingGroupId=null,this.rerenderTable()})():V.key==="Escape"&&(this.renamingGroupId=null,this.rerenderTable())});let F=P.createEl("button",{cls:"wl-group-action-btn",text:"\u2713"});F.title="Save",F.addEventListener("click",V=>{V.stopPropagation(),(async()=>{let G=I.value.trim();if(G&&G!==t.name){let Mt={...t,name:G};await this.dataManager.updateGroup(Mt)}this.renamingGroupId=null,this.rerenderTable()})()});let _=P.createEl("button",{cls:"wl-group-action-btn",text:"\u2715"});_.title="Cancel",_.addEventListener("click",V=>{V.stopPropagation(),this.renamingGroupId=null,this.rerenderTable()}),window.setTimeout(()=>I.focus(),0)}else{let P=r.createDiv({cls:"wl-group-name-row"});P.createSpan({cls:"wl-row-title-text wl-group-name",text:t.name});let I=P.createEl("button",{cls:"wl-group-action-btn",text:"\u270F"});I.title="Rename group",I.addEventListener("click",_=>{_.stopPropagation(),this.renamingGroupId=t.id,this.rerenderTable()});let F=P.createEl("button",{cls:"wl-group-action-btn wl-group-action-btn-delete wl-btn-danger",text:"\u2715"});F.title="Delete group (titles are kept)",F.addEventListener("click",_=>{_.stopPropagation(),new N(this.plugin.app,`Delete group "${t.name}"? All titles inside will be returned to the main list.`,()=>{this.dataManager.removeGroup(t.id).then(()=>{this.expandedGroups.delete(t.id),this.rerenderTable()})}).open()})}let o=(A=(q=e[0])==null?void 0:q.type)!=null?A:"";if(o){let P=this.getTagDef(o,this.plugin.settings.types),I=this.plugin.settings.coloredTypeBadges,F=r.createSpan({cls:I?"wl-badge wl-badge-sm":"wl-badge-plain",text:o});I&&P&&(F.style.backgroundColor=H(o,P.color,this.plugin.settings.colorTheme))}let l=r.createDiv({cls:"wl-group-stats"}),c=e.reduce((P,I)=>P+this.dataManager.calcTimeWatched(I),0),d=e.reduce((P,I)=>P+this.dataManager.calcTimeRemaining(I),0);l.createSpan({text:`${e.length} title${e.length!==1?"s":""}`}),l.createSpan({text:` \xB7 ${z(c)} watched`}),l.createSpan({text:` \xB7 ${z(d)} left`});let u=r.createDiv({cls:"wl-progress-wrap"});u.createDiv({cls:"wl-progress-bar"}).style.width=`${this.getGroupProgress(e)}%`;let h=n.createDiv({cls:"wl-col-priority"}),p=this.getGroupHighestPriority(e);if(p){let P=this.getTagDef(p,this.plugin.settings.priorities),I=h.createSpan({cls:"wl-priority-badge",text:p});P&&(I.style.color=P.color)}let m=n.createDiv({cls:"wl-col-started"}),v=this.getGroupStartedDate(e);m.textContent=v?Q(v):"\u2014";let f=n.createDiv({cls:"wl-col-rating"}),y=this.getGroupRating(e);y>0?f.createSpan({cls:"wl-row-rating",text:`\u2605 ${y.toFixed(1)}/5`}):f.createSpan({cls:"wl-row-rating wl-row-rating-empty",text:"\u2014"});let w=n.createDiv({cls:"wl-col-status"}),b=this.getGroupStatus(e),S=this.getTagDef(b,this.plugin.settings.statuses),k=this.plugin.settings.coloredTypeBadges,E=w.createSpan({cls:k?"wl-badge":"wl-badge-plain",text:b});k&&(S?E.style.backgroundColor=H(b,S.color,this.plugin.settings.colorTheme):b==="In Progress"&&(E.style.backgroundColor=H("In Progress","#724CF9",this.plugin.settings.colorTheme)));let D=this.pinnedGroupId===t.id,x=n.createDiv({cls:"wl-col-pin"}).createSpan({cls:`wl-pin-icon${D?" is-pinned":""}`,text:"\u{1F4CC}"});if(x.title=D?"Unpin":"Pin to top",x.addEventListener("click",P=>{if(P.stopPropagation(),this.pinnedGroupId=D?null:t.id,this.dataManager.setPinnedGroupId(this.pinnedGroupId),this.pinnedGroupId)for(let I of this.dataManager.getTitles())I.pinned&&(I.pinned=!1,this.dataManager.updateTitle(I));this.rerenderTable()}),n.addEventListener("click",()=>{if(this.renamingGroupId!==t.id){if(this.selectionMode){this.selectedItems.has(t.id)?this.selectedItems.delete(t.id):this.selectedItems.add(t.id),this.render();return}s?this.expandedGroups.delete(t.id):this.expandedGroups.add(t.id),this.rerenderTable()}}),s)for(let P of e)this.renderRow(i,P,!0)}getGroupProgress(i){let t=i.reduce((s,a)=>s+a.watchedEpisodes.length,0),e=i.reduce((s,a)=>s+this.dataManager.getEffectiveTotal(a),0);return e===0?0:Math.min(100,Math.round(t/e*100))}getGroupStatus(i){if(i.length===0)return"Plan to watch";let t=i.map(e=>e.status);return t.some(e=>e==="Watching")?"Watching":t.every(e=>e==="Completed")?"Completed":t.every(e=>e==="Plan to watch")?"Plan to watch":"In Progress"}getGroupStartedDate(i){var e;let t=i.map(s=>s.dateStarted).filter(s=>s!==null);return t.length===0?null:(e=t.sort()[0])!=null?e:null}getGroupRating(i){let t=i.filter(e=>e.rating>0);return t.length===0?0:t.reduce((e,s)=>e+s.rating,0)/t.length}getGroupHighestPriority(i){let t=null,e=1/0;for(let s of i){let a=ie.indexOf(s.priority);a!==-1&&aw.stopPropagation());let s=e.createDiv({cls:"wl-accordion-header"}),a=s.createDiv({cls:"wl-acc-header-left"}),n=t.totalEpisodes>0?` \xB7 ${t.totalEpisodes} eps total`:"",r=t.dateStarted?`Started ${Q(t.dateStarted)}`:"Not started",o=a.createDiv({cls:"wl-acc-subtitle"});if(o.createSpan({cls:"wl-acc-subtitle-text",text:`${r}${n}`}),t.externalLink){let w=o.createEl("a",{cls:"wl-acc-link-icon",text:"\u{1F310}"});w.href=t.externalLink,w.title="Open external link",w.target="_blank",w.rel="noopener noreferrer",w.addEventListener("click",b=>b.stopPropagation())}let l=t.watchedEpisodes.length,c=this.dataManager.getEffectiveTotal(t),d=this.dataManager.calcTimeWatched(t),u=this.dataManager.calcTimeRemainingForModal(t),h=this.dataManager.getProgress(t),p=s.createDiv({cls:"wl-acc-right-group"}),m=(w,b)=>{let S=p.createDiv({cls:"wl-acc-stat-block"});S.createDiv({cls:"wl-acc-percent",text:w}),S.createDiv({cls:"wl-acc-progress-label",text:b})};m(z(u),"left"),m(z(d),"watched"),m(`${l} / ${c}`,"episodes");let v=p.createDiv({cls:"wl-acc-header-right"});v.createDiv({cls:"wl-acc-percent",text:`${h}%`}),v.createDiv({cls:"wl-acc-progress-label",text:"progress"});let f=v.createDiv({cls:"wl-acc-progress-wrap"});f.createDiv({cls:"wl-progress-bar"}).style.width=`${h}%`;let y=e.createDiv({cls:"wl-accordion-body"});t.type==="Movie"?this.renderMovieBody(y,t):this.renderEpisodesBody(y,t),this.renderAccordionFooter(e,t)}renderMovieBody(i,t){let e=i.createDiv({cls:"wl-movie-row"}),s=e.createEl("input",{cls:"wl-movie-checkbox",attr:{type:"checkbox"}});s.checked=t.watchedEpisodes.includes(1),e.createSpan({cls:"wl-movie-label",text:"Watched"}),s.addEventListener("change",a=>{a.stopPropagation(),this.dataManager.markEpisodeWatched(t.id,1,s.checked).then(()=>this.rerenderTable())})}renderEpisodesBody(i,t){if(t.seasons.length===0){t.totalEpisodes>0&&this.renderEpisodeGrid(i,t,null);return}t.seasons.forEach((e,s)=>{var h,p;let a=this.collapsedSeasons.has(s),n=i.createDiv({cls:"wl-season-wrap"}),r=n.createDiv({cls:"wl-season-header"}),o=r.createSpan({cls:"wl-season-badge"});o.textContent=e.name;let l=this.plugin.settings.seasonPalette;o.style.backgroundColor=(h=l[s%l.length])!=null?h:"#888780";let c=((p=e.skippedEpisodes)!=null?p:[]).length,d=c>0?` (${c} to skip)`:"";r.createSpan({cls:"wl-season-ep-count",text:`${e.episodes} eps${d}`});let u=r.createSpan({cls:`wl-chevron${a?"":" is-open"}`,text:"\u203A"});a||this.renderEpisodeGrid(n,t,e),r.addEventListener("click",m=>{var v;m.stopPropagation(),a?(a=!1,this.collapsedSeasons.delete(s),u.classList.add("is-open"),this.renderEpisodeGrid(n,t,e)):(a=!0,this.collapsedSeasons.add(s),u.classList.remove("is-open"),(v=n.querySelector(".wl-episode-grid"))==null||v.remove()),this.expandedId&&this.dataManager.persistCollapsedSeasons(this.expandedId,this.collapsedSeasons)})})}renderEpisodeGrid(i,t,e){let s=i.createDiv({cls:"wl-episode-grid"}),a=e?e.episodes:t.totalEpisodes,n=e?e.offset:0,r=Array.from({length:a},(d,u)=>n+u+1),o=s.createDiv({cls:"wl-season-fill-btn"}),l=()=>{let d=new Set(t.watchedEpisodes),u=r.length>0&&r.every(h=>d.has(h));o.classList.toggle("is-clear",u),o.classList.toggle("is-fill",!u),o.textContent=u?"\u2717":"\u2713",o.title=u?"Clear all episodes in this season":"Mark all episodes in this season as watched"};l(),o.addEventListener("click",d=>{d.stopPropagation();let u=new Set(t.watchedEpisodes),h=r.length>0&&r.every(p=>u.has(p));this.dataManager.markSeasonWatched(t.id,r,!h,e==null?void 0:e.name).then(()=>this.rerenderTable())});let c=this.plugin.settings.episodeNumbering==="per-season";for(let d=0;d{var w;let f=t.watchedEpisodes.includes(u),y=e?((w=e.skippedEpisodes)!=null?w:[]).includes(h):!1;m.classList.toggle("is-watched",f),m.classList.toggle("is-skipped",y),m.textContent=y&&!f?"\u2014":f?"\u2713":String(p),m.title=`Episode ${u}${y?" (skipped)":""}`};v(),m.addEventListener("click",f=>{f.stopPropagation();let y=t.watchedEpisodes.includes(u);this.dataManager.applyEpisodeWatchedToggle(t.id,u,!y),v(),l(),this.updateAccordionStats(m,t,e)})}}updateAccordionStats(i,t,e){var h;let s=i.closest(".wl-accordion");if(!s)return;let a=this.dataManager.calcTimeRemainingForModal(t),n=this.dataManager.calcTimeWatched(t),r=t.watchedEpisodes.length,o=this.dataManager.getEffectiveTotal(t),l=this.dataManager.getProgress(t),c=s.querySelectorAll(".wl-acc-stat-block .wl-acc-percent");c[0]&&(c[0].textContent=z(a)),c[1]&&(c[1].textContent=z(n)),c[2]&&(c[2].textContent=`${r} / ${o}`);let d=s.querySelector(".wl-acc-header-right .wl-acc-percent");d&&(d.textContent=`${l}%`);let u=s.querySelector(".wl-acc-header-right .wl-progress-bar");if(u&&(u.style.width=`${l}%`),e){let p=i.closest(".wl-episode-grid"),m=p==null?void 0:p.parentElement,v=m==null?void 0:m.querySelector(".wl-season-header .wl-season-ep-count");if(v){let f=((h=e.skippedEpisodes)!=null?h:[]).length,y=f>0?` (${f} to skip)`:"";v.textContent=`${e.episodes} eps${y}`}}}renderAccordionFooter(i,t){let e=i.createDiv({cls:"wl-accordion-footer"}),s=e.createDiv({cls:"wl-stars-row"});s.createSpan({cls:"wl-stars-label",text:"Rating"});let a=s.createDiv({cls:"wl-stars"});for(let w=1;w<=5;w++)a.createSpan({cls:`wl-star${t.rating>=w?" is-active":""}`,text:"\u2605"}).addEventListener("click",S=>{S.stopPropagation(),(async()=>{let k=this.dataManager.getTitle(t.id);k&&(k.rating=k.rating===w?0:w,await this.dataManager.updateTitle(k),this.rerenderTable())})()});let n=()=>{var S;let b=s.querySelector(".wl-rating-divider");for(;b;){let k=b;b=b.nextSibling,(S=k.parentNode)==null||S.removeChild(k)}$t(s,this.plugin,t.id,n)};$t(s,this.plugin,t.id,n),ye(this.plugin,t.id,n);let o=e.createDiv({cls:"wl-footer-row"}).createEl("input",{cls:"wl-notes-input",attr:{type:"text",placeholder:"Add a note..."}});o.value=t.notes,o.addEventListener("click",w=>w.stopPropagation()),o.addEventListener("change",()=>{(async()=>{let w=this.dataManager.getTitle(t.id);w&&(w.notes=o.value,await this.dataManager.updateTitle(w),this.rerenderTable())})()});let l=e.createDiv({cls:"wl-footer-row"});l.createSpan({cls:"wl-footer-label",text:"Date watched"});let c=l.createEl("button",{cls:"wl-btn wl-btn-sm wl-footer-today-btn",text:"Today",attr:{title:"Fill with today\u2019s date"}}),d=l.createEl("input",{cls:"wl-footer-date",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});d.value=Q(t.dateFinished);let u=()=>{c.toggleClass("is-dimmed",!!d.value.trim())};u(),d.addEventListener("click",w=>w.stopPropagation()),d.addEventListener("change",()=>{(async()=>{let w=this.dataManager.getTitle(t.id);if(!w)return;let b=j(d.value);if(d.value.trim()&&!b){d.addClass("wl-input-error");return}d.removeClass("wl-input-error"),w.dateFinished=b,await this.dataManager.updateTitle(w),this.rerenderTable()})()}),c.addEventListener("click",w=>{if(w.stopPropagation(),d.value.trim())return;let b=new Date,S=String(b.getDate()).padStart(2,"0"),k=String(b.getMonth()+1).padStart(2,"0"),E=b.getFullYear();d.value=`${S}/${k}/${E}`,u(),d.dispatchEvent(new Event("change"))});let h=e.createDiv({cls:"wl-footer-row"});h.createSpan({cls:"wl-footer-label",text:"Status"});let p=h.createEl("select",{cls:"wl-select wl-select-sm"});for(let w of this.plugin.settings.statuses){if(w.name==="To be released")continue;let b=p.createEl("option",{text:w.name,value:w.name});w.name===t.status&&(b.selected=!0)}p.addEventListener("click",w=>w.stopPropagation()),p.addEventListener("change",()=>{(async()=>{let w=this.dataManager.getTitle(t.id);w&&(w.status=p.value,await this.dataManager.updateTitle(w),this.rerenderTable())})()});let m=e.createDiv({cls:"wl-footer-row wl-footer-action-row"});m.createEl("button",{cls:"wl-delete-btn wl-btn-danger",text:"Remove"}).addEventListener("click",w=>{w.stopPropagation(),new N(this.plugin.app,`Remove "${t.title}" from watchlog?`,()=>{this.dataManager.removeTitle(t.id).then(()=>{this.expandedId=null,this.rerenderTable()})}).open()}),m.createDiv({cls:"wl-add-btn-wrap"}).createEl("button",{cls:"wl-edit-btn",text:"Edit"}).addEventListener("click",w=>{w.stopPropagation();let b=this.dataManager.getTitle(t.id);b&&new St(this.plugin.app,this.plugin,this.dataManager,b,()=>{this.rerenderTable()}).open()})}compareTitlesByKey(i,t,e){switch(i){case"title-asc":return t.title.localeCompare(e.title);case"title-desc":return e.title.localeCompare(t.title);case"dateAdded-newest":return new Date(e.dateAdded).getTime()-new Date(t.dateAdded).getTime();case"dateAdded-oldest":return new Date(t.dateAdded).getTime()-new Date(e.dateAdded).getTime();case"progress-high":return this.dataManager.getProgress(e)-this.dataManager.getProgress(t);case"progress-low":return this.dataManager.getProgress(t)-this.dataManager.getProgress(e);case"rating-high":{let s=t.rating===0?-1:t.rating;return(e.rating===0?-1:e.rating)-s}case"rating-low":return t.rating===0&&e.rating===0?0:t.rating===0?1:e.rating===0?-1:t.rating-e.rating;case"priority":{let s=ie.indexOf(t.priority),a=ie.indexOf(e.priority);return(s===-1?99:s)-(a===-1?99:a)}case"started-asc":{let s=t.dateStarted?new Date(t.dateStarted).getTime():1/0,a=e.dateStarted?new Date(e.dateStarted).getTime():1/0;return s-a}case"started-desc":{let s=t.dateStarted?new Date(t.dateStarted).getTime():null,a=e.dateStarted?new Date(e.dateStarted).getTime():null;return s==null&&a==null?0:s==null?1:a==null?-1:a-s}case"status-asc":return this.getStatusIndex(t.status)-this.getStatusIndex(e.status);case"status-desc":return this.getStatusIndex(e.status)-this.getStatusIndex(t.status);case"dateWatched-newest":{let s=t.dateFinished?new Date(t.dateFinished).getTime():0;return(e.dateFinished?new Date(e.dateFinished).getTime():0)-s}case"dateWatched-oldest":{let s=t.dateFinished?new Date(t.dateFinished).getTime():1/0,a=e.dateFinished?new Date(e.dateFinished).getTime():1/0;return s-a}case"timeLeft-high":return this.dataManager.calcTimeRemaining(e)-this.dataManager.calcTimeRemaining(t);case"timeLeft-low":return this.dataManager.calcTimeRemaining(t)-this.dataManager.calcTimeRemaining(e);case"timeWatched-high":return this.dataManager.calcTimeWatched(e)-this.dataManager.calcTimeWatched(t);case"timeWatched-low":return this.dataManager.calcTimeWatched(t)-this.dataManager.calcTimeWatched(e);default:return 0}}getFilteredSortedTitles(){let i=this.dataManager.getTitles();if(this.searchQuery.trim()){let s=this.searchQuery.toLowerCase();i=i.filter(a=>a.title.toLowerCase().includes(s))}i=i.filter(s=>this.titlePassesFilters(s));let t=tt.sortBaseAndDirToKey(this.filterSort,this.filterSortDir),e=this.filterSecondSort==="none"?"none":tt.sortBaseAndDirToKey(this.filterSecondSort,this.filterSecondSortDir);return i=[...i].sort((s,a)=>{let n=this.compareTitlesByKey(t,s,a);return n!==0||e==="none"?n:this.compareTitlesByKey(e,s,a)}),i}getTagDef(i,t){return t.find(e=>e.name===i)}};tt.SORT_DEFAULT_DIR={title:"asc",dateAdded:"desc",progress:"desc",rating:"desc",priority:"asc",started:"asc",status:"asc",dateWatched:"desc",timeLeft:"desc",timeWatched:"desc"};var Ce=tt;var pt=require("obsidian");var At=require("obsidian");function Me(g){return"malId"in g}var xe=class extends At.Modal{constructor(t,e,s,a){super(t);this.selectedType="Anime";this.searchQuery="";this.searchResults=[];this.isSearching=!1;this.searchGeneration=0;this.fieldTitle="";this.fieldEpisodes=0;this.fieldDuration=0;this.fieldReleaseDate="";this.fieldLink="";this.resultsEl=null;this.formEl=null;this.searchDebounce=null;this.plugin=e,this.dataManager=s,this.onAdded=a}onOpen(){this.titleEl.setText("Add to maybe"),this.contentEl.addClass("wl-add-modal"),this.buildUI()}onClose(){this.contentEl.empty(),this.searchDebounce&&window.clearTimeout(this.searchDebounce)}buildUI(){let t=this.contentEl;t.empty();let e=t.createDiv({cls:"wl-modal-row"});e.createSpan({cls:"wl-modal-label",text:"Type"});let s=e.createEl("select",{cls:"wl-select"});for(let o of this.plugin.settings.types){let l=s.createEl("option",{text:o.name,value:o.name});o.name===this.selectedType&&(l.selected=!0)}s.addEventListener("change",()=>{this.selectedType=s.value,this.searchResults=[],this.renderResults(),this.renderForm()});let a=t.createDiv({cls:"wl-modal-row"});a.createSpan({cls:"wl-modal-label",text:"Search"});let n=a.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Search for a title..."}});n.value=this.searchQuery,n.addEventListener("input",()=>{this.searchQuery=n.value,this.searchDebounce&&window.clearTimeout(this.searchDebounce),this.searchDebounce=window.setTimeout(()=>void this.performSearch(),600)}),a.createEl("button",{cls:"wl-btn",text:"Search"}).addEventListener("click",()=>void this.performSearch()),this.resultsEl=t.createDiv({cls:"wl-modal-results"}),this.formEl=t.createDiv({cls:"wl-modal-form"}),this.renderForm()}async performSearch(){var e,s;if(!this.searchQuery.trim())return;let t=++this.searchGeneration;this.isSearching=!0,this.renderResults();try{let a=this.plugin.apiService,n=(e=this.plugin.settings.activeApi)!=null?e:"OMDb",r=at(this.selectedType,this.plugin.settings.typeApiMapping),o=this.selectedType==="Movie",l=[];if(r===""?new At.Notice(`No API configured for type "${this.selectedType}". Configure it in Settings \u2192 API.`):r==="anime"?l=((s=this.plugin.settings.animeApiSource)!=null?s:"jikan")==="anilist"?await a.searchAniList(this.searchQuery):await a.searchAnime(this.searchQuery):n==="TMDB"?l=await a.searchTmdb(this.searchQuery,o?"movie":"series"):l=await a.searchOmdb(this.searchQuery,o?"movie":"series"),t!==this.searchGeneration)return;this.searchResults=l}catch(a){if(t!==this.searchGeneration)return;new At.Notice("Search failed. Check your connection and API settings."),this.searchResults=[]}finally{t===this.searchGeneration&&(this.isSearching=!1,this.renderResults())}}renderResults(){if(this.resultsEl){if(this.resultsEl.empty(),this.isSearching){this.resultsEl.createDiv({cls:"wl-modal-loading",text:"Searching..."});return}this.searchResults.length&&this.searchResults.forEach((t,e)=>{let s=this.resultsEl.createDiv({cls:"wl-result-item"}),a=Me(t)?`${t.episodes} eps`:t.episodes>0?`${t.episodes} eps`:t.mediaType;s.createDiv({cls:"wl-result-title",text:t.title}),s.createDiv({cls:"wl-result-meta",text:`${a} \xB7 ${t.releaseDate}`}),s.dataset.idx=String(e),s.addEventListener("click",()=>void this.selectResult(t,s))})}}async selectResult(t,e){var r;if(this.resultsEl)for(let o of Array.from(this.resultsEl.children))o.removeClass("is-selected");e.addClass("is-selected");let s=++this.searchGeneration,a=this.plugin.apiService,n=(r=this.plugin.settings.activeApi)!=null?r:"OMDb";try{if(!Me(t)&&t.mediaType==="tv"){let o=n==="TMDB"?await a.getTmdbTvDetails(t.imdbId):await a.getOmdbTvDetails(t.imdbId);if(s!==this.searchGeneration)return;o&&(this.fieldTitle=o.title,this.fieldEpisodes=o.episodes,this.fieldDuration=o.episodeDuration,this.fieldReleaseDate=o.releaseDate,this.fieldLink=o.url)}else if(!Me(t)&&t.mediaType==="movie"){let o=n==="TMDB"?await a.getTmdbMovieDetails(t.imdbId):await a.getOmdbMovieDetails(t.imdbId);if(s!==this.searchGeneration)return;o&&(this.fieldTitle=o.title,this.fieldEpisodes=o.episodes,this.fieldDuration=o.episodeDuration,this.fieldReleaseDate=o.releaseDate,this.fieldLink=o.url)}else{let o=t;this.fieldTitle=o.title,this.fieldEpisodes=o.episodes,this.fieldDuration=o.duration,this.fieldReleaseDate=o.releaseDate,this.fieldLink=o.url}}catch(o){if(s!==this.searchGeneration)return;this.fieldTitle=t.title,this.fieldEpisodes=t.episodes,this.fieldDuration=Me(t)?t.duration:t.episodeDuration,this.fieldReleaseDate=t.releaseDate,this.fieldLink=t.url}s===this.searchGeneration&&this.renderForm()}renderForm(){if(!this.formEl)return;this.formEl.empty();let t=f=>{let y=this.formEl.createDiv({cls:"wl-modal-row"});return y.createSpan({cls:"wl-modal-label",text:f}),y},s=t("Title").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Title name"}});s.value=this.fieldTitle,s.addEventListener("input",()=>{this.fieldTitle=s.value});let n=t("Episodes").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0",placeholder:"0"}});n.value=String(this.fieldEpisodes),n.addEventListener("input",()=>{this.fieldEpisodes=parseInt(n.value)||0});let o=t("Ep. duration (min)").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0",placeholder:"24"}});o.value=String(this.fieldDuration),o.addEventListener("input",()=>{this.fieldDuration=parseInt(o.value)||0});let c=t("Release date").createDiv({cls:"wl-modal-input-stack"}),d=c.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Date (dd-mm-yyyy or yyyy-mm-dd)"}});d.value=this.fieldReleaseDate;let u=c.createDiv({cls:"wl-modal-error wl-hidden"});d.addEventListener("change",()=>{let f=d.value.trim();if(!f){this.fieldReleaseDate="",u.addClass("wl-hidden");return}let y=Pt(f);y?(this.fieldReleaseDate=y,d.value=y,u.addClass("wl-hidden")):(this.fieldReleaseDate=f,u.textContent="Unrecognised format.",u.removeClass("wl-hidden"))});let p=t("External link").createEl("input",{cls:"wl-modal-input",attr:{type:"url",placeholder:"https://example.com"}});p.value=this.fieldLink,p.addEventListener("input",()=>{this.fieldLink=p.value}),this.formEl.createDiv({cls:"wl-modal-btn-row"}).createEl("button",{cls:"wl-btn wl-btn-primary",text:"Add to maybe"}).addEventListener("click",()=>void this.addMaybeTitle())}async addMaybeTitle(){let t=this.fieldTitle.trim();if(!t){new At.Notice("Please enter a title name.");return}let e={id:this.dataManager.generateMaybeId(t),title:t,type:this.selectedType,releaseDate:this.fieldReleaseDate||null,externalLink:this.fieldLink,totalEpisodes:this.fieldEpisodes,episodeDuration:this.fieldDuration,dateAdded:new Date().toISOString()};await this.dataManager.addMaybeTitle(e),new At.Notice(`"${t}" added to Maybe.`),this.close(),this.onAdded()}};var Le=require("obsidian");var se=class extends Le.Modal{constructor(i,t,e,s,a,n,r,o,l){var u,h;super(i),this.item=t,this.kind=e,this.schedule=s?{...s}:{recurrence:"once"},this.schedule.releaseTime=void 0,!this.schedule.releaseDate&&t.releaseDate&&/^\d{4}-\d{2}-\d{2}$/.test(t.releaseDate)&&(this.schedule.releaseDate=t.releaseDate),this.currentVolume=a,this.currentChapter=n;let c=(u=t.totalChapters)!=null?u:0,d=e==="manga"&&(h=t.totalVolumes)!=null?h:0;this.totalChapters=o!=null?o:c>0?c:null,this.totalVolumes=r!=null?r:d>0?d:null,this.onSave=l}onOpen(){this.titleEl.setText("Set reading schedule"),this.contentEl.addClass("wl-add-modal"),this.renderForm()}onClose(){this.contentEl.empty()}renderForm(){this.contentEl.empty(),this.contentEl.addClass("wl-add-modal");let i=this.contentEl,t=u=>{let h=i.createDiv({cls:"wl-modal-row"});return h.createSpan({cls:"wl-modal-label",text:u}),h},e=(u,h,p,m)=>{let f=t(u).createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0",placeholder:p}});h!==null&&(f.value=String(h)),f.addEventListener("input",()=>{m(parseInt(f.value)||null)})},a=t("Recurrence").createEl("select",{cls:"wl-select"}),n=[["once","Once"],["daily","Daily"],["weekly","Weekly"],["monthly","Monthly"]];for(let[u,h]of n){let p=a.createEl("option",{text:h,value:u});u===this.schedule.recurrence&&(p.selected=!0)}let r=i.createDiv(),o=()=>{var h;r.empty();let u=this.schedule.recurrence;if(u==="once"){let p=r.createDiv({cls:"wl-modal-row"});p.createSpan({cls:"wl-modal-label",text:"Date"});let m=p.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});m.value=this.schedule.releaseDate?this.schedule.releaseDate.split("-").reverse().join("/"):"",m.addEventListener("change",()=>{let v=j(m.value);v&&(this.schedule.releaseDate=v)})}if(u==="weekly"){let p=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],m=r.createDiv({cls:"wl-modal-row"});m.createSpan({cls:"wl-modal-label",text:"Day of week"});let v=m.createEl("select",{cls:"wl-select"});p.forEach((f,y)=>{var b;let w=v.createEl("option",{text:f,value:String(y)});y===((b=this.schedule.dayOfWeek)!=null?b:6)&&(w.selected=!0)}),v.addEventListener("change",()=>{this.schedule.dayOfWeek=parseInt(v.value)})}if(u==="monthly"){let p=r.createDiv({cls:"wl-modal-row"});p.createSpan({cls:"wl-modal-label",text:"Day of month"});let m=p.createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"1",max:"31",placeholder:"1"}});m.value=String((h=this.schedule.dayOfMonth)!=null?h:1),m.addEventListener("input",()=>{this.schedule.dayOfMonth=parseInt(m.value)||1})}};a.addEventListener("change",()=>{this.schedule.recurrence=a.value,o()}),o(),e("Current chapter",this.currentChapter,"E.g. 12",u=>{this.currentChapter=u}),e("Current volume",this.currentVolume,"E.g. 2",u=>{this.currentVolume=u}),e("Total chapters",this.totalChapters,"E.g. 120",u=>{this.totalChapters=u}),e("Total volumes",this.totalVolumes,"E.g. 12",u=>{this.totalVolumes=u}),i.createDiv({cls:"wl-modal-info wl-schedule-hint",text:"Titles with 0 or 1 total chapters will be treated as a single release date, like a book."});let l=i.createDiv({cls:"wl-modal-btn-row"});l.createEl("button",{cls:"wl-btn wl-btn-mr",text:"Cancel"}).addEventListener("click",()=>this.close()),l.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",()=>{(async()=>{if(this.schedule.recurrence==="once"&&!this.schedule.releaseDate){new Le.Notice("Set a release date.");return}await this.onSave(this.schedule,this.currentVolume,this.currentChapter,this.totalVolumes,this.totalChapters),this.close()})()})}};var ns=require("obsidian"),Re=class extends ns.FuzzySuggestModal{constructor(i,t,e){super(i),this.items=t,this.onSelect=e,this.setPlaceholder("Search a title to add to Upcoming...")}getItems(){return this.items}getItemText(i){return`${i.title} (${i.typeLabel})`}onChooseItem(i){this.onSelect(i)}};function di(g){if(g<30)return`in ${g} days`;let i=Math.round(g/30);return`in ${g} days (${i} month${i!==1?"s":""})`}function Ae(g){if(!g.releaseTime)return!0;let i=new Date,[t,e]=g.releaseTime.split(":"),s=parseInt(t!=null?t:"0"),a=parseInt(e!=null?e:"0");return i.getHours()>s||i.getHours()===s&&i.getMinutes()>=a}function ui(g,i,t){let e=new Date,s=new Date(e.getFullYear(),e.getMonth(),e.getDate()),a=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`,n=t===a;if(g.recurrence==="once"){if(!g.releaseDate)return{kind:"future",label:"\u2014",daysUntil:9999};let r=new Date(g.releaseDate+"T00:00:00"),o=new Date(r.getFullYear(),r.getMonth(),r.getDate());if(o.getTime()c.name===t.type),s=this.plugin.settings.coloredTypeBadges;return{source:"watchlist",id:t.id,title:t.title,typeName:t.type,typeColor:s&&e?H(t.type,e.color,this.plugin.settings.colorTheme):null,externalLink:t.externalLink,isSingle:t.totalEpisodes<=1,totalUnits:(l=i.totalEpisodes)!=null?l:t.totalEpisodes,unitNoun:"episode",unitNounCap:"Episode",groupNounCap:"Season",nextLabel:"Airing next",planStatus:"Plan to watch"}}static getMaybeDueCount(i){let t=new Date;t.setHours(0,0,0,0);let e=t.toISOString().split("T")[0];return i.getMaybeTitles().filter(s=>!!s.releaseDate&&s.releaseDate<=e).length}static getAiredDueCount(i,t){var r,o;let e=i.getAirtimeEntries(),s=i.getTitles(),a=new Map(s.map(l=>[l.id,l])),n=0;for(let l of e){let c;if(l.source==="reading"){if(t&&!(((r=l.readingKind)!=null?r:"book")==="book"?t.getBook(l.titleId):t.getManga(l.titleId)))continue;c=((o=l.totalEpisodes)!=null?o:0)<=1}else{let u=a.get(l.titleId);if(!u)continue;c=u.totalEpisodes<=1}let d=ui(l.schedule,c,l.lastAcknowledgedDate);(d.kind==="aired"||d.kind==="due")&&n++}return n}render(){this.container.empty(),this.container.addClass("wl-airtime"),this.onCountChange&&this.onCountChange(g.getAiredDueCount(this.dataManager,this.readingDataManager)+g.getMaybeDueCount(this.dataManager)),this.renderInnerTabBar(),this.currentSubTab==="tracker"?this.renderTracker():this.currentSubTab==="history"?this.renderHistory():this.renderMaybe()}renderInnerTabBar(){let i=this.container.createDiv({cls:"wl-inner-tab-bar"}),t=g.getAiredDueCount(this.dataManager,this.readingDataManager),e=g.getMaybeDueCount(this.dataManager),s=[{key:"tracker",label:"Tracker",badge:t},{key:"history",label:"Log",badge:0},{key:"maybe",label:"Maybe",badge:e}];for(let{key:a,label:n,badge:r}of s){let o=r>0?`${n} (${r})`:n;i.createEl("button",{cls:`wl-inner-tab-btn${this.currentSubTab===a?" is-active":""}`,text:o}).addEventListener("click",()=>{this.currentSubTab!==a&&(this.currentSubTab=a,this.selectionMode=!1,this.selectedItems.clear(),this.searchQuery="",this.render())})}}renderTracker(){this.plugin.settings.showHintBanners&&this.container.createDiv({cls:"wl-cl-draft-banner",text:'\u26A0 All titles with a release date in the future will be automatically marked as "To be released" in Watchlist and added here.'}),this.renderHeader(),this.renderSearch(),this.renderCards()}renderHistory(){let i=new Date;i.setHours(0,0,0,0);let t=i.toISOString().split("T")[0],e=new Date(i);e.setMonth(e.getMonth()-6);let s=e.toISOString().split("T")[0],a=this.dataManager.getTitles().filter(r=>!!r.releaseDate&&r.releaseDate<=t&&r.releaseDate>=s).sort((r,o)=>{var l,c;return((l=o.releaseDate)!=null?l:"").localeCompare((c=r.releaseDate)!=null?c:"")});if(a.length===0){this.container.createDiv({cls:"wl-empty-state",text:"No past releases yet."});return}let n=this.container.createDiv({cls:"wl-airtime-cards"});for(let r of a)this.renderHistoryCard(n,r)}renderHistoryCard(i,t){let e=i.createDiv({cls:"wl-airtime-card wl-airtime-history-card"}),s=e.createDiv({cls:"wl-airtime-card-left"});s.createDiv({cls:"wl-airtime-card-title",text:t.title});let a=s.createDiv({cls:"wl-airtime-card-meta"}),n=this.plugin.settings.types.find(u=>u.name===t.type),r=this.plugin.settings.coloredTypeBadges,o=a.createSpan({cls:r?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});r&&n&&(o.style.backgroundColor=H(t.type,n.color,this.plugin.settings.colorTheme)),t.releaseDate&&a.createSpan({cls:"wl-airtime-schedule",text:t.releaseDate});let l=e.createDiv({cls:"wl-airtime-card-right wl-airtime-history-right"});t.releaseDate&&l.createDiv({cls:"wl-airtime-pill wl-airtime-pill-aired",text:da(t.releaseDate)});let c=l.createEl("button",{cls:"wl-airtime-action-btn",text:"\u{1F310}"});c.title="Open page",c.addEventListener("click",u=>{u.stopPropagation(),t.externalLink?activeWindow.open(t.externalLink,"_blank"):new pt.Notice("No external link set for this title.")});let d=l.createEl("button",{cls:"wl-airtime-action-btn wl-airtime-action-btn-delete wl-btn-danger",text:"\u2715"});d.title="Remove from watchlist",d.addEventListener("click",u=>{u.stopPropagation(),new N(this.plugin.app,`Remove "${t.title}" from Watchlist?`,()=>{this.dataManager.removeTitle(t.id).then(()=>this.render())}).open()})}renderMaybe(){let i=this.dataManager.getMaybeTitles(),t=this.container.createDiv({cls:"wl-list-header"});if(i.length>0&&t.createSpan({cls:"wl-list-count",text:String(i.length)}),t.createDiv({cls:"wl-header-controls"}).createDiv({cls:"wl-header-controls-right"}).createDiv({cls:"wl-add-btn-wrap"}).createEl("button",{cls:"wl-add-btn wl-btn-success",text:"+ add"}).addEventListener("click",c=>{c.stopPropagation(),new xe(this.plugin.app,this.plugin,this.dataManager,()=>this.render()).open()}),i.length===0){this.container.createDiv({cls:"wl-empty-state",text:`No "Maybe" titles yet. Click + Add to track something you're considering.`});return}let r=new Date;r.setHours(0,0,0,0);let o=this.container.createDiv({cls:"wl-airtime-cards"}),l=[...i].sort((c,d)=>{var p,m;let u=(p=c.releaseDate)!=null?p:"",h=(m=d.releaseDate)!=null?m:"";return!u&&!h?c.dateAdded.localeCompare(d.dateAdded):u?h?u.localeCompare(h):-1:1});for(let c of l)this.renderMaybeCard(o,c,r)}renderMaybeCard(i,t,e){var f;let s={recurrence:"once",releaseDate:(f=t.releaseDate)!=null?f:void 0},a=ui(s,!0),n="wl-maybe-card";a.kind==="due"&&(n+=" wl-airtime-card-aired is-due");let r=i.createDiv({cls:n}),o=r.createDiv({cls:"wl-maybe-card-left"});o.createSpan({cls:"wl-maybe-card-title",text:t.title});let l=this.plugin.settings.types.find(y=>y.name===t.type),c=this.plugin.settings.coloredTypeBadges,d=o.createSpan({cls:c?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});c&&l&&(d.style.backgroundColor=H(t.type,l.color,this.plugin.settings.colorTheme));let u={"today-before":"wl-airtime-pill wl-airtime-pill-today-series",future:"wl-airtime-pill wl-airtime-pill-days",aired:"wl-airtime-pill wl-airtime-pill-aired",due:"wl-airtime-pill wl-airtime-pill-due"},h=a.kind==="future"&&a.label==="Tomorrow"?"wl-airtime-pill wl-airtime-pill-tomorrow":u[a.kind],p=r.createDiv({cls:"wl-maybe-card-right"});p.createDiv({cls:h,text:t.releaseDate?a.label:"\u2014"});let m=p.createEl("button",{cls:"wl-airtime-action-btn",text:"\u{1F310}"});m.title="Open page",m.addEventListener("click",y=>{y.stopPropagation(),t.externalLink?activeWindow.open(t.externalLink,"_blank"):new pt.Notice("No external link set.")});let v=p.createEl("button",{cls:"wl-airtime-action-btn wl-airtime-action-btn-delete wl-btn-danger",text:"\u2715"});v.title="Remove from maybe",v.addEventListener("click",y=>{y.stopPropagation(),new N(this.plugin.app,`Remove "${t.title}" from Maybe?`,()=>{this.dataManager.removeMaybeTitle(t.id).then(()=>this.render())}).open()})}renderSearch(){let t=this.container.createDiv({cls:"wl-search-wrap"}).createEl("input",{cls:"wl-search-input",attr:{type:"text",placeholder:"Search upcoming..."}});t.value=this.searchQuery;let e=null;t.addEventListener("input",()=>{this.searchQuery=t.value,e!==null&&window.clearTimeout(e),e=window.setTimeout(()=>{e=null,this.rerenderCards()},250)})}rerenderCards(){let i=this.container.querySelector(".wl-airtime-cards"),t=this.container.querySelector(".wl-empty-state");i&&i.remove(),t&&t.remove(),this.renderCards()}renderHeader(){let i=this.container.createDiv({cls:"wl-list-header"}),t=this.dataManager.getAirtimeEntries().filter(o=>this.resolveEntry(o)!==null).length;t>0&&i.createSpan({cls:"wl-list-count",text:String(t)});let e=i.createDiv({cls:"wl-header-controls"});if(this.selectionMode&&this.selectedItems.size>0&&this.renderActionBar(e),this.selectionMode){let o=this.selectedItems.size>0,l=e.createEl("button",{cls:"wl-btn wl-btn-sm",text:o?"None":"All"});l.title=o?"Deselect all":"Select all visible",l.addEventListener("click",()=>{if(this.selectedItems.size>0)this.selectedItems.clear();else for(let c of this.dataManager.getAirtimeEntries())this.selectedItems.add(c.id);this.render()})}let s=e.createDiv({cls:"wl-header-controls-right"});s.createEl("button",{cls:`wl-btn wl-btn-sm${this.selectionMode?" is-active":""}`,text:"Select"}).addEventListener("click",()=>{this.selectionMode=!this.selectionMode,this.selectedItems.clear(),this.render()}),s.createDiv({cls:"wl-add-btn-wrap"}).createEl("button",{cls:"wl-add-btn wl-btn-success",text:"+ add"}).addEventListener("click",o=>{o.stopPropagation(),this.openAddFlow()})}renderActionBar(i){let e=i.createDiv({cls:"wl-action-bar"}).createEl("button",{cls:"wl-group-action-btn wl-group-action-btn-delete wl-btn-danger",text:"\u2715"});e.title="Remove from upcoming",e.addEventListener("click",s=>{s.stopPropagation();let a=this.selectedItems.size;new N(this.plugin.app,`Remove ${a} selected item${a!==1?"s":""} from Upcoming? This cannot be undone.`,()=>{(async()=>(await this.dataManager.removeAirtimeEntriesBatch(Array.from(this.selectedItems)),this.selectedItems.clear(),this.render()))()}).open()})}openAddFlow(){let i=this.dataManager.getAirtimeEntries(),t=new Set(i.filter(a=>a.source!=="reading").map(a=>a.titleId)),e=new Set(i.filter(a=>a.source==="reading").map(a=>a.titleId)),s=[];for(let a of this.dataManager.getTitles())t.has(a.id)||s.push({source:"watchlist",id:a.id,title:a.title,typeLabel:a.type});for(let a of this.readingDataManager.getBooks())e.has(a.id)||s.push({source:"reading",kind:"book",id:a.id,title:a.title,typeLabel:"Book"});for(let a of this.readingDataManager.getMangaList())e.has(a.id)||s.push({source:"reading",kind:"manga",id:a.id,title:a.title,typeLabel:"Manga"});if(this.dataManager.getTitles().length===0&&this.readingDataManager.getBooks().length===0&&this.readingDataManager.getMangaList().length===0){new pt.Notice("No titles in your watchlog or reading library yet.");return}if(s.length===0){new pt.Notice("Everything is already in upcoming.");return}new Re(this.plugin.app,s,a=>{var n;if(a.source==="reading"){let r=(n=a.kind)!=null?n:"book",o=r==="book"?this.readingDataManager.getBook(a.id):this.readingDataManager.getManga(a.id);o&&this.startAddWithReading(o,r)}else{let r=this.dataManager.getTitle(a.id);r&&this.startAddWithTitle(r)}}).open()}startAddWithReading(i,t){let e=i.releaseDate&&/^\d{4}-\d{2}-\d{2}$/.test(i.releaseDate)?{recurrence:"once",releaseDate:i.releaseDate}:null;new se(this.plugin.app,i,t,e,null,null,null,null,async(s,a,n,r,o)=>{let l={id:this.dataManager.generateReadingAirtimeId(i.id),titleId:i.id,source:"reading",readingKind:t,schedule:s,currentSeason:a!=null?a:void 0,currentEpisode:n!=null?n:void 0,totalSeasons:r!=null?r:void 0,totalEpisodes:o!=null?o:void 0,dateAdded:new Date().toISOString()};await this.dataManager.addAirtimeEntry(l),await this.syncReadingItemFromSchedule(i.id,t,s,r,o),this.render()}).open()}async syncReadingItemFromSchedule(i,t,e,s,a){var n,r;if(t==="book"){let o=this.readingDataManager.getBook(i);if(!o)return;let l=!1;if(a!==null&&a!==o.totalChapters&&(o.totalChapters=a,l=!0),e.recurrence==="once"&&yt(e.releaseDate)){let c=(n=e.releaseDate)!=null?n:null;o.releaseDate!==c&&(o.releaseDate=c,l=!0)}l&&await this.readingDataManager.updateBook(o)}else{let o=this.readingDataManager.getManga(i);if(!o)return;let l=!1;if(a!==null&&a!==o.totalChapters&&(o.totalChapters=a,l=!0),s!==null&&s!==o.totalVolumes&&(o.totalVolumes=s,l=!0),e.recurrence==="once"&&yt(e.releaseDate)){let c=(r=e.releaseDate)!=null?r:null;o.releaseDate!==c&&(o.releaseDate=c,l=!0)}l&&await this.readingDataManager.updateManga(o)}}async revertToBeReleasedStatus(i,t){var e;if(t.source==="reading")if(((e=i.readingKind)!=null?e:"book")==="book"){let a=this.readingDataManager.getBook(i.titleId);a&&a.status==="To be released"&&(a.status="Plan to Read",await this.readingDataManager.updateBook(a))}else{let a=this.readingDataManager.getManga(i.titleId);a&&a.status==="To be released"&&(a.status="Plan to Read",await this.readingDataManager.updateManga(a))}else{let s=this.dataManager.getTitle(i.titleId);s&&s.status==="To be released"&&(s.status="Plan to watch",await this.dataManager.updateTitle(s))}}async startAddWithTitle(i){let t=null;if(i.type==="Anime"&&i.malId)try{let e=await this.plugin.apiService.getAnimeScheduleByMalId(i.malId);e&&(t={recurrence:"weekly",dayOfWeek:e.dayOfWeek,releaseTime:e.time},new pt.Notice("Schedule auto-filled from myanimelist."))}catch(e){}!t&&i.releaseDate&&/^\d{4}-\d{2}-\d{2}$/.test(i.releaseDate)&&(t={recurrence:"once",releaseDate:i.releaseDate}),new Ie(this.plugin.app,i,t,null,null,null,null,async(e,s,a,n,r)=>{var c;let o={id:this.dataManager.generateAirtimeId(i.id),titleId:i.id,schedule:e,currentSeason:s!=null?s:void 0,currentEpisode:a!=null?a:void 0,totalSeasons:n!=null?n:void 0,totalEpisodes:r!=null?r:void 0,dateAdded:new Date().toISOString()};await this.dataManager.addAirtimeEntry(o);let l=this.dataManager.getTitle(i.id);if(l){let d=!1;if(r!==null&&r!==l.totalEpisodes&&(l.totalEpisodes=r,d=!0),e.recurrence==="once"){let u=(c=e.releaseDate)!=null?c:null;l.releaseDate!==u&&(l.releaseDate=u,d=!0)}d&&await this.dataManager.updateTitle(l)}this.render()}).open()}renderCards(){let i=this.dataManager.getAirtimeEntries();if(i.length===0){this.container.createDiv({cls:"wl-empty-state",text:"No titles in Upcoming. Click + Add to track airing schedules."});return}let t=this.searchQuery.trim().toLowerCase(),e=i.map(a=>{let n=this.resolveEntry(a);if(!n||t&&!n.title.toLowerCase().includes(t))return null;let r=ui(a.schedule,n.isSingle,a.lastAcknowledgedDate);return{entry:a,r:n,countdown:r}}).filter(a=>a!==null).sort((a,n)=>{let r=c=>c==="aired"||c==="due"?0:c==="today-before"?1:2,o=r(a.countdown.kind),l=r(n.countdown.kind);return o!==l?o-l:a.countdown.daysUntil-n.countdown.daysUntil});if(e.length===0){this.container.createDiv({cls:"wl-empty-state",text:"No upcoming titles match your search."});return}let s=this.container.createDiv({cls:"wl-airtime-cards"});for(let{entry:a,r:n,countdown:r}of e)this.renderCard(s,a,n,r)}renderCard(i,t,e,s){let a=e.isSingle,n=e.totalUnits,r=!a&&t.currentEpisode!==void 0&&n>0&&t.currentEpisode>=n,o=a&&s.kind==="due"||!a&&s.kind==="aired",l="wl-airtime-card";(s.kind==="aired"||s.kind==="due")&&(l+=" wl-airtime-card-aired"),s.kind==="aired"&&(l+=" is-aired"),s.kind==="due"&&(l+=" is-due"),this.selectionMode&&this.selectedItems.has(t.id)&&(l+=" wl-row-selected");let c=i.createDiv({cls:l});if(this.selectionMode){let S=c.createEl("input",{attr:{type:"checkbox"}});S.addClass("wl-airtime-select-cb"),S.checked=this.selectedItems.has(t.id),S.addEventListener("click",k=>k.stopPropagation()),S.addEventListener("change",()=>{S.checked?this.selectedItems.add(t.id):this.selectedItems.delete(t.id),this.render()}),c.addEventListener("click",()=>{this.selectedItems.has(t.id)?this.selectedItems.delete(t.id):this.selectedItems.add(t.id),this.render()})}let d=c.createDiv({cls:"wl-airtime-card-left"});d.createDiv({cls:"wl-airtime-card-title",text:e.title});let u=d.createDiv({cls:"wl-airtime-card-meta"}),h=u.createSpan({cls:e.typeColor?"wl-badge wl-badge-sm":"wl-badge-plain",text:e.typeName});if(e.typeColor&&(h.style.backgroundColor=e.typeColor),u.createSpan({cls:"wl-airtime-schedule",text:Ui(t.schedule)}),!a&&(t.currentSeason!==void 0||t.currentEpisode!==void 0)){let S=[];t.currentSeason!==void 0&&S.push(`${e.groupNounCap} ${t.currentSeason}`),t.currentEpisode!==void 0&&S.push(`${e.unitNounCap} ${t.currentEpisode}`),S.push(e.nextLabel);let k=r?"wl-ep-badge wl-ep-badge-final":"wl-ep-badge";d.createDiv({cls:k,text:S.join(" \xB7 ")})}let p=c.createDiv({cls:"wl-airtime-card-right"}),m={"today-before":"wl-airtime-pill wl-airtime-pill-today-series",future:"wl-airtime-pill wl-airtime-pill-days",aired:"wl-airtime-pill wl-airtime-pill-aired",due:"wl-airtime-pill wl-airtime-pill-due"},v=s.kind==="future"&&s.label==="Tomorrow"?"wl-airtime-pill wl-airtime-pill-tomorrow":m[s.kind];p.createDiv({cls:v,text:s.label});let f=p.createDiv({cls:"wl-airtime-actions"});if(o){let S=f.createEl("button",{cls:"wl-airtime-action-btn wl-airtime-action-btn-tick",text:"\u2713"});S.title=a?"Mark as released":r?`Final ${e.unitNoun} \u2014 mark done`:`Mark ${e.unitNoun} as aired`,S.addEventListener("click",k=>{var D;k.stopPropagation();let E=a?`"${e.title}" has been released. + `;try{return(s=(e=(await this.throttleAniList(()=>this.postJsonWithTimeout(Ss,{query:t,variables:{id:i}}))).data)==null?void 0:e.Media)!=null?s:null}catch(a){return null}}async searchAnime(i){var e;let t=`${qt}/anime?q=${encodeURIComponent(i)}&limit=10&sfw=false`;try{return((e=(await this.fetchWithTimeout(t)).data)!=null?e:[]).map(a=>this.mapJikanAnime(a))}catch(s){return[]}}jikanTrailerUrl(i){var e;if(!i)return"none";let t=((e=i.youtube_id)!=null?e:"")||Cs(i.url)||Cs(i.embed_url);return t?Fe(t):"none"}mapJikanAnime(i){var r,o,l,c,d,u,h,p,m,f,y;let e=((r=i.duration)!=null?r:"24 min per ep").match(/(\d+)\s*min/),s=e&&e[1]?parseInt(e[1]):24,a=(o=i.episodes)!=null?o:0,n=a>0?[{name:"Season 1",episodes:a,offset:0}]:[];return{malId:i.mal_id,title:(l=i.title_english)!=null?l:i.title,episodes:a,duration:s,releaseDate:(c=i.aired)!=null&&c.from&&(d=i.aired.from.split("T")[0])!=null?d:"",url:i.url,seasons:n,posterUrl:(y=(f=(h=(u=i.images)==null?void 0:u.jpg)==null?void 0:h.small_image_url)!=null?f:(m=(p=i.images)==null?void 0:p.jpg)==null?void 0:m.image_url)!=null?y:void 0,trailerUrl:this.jikanTrailerUrl(i.trailer)}}async searchOmdb(i,t){var s;if(!this.omdbApiKey)return[];let e=`${At}/?s=${encodeURIComponent(i)}&type=${t}&apikey=${encodeURIComponent(this.omdbApiKey)}`;try{let a=await this.fetchWithTimeout(e);return a.Response==="False"?[]:((s=a.Search)!=null?s:[]).slice(0,10).map(n=>({imdbId:n.imdbID,title:n.Title,mediaType:t==="movie"?"movie":"tv",episodes:t==="movie"?1:0,episodeDuration:0,releaseDate:n.Year?`${n.Year}-01-01`:"",url:`https://www.imdb.com/title/${n.imdbID}`,seasons:[]}))}catch(a){return[]}}async getOmdbMovieDetails(i){var e;if(!this.omdbApiKey)return null;let t=`${At}/?i=${encodeURIComponent(i)}&apikey=${encodeURIComponent(this.omdbApiKey)}`;try{let s=await this.fetchWithTimeout(t);if(s.Response==="False"||!s.imdbID)return null;let a=s.Runtime?parseInt(s.Runtime.replace(/[^0-9]/g,"")):120;return{imdbId:s.imdbID,title:s.Title,mediaType:"movie",episodes:1,episodeDuration:isNaN(a)?120:a,releaseDate:this.parseOmdbDate((e=s.Released)!=null?e:s.Year),url:`https://www.imdb.com/title/${s.imdbID}`,seasons:[{name:"Movie",episodes:1,offset:0}],trailerUrl:"none",director:Qt(s.Director),cast:Qt(s.Actors)}}catch(s){return null}}async getOmdbTvDetails(i){var e,s;if(!this.omdbApiKey)return null;let t=`${At}/?i=${encodeURIComponent(i)}&apikey=${encodeURIComponent(this.omdbApiKey)}`;try{let a=await this.fetchWithTimeout(t);if(a.Response==="False"||!a.imdbID)return null;let n=parseInt((e=a.totalSeasons)!=null?e:"1")||1,r=[],o=0;for(let c=1;c<=n;c++){let d=await this.getOmdbSeasonEpisodeCount(i,c);if(d===null)break;r.push({name:`Season ${c}`,episodes:d,offset:o}),o+=d}let l=r.reduce((c,d)=>c+d.episodes,0);return{imdbId:a.imdbID,title:a.Title,mediaType:"tv",episodes:l,episodeDuration:45,releaseDate:this.parseOmdbDate((s=a.Released)!=null?s:a.Year),url:`https://www.imdb.com/title/${a.imdbID}`,seasons:r,trailerUrl:"none",director:Qt(a.Director),cast:Qt(a.Actors)}}catch(a){return null}}async getOmdbSeasonEpisodeCount(i,t){var s;let e=`${At}/?i=${encodeURIComponent(i)}&Season=${t}&apikey=${encodeURIComponent(this.omdbApiKey)}`;try{let a=await this.fetchWithTimeout(e);return a.Response==="False"?null:((s=a.Episodes)!=null?s:[]).length}catch(a){return null}}async getAnimeScheduleByMalId(i){var t;try{let e=`${qt}/anime/${i}`,a=(t=(await this.fetchWithTimeout(e)).data)==null?void 0:t.broadcast;if(!(a!=null&&a.day)||!a.time)return null;let r={Mondays:1,Tuesdays:2,Wednesdays:3,Thursdays:4,Fridays:5,Saturdays:6,Sundays:0}[a.day];return r===void 0?null:{dayOfWeek:r,time:a.time}}catch(e){return null}}async getJikanTrailerByMalId(i){var t;try{let e=`${qt}/anime/${i}`,s=await this.throttleJikan(()=>this.fetchWithTimeout(e));return this.jikanTrailerUrl((t=s.data)==null?void 0:t.trailer)}catch(e){return"none"}}parseOmdbDate(i){let t={Jan:"01",Feb:"02",Mar:"03",Apr:"04",May:"05",Jun:"06",Jul:"07",Aug:"08",Sep:"09",Oct:"10",Nov:"11",Dec:"12"},e=i.match(/^(\d{2})\s+([A-Za-z]{3})\s+(\d{4})$/);if(e&&e[1]&&e[2]&&e[3]){let s=t[e[2]];if(s)return`${e[3]}-${s}-${e[1]}`}return i}async getOmdbByImdbId(i){if(!this.omdbApiKey)return null;let t=`${At}/?i=${encodeURIComponent(i)}&apikey=${encodeURIComponent(this.omdbApiKey)}`;try{let e=await this.fetchWithTimeout(t);return e.Response==="False"||!e.imdbID?null:e.Type==="movie"?this.getOmdbMovieDetails(i):this.getOmdbTvDetails(i)}catch(e){return null}}async searchTmdb(i,t){var a;if(!this.tmdbApiKey)return[];let s=`${pt}/search/${t==="movie"?"movie":"tv"}?query=${encodeURIComponent(i)}&page=1`;try{return((a=(await this.fetchWithTimeout(s,this.tmdbHeaders())).results)!=null?a:[]).slice(0,10).map(r=>{var o,l,c,d;return{imdbId:String(r.id),title:(l=(o=r.title)!=null?o:r.name)!=null?l:"",mediaType:t==="movie"?"movie":"tv",episodes:0,episodeDuration:0,releaseDate:(d=(c=r.release_date)!=null?c:r.first_air_date)!=null?d:"",url:"",seasons:[],posterUrl:r.poster_path?`https://image.tmdb.org/t/p/w92${r.poster_path}`:void 0}})}catch(n){return[]}}pickTmdbTrailer(i){var s,a;let t=(i!=null?i:[]).filter(n=>n.site==="YouTube"&&n.key),e=(a=(s=t.find(n=>n.type==="Trailer"&&n.official===!0))!=null?s:t.find(n=>n.type==="Trailer"))!=null?a:t.find(n=>n.type==="Teaser");return e?Fe(e.key):"none"}async getTmdbMovieDetails(i){var t,e,s,a,n;if(!this.tmdbApiKey)return null;try{let[r,o]=await Promise.all([this.fetchWithTimeout(`${pt}/movie/${i}?append_to_response=videos,credits`,this.tmdbHeaders()),this.fetchWithTimeout(`${pt}/movie/${i}/external_ids`,this.tmdbHeaders())]),l=r,d=(e=(t=o.imdb_id)!=null?t:l.imdb_id)!=null?e:"";return{imdbId:String(l.id),title:l.title,mediaType:"movie",episodes:1,episodeDuration:(s=l.runtime)!=null?s:120,releaseDate:(a=l.release_date)!=null?a:"",url:d?`https://www.imdb.com/title/${d}`:"",seasons:[{name:"Movie",episodes:1,offset:0}],trailerUrl:this.pickTmdbTrailer((n=l.videos)==null?void 0:n.results),...Ci(l.credits)}}catch(r){return null}}async getTmdbTvDetails(i){var t,e,s,a,n,r,o;if(!this.tmdbApiKey)return null;try{let[l,c]=await Promise.all([this.fetchWithTimeout(`${pt}/tv/${i}?append_to_response=videos,credits`,this.tmdbHeaders()),this.fetchWithTimeout(`${pt}/tv/${i}/external_ids`,this.tmdbHeaders())]),d=l,h=(t=c.imdb_id)!=null?t:"",p=((e=d.seasons)!=null?e:[]).filter(v=>v.season_number!==0),m=0,f=p.map(v=>{let w={name:v.name,episodes:v.episode_count,offset:m};return m+=v.episode_count,w}),y=f.reduce((v,w)=>v+w.episodes,0)||((s=d.number_of_episodes)!=null?s:0);return{imdbId:String(d.id),title:d.name,mediaType:"tv",episodes:y,episodeDuration:(n=((a=d.episode_run_time)!=null?a:[])[0])!=null?n:45,releaseDate:(r=d.first_air_date)!=null?r:"",url:h?`https://www.imdb.com/title/${h}`:"",seasons:f,trailerUrl:this.pickTmdbTrailer((o=d.videos)==null?void 0:o.results),...Ci(d.credits)}}catch(l){return null}}async getTmdbByImdbId(i){if(!this.tmdbApiKey)return null;let t=`${pt}/find/${encodeURIComponent(i)}?external_source=imdb_id`;try{let e=await this.fetchWithTimeout(t,this.tmdbHeaders());return e.movie_results&&e.movie_results.length>0?this.getTmdbMovieDetails(String(e.movie_results[0].id)):e.tv_results&&e.tv_results.length>0?this.getTmdbTvDetails(String(e.tv_results[0].id)):null}catch(e){return null}}parseOmdbVotes(i){if(!i||i==="N/A")return 0;let t=parseInt(i.replace(/,/g,""),10);return isNaN(t)?0:t}parseOmdbRating(i){if(!i||i==="N/A")return 0;let t=parseFloat(i);return isNaN(t)?0:t}extractImdbId(i){let t=i.match(/tt\d+/);return t?t[0]:""}async fetchMalRating(i){var t,e,s,a;try{let n=`${qt}/anime/${i}`,r=await this.fetchWithTimeout(n),o=(e=(t=r.data)==null?void 0:t.score)!=null?e:0,l=(a=(s=r.data)==null?void 0:s.scored_by)!=null?a:0;return!o&&!l?null:{rating:o,votes:l}}catch(n){return null}}async fetchAniListRating(i){var a,n;let t=await this.getAniListById(i);if(!t)return null;let e=(a=t.averageScore)!=null?a:0,s=(n=t.popularity)!=null?n:0;return!e&&!s?null:{rating:e,votes:s}}async fetchOmdbRating(i){if(!this.omdbApiKey)return null;try{let t=`${At}/?i=${encodeURIComponent(i)}&apikey=${encodeURIComponent(this.omdbApiKey)}`,e=await this.fetchWithTimeout(t);if(e.Response==="False")return null;let s=this.parseOmdbRating(e.imdbRating),a=this.parseOmdbVotes(e.imdbVotes);return!s&&!a?null:{rating:s,votes:a}}catch(t){return null}}async fetchTmdbRatingByImdb(i){var t,e;if(!this.tmdbApiKey)return null;try{let s=`${pt}/find/${encodeURIComponent(i)}?external_source=imdb_id`,a=await this.fetchWithTimeout(s,this.tmdbHeaders()),n=a.movie_results&&a.movie_results[0]||a.tv_results&&a.tv_results[0]||null;if(!n)return null;let r=(t=n.vote_average)!=null?t:0,o=(e=n.vote_count)!=null?e:0;return!r&&!o?null:{rating:r,votes:o}}catch(s){return null}}async fetchCommunityRating(i,t="jikan",e=""){var o,l,c;let s=((o=i.malId)!=null?o:0)>0,a=((l=i.anilistId)!=null?l:0)>0,n=e||(i.type==="Anime"?"anime":i.type==="Movie"||i.type==="TV Show"||i.type==="TvShow"?"movie":"");if(n==="")return null;if(n==="anime")if(t==="anilist"){if(a){let d=await this.fetchAniListRating(i.anilistId);if(d)return{...d,source:"anilist"}}if(s){let d=await this.fetchMalRating(i.malId);if(d)return{...d,source:"mal"}}}else{if(s){let d=await this.fetchMalRating(i.malId);if(d)return{...d,source:"mal"}}if(a){let d=await this.fetchAniListRating(i.anilistId);if(d)return{...d,source:"anilist"}}}let r=this.extractImdbId((c=i.externalLink)!=null?c:"");if(r){if(this.omdbApiKey){let d=await this.fetchOmdbRating(r);if(d)return{...d,source:"imdb"}}if(this.tmdbApiKey){let d=await this.fetchTmdbRatingByImdb(r);if(d)return{...d,source:"tmdb"}}}return null}async fetchTrailer(i,t="jikan",e=""){var a,n,r;let s=e||(i.type==="Anime"?"anime":i.type==="Movie"||i.type==="TV Show"||i.type==="TvShow"?"movie":"");if(s==="anime"){let o=((a=i.malId)!=null?a:0)>0,l=((n=i.anilistId)!=null?n:0)>0,c=async()=>{var p;if(!l)return"none";let h=await this.getAniListById(i.anilistId);return((p=h==null?void 0:h.trailer)==null?void 0:p.site)==="youtube"&&h.trailer.id?Fe(h.trailer.id):"none"},d=async()=>o?this.getJikanTrailerByMalId(i.malId):"none",u=t==="anilist"?[c,d]:[d,c];for(let h of u){let p=await h();if(p&&p!=="none")return p}return"none"}if(s==="movie"){let o=this.extractImdbId((r=i.externalLink)!=null?r:"");if(o&&this.tmdbApiKey){let l=await this.getTmdbByImdbId(o);if(l!=null&&l.trailerUrl&&l.trailerUrl!=="none")return l.trailerUrl}return"none"}return"none"}async fetchCredits(i,t="OMDb"){var r;let e=this.extractImdbId((r=i.externalLink)!=null?r:"");if(!e)return null;let s=async()=>{if(!this.omdbApiKey)return null;try{let o=`${At}/?i=${encodeURIComponent(e)}&apikey=${encodeURIComponent(this.omdbApiKey)}`,l=await this.fetchWithTimeout(o);return l.Response==="False"||!l.imdbID?null:{director:Qt(l.Director),cast:Qt(l.Actors)}}catch(o){return null}},a=async()=>{var o,l,c,d;if(!this.tmdbApiKey)return null;try{let u=`${pt}/find/${encodeURIComponent(e)}?external_source=imdb_id`,h=await this.fetchWithTimeout(u,this.tmdbHeaders()),p=(l=(o=h.movie_results)==null?void 0:o[0])==null?void 0:l.id,m=(d=(c=h.tv_results)==null?void 0:c[0])==null?void 0:d.id,f=p!==void 0?`movie/${p}`:m!==void 0?`tv/${m}`:null;if(!f)return null;let y=await this.fetchWithTimeout(`${pt}/${f}/credits`,this.tmdbHeaders());return Ci(y)}catch(u){return null}},n=t==="TMDB"?[a,s]:[s,a];for(let o of n){let l=await o();if(l)return l}return null}googleCoverUrl(i){var s,a,n,r,o,l;let t=i.imageLinks;if(!t)return"";let e=(l=(o=(r=(n=(a=(s=t.extraLarge)!=null?s:t.large)!=null?a:t.medium)!=null?n:t.small)!=null?r:t.thumbnail)!=null?o:t.smallThumbnail)!=null?l:"";return e?e.replace(/^http:/,"https:").replace(/&edge=curl/g,""):""}googleReleaseDate(i){return i?/^\d{4}-\d{2}-\d{2}$/.test(i)?i:/^\d{4}-\d{2}$/.test(i)?`${i}-01`:/^\d{4}$/.test(i)?`${i}-01-01`:i:""}mapGoogleVolume(i){var n,r,o,l,c,d,u,h,p;let t=(n=i.volumeInfo)!=null?n:{},e=(r=t.publishedDate)!=null?r:"",s=e&&parseInt(e.slice(0,4),10)||0;return{title:t.subtitle?`${(o=t.title)!=null?o:""}: ${t.subtitle}`:(l=t.title)!=null?l:"",author:((c=t.authors)!=null?c:[]).join(", "),year:s,totalPages:(d=t.pageCount)!=null?d:0,coverUrl:this.googleCoverUrl(t),googleBooksId:(u=i.id)!=null?u:"",releaseDate:this.googleReleaseDate(e),url:(p=(h=t.infoLink)!=null?h:t.canonicalVolumeLink)!=null?p:""}}async googleBooksFetch(i){var r;let t=this.googleBooksApiKey.trim();if(!t)throw new gt("no-key","Google Books API key not set");let e=i.includes("?")?"&":"?",s=`${Ma}${i}${e}key=${encodeURIComponent(t)}`,a=null,n=new Promise((o,l)=>{a=window.setTimeout(()=>l(new gt("network","Request timed out")),Ti)});try{let o=(0,$e.requestUrl)({url:s,throw:!1}).then(l=>{if(l.status===429||l.status===403)throw new gt("rate-limited",`Google Books returned ${l.status}`,l.status);if(l.status<200||l.status>=300)throw new gt("http",`Google Books returned ${l.status}`,l.status);try{return l.json}catch(c){throw new gt("parse","Failed to parse Google Books response")}});return await Promise.race([o,n])}catch(o){throw o instanceof gt?o:new gt("network",(r=o==null?void 0:o.message)!=null?r:"Network error")}finally{a!==null&&window.clearTimeout(a)}}async searchGoogleBooks(i){var e;return((e=(await this.googleBooksFetch(`/volumes?q=${encodeURIComponent(i)}&maxResults=10`)).items)!=null?e:[]).slice(0,10).map(s=>this.mapGoogleVolume(s))}async checkGoogleBooksConnection(){let i=await this.googleBooksFetch("/volumes?q=tolkien&maxResults=1");return Array.isArray(i.items)}mapJikanManga(i){var s,a,n,r,o,l,c,d,u,h,p,m;let t=(a=(s=i.published)==null?void 0:s.from)!=null?a:"",e=t&&parseInt(t.slice(0,4),10)||0;return{malId:i.mal_id,title:(n=i.title_english)!=null?n:i.title,author:((r=i.authors)!=null?r:[]).map(f=>f.name).join(", "),year:e,totalChapters:(o=i.chapters)!=null?o:0,totalVolumes:(l=i.volumes)!=null?l:0,coverUrl:(u=(d=(c=i.images)==null?void 0:c.jpg)==null?void 0:d.image_url)!=null?u:"",releaseDate:(h=i.published)!=null&&h.from&&(p=i.published.from.split("T")[0])!=null?p:"",url:(m=i.url)!=null?m:`https://myanimelist.net/manga/${i.mal_id}`}}async searchManga(i){var e;let t=`${qt}/manga?q=${encodeURIComponent(i)}&limit=10`;try{return((e=(await this.throttleJikan(()=>this.fetchWithTimeout(t))).data)!=null?e:[]).map(a=>this.mapJikanManga(a))}catch(s){return[]}}async getMangaByMalId(i){let t=`${qt}/manga/${i}`;try{let e=await this.throttleJikan(()=>this.fetchWithTimeout(t));return e.data?this.mapJikanManga(e.data):null}catch(e){return null}}async getGoogleBookById(i){if(!i)return null;let t=await this.googleBooksFetch(`/volumes/${encodeURIComponent(i)}`);return!t||!t.id?null:this.mapGoogleVolume(t)}async checkTmdbConnection(){if(!this.tmdbApiKey)return!1;try{let i=`${pt}/movie/550`;return(await this.fetchWithTimeout(i,this.tmdbHeaders())).id!==void 0}catch(i){return!1}}async checkOmdbConnection(){if(!this.omdbApiKey)return!1;try{let i=`${At}/?i=tt0111161&apikey=${encodeURIComponent(this.omdbApiKey)}`;return(await this.fetchWithTimeout(i)).Response==="True"}catch(i){return!1}}};var Li=require("obsidian");var ks="https://api.jikan.moe/v4",ki="https://www.omdbapi.com",Mi="https://api.themoviedb.org/3",xi="https://image.tmdb.org/t/p/w300",xa="https://graphql.anilist.co",Ms=8e3,La=400,Ra=700,Aa=30,Ia=100,We=class{constructor(i,t){this.queue=[];this.isProcessing=!1;this.disposed=!1;this.dataManager=i,this.getSettings=t}destroy(){this.disposed=!0,this.clearQueue()}enqueue(i){return new Promise(t=>{if(this.disposed){t(null);return}this.queue.push({title:i,resolve:t}),this.processQueue()})}clearQueue(){let i=this.queue.splice(0);for(let t of i)t.resolve(null)}async processQueue(){if(!this.isProcessing){for(this.isProcessing=!0;this.queue.length>0&&!this.disposed;){let i=this.queue.shift();if(!i)break;if(i.title.manualPosterUrl&&i.title.manualPosterUrl.trim()!==""){i.resolve(i.title.manualPosterUrl);continue}try{let e=await this.fetchPosterForTitle(i.title);if(this.disposed){i.resolve(null);break}let s=e||"none";this.dataManager.updatePosterUrl(i.title.id,s),i.resolve(e)}catch(e){this.disposed||this.dataManager.updatePosterUrl(i.title.id,"none"),i.resolve(null)}let t=this.getDelayForTitle(i.title);t>0&&await new Promise(e=>window.setTimeout(e,t))}this.isProcessing=!1}}getDelayForTitle(i){let t=this.getSettings();return tt(i.type,t.typeApiMapping)==="anime"?i.anilistId&&i.anilistId>0?Ra:La:t.tmdbApiKey?Aa:t.omdbApiKey?Ia:0}async fetchPosterForTitle(i){if(i.posterUrl&&i.posterUrl.startsWith("http"))return i.posterUrl;if(i.posterUrl==="none")return null;let t=this.getSettings(),e=tt(i.type,t.typeApiMapping);return e==="anime"?this.fetchAnimePoster(i):e==="movie"?this.fetchMediaPoster(i):null}cleanTitleForSearch(i){return i.replace(/\s*-?\s*[Ss]eason\s*\d+/gi,"").replace(/\s*-?\s*[Ss]eries\s*\d+/gi,"").replace(/\s*-?\s*[Pp]art\s*\d+/gi,"").replace(/\s*-?\s*[Vv]ol(ume)?\.?\s*\d+/gi,"").replace(/\s*\(\d{4}\)/g,"").replace(/\s*-?\s*[Ss]\d+/gi,"").replace(/\s+/g," ").trim()||i}async fetchAnimePoster(i){var r,o,l,c,d,u,h,p,m,f,y,v;if(i.anilistId&&i.anilistId>0){let b=await this.postJson(xa,{query:"query ($id: Int) { Media(id: $id, type: ANIME) { coverImage { large medium } } }",variables:{id:i.anilistId}}),E=(o=(r=b==null?void 0:b.data)==null?void 0:r.Media)==null?void 0:o.coverImage;return(c=(l=E==null?void 0:E.large)!=null?l:E==null?void 0:E.medium)!=null?c:null}if(i.malId){let w=`${ks}/anime/${i.malId}`,b=await this.fetchJson(w),E=(u=(d=b==null?void 0:b.data)==null?void 0:d.images)==null?void 0:u.jpg;return(p=(h=E==null?void 0:E.large_image_url)!=null?h:E==null?void 0:E.image_url)!=null?p:null}let t=encodeURIComponent(this.cleanTitleForSearch(i.title)),e=`${ks}/anime?q=${t}&limit=1`,s=await this.fetchJson(e),a=(m=s==null?void 0:s.data)==null?void 0:m[0],n=(f=a==null?void 0:a.images)==null?void 0:f.jpg;return(v=(y=n==null?void 0:n.large_image_url)!=null?y:n==null?void 0:n.image_url)!=null?v:null}extractImdbId(i){let t=(i!=null?i:"").match(/tt\d+/);return t?t[0]:""}getReleaseYear(i){var e;let t=((e=i.releaseDate)!=null?e:"").match(/^(\d{4})/);return t&&t[1]?parseInt(t[1],10):null}resolveMediaKind(i){if(i.type==="Movie")return"movie";if(i.type==="TV Show"||i.type==="TvShow")return"tv";let t=i.totalEpisodes;return t===1?"movie":t>1?"tv":null}pickTmdbPoster(i,t){var s;if(!i||i.length===0)return null;if(t!==null){let a=String(t),n=i.find(r=>{var l,c;return((c=(l=r.release_date)!=null?l:r.first_air_date)!=null?c:"").startsWith(a)&&r.poster_path});if(n!=null&&n.poster_path)return n.poster_path}let e=i.find(a=>a.poster_path);return(s=e==null?void 0:e.poster_path)!=null?s:null}async fetchMediaPoster(i){var r,o,l,c,d,u;let t=this.getSettings(),e=this.cleanTitleForSearch(i.title),s=this.extractImdbId(i.externalLink),a=this.getReleaseYear(i),n=this.resolveMediaKind(i);if(t.tmdbApiKey){let h={Authorization:`Bearer ${t.tmdbApiKey}`};if(s){let v=`${Mi}/find/${encodeURIComponent(s)}?external_source=imdb_id`,w=await this.fetchJson(v,h),b=(c=(l=(r=w==null?void 0:w.movie_results)==null?void 0:r[0])!=null?l:(o=w==null?void 0:w.tv_results)==null?void 0:o[0])!=null?c:null;if(b!=null&&b.poster_path)return`${xi}${b.poster_path}`}if(n!==null){let v=n==="movie"?"movie":"tv",w=encodeURIComponent(e),b=`${Mi}/search/${v}?query=${w}&page=1`,E=await this.fetchJson(b,h),D=this.pickTmdbPoster(E==null?void 0:E.results,a);return D?`${xi}${D}`:null}let p=encodeURIComponent(e),m=`${Mi}/search/multi?query=${p}&page=1`,f=await this.fetchJson(m,h),y=(u=(d=f==null?void 0:f.results)==null?void 0:d[0])==null?void 0:u.poster_path;return y?`${xi}${y}`:null}if(t.omdbApiKey){let h=encodeURIComponent(t.omdbApiKey);if(s){let v=`${ki}/?i=${encodeURIComponent(s)}&apikey=${h}`,w=await this.fetchJson(v),b=w==null?void 0:w.Poster;if(b&&b!=="N/A")return b}let p=encodeURIComponent(e);if(n!==null){let w=`${ki}/?t=${p}&type=${n==="movie"?"movie":"series"}&apikey=${h}`,b;if(a!==null){let E=await this.fetchJson(`${w}&y=${a}`);b=E==null?void 0:E.Poster}if(!b||b==="N/A"){let E=await this.fetchJson(w);b=E==null?void 0:E.Poster}return b&&b!=="N/A"?b:null}let m=`${ki}/?t=${p}&apikey=${h}`,f=await this.fetchJson(m),y=f==null?void 0:f.Poster;return y&&y!=="N/A"?y:null}return null}async fetchJson(i,t){let e=null,s=new Promise((a,n)=>{e=window.setTimeout(()=>n(new Error("Request timed out")),Ms)});try{let a=(0,Li.requestUrl)({url:i,headers:t}).then(n=>n.json);return await Promise.race([a,s])}finally{e!==null&&window.clearTimeout(e)}}async postJson(i,t,e){let s=null,a=new Promise((n,r)=>{s=window.setTimeout(()=>r(new Error("Request timed out")),Ms)});try{let n=(0,Li.requestUrl)({url:i,method:"POST",headers:{"Content-Type":"application/json",...e!=null?e:{}},body:JSON.stringify(t)}).then(r=>r.json);return await Promise.race([n,a])}finally{s!==null&&window.clearTimeout(s)}}};var ut=require("obsidian");var xs=2*Math.PI*45,Oe=class{constructor(i,t,e,s){this.container=i,this.plugin=t,this.dataManager=e,this.readingData=s}render(){this.container.empty(),this.container.addClass("wl-dashboard");let i=this.dataManager.getTitles(),t=new Map;for(let c of i){let d=t.get(c.type);d?d.push(c):t.set(c.type,[c])}let e=i.filter(c=>c.status==="Plan to watch"),s=this.readingData.getBooks(),a=this.readingData.getMangaList(),n=i.length+s.length+a.length,r=i.reduce((c,d)=>c+(d.status==="Completed"?1:0),0)+s.reduce((c,d)=>c+(d.status==="Completed"?1:0),0)+a.reduce((c,d)=>c+(d.status==="Completed"?1:0),0),o=this.aggregateBooks(s),l=this.aggregateManga(a);this.renderCards(i,t,o,l),this.renderSummaryMetrics(n,r),this.renderSuggestions(e),this.renderRecentlyWatched(),this.renderRecentlyAdded()}statsFor(i){let t=new Set(["Dropped","To be released"]),e=0,s=0;for(let a of i)t.has(a.status)||(e++,a.status==="Completed"&&s++);return{watched:s,total:e}}renderCards(i,t,e,s){var d;let a=this.plugin.settings.dashboardCardStyle==="rectangles",n=this.container.createDiv({cls:"wl-rings-grid"}),r=this.statsFor(i),o=r.total===0?0:Math.round(r.watched/r.total*100),l=this.dataManager.getTotalTimeWatched(),c=this.dataManager.getTotalTimeRemaining();this.renderUnifiedCard(n,a,o,r,j(l),j(c));for(let u of this.plugin.settings.types){let h=this.statsFor((d=t.get(u.name))!=null?d:[]),p=h.total===0?0:Math.round(h.watched/h.total*100);if(a){let m=n.createDiv({cls:"wl-rect-item"});this.fillRect(m,u.name,u.color,p,h),m.createDiv({cls:"wl-rect-subline",text:"\xA0"})}else{let m=n.createDiv({cls:"wl-ring-item"});this.fillRing(m,u.name,u.color,p,h),m.createDiv({cls:"wl-ring-subtitle wl-ring-subline",text:"\xA0"})}}this.renderReadingCard(n,a,"Books",e),this.renderReadingCard(n,a,"Manga",s)}renderUnifiedCard(i,t,e,s,a,n){let r=i.createDiv({cls:t?"wl-dash-unified wl-dash-unified-bordered":"wl-dash-unified"}),o=r.createDiv({cls:t?"wl-dash-seg":"wl-dash-seg wl-dash-seg-center"});t?this.fillRect(o,"Total","#7F77DD",e,s):this.fillRing(o.createDiv({cls:"wl-ring-item"}),"Total","#7F77DD",e,s),this.renderTimeSegment(r,"Time Watched",a),this.renderTimeSegment(r,"Time Remaining",n)}renderTimeSegment(i,t,e){let s=i.createDiv({cls:"wl-dash-seg wl-dash-seg-center"});s.createDiv({cls:"wl-dash-seg-label",text:t}),s.createDiv({cls:"wl-dash-seg-value",text:e})}aggregateBooks(i){let t={left:0,read:0,total:0,volumesRead:0,totalVolumes:0};for(let e of i)e.status!=="To be released"&&((e.status==="Reading"||e.status==="Plan to Read")&&t.left++,t.read+=e.pagesRead,t.total+=e.totalPages);return t}aggregateManga(i){let t={left:0,read:0,total:0,volumesRead:0,totalVolumes:0};for(let e of i)e.status!=="To be released"&&((e.status==="Reading"||e.status==="Plan to Read")&&t.left++,t.read+=e.chaptersRead,t.total+=e.totalChapters,t.volumesRead+=e.volumesRead,t.totalVolumes+=e.totalVolumes);return t}renderReadingCard(i,t,e,s){let a=s.total>0?Math.round(s.read/s.total*100):0,n=Pe(e==="Books"?"book":"manga",this.plugin.settings),r=e==="Books"?`${s.read} / ${s.total} pages`:`${s.read} / ${s.total} chapters \xB7 ${s.volumesRead} / ${s.totalVolumes} vol`;if(t){let o=i.createDiv({cls:"wl-rect-item"}),l=o.createDiv({cls:"wl-rect-top"});l.createSpan({cls:"wl-rect-label",text:e}),l.createSpan({cls:"wl-rect-unwatched",text:`${s.left} left`}),o.createDiv({cls:"wl-rect-value",text:`${a}%`});let d=o.createDiv({cls:"wl-rect-bar-wrap"}).createDiv({cls:"wl-rect-bar"});d.style.width=`${a}%`,d.style.backgroundColor=n,o.createDiv({cls:"wl-rect-subline",text:r})}else{let o=i.createDiv({cls:"wl-ring-item"}),l=this.makeRingSvg(a,n,`${a}%`,"",!0);o.appendChild(l),o.createDiv({cls:"wl-ring-label",text:e}),o.createDiv({cls:"wl-ring-subtitle",text:`${s.left} left`}),o.createDiv({cls:"wl-ring-subtitle wl-ring-subline",text:r})}}makeRingSvg(i,t,e,s,a=!1){let n="http://www.w3.org/2000/svg",r=activeDocument.createElementNS(n,"svg");r.setAttribute("viewBox","0 0 120 120"),r.setAttribute("width","110"),r.setAttribute("height","110"),r.addClass("wl-ring-svg");let o=activeDocument.createElementNS(n,"circle");o.setAttribute("cx","60"),o.setAttribute("cy","60"),o.setAttribute("r","45"),o.setAttribute("fill","none"),o.setAttribute("stroke-width","10"),o.addClass("wl-ring-track"),r.appendChild(o);let l=activeDocument.createElementNS(n,"circle");l.setAttribute("cx","60"),l.setAttribute("cy","60"),l.setAttribute("r","45"),l.setAttribute("fill","none"),a?l.style.stroke=t:l.setAttribute("stroke",t),l.setAttribute("stroke-width","10"),l.setAttribute("stroke-linecap","round"),l.setAttribute("stroke-dasharray",String(xs)),l.setAttribute("stroke-dashoffset",String(xs*(1-i/100))),l.setAttribute("transform","rotate(-90 60 60)"),l.addClass("wl-ring-arc"),r.appendChild(l);let c=activeDocument.createElementNS(n,"text");if(c.setAttribute("x","60"),c.setAttribute("y",s?"55":"60"),c.setAttribute("text-anchor","middle"),c.setAttribute("dominant-baseline","middle"),c.addClass("wl-ring-percent-text"),c.textContent=e,r.appendChild(c),s){let d=activeDocument.createElementNS(n,"text");d.setAttribute("x","60"),d.setAttribute("y","72"),d.setAttribute("text-anchor","middle"),d.addClass("wl-ring-sub-text"),d.textContent=s,r.appendChild(d)}return r}fillRing(i,t,e,s,a){let n=this.makeRingSvg(s,e,`${s}%`,`${a.watched}/${a.total}`);i.appendChild(n),i.createDiv({cls:"wl-ring-label",text:t});let r=a.total-a.watched;i.createDiv({cls:"wl-ring-subtitle",text:`${r} unwatched`})}fillRect(i,t,e,s,a){let n=i.createDiv({cls:"wl-rect-top"});n.createSpan({cls:"wl-rect-label",text:t});let r=a.total-a.watched;n.createSpan({cls:"wl-rect-unwatched",text:`${r} left`}),i.createDiv({cls:"wl-rect-value",text:`${s}%`});let l=i.createDiv({cls:"wl-rect-bar-wrap"}).createDiv({cls:"wl-rect-bar"});l.style.width=`${s}%`,l.style.backgroundColor=e}renderSummaryMetrics(i,t){let e=this.container.createDiv({cls:"wl-summary-metrics"});this.renderMetricRow(e,"Titles in library",String(i)),this.renderMetricRow(e,"Completed",String(t))}renderMetricRow(i,t,e){let s=i.createDiv({cls:"wl-metric-row"});s.createSpan({cls:"wl-metric-label",text:t}),s.createSpan({cls:"wl-metric-value",text:e})}renderSuggestions(i){if(i.length===0)return;let t=this.container.createDiv({cls:"wl-suggestions"});t.createDiv({cls:"wl-section-title",text:"Don't know what to watch next?"});let e=t.createDiv({cls:"wl-suggestions-grid"}),s=d=>{var h,p,m,f;let u=i.filter(y=>y.type===d).filter(y=>y.totalEpisodes>0||y.episodeDuration>0);return u.length===0?(p=(h=i.filter(v=>v.type===d)[0])==null?void 0:h.title)!=null?p:null:(u.sort((y,v)=>{let w=y.totalEpisodes>0?y.totalEpisodes*(y.episodeDuration||24):y.episodeDuration,b=v.totalEpisodes>0?v.totalEpisodes*(v.episodeDuration||24):v.episodeDuration;return w-b}),(f=(m=u[0])==null?void 0:m.title)!=null?f:null)},a=["Anime","Movie","TV Show"];for(let d of a){let u=s(d),h=e.createDiv({cls:"wl-suggestion-card"});h.createDiv({cls:"wl-suggestion-label",text:`Shortest ${d}`}),h.createDiv({cls:`wl-suggestion-title${u?"":" wl-suggestion-empty"}`,text:u!=null?u:"Nothing planned"})}let n=e.createDiv({cls:"wl-suggestion-card"}),r=n.createDiv({cls:"wl-suggestion-random-header"});r.createDiv({cls:"wl-suggestion-label",text:"Random"});let o=r.createEl("button",{cls:"wl-suggestion-shuffle",text:"\u{1F500}"});o.title="Pick another";let l=()=>{var d,u;return(u=(d=i[Math.floor(Math.random()*i.length)])==null?void 0:d.title)!=null?u:""},c=n.createDiv({cls:"wl-suggestion-title",text:l()});o.addEventListener("click",()=>{c.textContent=l()})}renderRecentlyWatched(){let i=this.container.createDiv({cls:"wl-recently-watched"});i.createDiv({cls:"wl-section-title",text:"Recently watched"});let t=this.dataManager.getRecentlyWatched(3);if(t.length===0){i.createDiv({cls:"wl-empty-state",text:"No titles watched yet."});return}for(let e of t){let s=i.createDiv({cls:"wl-rw-item"});s.createDiv({cls:"wl-rw-title",text:e.title});let a=this.getTagDef(e.type,this.plugin.settings.types),n=this.plugin.settings.coloredTypeBadges,o=s.createDiv({cls:"wl-rw-col-badge"}).createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:e.type});n&&a&&(o.style.backgroundColor=N(e.type,a.color,this.plugin.settings.colorTheme));let l=s.createDiv({cls:"wl-rw-col-ep"}),c=e.type==="Movie";if(!c){let u=this.dataManager.getNextUnwatchedEpisode(e);l.textContent=u!==null?`Ep ${u}`:"\u2713"}let d=s.createDiv({cls:"wl-rw-col-pct"});c?d.textContent=e.watchedEpisodes.includes(1)?"100%":"0%":d.textContent=`${this.dataManager.getProgress(e)}%`}}renderRecentlyAdded(){let i=this.container.createDiv({cls:"wl-recently-watched"});i.createDiv({cls:"wl-section-title",text:"Recently added"});let t=this.dataManager.getRecentlyAdded(3);if(t.length===0){i.createDiv({cls:"wl-empty-state",text:"No titles in your library yet."});return}for(let e of t){let s=i.createDiv({cls:"wl-rw-item"});s.createDiv({cls:"wl-rw-title",text:e.title});let a=this.getTagDef(e.type,this.plugin.settings.types),n=this.plugin.settings.coloredTypeBadges,o=s.createDiv({cls:"wl-rw-col-badge"}).createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:e.type});n&&a&&(o.style.backgroundColor=N(e.type,a.color,this.plugin.settings.colorTheme));let l=s.createDiv({cls:"wl-rw-col-ep"}),c=e.type==="Movie";if(!c){let u=this.dataManager.getNextUnwatchedEpisode(e);l.textContent=u!==null?`Ep ${u}`:"\u2713"}let d=s.createDiv({cls:"wl-rw-col-pct"});c?d.textContent=e.watchedEpisodes.includes(1)?"100%":"0%":d.textContent=`${this.dataManager.getProgress(e)}%`}}getTagDef(i,t){return t.find(e=>e.name===i)}};var qs=require("obsidian");function Pt(g){return Array.isArray?Array.isArray(g):$s(g)==="[object Array]"}function Pa(g){if(typeof g=="string")return g;if(typeof g=="bigint")return g.toString();let i=g+"";return i=="0"&&1/g==-1/0?"-0":i}function Ri(g){return g==null?"":Pa(g)}function J(g){return typeof g=="string"}function Ne(g){return typeof g=="number"}function Ba(g){return g===!0||g===!1||Fa(g)&&$s(g)=="[object Boolean]"}function Fs(g){return typeof g=="object"}function Fa(g){return Fs(g)&&g!==null}function et(g){return g!=null}function He(g){return!g.trim().length}function $s(g){return g==null?g===void 0?"[object Undefined]":"[object Null]":Object.prototype.toString.call(g)}var $a="Incorrect 'index' type",Wa=g=>`Invalid value for key ${g}`,Oa=g=>`Pattern length exceeds max of ${g}.`,Ha=g=>`Missing ${g} property in key`,Na=g=>`Property 'weight' in key '${g}' must be a positive integer`,Ls=Object.prototype.hasOwnProperty,Ai=class{constructor(i){this._keys=[],this._keyMap={};let t=0;i.forEach(e=>{let s=Ws(e);this._keys.push(s),this._keyMap[s.id]=s,t+=s.weight}),this._keys.forEach(e=>{e.weight/=t})}get(i){return this._keyMap[i]}keys(){return this._keys}toJSON(){return JSON.stringify(this._keys)}};function Ws(g){let i=null,t=null,e=null,s=1,a=null;if(J(g)||Pt(g))e=g,i=Rs(g),t=Ii(g);else{if(!Ls.call(g,"name"))throw new Error(Ha("name"));let n=g.name;if(e=n,Ls.call(g,"weight")&&(s=g.weight,s<=0))throw new Error(Na(n));i=Rs(n),t=Ii(n),a=g.getFn}return{path:i,id:t,weight:s,src:e,getFn:a}}function Rs(g){return Pt(g)?g:g.split(".")}function Ii(g){return Pt(g)?g.join("."):g}function _a(g,i){let t=[],e=!1,s=(a,n,r,o)=>{if(et(a))if(!n[r])t.push(o!==void 0?{v:a,i:o}:a);else{let l=n[r],c=a[l];if(!et(c))return;if(r===n.length-1&&(J(c)||Ne(c)||Ba(c)||typeof c=="bigint"))t.push(o!==void 0?{v:Ri(c),i:o}:Ri(c));else if(Pt(c)){e=!0;for(let d=0,u=c.length;dg.score===i.score?g.idx{this._keysMap[t.id]=e})}create(){this.isCreated||!this.docs.length||(this.isCreated=!0,J(this.docs[0])?this.docs.forEach((i,t)=>{this._addString(i,t)}):this.docs.forEach((i,t)=>{this._addObject(i,t)}),this.norm.clear())}add(i){let t=this.size();J(i)?this._addString(i,t):this._addObject(i,t)}removeAt(i){this.records.splice(i,1);for(let t=i,e=this.size();t=0;t-=1)this.records.splice(i[t],1);for(let t=0,e=this.records.length;t{let n=s.getFn?s.getFn(i):this.getFn(i,s.path);if(et(n)){if(Pt(n)){let r=[];for(let o=0,l=n.length;ot),records:this.records}}};function Os(g,i,{getFn:t=F.getFn,fieldNormWeight:e=F.fieldNormWeight}={}){let s=new pe({getFn:t,fieldNormWeight:e});return s.setKeys(g.map(Ws)),s.setSources(i),s.create(),s}function qa(g,{getFn:i=F.getFn,fieldNormWeight:t=F.fieldNormWeight}={}){let{keys:e,records:s}=g,a=new pe({getFn:i,fieldNormWeight:t});return a.setKeys(e),a.setIndexRecords(s),a}function Qa(g=[],i=F.minMatchCharLength){let t=[],e=-1,s=-1,a=0;for(let n=g.length;a=i&&t.push([e,s]),e=-1)}return g[a-1]&&a-e>=i&&t.push([e,a-1]),t}var Ht=32;function Ya(g,i,t,{location:e=F.location,distance:s=F.distance,threshold:a=F.threshold,findAllMatches:n=F.findAllMatches,minMatchCharLength:r=F.minMatchCharLength,includeMatches:o=F.includeMatches,ignoreLocation:l=F.ignoreLocation}={}){if(i.length>Ht)throw new Error(Oa(Ht));let c=i.length,d=g.length,u=Math.max(0,Math.min(e,d)),h=a,p=u,m=(T,M)=>{let x=T/c;if(l)return x;let C=Math.abs(u-M);return s?x+C/s:C?1:x},f=r>1||o,y=f?Array(d):[],v;for(;(v=g.indexOf(i,p))>-1;){let T=m(0,v);if(h=Math.min(T,h),p=v+c,f){let M=0;for(;M=C;k-=1){let R=k-1,P=t[g[R]];if(f&&(y[R]=+!!P),I[k]=(I[k+1]<<1|1)&P,T&&(I[k]|=(w[k+1]|w[k])<<1|1|w[k+1]),I[k]&D&&(b=m(T,R),b<=h)){if(h=b,p=R,p<=u)break;C=Math.max(1,2*u-p)}}if(m(T+1,u)>h)break;w=I}let S={isMatch:p>=0,score:Math.max(.001,b)};if(f){let T=Qa(y,r);T.length?o&&(S.indices=T):S.isMatch=!1}return S}function Ja(g){let i={};for(let t=0,e=g.length;tt[0]-e[0]||t[1]-e[1]);let i=[g[0]];for(let t=1,e=g.length;tg.normalize("NFD").replace(/[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F]/g,"").replace(Xa,i=>Hs[i]):g=>g,me=class{constructor(i,{location:t=F.location,threshold:e=F.threshold,distance:s=F.distance,includeMatches:a=F.includeMatches,findAllMatches:n=F.findAllMatches,minMatchCharLength:r=F.minMatchCharLength,isCaseSensitive:o=F.isCaseSensitive,ignoreDiacritics:l=F.ignoreDiacritics,ignoreLocation:c=F.ignoreLocation}={}){if(this.options={location:t,threshold:e,distance:s,includeMatches:a,findAllMatches:n,minMatchCharLength:r,isCaseSensitive:o,ignoreDiacritics:l,ignoreLocation:c},i=o?i:i.toLowerCase(),i=l?ge(i):i,this.pattern=i,this.chunks=[],!this.pattern.length)return;let d=(h,p)=>{this.chunks.push({pattern:h,alphabet:Ja(h),startIndex:p})},u=this.pattern.length;if(u>Ht){let h=0,p=u%Ht,m=u-p;for(;h{let{isMatch:v,score:w,indices:b}=Ya(i,m,f,{location:a+y,distance:n,threshold:r,findAllMatches:o,minMatchCharLength:l,includeMatches:s,ignoreLocation:c});v&&(h=!0),u+=w,v&&b&&d.push(...b)});let p={isMatch:h,score:h?u/this.chunks.length:1};return h&&s&&(p.indices=qi(d)),p}},mt=class{constructor(i){this.pattern=i}static isMultiMatch(i){return As(i,this.multiRegex)}static isSingleMatch(i){return As(i,this.singleRegex)}search(i){return{isMatch:!1,score:1}}};function As(g,i){let t=g.match(i);return t?t[1]:null}var Pi=class extends mt{constructor(i){super(i)}static get type(){return"exact"}static get multiRegex(){return/^="(.*)"$/}static get singleRegex(){return/^=(.*)$/}search(i){let t=i===this.pattern;return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}},Bi=class extends mt{constructor(i){super(i)}static get type(){return"inverse-exact"}static get multiRegex(){return/^!"(.*)"$/}static get singleRegex(){return/^!(.*)$/}search(i){let e=i.indexOf(this.pattern)===-1;return{isMatch:e,score:e?0:1,indices:[0,i.length-1]}}},Fi=class extends mt{constructor(i){super(i)}static get type(){return"prefix-exact"}static get multiRegex(){return/^\^"(.*)"$/}static get singleRegex(){return/^\^(.*)$/}search(i){let t=i.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}},$i=class extends mt{constructor(i){super(i)}static get type(){return"inverse-prefix-exact"}static get multiRegex(){return/^!\^"(.*)"$/}static get singleRegex(){return/^!\^(.*)$/}search(i){let t=!i.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,i.length-1]}}},Wi=class extends mt{constructor(i){super(i)}static get type(){return"suffix-exact"}static get multiRegex(){return/^"(.*)"\$$/}static get singleRegex(){return/^(.*)\$$/}search(i){let t=i.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[i.length-this.pattern.length,i.length-1]}}},Oi=class extends mt{constructor(i){super(i)}static get type(){return"inverse-suffix-exact"}static get multiRegex(){return/^!"(.*)"\$$/}static get singleRegex(){return/^!(.*)\$$/}search(i){let t=!i.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,i.length-1]}}},_e=class extends mt{constructor(i,{location:t=F.location,threshold:e=F.threshold,distance:s=F.distance,includeMatches:a=F.includeMatches,findAllMatches:n=F.findAllMatches,minMatchCharLength:r=F.minMatchCharLength,isCaseSensitive:o=F.isCaseSensitive,ignoreDiacritics:l=F.ignoreDiacritics,ignoreLocation:c=F.ignoreLocation}={}){super(i),this._bitapSearch=new me(i,{location:t,threshold:e,distance:s,includeMatches:a,findAllMatches:n,minMatchCharLength:r,isCaseSensitive:o,ignoreDiacritics:l,ignoreLocation:c})}static get type(){return"fuzzy"}static get multiRegex(){return/^"(.*)"$/}static get singleRegex(){return/^(.*)$/}search(i){return this._bitapSearch.searchIn(i)}},Ue=class extends mt{constructor(i){super(i)}static get type(){return"include"}static get multiRegex(){return/^'"(.*)"$/}static get singleRegex(){return/^'(.*)$/}search(i){let t=0,e,s=[],a=this.pattern.length;for(;(e=i.indexOf(this.pattern,t))>-1;)t=e+a,s.push([e,t-1]);let n=!!s.length;return{isMatch:n,score:n?0:1,indices:s}}},Hi=[Pi,Ue,Fi,$i,Oi,Wi,Bi,_e],Is=Hi.length,Za="\0",tn="|";function en(g){let i=[],t=g.length,e=0;for(;e=t)break;let s=e;for(;s=t||g[a]===" "){s++;break}if(g[a]==="$"&&(a+1>=t||g[a+1]===" ")){s+=2;break}}s++}i.push(g.substring(e,s)),e=s}else{for(;s{let s=e.replace(/\u0000/g,"|"),a=en(s.trim()).filter(r=>r&&!!r.trim()),n=[];for(let r=0,o=a.length;r!!(g[Ge.AND]||g[Ge.OR]),nn=g=>!!g[Ui.PATH],rn=g=>!Pt(g)&&Fs(g)&&!Vi(g),Ps=g=>({[Ge.AND]:Object.keys(g).map(i=>({[i]:g[i]}))});function Ns(g,i,{auto:t=!0}={}){let e=s=>{if(J(s)){let o={keyId:null,pattern:s};return t&&(o.searcher=Ve(s,i)),o}let a=Object.keys(s),n=nn(s);if(!n&&a.length>1&&!Vi(s))return e(Ps(s));if(rn(s)){let o=n?s[Ui.PATH]:a[0],l=n?s[Ui.PATTERN]:s[o];if(!J(l))throw new Error(Wa(o));let c={keyId:Ii(o),pattern:l};return t&&(c.searcher=Ve(l,i)),c}let r={children:[],operator:a[0]};return a.forEach(o=>{let l=s[o];Pt(l)&&l.forEach(c=>{r.children.push(e(c))})}),r};return Vi(g)||(g=Ps(g)),e(g)}function Gi(g,{ignoreFieldNorm:i=F.ignoreFieldNorm}){let t=1;return g.forEach(({key:e,norm:s,score:a})=>{let n=e?e.weight:null;t*=Math.pow(a===0&&n?Number.EPSILON:a,(n||1)*(i?1:s))}),t}function on(g,{ignoreFieldNorm:i=F.ignoreFieldNorm}){g.forEach(t=>{t.score=Gi(t.matches,{ignoreFieldNorm:i})})}var Ki=class{constructor(i){this.limit=i,this.heap=[]}get size(){return this.heap.length}shouldInsert(i){return this.size0;){let e=i-1>>1;if(t[i].score<=t[e].score)break;let s=t[i];t[i]=t[e],t[e]=s,i=e}}_sinkDown(i){let t=this.heap,e=t.length,s=i;do{i=s;let a=2*i+1,n=2*i+2;if(at[s].score&&(s=a),nt[s].score&&(s=n),s!==i){let r=t[i];t[i]=t[s],t[s]=r}}while(s!==i)}};function ln(g,i){let t=g.matches;i.matches=[],et(t)&&t.forEach(e=>{if(!et(e.indices)||!e.indices.length)return;let{indices:s,value:a}=e,n={indices:s,value:a};e.key&&(n.key=e.key.src),e.idx>-1&&(n.refIndex=e.idx),i.matches.push(n)})}function cn(g,i){i.score=g.score}function dn(g,i,{includeMatches:t=F.includeMatches,includeScore:e=F.includeScore}={}){let s=[];return t&&s.push(ln),e&&s.push(cn),g.map(a=>{let{idx:n}=a,r={item:i[n],refIndex:n};return s.length&&s.forEach(o=>{o(a,r)}),r})}var un=/\b\w+\b/g;function zi({isCaseSensitive:g=!1,ignoreDiacritics:i=!1}={}){return{tokenize(t){return g||(t=t.toLowerCase()),i&&(t=ge(t)),t.match(un)||[]}}}function hn(g,i,t){var r;let e=new Map,s=new Map,a=0;function n(o,l,c,d){let u=t.tokenize(o);if(!u.length)return;a++;let h=new Map;for(let p of u)h.set(p,(h.get(p)||0)+1);for(let[p,m]of h){let f={docIdx:l,keyIdx:c,subIdx:d,tf:m},y=e.get(p);y||(y=[],e.set(p,y)),y.push(f),s.set(p,(s.get(p)||0)+1)}}for(let o of g){let{i:l,v:c,$:d}=o;if(c!==void 0){n(c,l,-1,-1);continue}if(d)for(let u=0;un.docIdx!==i),a=e.length-s.length;a>0&&(g.fieldCount-=a,g.df.set(t,(g.df.get(t)||0)-a),s.length===0?(g.terms.delete(t),g.df.delete(t)):g.terms.set(t,s))}}var X=class{constructor(i,t,e){this.options={...F,...t},this.options.useExtendedSearch,this.options.useTokenSearch,this._keyStore=new Ai(this.options.keys),this._docs=i,this._myIndex=null,this._invertedIndex=null,this.setCollection(i,e),this._lastQuery=null,this._lastSearcher=null}_getSearcher(i){if(this._lastQuery===i)return this._lastSearcher;let t=this._invertedIndex?{...this.options,_invertedIndex:this._invertedIndex}:this.options,e=Ve(i,t);return this._lastQuery=i,this._lastSearcher=e,e}setCollection(i,t){if(this._docs=i,t&&!(t instanceof pe))throw new Error($a);if(this._myIndex=t||Os(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight}),this.options.useTokenSearch){let e=zi({isCaseSensitive:this.options.isCaseSensitive,ignoreDiacritics:this.options.ignoreDiacritics});this._invertedIndex=hn(this._myIndex.records,this._myIndex.keys.length,e)}}add(i){if(et(i)&&(this._docs.push(i),this._myIndex.add(i),this._invertedIndex)){let t=this._myIndex.records[this._myIndex.records.length-1],e=zi({isCaseSensitive:this.options.isCaseSensitive,ignoreDiacritics:this.options.ignoreDiacritics});pn(this._invertedIndex,t,this._myIndex.keys.length,e)}}remove(i=()=>!1){let t=[],e=[];for(let s=0,a=this._docs.length;s=0;s-=1)this._docs.splice(e[s],1);this._myIndex.removeAll(e)}return t}removeAt(i){this._invertedIndex&&Bs(this._invertedIndex,i);let t=this._docs.splice(i,1)[0];return this._myIndex.removeAt(i),t}getIndex(){return this._myIndex}search(i,t){let{limit:e=-1}=t||{},{includeMatches:s,includeScore:a,shouldSort:n,sortFn:r,ignoreFieldNorm:o}=this.options;if(J(i)&&!i.trim()){let d=this._docs.map((u,h)=>({item:u,refIndex:h}));return Ne(e)&&e>-1&&(d=d.slice(0,e)),d}let l=Ne(e)&&e>0&&J(i),c;if(l){let d=new Ki(e);J(this._docs[0])?this._searchStringList(i,{heap:d,ignoreFieldNorm:o}):this._searchObjectList(i,{heap:d,ignoreFieldNorm:o}),c=d.extractSorted(r)}else c=J(i)?J(this._docs[0])?this._searchStringList(i):this._searchObjectList(i):this._searchLogical(i),on(c,{ignoreFieldNorm:o}),n&&c.sort(r),Ne(e)&&e>-1&&(c=c.slice(0,e));return dn(c,this._docs,{includeMatches:s,includeScore:a})}_searchStringList(i,{heap:t,ignoreFieldNorm:e}={}){let s=this._getSearcher(i),{records:a}=this._myIndex,n=t?null:[];return a.forEach(({v:r,i:o,n:l})=>{if(!et(r))return;let{isMatch:c,score:d,indices:u}=s.searchIn(r);if(c){let h={item:r,idx:o,matches:[{score:d,value:r,norm:l,indices:u}]};t?(h.score=Gi(h.matches,{ignoreFieldNorm:e}),t.shouldInsert(h.score)&&t.insert(h)):n.push(h)}}),n}_searchLogical(i){let t=Ns(i,this.options),e=(r,o,l)=>{if(!("children"in r)){let{keyId:h,searcher:p}=r,m;return h===null?(m=[],this._myIndex.keys.forEach((f,y)=>{m.push(...this._findMatches({key:f,value:o[y],searcher:p}))})):m=this._findMatches({key:this._keyStore.get(h),value:this._myIndex.getValueForItemAtKeyId(o,h),searcher:p}),m&&m.length?[{idx:l,item:o,matches:m}]:[]}let{children:c,operator:d}=r,u=[];for(let h=0,p=c.length;h{if(et(r)){let l=e(t,r,o);l.length&&(a.has(o)||(a.set(o,{idx:o,item:r,matches:[]}),n.push(a.get(o))),l.forEach(({matches:c})=>{a.get(o).matches.push(...c)}))}}),n}_searchObjectList(i,{heap:t,ignoreFieldNorm:e}={}){let s=this._getSearcher(i),{keys:a,records:n}=this._myIndex,r=t?null:[];return n.forEach(({$:o,i:l})=>{if(!et(o))return;let c=[],d=!1,u=!1;if(a.forEach((h,p)=>{let m=this._findMatches({key:h,value:o[p],searcher:s});m.length?(c.push(...m),m[0].hasInverse&&(u=!0)):d=!0}),!(u&&d)&&c.length){let h={idx:l,item:o,matches:c};t?(h.score=Gi(h.matches,{ignoreFieldNorm:e}),t.shouldInsert(h.score)&&t.insert(h)):r.push(h)}}),r}_findMatches({key:i,value:t,searcher:e}){if(!et(t))return[];let s=[];if(Pt(t))t.forEach(({v:a,i:n,n:r})=>{if(!et(a))return;let{isMatch:o,score:l,indices:c,hasInverse:d}=e.searchIn(a);o&&s.push({score:l,key:i,value:a,idx:n,norm:r,indices:c,hasInverse:d})});else{let{v:a,n}=t,{isMatch:r,score:o,indices:l,hasInverse:c}=e.searchIn(a);r&&s.push({score:o,key:i,value:a,norm:n,indices:l,hasInverse:c})}return s}},ji=class{static condition(i,t){return t.useTokenSearch}constructor(i,t){this.options=t,this.analyzer=zi({isCaseSensitive:t.isCaseSensitive,ignoreDiacritics:t.ignoreDiacritics});let e=this.analyzer.tokenize(i),s=t._invertedIndex,{df:a,fieldCount:n}=s;this.termSearchers=[],this.idfWeights=[];for(let r of e){this.termSearchers.push(new me(r,{location:t.location,threshold:t.threshold,distance:t.distance,includeMatches:t.includeMatches,findAllMatches:t.findAllMatches,minMatchCharLength:t.minMatchCharLength,isCaseSensitive:t.isCaseSensitive,ignoreDiacritics:t.ignoreDiacritics,ignoreLocation:!0}));let o=a.get(r)||0,l=Math.log(1+(n-o+.5)/(o+.5));this.idfWeights.push(l)}}searchIn(i){if(!this.termSearchers.length)return{isMatch:!1,score:1};let t=[],e=0,s=0,a=0;for(let o=0;o0?1-e/s:0,r={isMatch:!0,score:Math.max(.001,n)};return this.options.includeMatches&&t.length&&(r.indices=qi(t)),r}};X.version="7.3.0";X.createIndex=Os;X.parseIndex=qa;X.config=F;X.match=function(g,i,t){return Ve(g,{...F,...t}).searchIn(i)};X.parseQuery=Ns;Qi(Ni);Qi(ji);X.use=function(...g){g.forEach(i=>Qi(i))};var fe=require("obsidian");var gn=30*24*60*60*1e3,Vs={imdb:"IMDb",mal:"MAL",anilist:"AniList",tmdb:"TMDB"};function mn(g,i){return i==="anilist"?`${Math.round(g)}%`:g.toFixed(g>=10?0:1)}function Yt(g,i,t,e){var o,l,c,d,u,h;let s=i.dataManager.getTitle(t);if(!s)return;g.createSpan({cls:"wl-rating-divider"});let a=g.createDiv({cls:"wl-community-badge"});if(!!s.communitySource&&((o=s.communityRating)!=null?o:0)>0){let p=(l=s.communitySource)!=null?l:"",m=(c=Vs[p])!=null?c:p.toUpperCase();a.createSpan({cls:`wl-community-source wl-community-source--${p}`,text:m}),a.createSpan({cls:"wl-community-score",text:mn((d=s.communityRating)!=null?d:0,p)}),((u=s.communityVotes)!=null?u:0)>0&&a.createSpan({cls:"wl-community-votes",text:`(${bs((h=s.communityVotes)!=null?h:0)})`})}else a.createSpan({cls:"wl-community-empty",text:"No community rating"});let r=a.createEl("button",{cls:"wl-community-refresh",text:"\u27F3",attr:{title:"Refresh community rating",type:"button"}});r.addEventListener("click",p=>{p.stopPropagation(),Ji(i,t,r,!0).then(()=>{e&&e()})})}var Yi=new Set;function Ke(g,i,t){var a,n;let e=g.dataManager.getTitle(i);if(!e)return;let s=(a=e.communityRatingLastFetched)!=null?a:"";if(s){let r=Date.parse(s);if(!isNaN(r)&&Date.now()-r{r&&t&&t()}).finally(()=>{Yi.delete(i)})))}function fn(g,i,t){var s,a,n;let e=tt(g.type,t);return e===""?!1:e==="anime"?i==="anilist"?((s=g.anilistId)!=null?s:0)>0:((a=g.malId)!=null?a:0)>0:!!((n=g.externalLink)!=null?n:"").match(/tt\d+/)}async function vn(g,i){var n;let t=g.dataManager.getTitle(i);if(!t)return!1;let e=(n=g.settings.animeApiSource)!=null?n:"jikan",s=tt(t.type,g.settings.typeApiMapping),a=await g.apiService.fetchCommunityRating(t,e,s);return a?(g.dataManager.updateCommunityRating(i,a.rating,a.votes,a.source),!0):!1}async function Ji(g,i,t,e){var a,n,r,o,l;let s=g.dataManager.getTitle(i);if(!s)return!1;t&&t.addClass("is-loading");try{let c=(a=g.settings.animeApiSource)!=null?a:"jikan",d=tt(s.type,g.settings.typeApiMapping);if(d==="")return e&&new fe.Notice(`No API configured for type "${s.type}". Configure it in Settings \u2192 API.`),!1;if(d==="anime"){let h=c==="anilist";if(h?((n=s.anilistId)!=null?n:0)>0:((r=s.malId)!=null?r:0)>0){let m=h?`https://anilist.co/anime/${s.anilistId}`:`https://myanimelist.net/anime/${s.malId}`;s.externalLink!==m&&(s.externalLink=m,await g.dataManager.updateTitle(s))}else{let m=await wn(g,s,h);if(!m)return e&&new fe.Notice(`Could not find matching title on ${h?"AniList":"MAL"}.`),!1;let f=g.dataManager.getTitle(i);if(!f)return!1;h?(f.anilistId=(o=m.anilistId)!=null?o:0,f.externalLink=`https://anilist.co/anime/${f.anilistId}`):(f.malId=m.malId,f.externalLink=`https://myanimelist.net/anime/${f.malId}`),await g.dataManager.updateTitle(f),s=f}}let u=await g.apiService.fetchCommunityRating(s,c,d);if(!u)return e&&new fe.Notice("Could not fetch community rating."),!1;if(g.dataManager.updateCommunityRating(i,u.rating,u.votes,u.source),e){let h=(l=Vs[u.source])!=null?l:u.source;new fe.Notice(`Rating updated from ${h}.`)}return!0}finally{t&&t.removeClass("is-loading")}}function _s(g){return g.toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function Us(g,i){let t=_s(g),e=_s(i);if(!t||!e)return!1;if(t===e||t.includes(e)||e.includes(t))return!0;let s=new Set(t.split(" ").filter(o=>o.length>2)),a=new Set(e.split(" ").filter(o=>o.length>2));if(s.size===0||a.size===0)return!1;let n=0;for(let o of s)a.has(o)&&n++;let r=Math.min(s.size,a.size);return n/r>=.5}async function wn(g,i,t){let e=t?await g.apiService.searchAniList(i.title):await g.apiService.searchAnime(i.title);if(!e.length)return null;let s=e[0];if(Us(i.title,s.title))return s;for(let a=1;a{a.remove()}}return s}function Nt(g){return"malId"in g}var ft=class extends Jt.Modal{constructor(t,e,s,a,n){super(t);this.selectedType="Anime";this.searchQuery="";this.searchResults=[];this.isSearching=!1;this.searchGeneration=0;this.autoSearch=!1;this.noApiMessage="";this.fieldTitle="";this.fieldEpisodes=0;this.fieldDuration=0;this.fieldReleaseDate="";this.fieldLink="";this.fieldSeasons=[];this.fieldStatus="Plan to watch";this.fieldPriority="Medium";this.fieldDateStarted="";this.fieldMalId=null;this.fieldAnilistId=null;this.fieldTrailerUrl="";this.fieldDirector=[];this.fieldCast=[];this.skipDuplicateCheck=!1;this.duplicateWarningEl=null;this.selectedGroupId="";this.newGroupName="";this.resultsEl=null;this.formEl=null;this.searchDebounce=null;this.plugin=e,this.dataManager=s,this.onAdded=a,this.selectedType=this.plugin.resolveDefaultAddType()||this.selectedType,n&&(this.selectedType=n.type,n.title&&(this.fieldTitle=n.title),n.searchQuery&&(this.searchQuery=n.searchQuery,this.autoSearch=!0),this.fieldEpisodes=n.episodes,this.fieldDuration=n.duration,this.fieldReleaseDate=n.releaseDate,this.fieldLink=n.link,this.fieldSeasons=n.seasons,n.trailerUrl!==void 0&&(this.fieldTrailerUrl=n.trailerUrl),n.director!==void 0&&(this.fieldDirector=n.director),n.cast!==void 0&&(this.fieldCast=n.cast))}onOpen(){this.titleEl.setText("Add title"),this.contentEl.addClass("wl-add-modal"),this.buildUI(),this.autoSearch&&this.performSearch()}onClose(){this.contentEl.empty(),this.searchDebounce&&window.clearTimeout(this.searchDebounce)}buildUI(){let t=this.contentEl;t.empty();let e=t.createDiv({cls:"wl-modal-row"});e.createSpan({cls:"wl-modal-label",text:"Type"});let s=e.createEl("select",{cls:"wl-select"});for(let o of this.plugin.settings.types){let l=s.createEl("option",{text:o.name,value:o.name});o.name===this.selectedType&&(l.selected=!0)}s.addEventListener("change",()=>{this.selectedType=s.value,this.searchResults=[],this.noApiMessage="",this.renderResults(),this.renderForm()});let a=t.createDiv({cls:"wl-modal-row"});a.createSpan({cls:"wl-modal-label",text:"Search"});let n=a.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Search for a title..."}});n.value=this.searchQuery,n.addEventListener("input",()=>{this.searchQuery=n.value,this.searchDebounce&&window.clearTimeout(this.searchDebounce),this.searchDebounce=window.setTimeout(()=>void this.performSearch(),600)}),a.createEl("button",{cls:"wl-btn",text:"Search"}).addEventListener("click",()=>void this.performSearch()),this.resultsEl=t.createDiv({cls:"wl-modal-results"}),this.formEl=t.createDiv({cls:"wl-modal-form"}),this.renderForm()}async performSearch(){var e,s;if(!this.searchQuery.trim())return;let t=++this.searchGeneration;this.isSearching=!0,this.renderResults();try{let a=this.plugin.apiService,n=(e=this.plugin.settings.activeApi)!=null?e:"OMDb",r=tt(this.selectedType,this.plugin.settings.typeApiMapping),o=this.selectedType==="Movie",l=[],c="";if(r===""?c=`No API configured for type "${this.selectedType}". Go to Settings \u2192 API to set one up.`:r==="anime"?l=((s=this.plugin.settings.animeApiSource)!=null?s:"jikan")==="anilist"?await a.searchAniList(this.searchQuery):await a.searchAnime(this.searchQuery):n==="TMDB"?l=await a.searchTmdb(this.searchQuery,o?"movie":"series"):l=await a.searchOmdb(this.searchQuery,o?"movie":"series"),t!==this.searchGeneration)return;this.noApiMessage=c,this.searchResults=l}catch(a){if(t!==this.searchGeneration)return;new Jt.Notice("Search failed. Check your connection and API settings."),this.searchResults=[]}finally{t===this.searchGeneration&&(this.isSearching=!1,this.renderResults())}}renderResults(){if(this.resultsEl){if(this.resultsEl.empty(),this.isSearching){this.resultsEl.createDiv({cls:"wl-modal-loading",text:"Searching..."});return}if(this.noApiMessage){let t=this.resultsEl.createDiv({cls:"wl-modal-no-api"});t.createSpan({cls:"wl-modal-no-api-icon",text:"\u2139"}),t.createSpan({cls:"wl-modal-no-api-text",text:this.noApiMessage});return}this.searchResults.length!==0&&this.searchResults.forEach((t,e)=>{let s=this.resultsEl.createDiv({cls:"wl-result-item wl-has-thumb"});ve(s,t.posterUrl,t.title,"\u{1F3AC}");let a=s.createDiv({cls:"wl-result-text"}),n=Nt(t)?`${t.episodes} eps`:t.episodes>0?`${t.episodes} eps`:t.mediaType;a.createDiv({cls:"wl-result-title",text:t.title}),a.createDiv({cls:"wl-result-meta",text:`${n} \xB7 ${t.releaseDate}`}),s.dataset.idx=String(e),s.addEventListener("click",()=>void this.selectResult(t,s))})}}async selectResult(t,e){var r,o,l,c,d,u,h,p,m,f,y;if(this.resultsEl)for(let v of Array.from(this.resultsEl.children))v.removeClass("is-selected");e.addClass("is-selected");let s=++this.searchGeneration,a=this.plugin.apiService,n=(r=this.plugin.settings.activeApi)!=null?r:"OMDb";try{if(!Nt(t)&&t.mediaType==="tv"){let v=n==="TMDB"?await a.getTmdbTvDetails(t.imdbId):await a.getOmdbTvDetails(t.imdbId);if(s!==this.searchGeneration)return;v&&(this.fieldTitle=v.title,this.fieldEpisodes=v.episodes,this.fieldDuration=v.episodeDuration,this.fieldReleaseDate=v.releaseDate,this.fieldLink=v.url,this.fieldSeasons=v.seasons,this.fieldTrailerUrl=(o=v.trailerUrl)!=null?o:"",this.fieldDirector=(l=v.director)!=null?l:[],this.fieldCast=(c=v.cast)!=null?c:[])}else if(!Nt(t)&&t.mediaType==="movie"){let v=n==="TMDB"?await a.getTmdbMovieDetails(t.imdbId):await a.getOmdbMovieDetails(t.imdbId);if(s!==this.searchGeneration)return;v&&(this.fieldTitle=v.title,this.fieldEpisodes=v.episodes,this.fieldDuration=v.episodeDuration,this.fieldReleaseDate=v.releaseDate,this.fieldLink=v.url,this.fieldSeasons=v.seasons,this.fieldTrailerUrl=(d=v.trailerUrl)!=null?d:"",this.fieldDirector=(u=v.director)!=null?u:[],this.fieldCast=(h=v.cast)!=null?h:[])}else{let v=t;this.fieldTitle=v.title,this.fieldEpisodes=v.episodes,this.fieldDuration=v.duration,this.fieldReleaseDate=v.releaseDate,this.fieldLink=v.url,this.fieldSeasons=v.seasons,this.fieldTrailerUrl=(p=v.trailerUrl)!=null?p:"",this.fieldDirector=[],this.fieldCast=[],v.anilistId&&v.anilistId>0?(this.fieldAnilistId=v.anilistId,this.fieldMalId=null):(this.fieldMalId=v.malId,this.fieldAnilistId=null)}}catch(v){this.fieldTitle=t.title,this.fieldEpisodes=(Nt(t),t.episodes),this.fieldDuration=Nt(t)?t.duration:t.episodeDuration,this.fieldReleaseDate=t.releaseDate,this.fieldLink=t.url,this.fieldSeasons=t.seasons,this.fieldTrailerUrl=(m=t.trailerUrl)!=null?m:"",this.fieldDirector=Nt(t)?[]:(f=t.director)!=null?f:[],this.fieldCast=Nt(t)?[]:(y=t.cast)!=null?y:[]}this.renderForm()}renderForm(){if(!this.formEl)return;this.formEl.empty();let t=k=>{let R=this.formEl.createDiv({cls:"wl-modal-row"});return R.createSpan({cls:"wl-modal-label",text:k}),R},e=(k,R,P=!1)=>{let B=k.createDiv({cls:P?"wl-modal-pair-cell wl-modal-pair-cell-right":"wl-modal-pair-cell"});return B.createSpan({cls:"wl-modal-label",text:R}),B},a=t("Title").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Title name"}});a.value=this.fieldTitle,a.addEventListener("input",()=>{this.fieldTitle=a.value});let n=this.formEl.createDiv({cls:"wl-modal-row wl-modal-row-pair"}),o=e(n,"Episodes").createEl("input",{cls:"wl-modal-input",attr:{type:"number",min:"0",placeholder:"0"}});o.value=String(this.fieldEpisodes),o.addEventListener("input",()=>{this.fieldEpisodes=parseInt(o.value)||0});let c=e(n,"Ep. duration (min)",!0).createEl("input",{cls:"wl-modal-input",attr:{type:"number",min:"0",placeholder:"24"}});c.value=String(this.fieldDuration),c.addEventListener("input",()=>{this.fieldDuration=parseInt(c.value)||0});let u=t("Release date").createDiv({cls:"wl-modal-input-stack"}),h=u.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Date (dd-mm-yyyy or yyyy-mm-dd)"}});h.value=this.fieldReleaseDate;let p=u.createDiv({cls:"wl-modal-error wl-hidden"});h.addEventListener("change",()=>{let k=h.value.trim();if(!k){this.fieldReleaseDate="",p.addClass("wl-hidden");return}let R=jt(k);R?(this.fieldReleaseDate=R,h.value=R,p.addClass("wl-hidden")):(this.fieldReleaseDate=k,p.textContent="Unrecognised format. Expected dd/mm/yyyy or yyyy-mm-dd.",p.removeClass("wl-hidden"))});let f=t("External link").createEl("input",{cls:"wl-modal-input",attr:{type:"url",placeholder:"https://example.com"}});f.value=this.fieldLink,f.addEventListener("input",()=>{this.fieldLink=f.value});let y=this.formEl.createDiv({cls:"wl-modal-row wl-modal-row-pair"}),w=e(y,"Status").createEl("select",{cls:"wl-select"});for(let k of this.plugin.settings.statuses.filter(R=>R.name!=="To be released")){let R=w.createEl("option",{text:k.name,value:k.name});k.name===this.fieldStatus&&(R.selected=!0)}w.addEventListener("change",()=>{this.fieldStatus=w.value});let E=e(y,"Priority",!0).createEl("select",{cls:"wl-select"});for(let k of this.plugin.settings.priorities){let R=E.createEl("option",{text:k.name,value:k.name});k.name===this.fieldPriority&&(R.selected=!0)}E.addEventListener("change",()=>{this.fieldPriority=E.value});let S=t("Date started").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"15/01/2024",maxlength:"10"}});S.value=this.fieldDateStarted?Q(this.fieldDateStarted):"",S.addEventListener("change",()=>{let k=q(S.value);S.value.trim()&&!k?S.addClass("wl-input-error"):(S.removeClass("wl-input-error"),this.fieldDateStarted=k!=null?k:"")});let T=this.dataManager.getGroups(),x=t("Add to group").createEl("select",{cls:"wl-select"});x.createEl("option",{text:"\u2014 none \u2014",value:""});for(let k of T){let R=x.createEl("option",{text:k.name,value:k.id});k.id===this.selectedGroupId&&(R.selected=!0)}let L=t("Or create new group").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"New group name..."}});L.value=this.newGroupName,x.addEventListener("change",()=>{this.selectedGroupId=x.value,this.selectedGroupId?(this.newGroupName="",L.value="",L.disabled=!0):L.disabled=!1}),L.addEventListener("input",()=>{this.newGroupName=L.value,this.newGroupName.trim()?(this.selectedGroupId="",x.value="",x.disabled=!0):x.disabled=!1}),this.selectedGroupId&&(L.disabled=!0),this.newGroupName.trim()&&(x.disabled=!0),this.fieldSeasons.length>0&&t("Seasons").createSpan({cls:"wl-modal-info",text:this.fieldSeasons.map(R=>`${R.name} (${R.episodes} eps)`).join(", ")}),this.formEl.createDiv({cls:"wl-modal-btn-row"}).createEl("button",{cls:"wl-btn wl-btn-primary",text:"Add to watchlog"}).addEventListener("click",()=>void this.addTitle())}showDuplicateWarning(t,e){if(this.duplicateWarningEl)return;let s=e.createDiv({cls:"wl-duplicate-warning"});this.duplicateWarningEl=s,s.createSpan({text:`"${t}" already exists. Add anyway?`});let a=s.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Continue"}),n=s.createEl("button",{cls:"wl-btn",text:"Cancel"});a.addEventListener("click",()=>{this.skipDuplicateCheck=!0,s.remove(),this.duplicateWarningEl=null,this.addTitle()}),n.addEventListener("click",()=>{s.remove(),this.duplicateWarningEl=null,this.skipDuplicateCheck=!1})}async addTitle(){var s;let t=this.fieldTitle.trim();if(!t){new Jt.Notice("Please enter a title name.");return}if(!this.skipDuplicateCheck&&this.dataManager.getTitles().find(n=>n.title.toLowerCase()===t.toLowerCase())){let n=this.contentEl.querySelector(".wl-modal-btn-row");n&&this.showDuplicateWarning(t,n);return}this.skipDuplicateCheck=!1;let e={id:this.dataManager.generateId(t),title:t,type:this.selectedType,status:this.fieldStatus,priority:this.fieldPriority,review:"",rating:0,notes:"",dateStarted:this.fieldDateStarted||null,dateFinished:null,dateAdded:new Date().toISOString(),dateModified:new Date().toISOString(),totalEpisodes:this.fieldEpisodes,episodeDuration:this.fieldDuration,releaseDate:this.fieldReleaseDate||null,externalLink:this.fieldLink,seasons:this.fieldSeasons,watchedEpisodes:[],posterUrl:"",trailerUrl:this.fieldTrailerUrl,manualTrailerUrl:"",...this.fieldDirector.length>0?{director:this.fieldDirector}:{},...this.fieldCast.length>0?{cast:this.fieldCast}:{},...this.fieldMalId!==null?{malId:this.fieldMalId}:{},...this.fieldAnilistId!==null?{anilistId:this.fieldAnilistId}:{}};if(e.status==="Completed"&&e.totalEpisodes>0&&(e.watchedEpisodes=Array.from({length:e.totalEpisodes},(a,n)=>n+1),this.plugin.settings.setFinishDateAutomatically&&(e.dateFinished=(s=new Date().toISOString().split("T")[0])!=null?s:null)),await this.dataManager.addTitle(e),this.plugin.settings.lastAddedType=e.type,this.plugin.saveSettings(),(async()=>{var o;let a=(o=this.plugin.settings.animeApiSource)!=null?o:"jikan",n=tt(e.type,this.plugin.settings.typeApiMapping);if(n==="")return;let r=await this.plugin.apiService.fetchCommunityRating(e,a,n);r&&this.dataManager.updateCommunityRating(e.id,r.rating,r.votes,r.source)})(),this.selectedGroupId)await this.dataManager.addTitleToGroup(this.selectedGroupId,e.id);else if(this.newGroupName.trim()){let a=this.newGroupName.trim(),n={id:this.dataManager.generateGroupId(a),name:a,titleIds:[e.id],dateAdded:new Date().toISOString()};await this.dataManager.addGroup(n)}new Jt.Notice(`"${t}" added to WatchLog.`),this.close(),this.onAdded()}};var Gs=require("obsidian");var ze=class extends Gs.Modal{constructor(t,e,s,a){super(t);this.urlInput=null;this.errorEl=null;this.addBtn=null;this.plugin=e,this.dataManager=s,this.onAdded=a}onOpen(){this.titleEl.setText("Add from URL");let t=this.contentEl;t.addClass("wl-add-modal"),t.createDiv({cls:"wl-modal-info",text:"Please enter an IMDb URL (e.g. https://www.imdb.com/title/tt1375666/)"});let e=t.createDiv({cls:"wl-modal-row"});this.urlInput=e.createEl("input",{cls:"wl-modal-input",attr:{type:"url",placeholder:"https://www.imdb.com/title/ttXXXXXXX/"}}),this.urlInput.addEventListener("keydown",a=>{a.key==="Enter"&&this.handleAdd()}),this.errorEl=t.createDiv({cls:"wl-modal-error"}),this.errorEl.hide();let s=t.createDiv({cls:"wl-modal-btn-row"});this.addBtn=s.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Add"}),this.addBtn.addEventListener("click",()=>void this.handleAdd()),window.setTimeout(()=>{var a;return(a=this.urlInput)==null?void 0:a.focus()},50)}onClose(){this.contentEl.empty()}async handleAdd(){var a,n,r;let e=((n=(a=this.urlInput)==null?void 0:a.value.trim())!=null?n:"").match(/tt\d+/);if(!e){this.showError("Title not found. Please check the URL and try again.");return}let s=e[0];this.addBtn&&(this.addBtn.disabled=!0,this.addBtn.textContent="Loading\u2026"),this.errorEl&&this.errorEl.hide();try{let o=this.plugin.settings.activeApi==="TMDB"?await this.plugin.apiService.getTmdbByImdbId(s):await this.plugin.apiService.getOmdbByImdbId(s);if(!o){this.showError("Title not found. Please check the URL and try again.");return}this.close();let l=o.mediaType==="movie"?"Movie":"TV Show";new ft(this.app,this.plugin,this.dataManager,this.onAdded,{title:o.title,type:l,episodes:o.episodes,duration:o.episodeDuration,releaseDate:o.releaseDate,link:o.url,seasons:o.seasons,trailerUrl:(r=o.trailerUrl)!=null?r:"",director:o.director,cast:o.cast}).open()}finally{this.addBtn&&(this.addBtn.disabled=!1,this.addBtn.textContent="Add")}}showError(t){this.errorEl&&(this.errorEl.textContent=t,this.errorEl.show())}};var Ks=require("obsidian"),je=class extends Ks.Modal{constructor(t,e){super(t);this.onChoice=e}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("wl-draft-choice-modal"),this.titleEl.setText("Add title");let e=t.createDiv({cls:"wl-draft-choice-grid"}),s=(a,n)=>{let r=e.createEl("button",{cls:"wl-draft-choice-btn"});r.createDiv({cls:"wl-draft-choice-label",text:a}),r.addEventListener("click",()=>{this.close(),this.onChoice(n)})};s("Add from URL","url"),s("Add manually / via API","manual")}onClose(){this.contentEl.empty()}};var qe=require("obsidian");function Qe(g){let{controls:i,renderSearch:t,renderActions:e}=g;if(!qe.Platform.isMobile){t(i),e(i);return}let s=g.expanded,a=i.createDiv({cls:"wl-toolbar-slot"}),n=a.createDiv({cls:"wl-toolbar-slot-pane wl-toolbar-fade"});t(n);let r=a.createDiv({cls:"wl-toolbar-slot-pane wl-toolbar-fade"});e(r);let o=()=>{n.toggleClass("wl-toolbar-pane-hidden",s),r.toggleClass("wl-toolbar-pane-hidden",!s)};o();let l=i.createEl("button",{cls:"wl-btn wl-btn-sm wl-toolbar-toggle-btn"}),c=()=>{(0,qe.setIcon)(l,s?"chevron-right":"chevron-left"),l.setAttr("aria-label",s?"Show search":"Show actions")};c(),l.addEventListener("click",()=>{s=!s,g.onToggleChange(s),o(),c()})}var we=require("obsidian");function yn(g){var t,e;let i=[];for(let s of g.split(",").map(a=>a.trim()).filter(Boolean)){let a=s.split("-");if(a.length===2){let n=parseInt((t=a[0])!=null?t:"0",10),r=parseInt((e=a[1])!=null?e:"0",10);if(!isNaN(n)&&!isNaN(r)&&n<=r)for(let o=n;o<=r;o++)i.push(o)}else{let n=parseInt(s,10);isNaN(n)||i.push(n)}}return[...new Set(i)].sort((s,a)=>s-a)}function bn(g){if(g.length===0)return"";let i=[...new Set(g)].sort((s,a)=>s-a),t=[],e=0;for(;ee?t.push(`${i[e]}-${i[s]}`):t.push(String(i[e])),e=s+1}return t.join(",")}function Xi(g){let i=g.split(` +`).map(s=>s.trim()).filter(Boolean),t=[],e=0;for(let s of i){let a=s.match(/^(.+?):\s*(\d+)(?:\s*\(([^)]+)\))?/);if(a&&a[1]&&a[2]){let n=parseInt(a[2],10),r=a[3]?yn(a[3]):[];t.push({name:a[1].trim(),episodes:n,offset:e,skippedEpisodes:r}),e+=n}}return t}function En(g){return g.map(i=>{let t=`${i.name}: ${i.episodes}`;return i.skippedEpisodes&&i.skippedEpisodes.length>0?`${t} (${bn(i.skippedEpisodes)})`:t}).join(` +`)}var Bt=class extends we.Modal{constructor(t,e,s,a,n){var r,o,l,c,d,u,h,p;super(t);this.originalGroupId="";this.selectedGroupId="";this.newGroupName="";this.skipDuplicateCheck=!1;this.duplicateWarningEl=null;this.notesInput=null;this.notesEditedByUser=!1;this.plugin=e,this.dataManager=s,this.original=a,this.onSaved=n,this.fieldTitle=a.title,this.fieldType=a.type,this.fieldEpisodes=a.totalEpisodes,this.fieldDuration=a.episodeDuration,this.fieldReleaseDate=(r=a.releaseDate)!=null?r:"",this.fieldLink=a.externalLink,this.fieldSeasonsText=En(a.seasons),this.fieldStatus=a.status,this.fieldPriority=a.priority,this.fieldReview=(o=a.review)!=null?o:"",this.fieldRating=a.rating,this.fieldNotes=a.notes,this.fieldDateStarted=(l=a.dateStarted)!=null?l:"",this.fieldDateFinished=(c=a.dateFinished)!=null?c:"",this.fieldPosterUrl=(d=a.manualPosterUrl)!=null?d:"",this.fieldTrailerUrl=(u=a.manualTrailerUrl)!=null?u:"",this.originalGroupId=(p=(h=this.dataManager.getGroups().find(m=>m.titleIds.includes(a.id)))==null?void 0:h.id)!=null?p:"",this.selectedGroupId=this.originalGroupId}onOpen(){this.titleEl.setText(`Edit: ${this.original.title}`),this.contentEl.addClass("wl-add-modal"),this.buildUI(),this.syncNotesFromFile()}async syncNotesFromFile(){let t=await this.dataManager.readNotesFromFile(this.original);t===null||this.notesEditedByUser||(this.fieldNotes=t,this.notesInput&&(this.notesInput.value=t))}onClose(){this.contentEl.empty()}buildUI(){let t=this.contentEl;t.empty();let e=$=>{let G=t.createDiv({cls:"wl-modal-row"});return G.createSpan({cls:"wl-modal-label",text:$}),G},s=($,G,Kt=!1)=>{let Ct=$.createDiv({cls:Kt?"wl-modal-pair-cell wl-modal-pair-cell-right":"wl-modal-pair-cell"});return Ct.createSpan({cls:"wl-modal-label",text:G}),Ct},n=e("Title").createEl("input",{cls:"wl-modal-input",attr:{type:"text"}});n.value=this.fieldTitle,n.addEventListener("input",()=>{this.fieldTitle=n.value});let o=e("Type").createEl("select",{cls:"wl-select"});for(let $ of this.plugin.settings.types){let G=o.createEl("option",{text:$.name,value:$.name});$.name===this.fieldType&&(G.selected=!0)}o.addEventListener("change",()=>{this.fieldType=o.value});let l=t.createDiv({cls:"wl-modal-row wl-modal-row-pair"}),d=s(l,"Status").createEl("select",{cls:"wl-select"}),u=this.fieldStatus==="To be released";for(let $ of this.plugin.settings.statuses){if($.name==="To be released"&&!u)continue;let G=d.createEl("option",{text:$.name,value:$.name});$.name===this.fieldStatus&&(G.selected=!0)}d.addEventListener("change",()=>{this.fieldStatus=d.value});let p=s(l,"Priority",!0).createEl("select",{cls:"wl-select"});for(let $ of this.plugin.settings.priorities){let G=p.createEl("option",{text:$.name,value:$.name});$.name===this.fieldPriority&&(G.selected=!0)}p.addEventListener("change",()=>{this.fieldPriority=p.value});let f=e("Rating").createDiv({cls:"wl-stars"}),y=()=>{f.empty();for(let $=1;$<=5;$++)f.createSpan({cls:`wl-star${this.fieldRating>=$?" is-active":""}`,text:"\u2605"}).addEventListener("click",()=>{this.fieldRating=this.fieldRating===$?0:$,y()})};y();let v=t.createDiv({cls:"wl-modal-row wl-modal-row-pair"}),w=s(v,"Total episodes"),b=w.createEl("input",{cls:"wl-modal-input",attr:{type:"number",min:"0"}});b.value=String(this.fieldEpisodes);let E=w.createSpan({cls:"wl-modal-skip-inline"}),D=w.createSpan({cls:"wl-modal-skip-inline"}),S=()=>{let G=Xi(this.fieldSeasonsText).reduce((Ct,ae)=>{var ne,re;return Ct+((re=(ne=ae.skippedEpisodes)==null?void 0:ne.length)!=null?re:0)},0);if(G===0){E.textContent="",D.textContent="";return}let Kt=Math.max(0,this.fieldEpisodes-G);E.textContent=`\xB7 ${G} to skip`,D.textContent=`\xB7 ${Kt} to watch`};b.addEventListener("input",()=>{this.fieldEpisodes=parseInt(b.value)||0,S()});let M=s(v,"Ep. duration (min)",!0).createEl("input",{cls:"wl-modal-input",attr:{type:"number",min:"0"}});M.value=String(this.fieldDuration),M.addEventListener("input",()=>{this.fieldDuration=parseInt(M.value)||0});let C=e("Release date").createDiv({cls:"wl-modal-input-stack"}),L=C.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Date (dd-mm-yyyy or yyyy-mm-dd)"}});L.value=this.fieldReleaseDate;let I=C.createDiv({cls:"wl-modal-error wl-hidden"});L.addEventListener("change",()=>{let $=L.value.trim();if(!$){this.fieldReleaseDate="",I.addClass("wl-hidden");return}let G=jt($);G?(this.fieldReleaseDate=G,L.value=G,I.addClass("wl-hidden")):(this.fieldReleaseDate=$,I.textContent="Unrecognised format. Expected dd/mm/yyyy or yyyy-mm-dd.",I.removeClass("wl-hidden"))});let k=e("External link").createEl("input",{cls:"wl-modal-input",attr:{type:"url",placeholder:"HTTPS://..."}});k.value=this.fieldLink,k.addEventListener("input",()=>{this.fieldLink=k.value});let P=e("Poster URL").createDiv({cls:"wl-modal-input-stack"}),B=P.createEl("input",{cls:"wl-modal-input",attr:{type:"url",placeholder:"https://example.com/poster.jpg"}});B.value=this.fieldPosterUrl,B.addEventListener("input",()=>{this.fieldPosterUrl=B.value}),P.createDiv({cls:"wl-modal-info",text:"Override the auto-fetched cover. Leave blank to let WatchLog fetch one again."});let U=e("Trailer URL").createDiv({cls:"wl-modal-input-stack"}),z=U.createEl("input",{cls:"wl-modal-input",attr:{type:"url",placeholder:"https://www.youtube.com/watch?v=..."}});z.value=this.fieldTrailerUrl,z.addEventListener("input",()=>{this.fieldTrailerUrl=z.value}),U.createDiv({cls:"wl-modal-info",text:"Override the auto-fetched trailer. Leave blank to use the fetched one."});let yt=t.createDiv({cls:"wl-modal-row wl-modal-row-pair"}),bt=s(yt,"Date started").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});bt.value=Q(this.fieldDateStarted),bt.addEventListener("change",()=>{let $=q(bt.value);bt.value.trim()&&!$?bt.addClass("wl-input-error"):(bt.removeClass("wl-input-error"),this.fieldDateStarted=$!=null?$:"")});let O=s(yt,"Date finished",!0).createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});O.value=Q(this.fieldDateFinished),O.addEventListener("change",()=>{let $=q(O.value);O.value.trim()&&!$?O.addClass("wl-input-error"):(O.removeClass("wl-input-error"),this.fieldDateFinished=$!=null?$:"")});let Y=this.dataManager.getGroups(),Tt=e("Add to group").createEl("select",{cls:"wl-select"});Tt.createEl("option",{text:"\u2014 none \u2014",value:""});for(let $ of Y){let G=Tt.createEl("option",{text:$.name,value:$.id});$.id===this.selectedGroupId&&(G.selected=!0)}let Ot=e("Or create new group").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"New group name..."}});Ot.value=this.newGroupName,Tt.addEventListener("change",()=>{this.selectedGroupId=Tt.value,this.selectedGroupId?(this.newGroupName="",Ot.value="",Ot.disabled=!0):Ot.disabled=!1}),Ot.addEventListener("input",()=>{this.newGroupName=Ot.value,this.newGroupName.trim()?(this.selectedGroupId="",Tt.value="",Tt.disabled=!0):Tt.disabled=!1}),this.selectedGroupId&&(Ot.disabled=!0),this.newGroupName.trim()&&(Tt.disabled=!0);let Re=e("Notes").createEl("textarea",{cls:"wl-modal-textarea",attr:{rows:"3",placeholder:"Your notes..."}});Re.value=this.fieldNotes,this.notesInput=Re,Re.addEventListener("input",()=>{this.notesEditedByUser=!0,this.fieldNotes=Re.value});let se=e("Seasons").createDiv({cls:"wl-modal-input-stack"}),Ae=se.createEl("textarea",{cls:"wl-modal-textarea",attr:{rows:"4",placeholder:`Season 1: 12 +Season 2: 13 (5,8,33-37)`}});Ae.value=this.fieldSeasonsText;let va=se.createDiv({cls:"wl-modal-season-total"}),fs=()=>{let $=Xi(Ae.value),G=$.reduce((Ct,ae)=>Ct+ae.episodes,0),Kt=$.reduce((Ct,ae)=>{var ne,re;return Ct+((re=(ne=ae.skippedEpisodes)==null?void 0:ne.length)!=null?re:0)},0);va.textContent=Kt>0?`Total episodes: ${G} \xB7 ${Kt} to skip`:`Total episodes: ${G}`};fs(),S(),Ae.addEventListener("input",()=>{this.fieldSeasonsText=Ae.value,fs(),S()}),se.createDiv({cls:"wl-modal-info",text:'Format: "Season Name: N" (e.g. "Season 1: 12")'}),se.createDiv({cls:"wl-modal-info",text:'Skip episodes: add "(1,3,5-10)" after count (e.g. "Season 1: 48 (33-37)")'}),se.createDiv({cls:"wl-modal-info",text:'Note: when adding a new season, remember to update "Total Episodes" so progress calculates correctly.'});let vs=t.createDiv({cls:"wl-modal-btn-row"});vs.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),vs.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save changes"}).addEventListener("click",()=>void this.saveTitle())}showDuplicateWarning(t,e){if(this.duplicateWarningEl)return;let s=e.createDiv({cls:"wl-duplicate-warning"});this.duplicateWarningEl=s,s.createSpan({text:`"${t}" already exists. Save anyway?`});let a=s.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Continue"}),n=s.createEl("button",{cls:"wl-btn",text:"Cancel"});a.addEventListener("click",()=>{this.skipDuplicateCheck=!0,s.remove(),this.duplicateWarningEl=null,this.saveTitle()}),n.addEventListener("click",()=>{s.remove(),this.duplicateWarningEl=null,this.skipDuplicateCheck=!1})}async saveTitle(){let t=this.fieldTitle.trim();if(!t){new we.Notice("Title name cannot be empty.");return}if(!this.skipDuplicateCheck&&this.dataManager.getTitles().find(h=>h.id!==this.original.id&&h.title.toLowerCase()===t.toLowerCase())){let h=this.contentEl.querySelector(".wl-modal-btn-row");h&&this.showDuplicateWarning(t,h);return}this.skipDuplicateCheck=!1;let e=Xi(this.fieldSeasonsText),s=this.fieldReleaseDate||null,a={...this.original,title:t,type:this.fieldType,status:this.fieldStatus,priority:this.fieldPriority,review:this.fieldReview,rating:this.fieldRating,notes:this.fieldNotes,totalEpisodes:this.fieldEpisodes,episodeDuration:this.fieldDuration,releaseDate:s,externalLink:this.fieldLink,seasons:e,dateStarted:this.fieldDateStarted||null,dateFinished:this.fieldDateFinished||null,manualPosterUrl:this.fieldPosterUrl.trim(),manualTrailerUrl:this.fieldTrailerUrl.trim()};a.status==="Completed"&&a.totalEpisodes>0&&(a.watchedEpisodes=Array.from({length:a.totalEpisodes},(u,h)=>h+1)),await this.dataManager.updateTitle(a);let r=this.dataManager.getAirtimeEntries().find(u=>u.titleId===a.id);if(r&&r.schedule.recurrence==="once"){let u=s!=null?s:void 0;r.schedule.releaseDate!==u&&(r.schedule.releaseDate=u,await this.dataManager.updateAirtimeEntry(r))}let o=new Date;o.setHours(0,0,0,0),(u=>u!==null&&/^\d{4}-\d{2}-\d{2}$/.test(u))(s)?new Date(s+"T12:00:00").getTime()>o.getTime()?(a.status!=="To be released"&&(a.status="To be released",await this.dataManager.updateTitle(a)),this.dataManager.getAirtimeEntries().some(f=>f.titleId===a.id)||await this.dataManager.autoAddToUpcoming(a)):a.status==="To be released"&&(a.status="Plan to watch",await this.dataManager.updateTitle(a),await this.dataManager.removeAirtimeEntriesForTitle(a.id)):!s&&a.status==="To be released"&&(a.status="Plan to watch",await this.dataManager.updateTitle(a),await this.dataManager.removeAirtimeEntriesForTitle(a.id));let c=this.newGroupName.trim();if(c!==""||this.selectedGroupId!==this.originalGroupId){if(this.originalGroupId){let u=this.dataManager.getGroup(this.originalGroupId);u&&(u.titleIds=u.titleIds.filter(h=>h!==a.id),await this.dataManager.updateGroup(u))}if(c){let u={id:this.dataManager.generateGroupId(c),name:c,titleIds:[a.id],dateAdded:new Date().toISOString()};await this.dataManager.addGroup(u)}else this.selectedGroupId&&await this.dataManager.addTitleToGroup(this.selectedGroupId,a.id)}new we.Notice(`"${t}" updated.`),this.close(),this.onSaved()}};var zs=require("obsidian"),_=class extends zs.Modal{constructor(i,t,e){super(i),this.message=t,this.onConfirm=e}onOpen(){let{contentEl:i}=this;i.createDiv({cls:"wl-confirm-msg",text:this.message});let t=i.createDiv({cls:"wl-modal-btn-row"});t.createEl("button",{cls:"wl-btn wl-btn-danger",text:"Confirm"}).addEventListener("click",()=>{this.close(),this.onConfirm()}),t.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close())}onClose(){this.contentEl.empty()}};var St=require("obsidian");var _t=require("obsidian");function Ye(g,i,t,e){let s=i.createEl("span",{cls:"wl-acc-link-icon"});return(0,_t.setIcon)(s,"file-text"),s.setAttr("aria-label","Open note"),s.title="Open note",s.addEventListener("click",a=>{a.stopPropagation();let n=t instanceof _t.TFile?t:g.vault.getAbstractFileByPath(t);if(!(n instanceof _t.TFile)){new _t.Notice("Note file not found for this title.");return}g.workspace.getLeaf().openFile(n),e==null||e()}),s}function Xt(g){var u;let{anchor:i,container:t,options:e,getOptionColor:s,onSelect:a,onClose:n}=g;t.querySelectorAll(".wl-reading-status-dropdown").forEach(h=>h.remove());let r=i.getBoundingClientRect(),o=t.createDiv({cls:"wl-reading-status-dropdown"});o.style.top=`${r.bottom+4}px`,o.style.left=`${r.left}px`;let l=t.ownerDocument,c=!1;for(let h of e){let p=typeof h=="string"?h:h.value,m=typeof h=="string"?h:(u=h.label)!=null?u:h.value,f=o.createDiv({cls:"wl-reading-status-option"}),y=f.createSpan({cls:"wl-reading-status-option-dot"}),v=s==null?void 0:s(p);v&&(y.style.backgroundColor=v),f.createSpan({text:m}),f.addEventListener("click",()=>{c=!0,o.remove(),l.removeEventListener("mousedown",d,!0),a(p)})}let d=h=>{o.contains(h.target)||(o.remove(),l.removeEventListener("mousedown",d,!0),c||n==null||n())};window.setTimeout(()=>l.addEventListener("mousedown",d,!0),0)}var Zi=new Set,ye=class extends St.Modal{constructor(t,e,s,a,n){super(t);this.changed=!1;this.notesEditedByUser=!1;this.collapsedSeasons=new Set;this.statsBoxEl=null;this.creditsEl=null;this.episodesSectionEl=null;this.starsWrapEl=null;this.plugin=e,this.dataManager=e.dataManager,this.title=s,this.onChanged=a,this.onPersonClick=n,this.collapsedSeasons=this.dataManager.getCollapsedSeasonsForTitle(s.id)}onOpen(){var e;let t=(e=this.plugin.settings.colorTheme)!=null?e:"default";this.modalEl.setAttribute("data-theme",t),this.contentEl.setAttribute("data-theme",t),this.contentEl.addClass("wl-view"),this.contentEl.addClass("wl-detail-modal"),this.renderAll()}onClose(){this.contentEl.empty(),this.changed&&this.onChanged&&this.onChanged()}getTagDef(t,e){return e.find(s=>s.name===t)}refreshTitle(){let t=this.dataManager.getTitle(this.title.id);t&&(this.title=t)}markChanged(){this.changed=!0}renderAll(){this.contentEl.empty(),this.renderHeader(this.contentEl),this.renderEpisodesSection(this.contentEl),this.renderRatingSection(this.contentEl),this.renderNotesSection(this.contentEl),this.renderDateSection(this.contentEl),this.renderFooter(this.contentEl)}renderHeader(t){let e=t.createDiv({cls:"wl-detail-header"});this.renderCover(e);let s=e.createDiv({cls:"wl-detail-header-left"});s.createEl("h2",{cls:"wl-detail-title",text:this.title.title});let a=s.createDiv({cls:"wl-detail-badge-row"}),n=this.getTagDef(this.title.type,this.plugin.settings.types),r=n?N(this.title.type,n.color,this.plugin.settings.colorTheme):"#888780",o=a.createSpan({cls:"wl-card-type-badge",text:this.title.type});if(o.style.backgroundColor=r,this.title.externalLink){let c=a.createEl("a",{cls:"wl-acc-link-icon",text:"\u{1F310}"});c.href=this.title.externalLink,c.title="Open external link",c.target="_blank",c.rel="noopener noreferrer"}Ye(this.app,a,this.dataManager.getNoteFilePath(this.title),()=>this.close());let l=a.createSpan({cls:"wl-reading-detail-status-wrap"});this.renderStatusBadge(l),this.statsBoxEl=s.createDiv({cls:"wl-detail-stats-box"}),this.renderStatsBox(),this.creditsEl=s.createDiv({cls:"wl-detail-credits"}),this.renderCreditsSection(),this.maybeBackfillCredits()}renderCreditsSection(){this.creditsEl&&(this.creditsEl.empty(),ts(this.creditsEl,this.title,this.onPersonClick?t=>{this.close(),this.onPersonClick(t)}:void 0))}maybeBackfillCredits(){let t=this.dataManager.getTitle(this.title.id);!t||!ws(t)||Zi.has(t.id)||(Zi.add(t.id),(async()=>{var e,s,a;try{let n=await this.plugin.apiService.fetchCredits(t,(e=this.plugin.settings.activeApi)!=null?e:"OMDb"),r=zt(t.director)?(s=n==null?void 0:n.director)!=null?s:[oe]:t.director,o=zt(t.cast)?(a=n==null?void 0:n.cast)!=null?a:[oe]:t.cast;await this.dataManager.updateCredits(t.id,r,o)}catch(n){}finally{Zi.delete(t.id)}this.refreshTitle(),this.renderCreditsSection()})())}renderCover(t){var h;let e=t.createDiv({cls:"wl-detail-cover"}),s=this.getTagDef(this.title.type,this.plugin.settings.types),a=s?N(this.title.type,s.color,this.plugin.settings.colorTheme):"#888780",n=e.createDiv({cls:"wl-detail-cover-placeholder"});n.style.backgroundColor=a;let r=(this.title.title.trim().charAt(0)||"?").toUpperCase();n.createSpan({text:r});let o=e.createEl("img",{cls:"wl-detail-cover-img"});o.alt=this.title.title;let l=p=>{o.src=p,e.addClass("has-poster")},c=()=>{e.removeClass("has-poster")},d=Rt(this.title),u=!!(this.title.manualPosterUrl&&this.title.manualPosterUrl.trim()!=="");d&&d.startsWith("http")?(l(d),o.onerror=()=>{c(),u||this.dataManager.updatePosterUrl(this.title.id,"none")}):!u&&this.title.posterUrl===""&&(n.addClass("is-loading"),(h=this.plugin.posterService)==null||h.enqueue(this.title).then(p=>{n.removeClass("is-loading"),p&&l(p)}))}renderStatsBox(){if(!this.statsBoxEl)return;this.statsBoxEl.empty();let t=this.title,e=this.dataManager.calcTimeRemainingForModal(t),s=this.dataManager.calcTimeWatched(t),a=t.watchedEpisodes.length,n=this.dataManager.getEffectiveTotal(t),r=this.dataManager.getProgress(t),o=(d,u)=>{let h=this.statsBoxEl.createDiv({cls:"wl-acc-stat-block"});h.createDiv({cls:"wl-acc-percent",text:d}),h.createDiv({cls:"wl-acc-progress-label",text:u})};o(j(e),"left"),o(j(s),"watched"),o(`${a} / ${n}`,"episodes");let l=this.statsBoxEl.createDiv({cls:"wl-acc-header-right"});l.createDiv({cls:"wl-acc-percent",text:`${r}%`}),l.createDiv({cls:"wl-acc-progress-label",text:"progress"});let c=l.createDiv({cls:"wl-acc-progress-wrap"});c.createDiv({cls:"wl-progress-bar"}).style.width=`${r}%`}renderEpisodesSection(t){this.episodesSectionEl=t.createDiv({cls:"wl-detail-episodes"}),this.renderEpisodesBody()}renderEpisodesBody(){if(!this.episodesSectionEl)return;this.episodesSectionEl.empty();let t=this.title;if(t.type==="Movie"){let e=this.episodesSectionEl.createDiv({cls:"wl-movie-row"}),s=e.createEl("input",{cls:"wl-movie-checkbox",attr:{type:"checkbox"}});s.checked=t.watchedEpisodes.includes(1),e.createSpan({cls:"wl-movie-label",text:"Watched"}),s.addEventListener("change",()=>{this.dataManager.markEpisodeWatched(t.id,1,s.checked).then(()=>{this.refreshTitle(),this.markChanged(),this.renderStatsBox()})});return}if(t.seasons.length===0){t.totalEpisodes>0&&this.renderEpisodeGrid(this.episodesSectionEl,null);return}t.seasons.forEach((e,s)=>{var h,p;let a=this.collapsedSeasons.has(s),n=this.episodesSectionEl.createDiv({cls:"wl-season-wrap"}),r=n.createDiv({cls:"wl-season-header"}),o=r.createSpan({cls:"wl-season-badge"});o.textContent=e.name;let l=this.plugin.settings.seasonPalette;o.style.backgroundColor=(h=l[s%l.length])!=null?h:"#888780";let c=((p=e.skippedEpisodes)!=null?p:[]).length,d=c>0?` (${c} to skip)`:"";r.createSpan({cls:"wl-season-ep-count",text:`${e.episodes} eps${d}`});let u=r.createSpan({cls:`wl-chevron${a?"":" is-open"}`,text:"\u203A"});a||this.renderEpisodeGrid(n,e),r.addEventListener("click",()=>{var m;a?(a=!1,this.collapsedSeasons.delete(s),u.classList.add("is-open"),this.renderEpisodeGrid(n,e)):(a=!0,this.collapsedSeasons.add(s),u.classList.remove("is-open"),(m=n.querySelector(".wl-episode-grid"))==null||m.remove()),this.dataManager.persistCollapsedSeasons(this.title.id,this.collapsedSeasons)})})}renderEpisodeGrid(t,e){let s=this.title,a=t.createDiv({cls:"wl-episode-grid"}),n=e?e.episodes:s.totalEpisodes,r=e?e.offset:0,o=Array.from({length:n},(u,h)=>r+h+1),l=a.createDiv({cls:"wl-season-fill-btn"}),c=()=>{let u=new Set(this.title.watchedEpisodes),h=o.length>0&&o.every(p=>u.has(p));l.classList.toggle("is-clear",h),l.classList.toggle("is-fill",!h),l.textContent=h?"\u2717":"\u2713",l.title=h?"Clear all episodes in this season":"Mark all episodes in this season as watched"};c(),l.addEventListener("click",()=>{let u=new Set(this.title.watchedEpisodes),h=o.length>0&&o.every(p=>u.has(p));this.dataManager.markSeasonWatched(this.title.id,o,!h,e==null?void 0:e.name).then(()=>{this.refreshTitle(),this.markChanged(),this.renderEpisodesBody(),this.renderStatsBox()})});let d=this.plugin.settings.episodeNumbering==="per-season";for(let u=0;u{var b;let v=this.title.watchedEpisodes.includes(h),w=e?((b=e.skippedEpisodes)!=null?b:[]).includes(p):!1;f.classList.toggle("is-watched",v),f.classList.toggle("is-skipped",w),f.textContent=w&&!v?"\u2014":v?"\u2713":String(m),f.title=`Episode ${h}${w?" (skipped)":""}`};y(),f.addEventListener("click",()=>{let v=this.title.watchedEpisodes.includes(h);this.dataManager.applyEpisodeWatchedToggle(this.title.id,h,!v),this.refreshTitle(),this.markChanged(),y(),c(),this.renderStatsBox()})}}renderRatingSection(t){let e=t.createDiv({cls:"wl-detail-rating"});e.createSpan({cls:"wl-stars-label",text:"Rating"}),this.starsWrapEl=e.createDiv({cls:"wl-stars wl-detail-stars"}),this.renderStars();let s=()=>{var r;let n=e.querySelector(".wl-rating-divider");for(;n;){let o=n;n=n.nextSibling,(r=o.parentNode)==null||r.removeChild(o)}Yt(e,this.plugin,this.title.id,s),this.renderTrailerControl(e),this.refreshTitle()};Yt(e,this.plugin,this.title.id,s),this.renderTrailerControl(e),Ke(this.plugin,this.title.id,s)}renderTrailerControl(t){let e=t.createSpan({cls:"wl-trailer-control"});this.paintTrailerControl(e)}paintTrailerControl(t){var n;t.empty();let e=(n=this.dataManager.getTitle(this.title.id))!=null?n:this.title,s=Be(e);if(s){let r=t.createEl("button",{cls:"wl-trailer-btn",attr:{type:"button",title:"Watch trailer on YouTube","aria-label":"Watch trailer on YouTube"}});(0,St.setIcon)(r,"youtube"),r.addEventListener("click",o=>{o.stopPropagation(),window.open(s,"_blank")});return}let a=t.createEl("button",{cls:"wl-community-refresh wl-trailer-refresh",attr:{type:"button",title:"Fetch trailer","aria-label":"Fetch trailer"}});(0,St.setIcon)(a,"refresh-cw"),a.addEventListener("click",r=>{r.stopPropagation(),this.refreshTrailer(a,t)})}async refreshTrailer(t,e){var a;let s=this.dataManager.getTitle(this.title.id);if(s){t.addClass("is-loading");try{let n=(a=this.plugin.settings.animeApiSource)!=null?a:"jikan",r=tt(s.type,this.plugin.settings.typeApiMapping),o=await this.plugin.apiService.fetchTrailer(s,n,r),l=!!o&&o!=="none";this.dataManager.updateTrailerUrl(s.id,l?o:"none"),l?this.paintTrailerControl(e):(new St.Notice("No trailer found"),t.removeClass("is-loading"))}catch(n){new St.Notice("No trailer found"),t.removeClass("is-loading")}}}renderStars(){if(this.starsWrapEl){this.starsWrapEl.empty();for(let t=1;t<=5;t++)this.starsWrapEl.createSpan({cls:`wl-star${this.title.rating>=t?" is-active":""}`,text:"\u2605"}).addEventListener("click",()=>{(async()=>{let s=this.dataManager.getTitle(this.title.id);s&&(s.rating=s.rating===t?0:t,await this.dataManager.updateTitle(s),this.refreshTitle(),this.markChanged(),this.renderStars())})()})}}renderNotesSection(t){let e=t.createDiv({cls:"wl-detail-notes"});e.createSpan({cls:"wl-stars-label",text:"Notes"});let s=e.createEl("textarea",{cls:"wl-detail-notes-input",attr:{placeholder:"Add notes...",rows:"3"}});s.value=this.title.notes;let a=()=>{s.setCssProps({height:"auto"}),s.setCssProps({height:`${s.scrollHeight}px`})};s.addEventListener("input",()=>{this.notesEditedByUser=!0,a()}),window.setTimeout(a,0),this.dataManager.readNotesFromFile(this.title).then(n=>{n===null||this.notesEditedByUser||(n!==s.value&&(s.value=n,a()),this.title.notes=n)}),s.addEventListener("blur",()=>{s.value!==this.title.notes&&(async()=>{let n=this.dataManager.getTitle(this.title.id);n&&(n.notes=s.value,await this.dataManager.updateTitle(n),this.refreshTitle(),this.markChanged())})()})}renderDateSection(t){let e=t.createDiv({cls:"wl-detail-date"});e.createSpan({cls:"wl-stars-label",text:"Date watched"});let s=e.createEl("button",{cls:"wl-btn wl-btn-sm wl-footer-today-btn",text:"Today"}),a=e.createEl("input",{cls:"wl-footer-date",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});a.value=Q(this.title.dateFinished);let n=()=>{s.toggleClass("is-dimmed",!!a.value.trim())};n(),a.addEventListener("change",()=>{(async()=>{let r=this.dataManager.getTitle(this.title.id);if(!r)return;let o=q(a.value);if(a.value.trim()&&!o){a.addClass("wl-input-error");return}a.removeClass("wl-input-error"),r.dateFinished=o,await this.dataManager.updateTitle(r),this.refreshTitle(),this.markChanged(),n()})()}),s.addEventListener("click",()=>{if(a.value.trim())return;let r=new Date,o=String(r.getDate()).padStart(2,"0"),l=String(r.getMonth()+1).padStart(2,"0"),c=r.getFullYear();a.value=`${o}/${l}/${c}`,n(),a.dispatchEvent(new Event("change"))})}statusColor(t){let e=this.getTagDef(t,this.plugin.settings.statuses);return e?N(t,e.color,this.plugin.settings.colorTheme):"#888780"}renderStatusBadge(t){t.empty();let e=this.title.status,s=t.createSpan({cls:"wl-reading-detail-status",text:e});s.style.backgroundColor=this.statusColor(e),s.title="Click to change status",s.addEventListener("click",a=>{a.stopPropagation(),this.openStatusDropdown(s,t)})}openStatusDropdown(t,e){Xt({anchor:t,container:this.contentEl,options:this.plugin.settings.statuses.filter(s=>s.name!=="To be released").map(s=>s.name),getOptionColor:s=>this.statusColor(s),onSelect:s=>void this.saveStatus(s).then(()=>this.renderStatusBadge(e))})}async saveStatus(t){let e=this.dataManager.getTitle(this.title.id);e&&(e.status=t,await this.dataManager.updateTitle(e),this.refreshTitle(),this.markChanged())}renderFooter(t){let e=t.createDiv({cls:"wl-detail-footer"});e.createEl("button",{cls:"wl-delete-btn wl-btn-danger wl-detail-remove",text:"Remove"}).addEventListener("click",()=>{new _(this.plugin.app,`Remove "${this.title.title}" from watchlog?`,()=>{this.dataManager.removeTitle(this.title.id).then(()=>{this.markChanged(),this.close()})}).open()}),e.createEl("button",{cls:"wl-edit-btn wl-detail-edit",text:"Edit"}).addEventListener("click",()=>{let n=this.dataManager.getTitle(this.title.id);n&&(this.close(),new Bt(this.plugin.app,this.plugin,this.dataManager,n,()=>{this.onChanged&&this.onChanged()}).open())})}};function ts(g,i,t){let e=(s,a)=>{if(zt(a))return;let n=g.createDiv({cls:"wl-credits-row"});n.createSpan({cls:"wl-credits-label",text:s});let r=kt(a);if(r.length===0){n.createSpan({cls:"wl-credits-empty",text:"\u2014"});return}r.forEach((o,l)=>{l>0&&n.createSpan({cls:"wl-credits-sep",text:", "});let c=n.createSpan({cls:"wl-credits-name",text:o});t&&(c.addClass("is-clickable"),c.title=`Show titles with ${o}`,c.addEventListener("click",d=>{d.stopPropagation(),t(o)}))})};e("Director",i.director),e("Cast",i.cast)}var Je=class extends St.Modal{constructor(t,e,s,a,n,r){super(t);this.changed=!1;this.plugin=e,this.dataManager=e.dataManager,this.group=s,this.members=a,this.onChanged=n,this.onPersonClick=r}onOpen(){var e;let t=(e=this.plugin.settings.colorTheme)!=null?e:"default";this.modalEl.setAttribute("data-theme",t),this.contentEl.setAttribute("data-theme",t),this.contentEl.addClass("wl-view"),this.contentEl.addClass("wl-detail-modal"),this.renderAll()}onClose(){this.contentEl.empty(),this.changed&&this.onChanged&&this.onChanged()}renderAll(){this.contentEl.empty();let t=this.contentEl.createDiv({cls:"wl-detail-header"}),e=t.createDiv({cls:"wl-detail-header-left"});e.createEl("h2",{cls:"wl-detail-title",text:this.group.name}),e.createDiv({cls:"wl-detail-group-meta",text:`${this.members.length} title${this.members.length!==1?"s":""}`});let s=this.members.reduce((d,u)=>d+this.dataManager.getEffectiveTotal(u),0),a=this.members.reduce((d,u)=>d+u.watchedEpisodes.length,0),n=s>0?Math.round(a/s*100):0,o=t.createDiv({cls:"wl-detail-stats-box"}).createDiv({cls:"wl-acc-header-right"});o.createDiv({cls:"wl-acc-percent",text:`${n}%`}),o.createDiv({cls:"wl-acc-progress-label",text:"progress"});let l=o.createDiv({cls:"wl-acc-progress-wrap"});l.createDiv({cls:"wl-progress-bar"}).style.width=`${n}%`;let c=this.contentEl.createDiv({cls:"wl-cards-grid wl-detail-group-grid"});for(let d of this.members){let u=Sn(this.plugin,d,{onOpenDetail:()=>{this.close(),new ye(this.plugin.app,this.plugin,d,()=>{this.changed=!0,this.onChanged&&this.onChanged()},this.onPersonClick).open()},onEdit:()=>{this.close(),new Bt(this.plugin.app,this.plugin,this.dataManager,d,()=>{this.changed=!0,this.onChanged&&this.onChanged()}).open()}});c.appendChild(u)}}};function Sn(g,i,t){var b;let e=g.settings,s=e.types.find(E=>E.name===i.type),a=e.statuses.find(E=>E.name===i.status),n=s?N(i.type,s.color,e.colorTheme):"#888780",o=activeDocument.createElement("div").createDiv({cls:"wl-card"});o.dataset.titleId=i.id;let l=o.createDiv({cls:"wl-card-poster-placeholder"});l.style.backgroundColor=n;let c=(i.title.trim().charAt(0)||"?").toUpperCase();l.createSpan({text:c});let d=o.createEl("img",{cls:"wl-card-poster"});d.alt=i.title;let u=E=>{d.src=E,o.addClass("has-poster")},h=()=>{o.removeClass("has-poster")},p=Rt(i),m=!!(i.manualPosterUrl&&i.manualPosterUrl.trim()!=="");if(p&&p.startsWith("http")?(u(p),d.onerror=()=>{h(),m||g.dataManager.updatePosterUrl(i.id,"none")}):!m&&i.posterUrl===""&&(l.addClass("is-loading"),(b=g.posterService)==null||b.enqueue(i).then(E=>{l.removeClass("is-loading"),E&&u(E)})),a){let E=o.createSpan({cls:"wl-card-status-badge",text:i.status});E.style.backgroundColor=N(i.status,a.color,e.colorTheme)}let f=o.createDiv({cls:"wl-card-overlay"});f.createSpan({cls:"wl-card-title",text:i.title});let y=f.createSpan({cls:"wl-card-type-badge",text:i.type});y.style.backgroundColor=n;let v=i.totalEpisodes;if(v&&v>0){let D=i.status==="Completed"?1:Math.max(0,Math.min(1,i.watchedEpisodes.length/v)),T=f.createDiv({cls:"wl-card-progress-bar"}).createDiv({cls:"wl-card-progress-fill"});T.style.width=`${D*100}%`}let w=o.createEl("button",{cls:"wl-card-menu-btn",text:"\u22EE"});return w.setAttr("aria-label","Edit"),w.addEventListener("click",E=>{E.stopPropagation(),t.onEdit()}),o.addEventListener("click",()=>t.onOpenDetail()),o}function js(g,i,t,e){let s=[];for(let n of i){let r=t(n);if(r&&r!=="none"&&r.trim()!==""&&(s.push(r),s.length===3))break}if(s.length===0){let n=g.createDiv({cls:"wl-card-poster-placeholder"});return n.style.backgroundColor=e.color,n.createSpan({text:e.letter}),n}let a=g.createDiv({cls:"wl-card-collage"});for(let n of s){let r=a.createDiv({cls:"wl-card-collage-strip"});r.style.backgroundImage=`url("${n.replace(/"/g,"%22")}")`}return a}var be=["High","Medium","Low"],at=class at{constructor(i,t,e){this.filterTypeExclude=new Set;this.filterStatusExclude=new Set;this.filterPriorityExclude=new Set;this.filterRatingExclude=new Set;this.filterGroupExclude=new Set;this.filterSort="dateAdded";this.filterSortDir="desc";this.filterSecondSort="none";this.filterSecondSortDir="asc";this.searchQuery="";this.expandedId=null;this.collapsedSeasons=new Set;this.expandedGroups=new Set;this.renamingGroupId=null;this.selectionMode=!1;this.selectedItems=new Set;this.pinnedGroupId=null;this.savedFilterActive=!1;this.savedFilterBtnEl=null;this.filterRatingEmptyOnly=!1;this.filterPriorityEmptyOnly=!1;this.filterRecentlyArrivedOnly=!1;this.filterGroupsOnly=!1;this.currentSubTab="list";this.toolbarExpanded=!1;this.scrollCleanup=null;this.cardsObserver=null;this.observedCards=new Set;this.cardsScrollContainer=null;this.cardsScrollSpacer=null;this.cardsGridEl=null;this.cardsDisplayItems=[];this.cardsScrollHandler=null;this.cardsScrollRAF=null;this.cardsResizeObserver=null;this.cardsLastFirst=-1;this.cardsLastLast=-1;this.cardsLastFirstRow=-1;this.cardsLastCols=-1;this.cardsLastCardHeight=-1;this.cardsLastTotalRows=-1;this.cardsLastScrollTop=0;this._cardsPersistentScrollTop=0;this.cardsRowHeight=0;this._lastScrollTop=0;this.scrollPositionListener=null;this.activeCleanups=[];this.toolbarActionsEl=null;this.STATUS_ORDER=["Watching","Plan to watch","Completed","To be released","Dropped"];var n,r,o,l,c,d,u,h,p,m,f,y,v,w,b,E,D;this.container=i,this.plugin=t,this.dataManager=e,this.currentSubTab=t.settings.defaultWatchlistView==="list"?"list":"cards",this.scrollPositionListener=()=>{this._lastScrollTop=this.container.scrollTop},this.container.addEventListener("scroll",this.scrollPositionListener,{passive:!0}),this.pinnedGroupId=e.getPinnedGroupId();let s=t.settings.listFilters;if(s){this.filterTypeExclude=new Set((n=s.typeExclude)!=null?n:[]),this.filterStatusExclude=new Set((r=s.statusExclude)!=null?r:[]),this.filterGroupExclude=new Set((o=s.groupExclude)!=null?o:[]),this.filterRatingExclude=new Set((l=s.ratingExclude)!=null?l:[]),this.filterPriorityExclude=new Set((c=s.priorityExclude)!=null?c:[]);let S=at.migrateSortKey((d=s.sort)!=null?d:"dateAdded-newest");this.filterSort=S.key,this.filterSortDir=(u=s.sortDir)!=null?u:S.dir;let T=at.migrateSortKey((h=s.secondSort)!=null?h:"none");this.filterSecondSort=T.key,this.filterSecondSortDir=(p=s.secondSortDir)!=null?p:T.dir,this.filterRatingEmptyOnly=(m=s.ratingEmptyOnly)!=null?m:!1,this.filterPriorityEmptyOnly=(f=s.priorityEmptyOnly)!=null?f:!1,this.filterRecentlyArrivedOnly=(y=s.recentlyArrivedOnly)!=null?y:!1,this.filterGroupsOnly=(v=s.groupsOnly)!=null?v:!1}let a=e.getSavedFilterPreset();if(a){let S=(T,M)=>T.size===M.length&&M.every(x=>T.has(x));this.savedFilterActive=S(this.filterTypeExclude,a.typeExclude)&&S(this.filterStatusExclude,a.statusExclude)&&S(this.filterGroupExclude,a.groupExclude)&&S(this.filterRatingExclude,a.ratingExclude)&&S(this.filterPriorityExclude,a.priorityExclude)&&this.filterRatingEmptyOnly===((w=a.ratingEmptyOnly)!=null?w:!1)&&this.filterPriorityEmptyOnly===((b=a.priorityEmptyOnly)!=null?b:!1)&&this.filterRecentlyArrivedOnly===((E=a.recentlyArrivedOnly)!=null?E:!1)&&this.filterGroupsOnly===((D=a.groupsOnly)!=null?D:!1)}}saveFiltersToSettings(){this.plugin.settings.listFilters={typeExclude:Array.from(this.filterTypeExclude),statusExclude:Array.from(this.filterStatusExclude),groupExclude:Array.from(this.filterGroupExclude),ratingExclude:Array.from(this.filterRatingExclude),priorityExclude:Array.from(this.filterPriorityExclude),sort:this.filterSort,sortDir:this.filterSortDir,secondSort:this.filterSecondSort,secondSortDir:this.filterSecondSortDir,ratingEmptyOnly:this.filterRatingEmptyOnly,priorityEmptyOnly:this.filterPriorityEmptyOnly,recentlyArrivedOnly:this.filterRecentlyArrivedOnly,groupsOnly:this.filterGroupsOnly},this.plugin.saveSettings()}hasActiveFilter(){return this.filterTypeExclude.size>0||this.filterStatusExclude.size>0||this.filterPriorityExclude.size>0||this.filterRatingExclude.size>0||this.filterGroupExclude.size>0||this.filterRatingEmptyOnly||this.filterPriorityEmptyOnly||this.filterRecentlyArrivedOnly||this.filterGroupsOnly}clearAllFilters(){this.filterTypeExclude.clear(),this.filterStatusExclude.clear(),this.filterPriorityExclude.clear(),this.filterRatingExclude.clear(),this.filterGroupExclude.clear(),this.filterRatingEmptyOnly=!1,this.filterPriorityEmptyOnly=!1,this.filterRecentlyArrivedOnly=!1,this.filterGroupsOnly=!1}applyPreset(i){var t,e,s,a;this.filterTypeExclude=new Set(i.typeExclude),this.filterStatusExclude=new Set(i.statusExclude),this.filterGroupExclude=new Set(i.groupExclude),this.filterRatingExclude=new Set(i.ratingExclude),this.filterPriorityExclude=new Set(i.priorityExclude),this.filterRatingEmptyOnly=(t=i.ratingEmptyOnly)!=null?t:!1,this.filterPriorityEmptyOnly=(e=i.priorityEmptyOnly)!=null?e:!1,this.filterRecentlyArrivedOnly=(s=i.recentlyArrivedOnly)!=null?s:!1,this.filterGroupsOnly=(a=i.groupsOnly)!=null?a:!1}deactivateSavedFilter(){var i;this.savedFilterActive&&(this.savedFilterActive=!1,(i=this.savedFilterBtnEl)==null||i.removeClass("wl-btn-preset-active"))}static isRecentlyArrived(i){if(!i.releaseDate||!/^\d{4}-\d{2}-\d{2}$/.test(i.releaseDate))return!1;let t=new Date(i.releaseDate+"T00:00:00").getTime(),e=new Date;e.setHours(0,0,0,0);let s=(e.getTime()-t)/864e5;return s>=0&&s<=7}titlePassesFilters(i){if(this.filterTypeExclude.size>0&&this.filterTypeExclude.has(i.type))return!1;if(this.filterRecentlyArrivedOnly){if(!at.isRecentlyArrived(i))return!1}else if(this.filterStatusExclude.size>0&&this.filterStatusExclude.has(i.status))return!1;if(this.filterRatingEmptyOnly){if(i.rating!==0)return!1}else if(this.filterRatingExclude.size>0&&this.filterRatingExclude.has(`${i.rating}\u2605`))return!1;if(this.filterPriorityEmptyOnly){if(i.priority)return!1}else if(this.filterPriorityExclude.size>0&&this.filterPriorityExclude.has(i.priority))return!1;return!0}destroy(){this.scrollPositionListener&&(this.container.removeEventListener("scroll",this.scrollPositionListener),this.scrollPositionListener=null),this.scrollCleanup&&(this.scrollCleanup(),this.scrollCleanup=null),this.destroyVirtualScroll(),this.dataManager.flushPendingSave()}render(){this._lastScrollTop=this.container.scrollTop||this._lastScrollTop,this.activeCleanups.forEach(i=>i()),this.activeCleanups=[],this.container.empty(),this.container.addClass("wl-list"),this.renderSubTabBar(),this.currentSubTab==="list"?this.renderListContent():this.renderCardsContent()}renderSubTabBar(){let i=this.container.createDiv({cls:"wl-inner-tab-bar"}),t=i.createEl("button",{cls:`wl-inner-tab-btn${this.currentSubTab==="cards"?" is-active":""}`,text:"Cards"});i.createEl("button",{cls:`wl-inner-tab-btn${this.currentSubTab==="list"?" is-active":""}`,text:"List"}).addEventListener("click",()=>{this.currentSubTab!=="list"&&(this.destroyVirtualScroll(),this.currentSubTab="list",this.render())}),t.addEventListener("click",()=>{this.currentSubTab!=="cards"&&(this.currentSubTab="cards",this.render())})}renderListContent(){this.renderHeader(),this.container.createDiv({cls:"wl-divider"}),this.renderTable(this._lastScrollTop)}renderCardsContent(){this.renderHeader(),this.container.createDiv({cls:"wl-divider"}),this.renderCardsView()}renderCardsView(){this.destroyVirtualScroll();let i=this.getDisplayItems();if(this.cardsDisplayItems=i,this.renderResultsCount(this.container,i),i.length===0){let a=this.container.createDiv({cls:"wl-cards-empty"});a.createSpan({cls:"wl-cards-empty-icon",text:"\u{1F3AC}"}),a.createEl("p",{cls:"wl-cards-empty-msg",text:"No titles match your filters"});return}let t=this.container.createDiv({cls:"wl-cards-scroll-container"}),e=t.createDiv({cls:"wl-cards-scroll-spacer"}),s=e.createDiv({cls:"wl-cards-grid wl-cards-grid-virtual"});this.cardsScrollContainer=t,this.cardsScrollSpacer=e,this.cardsGridEl=s,this.cardsLastFirst=-1,this.cardsLastLast=-1,this.cardsLastFirstRow=-1,this.cardsLastCols=-1,this.cardsLastCardHeight=-1,this.cardsLastTotalRows=-1,this.cardsScrollHandler=()=>{let a=t.scrollTop;this._cardsPersistentScrollTop=a;let n=this.cardsRowHeight>0?this.cardsRowHeight/2:50;Math.abs(a-this.cardsLastScrollTop){this.cardsScrollRAF=null,this.renderVisibleCards()})))},t.addEventListener("scroll",this.cardsScrollHandler,{passive:!0}),this.cardsResizeObserver=new ResizeObserver(()=>{this.cardsScrollRAF===null&&(this.cardsScrollRAF=window.requestAnimationFrame(()=>{this.cardsScrollRAF=null,this.renderVisibleCards()}))}),this.cardsResizeObserver.observe(t),this._cardsPersistentScrollTop>0&&(this.renderVisibleCards(),t.scrollTop=this._cardsPersistentScrollTop,this.cardsLastScrollTop=this._cardsPersistentScrollTop,this.renderVisibleCards())}getCardsGridMetrics(i){let s=Math.max(1,Math.floor((i+12)/152)),a=(i-12*(s-1))/s,n=a*1.5,r=n+12;return{cols:s,cardWidth:a,cardHeight:n,rowHeight:r}}renderVisibleCards(){let i=this.cardsScrollContainer,t=this.cardsScrollSpacer,e=this.cardsGridEl;if(!i||!t||!e)return;let s=i.scrollTop,a=i.clientHeight,n=i.clientWidth;if(n<=0||a<=0)return;let{cols:r,cardWidth:o,cardHeight:l,rowHeight:c}=this.getCardsGridMetrics(n);this.cardsRowHeight=c;let d=this.cardsDisplayItems.length,u=Math.ceil(d/r),h=Math.max(0,Math.floor(s/c)-2),p=Math.min(u-1,Math.ceil((s+a)/c)+2),m=h*r,f=Math.min(d-1,(p+1)*r-1),y=this.cardsLastFirst,v=this.cardsLastLast,w=m===y&&f===v,b=h===this.cardsLastFirstRow&&r===this.cardsLastCols&&l===this.cardsLastCardHeight&&u===this.cardsLastTotalRows;if(w&&b||(b||(t.style.height=`${u*c}px`,e.style.paddingTop=`${h*c}px`,e.style.setProperty("--wl-cards-cols",String(r)),e.style.setProperty("--wl-card-height",`${l}px`),this.cardsLastFirstRow=h,this.cardsLastCols=r,this.cardsLastCardHeight=l,this.cardsLastTotalRows=u),w))return;let E=y===-1||v===-1,D=!E&&m<=v&&f>=y;if(this.cardsLastFirst=m,this.cardsLastLast=f,E||!D){this.fullRenderCards(e,m,f,o,l),this.setupCardsObserver(i);return}if(m>y){let S=m-y;for(let T=0;Tv){let S=Math.max(v+1,m),T=activeDocument.createDocumentFragment();for(let M=S;M<=f;M++){let x=this.buildCardElement(M,o,l);x&&T.appendChild(x)}e.appendChild(T)}this.setupCardsObserver(i)}fullRenderCards(i,t,e,s,a){this.observedCards.clear(),i.empty();let n=activeDocument.createDocumentFragment();for(let r=t;r<=e;r++){let o=this.buildCardElement(r,s,a);o&&n.appendChild(o)}i.appendChild(n)}buildCardElement(i,t,e){let s=this.cardsDisplayItems[i];if(!s)return null;let a=activeDocument.createElement("div");return s.kind==="title"?this.renderTitleCard(a,s.data,t,e):this.renderGroupCard(a,s.data,s.members,t,e),a.firstElementChild}unobserveAndRemove(i){this.cardsObserver&&this.observedCards.has(i)&&(this.cardsObserver.unobserve(i),this.observedCards.delete(i)),i.remove()}setupCardsObserver(i){var e;this.cardsObserver||(this.cardsObserver=new IntersectionObserver(s=>this.handleCardIntersection(s),{root:i,rootMargin:"0px",threshold:0})),((e=this.cardsGridEl)!=null?e:i).querySelectorAll('.wl-card[data-needs-poster="true"]').forEach(s=>{let a=s;this.observedCards.has(a)||(this.cardsObserver.observe(a),this.observedCards.add(a))})}handleCardIntersection(i){var t;for(let e of i){if(!e.isIntersecting)continue;let s=e.target,a=s.dataset.titleId;if(!a)continue;(t=this.cardsObserver)==null||t.unobserve(s);let n=this.dataManager.getTitles().find(o=>o.id===a);if(!n||n.manualPosterUrl&&n.manualPosterUrl.trim()!==""||n.posterUrl||n.posterUrl==="none")continue;let r=s.querySelector(".wl-card-poster-placeholder");r==null||r.addClass("is-loading"),this.plugin.posterService.enqueue(n).then(o=>{r==null||r.removeClass("is-loading"),o&&this.applyPosterToCard(s,o)})}}applyPosterToCard(i,t){let e=i.querySelector(".wl-card-poster");e&&(e.onload=()=>{i.addClass("has-poster")},e.onerror=()=>{let s=i.dataset.titleId;s&&this.dataManager.updatePosterUrl(s,"none")},e.src=t)}destroyCardsObserver(){var i;this.cardsObserver&&(this.cardsObserver.disconnect(),this.cardsObserver=null),this.observedCards.clear(),(i=this.plugin.posterService)==null||i.clearQueue()}destroyVirtualScroll(){this.cardsScrollRAF!==null&&(window.cancelAnimationFrame(this.cardsScrollRAF),this.cardsScrollRAF=null),this.cardsResizeObserver&&(this.cardsResizeObserver.disconnect(),this.cardsResizeObserver=null),this.cardsScrollContainer&&this.cardsScrollHandler&&this.cardsScrollContainer.removeEventListener("scroll",this.cardsScrollHandler),this.cardsScrollHandler=null,this.cardsScrollContainer=null,this.cardsScrollSpacer=null,this.cardsGridEl=null,this.cardsDisplayItems=[],this.cardsLastFirst=-1,this.cardsLastLast=-1,this.cardsLastFirstRow=-1,this.cardsLastCols=-1,this.cardsLastCardHeight=-1,this.cardsLastTotalRows=-1,this.cardsLastScrollTop=0,this.cardsRowHeight=0,this.destroyCardsObserver()}renderTitleCard(i,t,e,s){let a=this.getTagDef(t.type,this.plugin.settings.types),n=this.getTagDef(t.status,this.plugin.settings.statuses),r=a?N(t.type,a.color,this.plugin.settings.colorTheme):"#888780",o=i.createDiv({cls:"wl-card"});o.dataset.titleId=t.id,this.selectedItems.has(t.id)&&o.addClass("wl-card-selected"),s!==void 0&&(o.style.height=`${s}px`);let l=o.createDiv({cls:"wl-card-poster-placeholder"});l.style.backgroundColor=r;let c=(t.title.trim().charAt(0)||"?").toUpperCase();l.createSpan({text:c});let d=o.createEl("img",{cls:"wl-card-poster"});d.alt=t.title,e!==void 0&&s!==void 0&&(d.width=Math.round(e),d.height=Math.round(s));let u=Rt(t),h=!!(t.manualPosterUrl&&t.manualPosterUrl.trim()!==""),p=!h&&!t.posterUrl&&t.posterUrl!=="none";if(u&&u.startsWith("http")?(d.onerror=()=>{o.removeClass("has-poster"),h||this.dataManager.updatePosterUrl(t.id,"none")},o.addClass("has-poster"),d.src=u):p&&(o.dataset.needsPoster="true"),n){let w=o.createSpan({cls:"wl-card-status-badge",text:t.status});w.style.backgroundColor=N(t.status,n.color,this.plugin.settings.colorTheme)}let m=o.createDiv({cls:"wl-card-overlay"});m.createSpan({cls:"wl-card-title",text:t.title});let f=m.createSpan({cls:"wl-card-type-badge",text:t.type});f.style.backgroundColor=r;let y=t.totalEpisodes;if(y&&y>0){let b=t.status==="Completed"?1:Math.max(0,Math.min(1,t.watchedEpisodes.length/y)),D=m.createDiv({cls:"wl-card-progress-bar"}).createDiv({cls:"wl-card-progress-fill"});D.style.width=`${b*100}%`}let v=o.createEl("button",{cls:"wl-card-menu-btn",text:"\u22EE"});v.setAttr("aria-label","More actions"),v.addEventListener("click",w=>{w.stopPropagation(),this.openCardContextMenu(o,v,t)}),o.addEventListener("click",()=>{if(this.selectionMode){this.toggleCardSelection(o,t.id);return}this.openDetailModalForTitle(t.id)})}openCardContextMenu(i,t,e){this.container.querySelectorAll(".wl-card-context-menu").forEach(h=>h.remove());let s=i.createDiv({cls:"wl-card-context-menu"}),a=s.createDiv({cls:"wl-card-context-item",text:"Edit title"}),n=s.createDiv({cls:"wl-card-context-item",text:"Refresh poster"}),r=s.createDiv({cls:"wl-card-context-item",text:"Refresh rating"}),o=i.getBoundingClientRect(),l=this.container.getBoundingClientRect();o.right>l.right-180&&s.classList.add("is-right-aligned");let c=i.ownerDocument,d=()=>{s.remove(),c.removeEventListener("click",u,!0)},u=h=>{!s.contains(h.target)&&h.target!==t&&d()};window.setTimeout(()=>c.addEventListener("click",u,!0),0),this.activeCleanups.push(()=>c.removeEventListener("click",u,!0)),a.addEventListener("click",h=>{h.stopPropagation(),d(),this.openEditModalForTitle(e.id)}),n.addEventListener("click",h=>{h.stopPropagation(),d(),this.refreshPosterForCard(i,e.id)}),r.addEventListener("click",h=>{h.stopPropagation(),d(),Ji(this.plugin,e.id,null,!0)})}refreshPosterForCard(i,t){let e=this.dataManager.getTitle(t);if(!e)return;this.dataManager.updatePosterUrl(t,""),i.dataset.needsPoster="true";let s=i.querySelector(".wl-card-poster"),a=i.querySelector(".wl-card-poster-placeholder");s&&s.removeAttribute("src"),i.removeClass("has-poster"),a&&a.addClass("is-loading"),this.plugin.posterService.enqueue(e).then(n=>{a==null||a.removeClass("is-loading"),n&&this.applyPosterToCard(i,n)})}renderGroupCard(i,t,e,s,a){var p,m;let n=(m=(p=e[0])==null?void 0:p.type)!=null?m:"",r=n?this.getTagDef(n,this.plugin.settings.types):void 0,o=r?N(n,r.color,this.plugin.settings.colorTheme):"#888780",l=i.createDiv({cls:"wl-card wl-card-group"});l.dataset.groupId=t.id,this.selectedItems.has(t.id)&&l.addClass("wl-card-selected"),a!==void 0&&(l.style.height=`${a}px`);let c=(t.name.trim().charAt(0)||"?").toUpperCase();js(l,e,Rt,{letter:c,color:o});let d=l.createDiv({cls:"wl-card-overlay"});d.createSpan({cls:"wl-card-title",text:t.name});let u=d.createSpan({cls:"wl-card-type-badge"});u.style.backgroundColor=o,u.textContent=`${e.length} title${e.length!==1?"s":""}`;let h=l.createEl("button",{cls:"wl-card-menu-btn",text:"\u22EE"});h.setAttr("aria-label","Group actions"),h.addEventListener("click",f=>{f.stopPropagation(),this.openGroupCardContextMenu(l,h,t)}),l.addEventListener("click",()=>{if(this.selectionMode){this.toggleCardSelection(l,t.id);return}new Je(this.plugin.app,this.plugin,t,e,()=>{this.render()},f=>this.applyPersonSearch(f)).open()})}openGroupCardContextMenu(i,t,e){this.container.querySelectorAll(".wl-card-context-menu").forEach(u=>u.remove());let s=i.createDiv({cls:"wl-card-context-menu"}),a=s.createDiv({cls:"wl-card-context-item",text:"Edit name"}),n=s.createDiv({cls:"wl-card-context-item",text:"Delete group"}),r=i.getBoundingClientRect(),o=this.container.getBoundingClientRect();r.right>o.right-180&&s.classList.add("is-right-aligned");let l=i.ownerDocument,c=()=>{s.remove(),l.removeEventListener("click",d,!0)},d=u=>{!s.contains(u.target)&&u.target!==t&&c()};window.setTimeout(()=>l.addEventListener("click",d,!0),0),this.activeCleanups.push(()=>l.removeEventListener("click",d,!0)),a.addEventListener("click",u=>{u.stopPropagation(),c(),this.openRenameGroupPrompt(e)}),n.addEventListener("click",u=>{u.stopPropagation(),c(),new _(this.plugin.app,`Delete group "${e.name}"? All titles inside will be returned to the main list.`,()=>{this.dataManager.removeGroup(e.id).then(()=>{this.expandedGroups.delete(e.id),this.render()})}).open()})}openRenameGroupPrompt(i){let t=new qs.Modal(this.plugin.app);t.titleEl.setText("Rename group");let e=t.contentEl.createEl("input",{cls:"wl-input",attr:{type:"text",value:i.name,placeholder:"Group name"}}),s=t.contentEl.createDiv({cls:"wl-modal-btn-row"}),a=()=>{let n=e.value.trim();n&&n!==i.name&&this.dataManager.updateGroup({...i,name:n}).then(()=>this.render()),t.close()};s.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",a),s.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>t.close()),e.addEventListener("keydown",n=>{n.key==="Enter"?a():n.key==="Escape"&&t.close()}),t.open(),window.setTimeout(()=>{e.focus(),e.select()},0)}openEditModalForTitle(i){let t=this.dataManager.getTitle(i);t&&new Bt(this.plugin.app,this.plugin,this.dataManager,t,()=>{this.render()}).open()}openDetailModalForTitle(i){let t=this.dataManager.getTitle(i);t&&new ye(this.plugin.app,this.plugin,t,()=>{this.render()},e=>this.applyPersonSearch(e)).open()}applyPersonSearch(i){this.searchQuery=i,this.render()}renderHeader(){let i=this.container.createDiv({cls:"wl-list-header"});if(this.plugin.importProgress){let{current:e,total:s,cancel:a}=this.plugin.importProgress,n=i.createDiv({cls:"wl-header-import-progress"}),o=n.createDiv({cls:"wl-header-import-track"}).createDiv({cls:"wl-header-import-fill"});o.style.width=`${s>0?Math.round(e/s*100):0}%`,n.createSpan({cls:"wl-header-import-text",text:`${e} / ${s}`}),n.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Cancel import"}).addEventListener("click",()=>a())}let t=i.createDiv({cls:"wl-header-controls"});Qe({controls:t,renderSearch:e=>this.renderSearch(e),renderActions:e=>{let s=e.createDiv({cls:"wl-toolbar-actions"});this.toolbarActionsEl=s,this.renderToolbarActions(s)},expanded:this.toolbarExpanded,onToggleChange:e=>{this.toolbarExpanded=e}})}refreshToolbarActions(){let i=this.toolbarActionsEl;!i||!i.isConnected||(i.empty(),this.renderToolbarActions(i))}setSelectionMode(i){this.selectionMode=i,this.selectedItems.clear(),this.refreshToolbarActions(),this.currentSubTab==="cards"?this.syncCardSelectionClasses():this.rerenderTable()}syncCardSelectionClasses(){let i=this.cardsGridEl;i&&i.querySelectorAll(".wl-card").forEach(t=>{var s;let e=(s=t.dataset.titleId)!=null?s:t.dataset.groupId;t.classList.toggle("wl-card-selected",!!e&&this.selectedItems.has(e))})}toggleCardSelection(i,t){this.selectedItems.has(t)?this.selectedItems.delete(t):this.selectedItems.add(t),i.classList.toggle("wl-card-selected",this.selectedItems.has(t)),this.refreshToolbarActions()}toggleRowSelection(i,t){let e=!this.selectedItems.has(t);e?this.selectedItems.add(t):this.selectedItems.delete(t),i.classList.toggle("wl-row-selected",e);let s=i.querySelector(".wl-col-select input");return s&&(s.checked=e),this.refreshToolbarActions(),e}renderToolbarActions(i){let t=this.dataManager.getSavedFilterPreset();if(t){let r=i.createEl("button",{cls:`wl-btn wl-btn-sm${this.savedFilterActive?" wl-btn-preset-active":""}`,text:"Saved filter"});this.savedFilterBtnEl=r,r.addEventListener("click",()=>{this.applyPreset(t),this.savedFilterActive=!0,this.saveFiltersToSettings(),this.refreshToolbarActions(),this.rerenderActiveSubTab()})}else this.savedFilterBtnEl=null;if(this.renderFiltersDropdown(i),this.renderSortingDropdown(i),this.selectionMode&&this.selectedItems.size>0&&this.renderActionBar(i),this.selectionMode){let r=this.selectedItems.size>0,o=i.createEl("button",{cls:"wl-btn wl-btn-sm",text:r?"None":"All"});o.title=r?"Deselect all":"Select all visible",o.addEventListener("click",()=>{if(this.selectedItems.size>0)this.selectedItems.clear();else for(let l of this.getDisplayItems())this.selectedItems.add(l.data.id);this.refreshToolbarActions(),this.currentSubTab==="cards"?this.syncCardSelectionClasses():this.rerenderTable()})}i.createEl("button",{cls:`wl-btn wl-btn-sm${this.selectionMode?" is-active":""}`,text:"Select"}).addEventListener("click",()=>{this.setSelectionMode(!this.selectionMode)}),i.createDiv({cls:"wl-header-controls-right"}).createDiv({cls:"wl-add-btn-wrap"}).createEl("button",{cls:"wl-add-btn wl-btn-success",text:"+ add"}).addEventListener("click",r=>{r.stopPropagation(),this.openAddTitleChooser()})}openAddTitleChooser(){new je(this.plugin.app,i=>{i==="url"?new ze(this.plugin.app,this.plugin,this.dataManager,()=>{this.render()}).open():this.openAddTitleModal()}).open()}renderFiltersDropdown(i){let t=i.createDiv({cls:"wl-add-btn-wrap"}),e=t.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Filters \u25BC"}),s=e.createSpan({cls:"wl-filter-dot"});this.hasActiveFilter()?s.show():s.hide();let a=i.createEl("button",{cls:"wl-btn wl-btn-sm wl-btn-clear-filters",text:"\u2715 clear"});a.title="Clear all filters",this.hasActiveFilter()?a.show():a.hide(),a.addEventListener("click",()=>{this.clearAllFilters(),this.saveFiltersToSettings(),this.deactivateSavedFilter(),s.hide(),a.hide(),this.rerenderTable()}),e.addEventListener("click",n=>{n.stopPropagation();let r=activeDocument.querySelector(".wl-filters-panel");if(r){r.remove();return}let o=activeDocument.body.createDiv({cls:"wl-dropdown wl-filters-panel wl-filters-panel-popup"}),l=e.getBoundingClientRect();o.style.top=`${l.bottom+4}px`,o.style.left=`${l.left}px`;let c=this.plugin.settings.types.map(C=>C.name),d=this.plugin.settings.statuses.map(C=>C.name),u=["1\u2605","2\u2605","3\u2605","4\u2605","5\u2605"],h=this.plugin.settings.priorities.map(C=>C.name),p=this.dataManager.getGroups().map(C=>C.name),m={typeExclude:new Set(this.filterTypeExclude),statusExclude:new Set(this.filterStatusExclude),ratingExclude:new Set(this.filterRatingExclude),priorityExclude:new Set(this.filterPriorityExclude),groupExclude:new Set(this.filterGroupExclude),filterRatingEmptyOnly:this.filterRatingEmptyOnly,filterPriorityEmptyOnly:this.filterPriorityEmptyOnly,filterRecentlyArrivedOnly:this.filterRecentlyArrivedOnly,filterGroupsOnly:this.filterGroupsOnly},f=[{label:"Type",opts:c,excludeSet:m.typeExclude},{label:"Status",opts:d,excludeSet:m.statusExclude},{label:"Rating",opts:u,excludeSet:m.ratingExclude},{label:"Priority",opts:h,excludeSet:m.priorityExclude}];p.length>0&&f.push({label:"Group",opts:p,excludeSet:m.groupExclude});let y=[],v=o.createDiv({cls:"wl-filter-global-btns"}),w=null;v.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Select all"}).addEventListener("click",C=>{C.stopPropagation();for(let{excludeSet:L}of f)L.clear();for(let{cb:L}of y)L.checked=!0;m.filterRecentlyArrivedOnly=!1,w&&(w.checked=!1)}),v.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Deselect all"}).addEventListener("click",C=>{C.stopPropagation();for(let{opts:L,excludeSet:I}of f)for(let H of L)I.add(H);for(let{cb:L}of y)L.checked=!1;m.filterRecentlyArrivedOnly=!1,w&&(w.checked=!1)});let D=this.dataManager.getSavedFilterPreset(),S=v.createEl("button",{cls:"wl-btn wl-btn-sm",text:D?"Delete":"Save"});S.addEventListener("click",C=>{(async()=>(C.stopPropagation(),S.textContent==="Save"?await this.dataManager.setSavedFilterPreset({typeExclude:Array.from(m.typeExclude),statusExclude:Array.from(m.statusExclude),groupExclude:Array.from(m.groupExclude),ratingExclude:Array.from(m.ratingExclude),priorityExclude:Array.from(m.priorityExclude),ratingEmptyOnly:m.filterRatingEmptyOnly,priorityEmptyOnly:m.filterPriorityEmptyOnly,recentlyArrivedOnly:m.filterRecentlyArrivedOnly,groupsOnly:m.filterGroupsOnly}):(await this.dataManager.setSavedFilterPreset(null),this.savedFilterActive=!1),o.remove(),this.render()))()});let T={};for(let{label:C}of f)T[C]=!0;for(let{label:C,opts:L,excludeSet:I}of f){let H=o.createDiv({cls:"wl-filter-section"}),k=H.createDiv({cls:"wl-filter-section-header"});k.createSpan({cls:"wl-filter-label",text:C});let R=k.createSpan({cls:"wl-filter-chevron",text:"\u25BC"}),P=H.createDiv({cls:"wl-filter-section-content wl-hidden"});k.addEventListener("click",V=>{var Y;V.stopPropagation(),T[C]=!T[C];let O=(Y=T[C])!=null?Y:!0;P.toggleClass("wl-hidden",O),R.textContent=O?"\u25BC":"\u25B2"});let B=P.createDiv({cls:"wl-filter-checkbox-row"}),K=B.createEl("input",{attr:{type:"checkbox"}});if(B.createSpan({cls:"wl-filter-all-toggle",text:"\u25C6 All"}),C==="Status"){let V=P.createDiv({cls:"wl-filter-checkbox-row"}),O=V.createEl("input",{attr:{type:"checkbox"}});O.checked=m.filterRecentlyArrivedOnly,V.createSpan({cls:"wl-recently-arrived-filter",text:"\u2726 Recently arrived"}),w=O,O.addEventListener("change",()=>{if(m.filterRecentlyArrivedOnly=O.checked,O.checked){I.clear();for(let Y of yt)Y.checked=!0}})}let U=null,z=[],yt=[];if(C==="Rating"||C==="Priority"){let V=P.createDiv({cls:"wl-filter-checkbox-row"});U=V.createEl("input",{attr:{type:"checkbox"}}),U.checked=C==="Rating"?m.filterRatingEmptyOnly:m.filterPriorityEmptyOnly,V.createSpan({text:"Empty"});let O=U;U.addEventListener("change",()=>{if(C==="Rating"?m.filterRatingEmptyOnly=O.checked:m.filterPriorityEmptyOnly=O.checked,O.checked){for(let Y of z)Y.checked=!0;I.clear()}})}if(C==="Group"){let V=P.createDiv({cls:"wl-filter-checkbox-row"}),O=V.createEl("input",{attr:{type:"checkbox"}});O.checked=m.filterGroupsOnly,V.createSpan({cls:"wl-recently-arrived-filter",text:"\u25C7 Groups only"}),O.addEventListener("change",()=>{m.filterGroupsOnly=O.checked}),P.createDiv({cls:"wl-filter-section-divider"})}for(let V of L){let O=P.createDiv({cls:"wl-filter-checkbox-row"}),Y=O.createEl("input",{attr:{type:"checkbox"}});Y.checked=!I.has(V),O.createSpan({text:V}),z.push(Y),C==="Status"&&yt.push(Y),y.push({cb:Y});let bi=U;Y.addEventListener("change",()=>{Y.checked?I.delete(V):I.add(V),C==="Status"&&w&&(m.filterRecentlyArrivedOnly=!1,w.checked=!1),(C==="Rating"||C==="Priority")&&bi&&(C==="Rating"?m.filterRatingEmptyOnly=!1:m.filterPriorityEmptyOnly=!1,bi.checked=!1)})}let yi=()=>{K.checked=z.length>0&&z.every(V=>V.checked)};yi();let bt=()=>{if(z.length>0&&z.every(O=>O.checked)){for(let O of z)O.checked=!1;for(let O of L)I.add(O)}else{for(let O of z)O.checked=!0;I.clear()}yi()};K.addEventListener("click",V=>{V.stopPropagation(),bt()}),B.addEventListener("click",V=>{V.target!==K&&(V.stopPropagation(),bt())})}o.createEl("button",{cls:"wl-btn wl-btn-sm wl-filter-apply-btn",text:"Apply"}).addEventListener("click",C=>{C.stopPropagation(),this.filterTypeExclude=m.typeExclude,this.filterStatusExclude=m.statusExclude,this.filterRatingExclude=m.ratingExclude,this.filterPriorityExclude=m.priorityExclude,this.filterGroupExclude=m.groupExclude,this.filterRatingEmptyOnly=m.filterRatingEmptyOnly,this.filterPriorityEmptyOnly=m.filterPriorityEmptyOnly,this.filterRecentlyArrivedOnly=m.filterRecentlyArrivedOnly,this.filterGroupsOnly=m.filterGroupsOnly,this.saveFiltersToSettings(),this.deactivateSavedFilter(),this.hasActiveFilter()?(s.show(),a.show()):(s.hide(),a.hide()),this.rerenderTable(),o.remove(),activeDocument.removeEventListener("mousedown",x,!1)});let x=C=>{let L=C.target;o.contains(L)||t.contains(L)||(o.remove(),activeDocument.removeEventListener("mousedown",x,!1))};window.setTimeout(()=>activeDocument.addEventListener("mousedown",x,!1),0)})}renderSortingDropdown(i){let t=i.createDiv({cls:"wl-add-btn-wrap"}),e=t.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Sorting \u25BC"});e.addEventListener("click",s=>{s.stopPropagation();let a=t.querySelector(".wl-dropdown");if(a){a.remove();return}let n=t.createDiv({cls:"wl-dropdown wl-sorting-panel"});if(window.innerWidth<=600){let c=e.getBoundingClientRect();n.addClass("wl-sorting-panel-mobile"),n.style.top=`${c.bottom+4}px`}let r=["Title","Date added","Progress","Rating","Priority","Started","Status","Date watched","Time left","Time watched"],o=(c,d,u,h)=>{let p=n.createDiv({cls:"wl-filter-row"});p.createSpan({cls:"wl-filter-label",text:c});let m=p.createEl("select",{cls:"wl-select"});if(!h){let y=m.createEl("option",{text:"None",value:"none"});y.selected=d==="none"}for(let y of r){let v=m.createEl("option",{text:y,value:y});this.sortLabelToKey(y)===d&&(v.selected=!0)}let f=p.createEl("button",{cls:"wl-btn wl-btn-sm wl-sort-dir-btn",text:u==="asc"?"\u2191":"\u2193"});f.title=u==="asc"?"Ascending \u2014 click to switch to descending":"Descending \u2014 click to switch to ascending",m.addEventListener("change",()=>{var v,w;let y=m.value==="none"?"none":this.sortLabelToKey(m.value);h?(this.filterSort=y,this.filterSortDir=(v=at.SORT_DEFAULT_DIR[y])!=null?v:"asc"):(this.filterSecondSort=y,this.filterSecondSortDir=(w=at.SORT_DEFAULT_DIR[y])!=null?w:"asc"),n.remove(),activeDocument.removeEventListener("click",l,!0),this.saveFiltersToSettings(),this.rerenderActiveSubTab()}),f.addEventListener("click",y=>{y.stopPropagation(),h?this.filterSortDir=this.filterSortDir==="asc"?"desc":"asc":this.filterSecondSortDir=this.filterSecondSortDir==="asc"?"desc":"asc",n.remove(),activeDocument.removeEventListener("click",l,!0),this.saveFiltersToSettings(),this.rerenderActiveSubTab()})};o("Sort by",this.filterSort,this.filterSortDir,!0),o("Then by",this.filterSecondSort,this.filterSecondSortDir,!1);let l=c=>{t.contains(c.target)||(n.remove(),activeDocument.removeEventListener("click",l,!0))};window.setTimeout(()=>activeDocument.addEventListener("click",l,!0),0)})}renderActionBar(i){let t=i.createDiv({cls:"wl-action-bar"}),e=t.createEl("button",{cls:"wl-group-action-btn wl-group-action-btn-delete wl-btn-danger",text:"\u2715"});e.title="Delete selected",e.addEventListener("click",o=>{o.stopPropagation();let l=this.selectedItems.size;new _(this.plugin.app,`Delete ${l} selected item${l!==1?"s":""}? This cannot be undone.`,()=>{(async()=>{let c=new Set(this.dataManager.getGroups().map(u=>u.id)),d=[];for(let u of Array.from(this.selectedItems))c.has(u)?(await this.dataManager.removeGroup(u),this.expandedGroups.delete(u)):(d.push(u),this.expandedId===u&&(this.expandedId=null));d.length>0&&await this.dataManager.removeTitlesBatch(d),this.selectedItems.clear(),this.render()})()}).open()});let s=t.createEl("select",{cls:"wl-select wl-select-sm"});s.createEl("option",{text:"Status\u2026",value:""});for(let o of this.plugin.settings.statuses.filter(l=>l.name!=="To be released"))s.createEl("option",{text:o.name,value:o.name});s.addEventListener("change",()=>{(async()=>{let o=s.value;if(!o)return;let l=new Set(this.dataManager.getGroups().map(d=>d.id)),c=[];for(let d of this.selectedItems){if(l.has(d))continue;let u=this.dataManager.getTitle(d);u&&(u.status=o,this.dataManager.updateTitleSilent(u),c.push(u))}if(c.length>0){await this.dataManager.save();for(let d of c)await this.dataManager.updateMarkdownFile(d)}s.value="",this.render()})()});let a=this.dataManager.getGroups(),n=Array.from(this.selectedItems).some(o=>this.dataManager.getGroups().some(l=>l.id===o)),r=t.createEl("select",{cls:"wl-select wl-select-sm"});n&&(r.disabled=!0,r.title="A group is selected \u2014 cannot move groups into other groups"),r.createEl("option",{text:"Group\u2026",value:""});for(let o of a)r.createEl("option",{text:o.name,value:o.id});r.createEl("option",{text:"Create new group\u2026",value:"__new__"}),r.addEventListener("change",()=>{(async()=>{let o=r.value;if(!o)return;let l=new Set(a.map(d=>d.id)),c=Array.from(this.selectedItems).filter(d=>!l.has(d));if(o==="__new__"){r.value="",r.hide();let d=t.createEl("input",{cls:"wl-modal-input wl-group-name-input",attr:{type:"text",placeholder:"Group name\u2026",maxlength:"64"}}),u=t.createEl("button",{cls:"wl-group-action-btn",text:"\u2713"});u.title="Create group";let h=t.createEl("button",{cls:"wl-group-action-btn",text:"\u2715"});h.title="Cancel";let p=async()=>{let m=d.value.trim();if(!m)return;let f={id:this.dataManager.generateGroupId(m),name:m,titleIds:c,dateAdded:new Date().toISOString()};await this.dataManager.addGroup(f),this.selectedItems.clear(),this.selectionMode=!1,this.render()};u.addEventListener("click",m=>{m.stopPropagation(),p()}),h.addEventListener("click",m=>{m.stopPropagation(),this.refreshToolbarActions()}),d.addEventListener("keydown",m=>{m.stopPropagation(),m.key==="Enter"&&p(),m.key==="Escape"&&this.refreshToolbarActions()}),d.addEventListener("click",m=>m.stopPropagation()),window.setTimeout(()=>d.focus(),0);return}for(let d of c)await this.dataManager.addTitleToGroup(o,d);r.value="",this.selectedItems.clear(),this.selectionMode=!1,this.render()})()})}openAddTitleModal(){new ft(this.plugin.app,this.plugin,this.dataManager,()=>{this.render()}).open()}renderSearch(i){let e=i.createDiv({cls:"wl-reading-search-wrap"}).createEl("input",{cls:"wl-reading-search-input",attr:{type:"text",placeholder:"Search titles..."}});e.value=this.searchQuery;let s=0;e.addEventListener("input",()=>{this.searchQuery=e.value,window.clearTimeout(s),s=window.setTimeout(()=>{this.rerenderActiveSubTab()},250)})}sortLabelToKey(i){var e;return(e={Title:"title","Date added":"dateAdded",Progress:"progress",Rating:"rating",Priority:"priority",Started:"started",Status:"status","Date watched":"dateWatched","Time left":"timeLeft","Time watched":"timeWatched"}[i])!=null?e:"dateAdded"}static migrateSortKey(i){var e;return(e={"title-asc":{key:"title",dir:"asc"},"title-desc":{key:"title",dir:"desc"},"dateAdded-newest":{key:"dateAdded",dir:"desc"},"dateAdded-oldest":{key:"dateAdded",dir:"asc"},"progress-high":{key:"progress",dir:"desc"},"progress-low":{key:"progress",dir:"asc"},"rating-high":{key:"rating",dir:"desc"},"rating-low":{key:"rating",dir:"asc"},priority:{key:"priority",dir:"asc"},"started-asc":{key:"started",dir:"asc"},"started-desc":{key:"started",dir:"desc"},"status-asc":{key:"status",dir:"asc"},"status-desc":{key:"status",dir:"desc"},"dateWatched-newest":{key:"dateWatched",dir:"desc"},"dateWatched-oldest":{key:"dateWatched",dir:"asc"},"timeLeft-high":{key:"timeLeft",dir:"desc"},"timeLeft-low":{key:"timeLeft",dir:"asc"},"timeWatched-high":{key:"timeWatched",dir:"desc"},"timeWatched-low":{key:"timeWatched",dir:"asc"},none:{key:"none",dir:"asc"}}[i])!=null?e:{key:i,dir:"desc"}}static sortBaseAndDirToKey(i,t){var s,a;return(a=(s={title:{asc:"title-asc",desc:"title-desc"},dateAdded:{asc:"dateAdded-oldest",desc:"dateAdded-newest"},progress:{asc:"progress-low",desc:"progress-high"},rating:{asc:"rating-low",desc:"rating-high"},priority:{asc:"priority",desc:"priority"},started:{asc:"started-asc",desc:"started-desc"},status:{asc:"status-asc",desc:"status-desc"},dateWatched:{asc:"dateWatched-oldest",desc:"dateWatched-newest"},timeLeft:{asc:"timeLeft-low",desc:"timeLeft-high"},timeWatched:{asc:"timeWatched-low",desc:"timeWatched-high"}}[i])==null?void 0:s[t])!=null?a:"dateAdded-newest"}rerenderTable(){if(this.currentSubTab!=="list"){this.rerenderActiveSubTab();return}let i=this._lastScrollTop,t=this.container.querySelector(".wl-table-section");t&&t.remove(),this.renderTable(i)}rerenderActiveSubTab(){if(this.currentSubTab==="cards")this.destroyVirtualScroll(),this.container.querySelectorAll(".wl-cards-scroll-container, .wl-cards-empty, .wl-table-section, .wl-results-count").forEach(i=>i.remove()),this.renderCardsView();else{let i=this._lastScrollTop,t=this.container.querySelector(".wl-table-section");t&&t.remove(),this.renderTable(i)}}renderResultsCount(i,t){let e=t.reduce((r,o)=>r+(o.kind==="title"?1:0),0),s=t.reduce((r,o)=>r+(o.kind==="group"?1:0),0),a=i.createDiv({cls:"wl-results-count"}),n=[];e>0&&n.push(`${e} title${e!==1?"s":""}`),s>0&&n.push(`${s} group${s!==1?"s":""}`),a.textContent=n.length>0?n.join(", "):"0 titles"}renderTable(i){this.scrollCleanup&&(this.scrollCleanup(),this.scrollCleanup=null);let t=this.container.createDiv({cls:"wl-table-section"}),e=this.getDisplayItems();this.renderResultsCount(t,e);let s=this.selectionMode?"wl-table wl-selection-mode":"wl-table",a=t.createDiv({cls:s}),n=a.createDiv({cls:"wl-table-header-row"});if(this.selectionMode&&n.createDiv({cls:"wl-col-select-h"}),n.createDiv({cls:"wl-col-title-h",text:"Title"}),n.createDiv({cls:"wl-col-priority-h",text:"Priority"}),n.createDiv({cls:"wl-col-started-h",text:"Started"}),n.createDiv({cls:"wl-col-rating-h",text:"Rating"}),n.createDiv({cls:"wl-col-status-h",text:"Status"}),e.length===0){a.createDiv({cls:"wl-empty-state",text:"No titles match your filters."});return}this.mountVirtualRows(a,e,i)}mountVirtualRows(i,t,e){var w;let o=t.map(()=>68);if(this.expandedId!==null){let b=t.findIndex(E=>E.kind==="title"&&E.data.id===this.expandedId);if(b!==-1){let E=t[b];if((E==null?void 0:E.kind)==="title"){let D=activeDocument.body.createDiv();D.style.cssText=`position:absolute;left:-9999px;top:0;width:${i.clientWidth}px;visibility:hidden;`,this.renderRow(D,E.data);let S=D.offsetHeight;D.remove(),S>0&&(o[b]=S)}}}for(let b=0;b0&&(o[b]=S)}let l=[],c=0;for(let b=0;b{var H,k,R,P;let b=u.scrollTop,E=u.clientHeight||600,D=5*44,S=b-h,T=S-D,M=S+E+D,x=0,C=t.length-1;for(;x<=C;){let B=x+C>>>1;((H=l[B])!=null?H:0)+((k=o[B])!=null?k:44)<=T?x=B+1:C=B-1}let L=Math.max(0,x),I=L;for(let B=L;B=M);B++)I=B;if(!(L===m&&I===f)){m=L,f=I,d.empty();for(let B=L;B<=I;B++){let K=t[B];if(!K)continue;let U=d.createDiv({cls:"wl-virt-item"});U.style.top=`${(P=l[B])!=null?P:0}px`,K.kind==="title"?this.renderRow(U,K.data):this.renderGroupRow(U,K.data,K.members)}}};y();let v=()=>{p===0&&(p=window.requestAnimationFrame(()=>{p=0,y()}))};u.addEventListener("scroll",v,{passive:!0}),this.scrollCleanup=()=>{u.removeEventListener("scroll",v),p!==0&&(window.cancelAnimationFrame(p),p=0)}}getDisplayItems(){let i=this.dataManager.getGroups(),t=this.dataManager.getGroupedTitleIds(),e=this.dataManager.getTitles(),s=new Map(e.map(c=>[c.id,c])),a=this.searchQuery.trim().toLowerCase(),n=this.getSearchMatchedIds(),r=this.filterGroupsOnly?[]:this.getFilteredSortedTitles(n).filter(c=>!t.has(c.id)),o=[];for(let c of i){if(this.filterGroupExclude.size>0&&this.filterGroupExclude.has(c.name))continue;let d=c.titleIds.map(h=>s.get(h)).filter(h=>h!==void 0);if(n){let h=c.name.toLowerCase().includes(a),p=d.some(m=>n.has(m.id));if(!h&&!p)continue}(this.filterTypeExclude.size>0||this.filterStatusExclude.size>0||this.filterRatingExclude.size>0||this.filterPriorityExclude.size>0)&&!d.some(h=>this.titlePassesFilters(h))||o.push({kind:"group",data:c,members:d})}return[...o,...r.map(c=>({kind:"title",data:c}))].sort((c,d)=>{let u=c.kind==="title"&&c.data.pinned||c.kind==="group"&&c.data.id===this.pinnedGroupId,h=d.kind==="title"&&d.data.pinned||d.kind==="group"&&d.data.id===this.pinnedGroupId;return u&&!h?-1:!u&&h?1:this.compareDisplayItems(c,d)})}getStatusIndex(i){let t=this.STATUS_ORDER.indexOf(i);return t===-1?99:t}compareDisplayItemsByKey(i,t,e){let s=p=>p.kind==="title"?p.data.title:p.data.name,a=p=>p.kind==="title"?this.dataManager.getProgress(p.data):this.getGroupProgress(p.members),n=p=>{if(p.kind==="title"){let f=be.indexOf(p.data.priority);return f===-1?99:f}let m=p.members.map(f=>be.indexOf(f.priority)).filter(f=>f!==-1);return m.length>0?Math.min(...m):99},r=p=>{if(p.kind==="title")return new Date(p.data.dateAdded).getTime();let m=p.members.map(f=>new Date(f.dateAdded).getTime());return m.length>0?Math.max(...m):0},o=p=>{if(p.kind==="title")return p.data.dateStarted?new Date(p.data.dateStarted).getTime():null;let m=p.members.map(f=>f.dateStarted?new Date(f.dateStarted).getTime():null).filter(f=>f!==null);return m.length>0?Math.min(...m):null},l=p=>p.kind==="title"?this.getStatusIndex(p.data.status):this.getStatusIndex(this.getGroupStatus(p.members)),c=p=>{if(p.kind==="title")return p.data.rating;let m=p.members.filter(f=>f.rating>0);return m.length===0?0:m.reduce((f,y)=>f+y.rating,0)/m.length},d=p=>{if(p.kind==="title")return p.data.dateFinished?new Date(p.data.dateFinished).getTime():0;let m=p.members.map(f=>f.dateFinished?new Date(f.dateFinished).getTime():0).filter(f=>f>0);return m.length>0?Math.max(...m):0},u=p=>p.kind==="title"?this.dataManager.calcTimeRemaining(p.data):p.members.reduce((m,f)=>m+this.dataManager.calcTimeRemaining(f),0),h=p=>p.kind==="title"?this.dataManager.calcTimeWatched(p.data):p.members.reduce((m,f)=>m+this.dataManager.calcTimeWatched(f),0);switch(i){case"title-asc":return s(t).localeCompare(s(e));case"title-desc":return s(e).localeCompare(s(t));case"dateAdded-newest":return r(e)-r(t);case"dateAdded-oldest":return r(t)-r(e);case"progress-high":return a(e)-a(t);case"progress-low":return a(t)-a(e);case"rating-high":{let p=c(t),m=c(e);return p===0&&m===0?0:p===0?1:m===0?-1:m-p}case"rating-low":{let p=c(t),m=c(e);return p===0&&m===0?0:p===0?1:m===0?-1:p-m}case"priority":return n(t)-n(e);case"status-asc":return l(t)-l(e);case"status-desc":return l(e)-l(t);case"started-asc":{let p=o(t),m=o(e);return p==null&&m==null?0:p==null?1:m==null?-1:p-m}case"started-desc":{let p=o(t),m=o(e);return p==null&&m==null?0:p==null?1:m==null?-1:m-p}case"dateWatched-newest":return d(e)-d(t);case"dateWatched-oldest":{let p=d(t)||1/0,m=d(e)||1/0;return p-m}case"timeLeft-high":return u(e)-u(t);case"timeLeft-low":return u(t)-u(e);case"timeWatched-high":return h(e)-h(t);case"timeWatched-low":return h(t)-h(e);default:return 0}}compareDisplayItems(i,t){let e=at.sortBaseAndDirToKey(this.filterSort,this.filterSortDir),s=this.compareDisplayItemsByKey(e,i,t);if(s!==0||this.filterSecondSort==="none")return s;let a=at.sortBaseAndDirToKey(this.filterSecondSort,this.filterSecondSortDir);return this.compareDisplayItemsByKey(a,i,t)}renderRow(i,t,e=!1){let s=this.expandedId===t.id,a=this.selectedItems.has(t.id),n=["wl-row",s?"is-expanded":"",e?"wl-row-indented":"",a?"wl-row-selected":""].filter(Boolean).join(" "),r=i.createDiv({cls:n});if(r.dataset.titleId=t.id,this.selectionMode){let T=r.createDiv({cls:"wl-col-select"}).createEl("input",{attr:{type:"checkbox"}});T.checked=a,T.addEventListener("click",M=>M.stopPropagation()),T.addEventListener("change",()=>{this.toggleRowSelection(r,t.id)})}let o=r.createDiv({cls:"wl-col-title"});o.createDiv({cls:"wl-row-title-text",text:t.title});let l=this.getTagDef(t.type,this.plugin.settings.types),c=this.plugin.settings.coloredTypeBadges,d=o.createDiv({cls:"wl-badge-row"}),u=d.createSpan({cls:c?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});c&&l&&(u.style.backgroundColor=N(t.type,l.color,this.plugin.settings.colorTheme)),at.isRecentlyArrived(t)&&d.createSpan({cls:"wl-recently-arrived",text:"\xB7 Recently arrived"});let p=o.createDiv({cls:"wl-progress-wrap"}).createDiv({cls:"wl-progress-bar"});p.style.width=`${this.dataManager.getProgress(t)}%`;let m=r.createDiv({cls:"wl-col-priority"});if(t.priority){let S=this.getTagDef(t.priority,this.plugin.settings.priorities),T=m.createSpan({cls:"wl-priority-badge",text:t.priority});S&&(T.style.color=S.color)}let f=r.createDiv({cls:"wl-col-started"});f.textContent=t.dateStarted?Q(t.dateStarted):"\u2014";let y=r.createDiv({cls:"wl-col-rating"});t.rating>0?y.createSpan({cls:"wl-row-rating",text:`\u2605 ${t.rating}/5`}):y.createSpan({cls:"wl-row-rating wl-row-rating-empty",text:"\u2014"});let v=r.createDiv({cls:"wl-col-status"}),w=this.getTagDef(t.status,this.plugin.settings.statuses),b=v.createSpan({cls:c?"wl-badge":"wl-badge-plain",text:t.status});c&&w&&(b.style.backgroundColor=N(t.status,w.color,this.plugin.settings.colorTheme));let D=r.createDiv({cls:"wl-col-pin"}).createSpan({cls:`wl-pin-icon${t.pinned?" is-pinned":""}`,text:"\u{1F4CC}"});D.title=t.pinned?"Unpin":"Pin to top",D.addEventListener("click",S=>{S.stopPropagation(),(async()=>{let T=this.dataManager.getTitle(t.id);if(!T)return;let M=!T.pinned;if(M)for(let x of this.dataManager.getTitles())x.id!==T.id&&x.pinned&&(x.pinned=!1,await this.dataManager.updateTitle(x));T.pinned=M,await this.dataManager.updateTitle(T),this.rerenderTable()})()}),r.addEventListener("click",()=>{if(this.selectionMode){this.toggleRowSelection(r,t.id);return}this.expandedId=s?null:t.id,s||(this.collapsedSeasons=this.dataManager.getCollapsedSeasonsForTitle(t.id)),this.rerenderTable()}),s&&!this.selectionMode&&this.renderAccordion(i,t)}renderGroupRow(i,t,e){var C,L,I,H,k;let s=this.expandedGroups.has(t.id),a=this.selectedItems.has(t.id),n=i.createDiv({cls:`wl-row wl-group-row${s?" is-expanded":""}${a?" wl-row-selected":""}`});if(n.dataset.type=(L=(C=e[0])==null?void 0:C.type)!=null?L:"",n.dataset.status=this.getGroupStatus(e),n.dataset.priority=(I=this.getGroupHighestPriority(e))!=null?I:"",n.dataset.rating=`${Math.round(this.getGroupRating(e))}\u2605`,n.dataset.group=t.name,this.selectionMode){let P=n.createDiv({cls:"wl-col-select"}).createEl("input",{attr:{type:"checkbox"}});P.checked=a,P.addEventListener("click",B=>B.stopPropagation()),P.addEventListener("change",()=>{this.toggleRowSelection(n,t.id)})}let r=n.createDiv({cls:"wl-col-title"});if(this.renamingGroupId===t.id){let R=r.createDiv({cls:"wl-group-name-row"}),P=R.createEl("input",{cls:"wl-group-rename-input",attr:{type:"text",value:t.name}});P.addEventListener("click",U=>U.stopPropagation()),P.addEventListener("keydown",U=>{U.stopPropagation(),U.key==="Enter"?(async()=>{let z=P.value.trim();if(z&&z!==t.name){let yt={...t,name:z};await this.dataManager.updateGroup(yt)}this.renamingGroupId=null,this.rerenderTable()})():U.key==="Escape"&&(this.renamingGroupId=null,this.rerenderTable())});let B=R.createEl("button",{cls:"wl-group-action-btn",text:"\u2713"});B.title="Save",B.addEventListener("click",U=>{U.stopPropagation(),(async()=>{let z=P.value.trim();if(z&&z!==t.name){let yt={...t,name:z};await this.dataManager.updateGroup(yt)}this.renamingGroupId=null,this.rerenderTable()})()});let K=R.createEl("button",{cls:"wl-group-action-btn",text:"\u2715"});K.title="Cancel",K.addEventListener("click",U=>{U.stopPropagation(),this.renamingGroupId=null,this.rerenderTable()}),window.setTimeout(()=>P.focus(),0)}else{let R=r.createDiv({cls:"wl-group-name-row"});R.createSpan({cls:"wl-row-title-text wl-group-name",text:t.name});let P=R.createEl("button",{cls:"wl-group-action-btn",text:"\u270F"});P.title="Rename group",P.addEventListener("click",K=>{K.stopPropagation(),this.renamingGroupId=t.id,this.rerenderTable()});let B=R.createEl("button",{cls:"wl-group-action-btn wl-group-action-btn-delete wl-btn-danger",text:"\u2715"});B.title="Delete group (titles are kept)",B.addEventListener("click",K=>{K.stopPropagation(),new _(this.plugin.app,`Delete group "${t.name}"? All titles inside will be returned to the main list.`,()=>{this.dataManager.removeGroup(t.id).then(()=>{this.expandedGroups.delete(t.id),this.rerenderTable()})}).open()})}let o=(k=(H=e[0])==null?void 0:H.type)!=null?k:"";if(o){let R=this.getTagDef(o,this.plugin.settings.types),P=this.plugin.settings.coloredTypeBadges,B=r.createSpan({cls:P?"wl-badge wl-badge-sm":"wl-badge-plain",text:o});P&&R&&(B.style.backgroundColor=N(o,R.color,this.plugin.settings.colorTheme))}let l=r.createDiv({cls:"wl-group-stats"}),c=e.reduce((R,P)=>R+this.dataManager.calcTimeWatched(P),0),d=e.reduce((R,P)=>R+this.dataManager.calcTimeRemaining(P),0);l.createSpan({text:`${e.length} title${e.length!==1?"s":""}`}),l.createSpan({text:` \xB7 ${j(c)} watched`}),l.createSpan({text:` \xB7 ${j(d)} left`});let u=r.createDiv({cls:"wl-progress-wrap"});u.createDiv({cls:"wl-progress-bar"}).style.width=`${this.getGroupProgress(e)}%`;let h=n.createDiv({cls:"wl-col-priority"}),p=this.getGroupHighestPriority(e);if(p){let R=this.getTagDef(p,this.plugin.settings.priorities),P=h.createSpan({cls:"wl-priority-badge",text:p});R&&(P.style.color=R.color)}let m=n.createDiv({cls:"wl-col-started"}),f=this.getGroupStartedDate(e);m.textContent=f?Q(f):"\u2014";let y=n.createDiv({cls:"wl-col-rating"}),v=this.getGroupRating(e);v>0?y.createSpan({cls:"wl-row-rating",text:`\u2605 ${v.toFixed(1)}/5`}):y.createSpan({cls:"wl-row-rating wl-row-rating-empty",text:"\u2014"});let w=n.createDiv({cls:"wl-col-status"}),b=this.getGroupStatus(e),E=this.getTagDef(b,this.plugin.settings.statuses),D=this.plugin.settings.coloredTypeBadges,S=w.createSpan({cls:D?"wl-badge":"wl-badge-plain",text:b});D&&(E?S.style.backgroundColor=N(b,E.color,this.plugin.settings.colorTheme):b==="In Progress"&&(S.style.backgroundColor=N("In Progress","#724CF9",this.plugin.settings.colorTheme)));let T=this.pinnedGroupId===t.id,x=n.createDiv({cls:"wl-col-pin"}).createSpan({cls:`wl-pin-icon${T?" is-pinned":""}`,text:"\u{1F4CC}"});if(x.title=T?"Unpin":"Pin to top",x.addEventListener("click",R=>{if(R.stopPropagation(),this.pinnedGroupId=T?null:t.id,this.dataManager.setPinnedGroupId(this.pinnedGroupId),this.pinnedGroupId)for(let P of this.dataManager.getTitles())P.pinned&&(P.pinned=!1,this.dataManager.updateTitle(P));this.rerenderTable()}),n.addEventListener("click",()=>{if(this.renamingGroupId!==t.id){if(this.selectionMode){this.toggleRowSelection(n,t.id);return}s?this.expandedGroups.delete(t.id):this.expandedGroups.add(t.id),this.rerenderTable()}}),s)for(let R of e)this.renderRow(i,R,!0)}getGroupProgress(i){let t=i.reduce((s,a)=>s+a.watchedEpisodes.length,0),e=i.reduce((s,a)=>s+this.dataManager.getEffectiveTotal(a),0);return e===0?0:Math.min(100,Math.round(t/e*100))}getGroupStatus(i){if(i.length===0)return"Plan to watch";let t=i.map(e=>e.status);return t.some(e=>e==="Watching")?"Watching":t.every(e=>e==="Completed")?"Completed":t.every(e=>e==="Plan to watch")?"Plan to watch":"In Progress"}getGroupStartedDate(i){var e;let t=i.map(s=>s.dateStarted).filter(s=>s!==null);return t.length===0?null:(e=t.sort()[0])!=null?e:null}getGroupRating(i){let t=i.filter(e=>e.rating>0);return t.length===0?0:t.reduce((e,s)=>e+s.rating,0)/t.length}getGroupHighestPriority(i){let t=null,e=1/0;for(let s of i){let a=be.indexOf(s.priority);a!==-1&&ab.stopPropagation());let s=e.createDiv({cls:"wl-accordion-header"}),a=s.createDiv({cls:"wl-acc-header-left"}),n=t.totalEpisodes>0?` \xB7 ${t.totalEpisodes} eps total`:"",r=t.dateStarted?`Started ${Q(t.dateStarted)}`:"Not started",o=a.createDiv({cls:"wl-acc-subtitle"});if(o.createSpan({cls:"wl-acc-subtitle-text",text:`${r}${n}`}),t.externalLink){let b=o.createEl("a",{cls:"wl-acc-link-icon",text:"\u{1F310}"});b.href=t.externalLink,b.title="Open external link",b.target="_blank",b.rel="noopener noreferrer",b.addEventListener("click",E=>E.stopPropagation())}let l=a.createDiv({cls:"wl-acc-credits"});ts(l,t,b=>this.applyPersonSearch(b));let c=t.watchedEpisodes.length,d=this.dataManager.getEffectiveTotal(t),u=this.dataManager.calcTimeWatched(t),h=this.dataManager.calcTimeRemainingForModal(t),p=this.dataManager.getProgress(t),m=s.createDiv({cls:"wl-acc-right-group"}),f=(b,E)=>{let D=m.createDiv({cls:"wl-acc-stat-block"});D.createDiv({cls:"wl-acc-percent",text:b}),D.createDiv({cls:"wl-acc-progress-label",text:E})};f(j(h),"left"),f(j(u),"watched"),f(`${c} / ${d}`,"episodes");let y=m.createDiv({cls:"wl-acc-header-right"});y.createDiv({cls:"wl-acc-percent",text:`${p}%`}),y.createDiv({cls:"wl-acc-progress-label",text:"progress"});let v=y.createDiv({cls:"wl-acc-progress-wrap"});v.createDiv({cls:"wl-progress-bar"}).style.width=`${p}%`;let w=e.createDiv({cls:"wl-accordion-body"});t.type==="Movie"?this.renderMovieBody(w,t):this.renderEpisodesBody(w,t),this.renderAccordionFooter(e,t)}renderMovieBody(i,t){let e=i.createDiv({cls:"wl-movie-row"}),s=e.createEl("input",{cls:"wl-movie-checkbox",attr:{type:"checkbox"}});s.checked=t.watchedEpisodes.includes(1),e.createSpan({cls:"wl-movie-label",text:"Watched"}),s.addEventListener("change",a=>{a.stopPropagation(),this.dataManager.markEpisodeWatched(t.id,1,s.checked).then(()=>this.rerenderTable())})}renderEpisodesBody(i,t){if(t.seasons.length===0){t.totalEpisodes>0&&this.renderEpisodeGrid(i,t,null);return}t.seasons.forEach((e,s)=>{var h,p;let a=this.collapsedSeasons.has(s),n=i.createDiv({cls:"wl-season-wrap"}),r=n.createDiv({cls:"wl-season-header"}),o=r.createSpan({cls:"wl-season-badge"});o.textContent=e.name;let l=this.plugin.settings.seasonPalette;o.style.backgroundColor=(h=l[s%l.length])!=null?h:"#888780";let c=((p=e.skippedEpisodes)!=null?p:[]).length,d=c>0?` (${c} to skip)`:"";r.createSpan({cls:"wl-season-ep-count",text:`${e.episodes} eps${d}`});let u=r.createSpan({cls:`wl-chevron${a?"":" is-open"}`,text:"\u203A"});a||this.renderEpisodeGrid(n,t,e),r.addEventListener("click",m=>{var f;m.stopPropagation(),a?(a=!1,this.collapsedSeasons.delete(s),u.classList.add("is-open"),this.renderEpisodeGrid(n,t,e)):(a=!0,this.collapsedSeasons.add(s),u.classList.remove("is-open"),(f=n.querySelector(".wl-episode-grid"))==null||f.remove()),this.expandedId&&this.dataManager.persistCollapsedSeasons(this.expandedId,this.collapsedSeasons)})})}renderEpisodeGrid(i,t,e){let s=i.createDiv({cls:"wl-episode-grid"}),a=e?e.episodes:t.totalEpisodes,n=e?e.offset:0,r=Array.from({length:a},(d,u)=>n+u+1),o=s.createDiv({cls:"wl-season-fill-btn"}),l=()=>{let d=new Set(t.watchedEpisodes),u=r.length>0&&r.every(h=>d.has(h));o.classList.toggle("is-clear",u),o.classList.toggle("is-fill",!u),o.textContent=u?"\u2717":"\u2713",o.title=u?"Clear all episodes in this season":"Mark all episodes in this season as watched"};l(),o.addEventListener("click",d=>{d.stopPropagation();let u=new Set(t.watchedEpisodes),h=r.length>0&&r.every(p=>u.has(p));this.dataManager.markSeasonWatched(t.id,r,!h,e==null?void 0:e.name).then(()=>this.rerenderTable())});let c=this.plugin.settings.episodeNumbering==="per-season";for(let d=0;d{var w;let y=t.watchedEpisodes.includes(u),v=e?((w=e.skippedEpisodes)!=null?w:[]).includes(h):!1;m.classList.toggle("is-watched",y),m.classList.toggle("is-skipped",v),m.textContent=v&&!y?"\u2014":y?"\u2713":String(p),m.title=`Episode ${u}${v?" (skipped)":""}`};f(),m.addEventListener("click",y=>{y.stopPropagation();let v=t.watchedEpisodes.includes(u);this.dataManager.applyEpisodeWatchedToggle(t.id,u,!v),f(),l(),this.updateAccordionStats(m,t,e)})}}updateAccordionStats(i,t,e){var h;let s=i.closest(".wl-accordion");if(!s)return;let a=this.dataManager.calcTimeRemainingForModal(t),n=this.dataManager.calcTimeWatched(t),r=t.watchedEpisodes.length,o=this.dataManager.getEffectiveTotal(t),l=this.dataManager.getProgress(t),c=s.querySelectorAll(".wl-acc-stat-block .wl-acc-percent");c[0]&&(c[0].textContent=j(a)),c[1]&&(c[1].textContent=j(n)),c[2]&&(c[2].textContent=`${r} / ${o}`);let d=s.querySelector(".wl-acc-header-right .wl-acc-percent");d&&(d.textContent=`${l}%`);let u=s.querySelector(".wl-acc-header-right .wl-progress-bar");if(u&&(u.style.width=`${l}%`),e){let p=i.closest(".wl-episode-grid"),m=p==null?void 0:p.parentElement,f=m==null?void 0:m.querySelector(".wl-season-header .wl-season-ep-count");if(f){let y=((h=e.skippedEpisodes)!=null?h:[]).length,v=y>0?` (${y} to skip)`:"";f.textContent=`${e.episodes} eps${v}`}}}renderAccordionFooter(i,t){let e=i.createDiv({cls:"wl-accordion-footer"}),s=e.createDiv({cls:"wl-stars-row"});s.createSpan({cls:"wl-stars-label",text:"Rating"});let a=s.createDiv({cls:"wl-stars"});for(let w=1;w<=5;w++)a.createSpan({cls:`wl-star${t.rating>=w?" is-active":""}`,text:"\u2605"}).addEventListener("click",E=>{E.stopPropagation(),(async()=>{let D=this.dataManager.getTitle(t.id);D&&(D.rating=D.rating===w?0:w,await this.dataManager.updateTitle(D),this.rerenderTable())})()});let n=()=>{var E;let b=s.querySelector(".wl-rating-divider");for(;b;){let D=b;b=b.nextSibling,(E=D.parentNode)==null||E.removeChild(D)}Yt(s,this.plugin,t.id,n)};Yt(s,this.plugin,t.id,n),Ke(this.plugin,t.id,n);let o=e.createDiv({cls:"wl-footer-row"}).createEl("input",{cls:"wl-notes-input",attr:{type:"text",placeholder:"Add a note..."}});o.value=t.notes,o.addEventListener("click",w=>w.stopPropagation()),o.addEventListener("change",()=>{(async()=>{let w=this.dataManager.getTitle(t.id);w&&(w.notes=o.value,await this.dataManager.updateTitle(w),this.rerenderTable())})()});let l=e.createDiv({cls:"wl-footer-row"});l.createSpan({cls:"wl-footer-label",text:"Date watched"});let c=l.createEl("button",{cls:"wl-btn wl-btn-sm wl-footer-today-btn",text:"Today",attr:{title:"Fill with today\u2019s date"}}),d=l.createEl("input",{cls:"wl-footer-date",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});d.value=Q(t.dateFinished);let u=()=>{c.toggleClass("is-dimmed",!!d.value.trim())};u(),d.addEventListener("click",w=>w.stopPropagation()),d.addEventListener("change",()=>{(async()=>{let w=this.dataManager.getTitle(t.id);if(!w)return;let b=q(d.value);if(d.value.trim()&&!b){d.addClass("wl-input-error");return}d.removeClass("wl-input-error"),w.dateFinished=b,await this.dataManager.updateTitle(w),this.rerenderTable()})()}),c.addEventListener("click",w=>{if(w.stopPropagation(),d.value.trim())return;let b=new Date,E=String(b.getDate()).padStart(2,"0"),D=String(b.getMonth()+1).padStart(2,"0"),S=b.getFullYear();d.value=`${E}/${D}/${S}`,u(),d.dispatchEvent(new Event("change"))});let h=e.createDiv({cls:"wl-footer-row"});h.createSpan({cls:"wl-footer-label",text:"Status"});let p=h.createEl("select",{cls:"wl-select wl-select-sm"});for(let w of this.plugin.settings.statuses){if(w.name==="To be released")continue;let b=p.createEl("option",{text:w.name,value:w.name});w.name===t.status&&(b.selected=!0)}p.addEventListener("click",w=>w.stopPropagation()),p.addEventListener("change",()=>{(async()=>{let w=this.dataManager.getTitle(t.id);w&&(w.status=p.value,await this.dataManager.updateTitle(w),this.rerenderTable())})()});let m=e.createDiv({cls:"wl-footer-row wl-footer-action-row"});m.createEl("button",{cls:"wl-delete-btn wl-btn-danger",text:"Remove"}).addEventListener("click",w=>{w.stopPropagation(),new _(this.plugin.app,`Remove "${t.title}" from watchlog?`,()=>{this.dataManager.removeTitle(t.id).then(()=>{this.expandedId=null,this.rerenderTable()})}).open()}),m.createDiv({cls:"wl-add-btn-wrap"}).createEl("button",{cls:"wl-edit-btn",text:"Edit"}).addEventListener("click",w=>{w.stopPropagation();let b=this.dataManager.getTitle(t.id);b&&new Bt(this.plugin.app,this.plugin,this.dataManager,b,()=>{this.rerenderTable()}).open()})}compareTitlesByKey(i,t,e){switch(i){case"title-asc":return t.title.localeCompare(e.title);case"title-desc":return e.title.localeCompare(t.title);case"dateAdded-newest":return new Date(e.dateAdded).getTime()-new Date(t.dateAdded).getTime();case"dateAdded-oldest":return new Date(t.dateAdded).getTime()-new Date(e.dateAdded).getTime();case"progress-high":return this.dataManager.getProgress(e)-this.dataManager.getProgress(t);case"progress-low":return this.dataManager.getProgress(t)-this.dataManager.getProgress(e);case"rating-high":{let s=t.rating===0?-1:t.rating;return(e.rating===0?-1:e.rating)-s}case"rating-low":return t.rating===0&&e.rating===0?0:t.rating===0?1:e.rating===0?-1:t.rating-e.rating;case"priority":{let s=be.indexOf(t.priority),a=be.indexOf(e.priority);return(s===-1?99:s)-(a===-1?99:a)}case"started-asc":{let s=t.dateStarted?new Date(t.dateStarted).getTime():1/0,a=e.dateStarted?new Date(e.dateStarted).getTime():1/0;return s-a}case"started-desc":{let s=t.dateStarted?new Date(t.dateStarted).getTime():null,a=e.dateStarted?new Date(e.dateStarted).getTime():null;return s==null&&a==null?0:s==null?1:a==null?-1:a-s}case"status-asc":return this.getStatusIndex(t.status)-this.getStatusIndex(e.status);case"status-desc":return this.getStatusIndex(e.status)-this.getStatusIndex(t.status);case"dateWatched-newest":{let s=t.dateFinished?new Date(t.dateFinished).getTime():0;return(e.dateFinished?new Date(e.dateFinished).getTime():0)-s}case"dateWatched-oldest":{let s=t.dateFinished?new Date(t.dateFinished).getTime():1/0,a=e.dateFinished?new Date(e.dateFinished).getTime():1/0;return s-a}case"timeLeft-high":return this.dataManager.calcTimeRemaining(e)-this.dataManager.calcTimeRemaining(t);case"timeLeft-low":return this.dataManager.calcTimeRemaining(t)-this.dataManager.calcTimeRemaining(e);case"timeWatched-high":return this.dataManager.calcTimeWatched(e)-this.dataManager.calcTimeWatched(t);case"timeWatched-low":return this.dataManager.calcTimeWatched(t)-this.dataManager.calcTimeWatched(e);default:return 0}}getSearchMatchedIds(){let i=this.searchQuery.trim();if(!i)return null;let t=this.dataManager.getTitles().map(s=>({id:s.id,title:s.title,director:kt(s.director),cast:kt(s.cast)})),e=new X(t,{keys:["title","director","cast"],threshold:.4,ignoreLocation:!0});return new Set(e.search(i).map(s=>s.item.id))}getFilteredSortedTitles(i){let t=this.dataManager.getTitles(),e=i!==void 0?i:this.getSearchMatchedIds();e&&(t=t.filter(n=>e.has(n.id))),t=t.filter(n=>this.titlePassesFilters(n));let s=at.sortBaseAndDirToKey(this.filterSort,this.filterSortDir),a=this.filterSecondSort==="none"?"none":at.sortBaseAndDirToKey(this.filterSecondSort,this.filterSecondSortDir);return t=[...t].sort((n,r)=>{let o=this.compareTitlesByKey(s,n,r);return o!==0||a==="none"?o:this.compareTitlesByKey(a,n,r)}),t}getTagDef(i,t){return t.find(e=>e.name===i)}};at.SORT_DEFAULT_DIR={title:"asc",dateAdded:"desc",progress:"desc",rating:"desc",priority:"asc",started:"asc",status:"asc",dateWatched:"desc",timeLeft:"desc",timeWatched:"desc"};var Xe=at;var vt=require("obsidian");var Ut=require("obsidian");function Ze(g){return"malId"in g}var ti=class extends Ut.Modal{constructor(t,e,s,a){super(t);this.selectedType="Anime";this.searchQuery="";this.searchResults=[];this.isSearching=!1;this.searchGeneration=0;this.fieldTitle="";this.fieldEpisodes=0;this.fieldDuration=0;this.fieldReleaseDate="";this.fieldLink="";this.resultsEl=null;this.formEl=null;this.searchDebounce=null;this.plugin=e,this.dataManager=s,this.onAdded=a}onOpen(){this.titleEl.setText("Add to maybe"),this.contentEl.addClass("wl-add-modal"),this.buildUI()}onClose(){this.contentEl.empty(),this.searchDebounce&&window.clearTimeout(this.searchDebounce)}buildUI(){let t=this.contentEl;t.empty();let e=t.createDiv({cls:"wl-modal-row"});e.createSpan({cls:"wl-modal-label",text:"Type"});let s=e.createEl("select",{cls:"wl-select"});for(let o of this.plugin.settings.types){let l=s.createEl("option",{text:o.name,value:o.name});o.name===this.selectedType&&(l.selected=!0)}s.addEventListener("change",()=>{this.selectedType=s.value,this.searchResults=[],this.renderResults(),this.renderForm()});let a=t.createDiv({cls:"wl-modal-row"});a.createSpan({cls:"wl-modal-label",text:"Search"});let n=a.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Search for a title..."}});n.value=this.searchQuery,n.addEventListener("input",()=>{this.searchQuery=n.value,this.searchDebounce&&window.clearTimeout(this.searchDebounce),this.searchDebounce=window.setTimeout(()=>void this.performSearch(),600)}),a.createEl("button",{cls:"wl-btn",text:"Search"}).addEventListener("click",()=>void this.performSearch()),this.resultsEl=t.createDiv({cls:"wl-modal-results"}),this.formEl=t.createDiv({cls:"wl-modal-form"}),this.renderForm()}async performSearch(){var e,s;if(!this.searchQuery.trim())return;let t=++this.searchGeneration;this.isSearching=!0,this.renderResults();try{let a=this.plugin.apiService,n=(e=this.plugin.settings.activeApi)!=null?e:"OMDb",r=tt(this.selectedType,this.plugin.settings.typeApiMapping),o=this.selectedType==="Movie",l=[];if(r===""?new Ut.Notice(`No API configured for type "${this.selectedType}". Configure it in Settings \u2192 API.`):r==="anime"?l=((s=this.plugin.settings.animeApiSource)!=null?s:"jikan")==="anilist"?await a.searchAniList(this.searchQuery):await a.searchAnime(this.searchQuery):n==="TMDB"?l=await a.searchTmdb(this.searchQuery,o?"movie":"series"):l=await a.searchOmdb(this.searchQuery,o?"movie":"series"),t!==this.searchGeneration)return;this.searchResults=l}catch(a){if(t!==this.searchGeneration)return;new Ut.Notice("Search failed. Check your connection and API settings."),this.searchResults=[]}finally{t===this.searchGeneration&&(this.isSearching=!1,this.renderResults())}}renderResults(){if(this.resultsEl){if(this.resultsEl.empty(),this.isSearching){this.resultsEl.createDiv({cls:"wl-modal-loading",text:"Searching..."});return}this.searchResults.length&&this.searchResults.forEach((t,e)=>{let s=this.resultsEl.createDiv({cls:"wl-result-item"}),a=Ze(t)?`${t.episodes} eps`:t.episodes>0?`${t.episodes} eps`:t.mediaType;s.createDiv({cls:"wl-result-title",text:t.title}),s.createDiv({cls:"wl-result-meta",text:`${a} \xB7 ${t.releaseDate}`}),s.dataset.idx=String(e),s.addEventListener("click",()=>void this.selectResult(t,s))})}}async selectResult(t,e){var r;if(this.resultsEl)for(let o of Array.from(this.resultsEl.children))o.removeClass("is-selected");e.addClass("is-selected");let s=++this.searchGeneration,a=this.plugin.apiService,n=(r=this.plugin.settings.activeApi)!=null?r:"OMDb";try{if(!Ze(t)&&t.mediaType==="tv"){let o=n==="TMDB"?await a.getTmdbTvDetails(t.imdbId):await a.getOmdbTvDetails(t.imdbId);if(s!==this.searchGeneration)return;o&&(this.fieldTitle=o.title,this.fieldEpisodes=o.episodes,this.fieldDuration=o.episodeDuration,this.fieldReleaseDate=o.releaseDate,this.fieldLink=o.url)}else if(!Ze(t)&&t.mediaType==="movie"){let o=n==="TMDB"?await a.getTmdbMovieDetails(t.imdbId):await a.getOmdbMovieDetails(t.imdbId);if(s!==this.searchGeneration)return;o&&(this.fieldTitle=o.title,this.fieldEpisodes=o.episodes,this.fieldDuration=o.episodeDuration,this.fieldReleaseDate=o.releaseDate,this.fieldLink=o.url)}else{let o=t;this.fieldTitle=o.title,this.fieldEpisodes=o.episodes,this.fieldDuration=o.duration,this.fieldReleaseDate=o.releaseDate,this.fieldLink=o.url}}catch(o){if(s!==this.searchGeneration)return;this.fieldTitle=t.title,this.fieldEpisodes=t.episodes,this.fieldDuration=Ze(t)?t.duration:t.episodeDuration,this.fieldReleaseDate=t.releaseDate,this.fieldLink=t.url}s===this.searchGeneration&&this.renderForm()}renderForm(){if(!this.formEl)return;this.formEl.empty();let t=y=>{let v=this.formEl.createDiv({cls:"wl-modal-row"});return v.createSpan({cls:"wl-modal-label",text:y}),v},s=t("Title").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Title name"}});s.value=this.fieldTitle,s.addEventListener("input",()=>{this.fieldTitle=s.value});let n=t("Episodes").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0",placeholder:"0"}});n.value=String(this.fieldEpisodes),n.addEventListener("input",()=>{this.fieldEpisodes=parseInt(n.value)||0});let o=t("Ep. duration (min)").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0",placeholder:"24"}});o.value=String(this.fieldDuration),o.addEventListener("input",()=>{this.fieldDuration=parseInt(o.value)||0});let c=t("Release date").createDiv({cls:"wl-modal-input-stack"}),d=c.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Date (dd-mm-yyyy or yyyy-mm-dd)"}});d.value=this.fieldReleaseDate;let u=c.createDiv({cls:"wl-modal-error wl-hidden"});d.addEventListener("change",()=>{let y=d.value.trim();if(!y){this.fieldReleaseDate="",u.addClass("wl-hidden");return}let v=jt(y);v?(this.fieldReleaseDate=v,d.value=v,u.addClass("wl-hidden")):(this.fieldReleaseDate=y,u.textContent="Unrecognised format.",u.removeClass("wl-hidden"))});let p=t("External link").createEl("input",{cls:"wl-modal-input",attr:{type:"url",placeholder:"https://example.com"}});p.value=this.fieldLink,p.addEventListener("input",()=>{this.fieldLink=p.value}),this.formEl.createDiv({cls:"wl-modal-btn-row"}).createEl("button",{cls:"wl-btn wl-btn-primary",text:"Add to maybe"}).addEventListener("click",()=>void this.addMaybeTitle())}async addMaybeTitle(){let t=this.fieldTitle.trim();if(!t){new Ut.Notice("Please enter a title name.");return}let e={id:this.dataManager.generateMaybeId(t),title:t,type:this.selectedType,releaseDate:this.fieldReleaseDate||null,externalLink:this.fieldLink,totalEpisodes:this.fieldEpisodes,episodeDuration:this.fieldDuration,dateAdded:new Date().toISOString()};await this.dataManager.addMaybeTitle(e),new Ut.Notice(`"${t}" added to Maybe.`),this.close(),this.onAdded()}};var ei=require("obsidian");var Ee=class extends ei.Modal{constructor(i,t,e,s,a,n,r,o,l){var u,h;super(i),this.item=t,this.kind=e,this.schedule=s?{...s}:{recurrence:"once"},this.schedule.releaseTime=void 0,!this.schedule.releaseDate&&t.releaseDate&&/^\d{4}-\d{2}-\d{2}$/.test(t.releaseDate)&&(this.schedule.releaseDate=t.releaseDate),this.currentVolume=a,this.currentChapter=n;let c=(u=t.totalChapters)!=null?u:0,d=e==="manga"&&(h=t.totalVolumes)!=null?h:0;this.totalChapters=o!=null?o:c>0?c:null,this.totalVolumes=r!=null?r:d>0?d:null,this.onSave=l}onOpen(){this.titleEl.setText("Set reading schedule"),this.contentEl.addClass("wl-add-modal"),this.renderForm()}onClose(){this.contentEl.empty()}renderForm(){this.contentEl.empty(),this.contentEl.addClass("wl-add-modal");let i=this.contentEl,t=u=>{let h=i.createDiv({cls:"wl-modal-row"});return h.createSpan({cls:"wl-modal-label",text:u}),h},e=(u,h,p,m)=>{let y=t(u).createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0",placeholder:p}});h!==null&&(y.value=String(h)),y.addEventListener("input",()=>{m(parseInt(y.value)||null)})},a=t("Recurrence").createEl("select",{cls:"wl-select"}),n=[["once","Once"],["daily","Daily"],["weekly","Weekly"],["monthly","Monthly"]];for(let[u,h]of n){let p=a.createEl("option",{text:h,value:u});u===this.schedule.recurrence&&(p.selected=!0)}let r=i.createDiv(),o=()=>{var h;r.empty();let u=this.schedule.recurrence;if(u==="once"){let p=r.createDiv({cls:"wl-modal-row"});p.createSpan({cls:"wl-modal-label",text:"Date"});let m=p.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});m.value=this.schedule.releaseDate?this.schedule.releaseDate.split("-").reverse().join("/"):"",m.addEventListener("change",()=>{let f=q(m.value);f&&(this.schedule.releaseDate=f)})}if(u==="weekly"){let p=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],m=r.createDiv({cls:"wl-modal-row"});m.createSpan({cls:"wl-modal-label",text:"Day of week"});let f=m.createEl("select",{cls:"wl-select"});p.forEach((y,v)=>{var b;let w=f.createEl("option",{text:y,value:String(v)});v===((b=this.schedule.dayOfWeek)!=null?b:6)&&(w.selected=!0)}),f.addEventListener("change",()=>{this.schedule.dayOfWeek=parseInt(f.value)})}if(u==="monthly"){let p=r.createDiv({cls:"wl-modal-row"});p.createSpan({cls:"wl-modal-label",text:"Day of month"});let m=p.createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"1",max:"31",placeholder:"1"}});m.value=String((h=this.schedule.dayOfMonth)!=null?h:1),m.addEventListener("input",()=>{this.schedule.dayOfMonth=parseInt(m.value)||1})}};a.addEventListener("change",()=>{this.schedule.recurrence=a.value,o()}),o(),e("Current chapter",this.currentChapter,"E.g. 12",u=>{this.currentChapter=u}),e("Current volume",this.currentVolume,"E.g. 2",u=>{this.currentVolume=u}),e("Total chapters",this.totalChapters,"E.g. 120",u=>{this.totalChapters=u}),e("Total volumes",this.totalVolumes,"E.g. 12",u=>{this.totalVolumes=u}),i.createDiv({cls:"wl-modal-info wl-schedule-hint",text:"Titles with 0 or 1 total chapters will be treated as a single release date, like a book."});let l=i.createDiv({cls:"wl-modal-btn-row"});l.createEl("button",{cls:"wl-btn wl-btn-mr",text:"Cancel"}).addEventListener("click",()=>this.close()),l.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",()=>{(async()=>{if(this.schedule.recurrence==="once"&&!this.schedule.releaseDate){new ei.Notice("Set a release date.");return}await this.onSave(this.schedule,this.currentVolume,this.currentChapter,this.totalVolumes,this.totalChapters),this.close()})()})}};var Qs=require("obsidian"),ii=class extends Qs.FuzzySuggestModal{constructor(i,t,e){super(i),this.items=t,this.onSelect=e,this.setPlaceholder("Search a title to add to Upcoming...")}getItems(){return this.items}getItemText(i){return`${i.title} (${i.typeLabel})`}onChooseItem(i){this.onSelect(i)}};function es(g){if(g<30)return`in ${g} days`;let i=Math.round(g/30);return`in ${g} days (${i} month${i!==1?"s":""})`}function si(g){if(!g.releaseTime)return!0;let i=new Date,[t,e]=g.releaseTime.split(":"),s=parseInt(t!=null?t:"0"),a=parseInt(e!=null?e:"0");return i.getHours()>s||i.getHours()===s&&i.getMinutes()>=a}function is(g,i,t){let e=new Date,s=new Date(e.getFullYear(),e.getMonth(),e.getDate()),a=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`,n=t===a;if(g.recurrence==="once"){if(!g.releaseDate)return{kind:"future",label:"\u2014",daysUntil:9999};let r=new Date(g.releaseDate+"T00:00:00"),o=new Date(r.getFullYear(),r.getMonth(),r.getDate());if(o.getTime()c.name===t.type),s=this.plugin.settings.coloredTypeBadges;return{source:"watchlist",id:t.id,title:t.title,typeName:t.type,typeColor:s&&e?N(t.type,e.color,this.plugin.settings.colorTheme):null,externalLink:t.externalLink,isSingle:t.totalEpisodes<=1,totalUnits:(l=i.totalEpisodes)!=null?l:t.totalEpisodes,unitNoun:"episode",unitNounCap:"Episode",groupNounCap:"Season",nextLabel:"Airing next",planStatus:"Plan to watch"}}static getMaybeDueCount(i){let t=new Date;t.setHours(0,0,0,0);let e=t.toISOString().split("T")[0];return i.getMaybeTitles().filter(s=>!!s.releaseDate&&s.releaseDate<=e).length}static getAiredDueCount(i,t){var r,o;let e=i.getAirtimeEntries(),s=i.getTitles(),a=new Map(s.map(l=>[l.id,l])),n=0;for(let l of e){let c;if(l.source==="reading"){if(t&&!(((r=l.readingKind)!=null?r:"book")==="book"?t.getBook(l.titleId):t.getManga(l.titleId)))continue;c=((o=l.totalEpisodes)!=null?o:0)<=1}else{let u=a.get(l.titleId);if(!u)continue;c=u.totalEpisodes<=1}let d=is(l.schedule,c,l.lastAcknowledgedDate);(d.kind==="aired"||d.kind==="due")&&n++}return n}render(){this.container.empty(),this.container.addClass("wl-airtime"),this.onCountChange&&this.onCountChange(g.getAiredDueCount(this.dataManager,this.readingDataManager)+g.getMaybeDueCount(this.dataManager)),this.renderInnerTabBar(),this.currentSubTab==="tracker"?this.renderTracker():this.currentSubTab==="history"?this.renderHistory():this.renderMaybe()}renderInnerTabBar(){let i=this.container.createDiv({cls:"wl-inner-tab-bar"}),t=g.getAiredDueCount(this.dataManager,this.readingDataManager),e=g.getMaybeDueCount(this.dataManager),s=[{key:"tracker",label:"Tracker",badge:t},{key:"history",label:"Log",badge:0},{key:"maybe",label:"Maybe",badge:e}];for(let{key:a,label:n,badge:r}of s){let o=r>0?`${n} (${r})`:n;i.createEl("button",{cls:`wl-inner-tab-btn${this.currentSubTab===a?" is-active":""}`,text:o}).addEventListener("click",()=>{this.currentSubTab!==a&&(this.currentSubTab=a,this.selectionMode=!1,this.selectedItems.clear(),this.searchQuery="",this.render())})}}renderTracker(){this.plugin.settings.showHintBanners&&this.container.createDiv({cls:"wl-cl-draft-banner",text:'\u26A0 All titles with a release date in the future will be automatically marked as "To be released" in Watchlist and added here.'}),this.renderHeader(),this.renderSearch(),this.renderCards()}renderHistory(){let i=new Date;i.setHours(0,0,0,0);let t=i.toISOString().split("T")[0],e=new Date(i);e.setMonth(e.getMonth()-6);let s=e.toISOString().split("T")[0],a=this.dataManager.getTitles().filter(r=>!!r.releaseDate&&r.releaseDate<=t&&r.releaseDate>=s).sort((r,o)=>{var l,c;return((l=o.releaseDate)!=null?l:"").localeCompare((c=r.releaseDate)!=null?c:"")});if(a.length===0){this.container.createDiv({cls:"wl-empty-state",text:"No past releases yet."});return}let n=this.container.createDiv({cls:"wl-airtime-cards"});for(let r of a)this.renderHistoryCard(n,r)}renderHistoryCard(i,t){let e=i.createDiv({cls:"wl-airtime-card wl-airtime-history-card"}),s=e.createDiv({cls:"wl-airtime-card-left"});s.createDiv({cls:"wl-airtime-card-title",text:t.title});let a=s.createDiv({cls:"wl-airtime-card-meta"}),n=this.plugin.settings.types.find(u=>u.name===t.type),r=this.plugin.settings.coloredTypeBadges,o=a.createSpan({cls:r?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});r&&n&&(o.style.backgroundColor=N(t.type,n.color,this.plugin.settings.colorTheme)),t.releaseDate&&a.createSpan({cls:"wl-airtime-schedule",text:t.releaseDate});let l=e.createDiv({cls:"wl-airtime-card-right wl-airtime-history-right"});t.releaseDate&&l.createDiv({cls:"wl-airtime-pill wl-airtime-pill-aired",text:Dn(t.releaseDate)});let c=l.createEl("button",{cls:"wl-airtime-action-btn",text:"\u{1F310}"});c.title="Open page",c.addEventListener("click",u=>{u.stopPropagation(),t.externalLink?activeWindow.open(t.externalLink,"_blank"):new vt.Notice("No external link set for this title.")});let d=l.createEl("button",{cls:"wl-airtime-action-btn wl-airtime-action-btn-delete wl-btn-danger",text:"\u2715"});d.title="Remove from watchlist",d.addEventListener("click",u=>{u.stopPropagation(),new _(this.plugin.app,`Remove "${t.title}" from Watchlist?`,()=>{this.dataManager.removeTitle(t.id).then(()=>this.render())}).open()})}renderMaybe(){let i=this.dataManager.getMaybeTitles(),t=this.container.createDiv({cls:"wl-list-header"});if(i.length>0&&t.createSpan({cls:"wl-list-count",text:String(i.length)}),t.createDiv({cls:"wl-header-controls"}).createDiv({cls:"wl-header-controls-right"}).createDiv({cls:"wl-add-btn-wrap"}).createEl("button",{cls:"wl-add-btn wl-btn-success",text:"+ add"}).addEventListener("click",c=>{c.stopPropagation(),new ti(this.plugin.app,this.plugin,this.dataManager,()=>this.render()).open()}),i.length===0){this.container.createDiv({cls:"wl-empty-state",text:`No "Maybe" titles yet. Click + Add to track something you're considering.`});return}let r=new Date;r.setHours(0,0,0,0);let o=this.container.createDiv({cls:"wl-airtime-cards"}),l=[...i].sort((c,d)=>{var p,m;let u=(p=c.releaseDate)!=null?p:"",h=(m=d.releaseDate)!=null?m:"";return!u&&!h?c.dateAdded.localeCompare(d.dateAdded):u?h?u.localeCompare(h):-1:1});for(let c of l)this.renderMaybeCard(o,c,r)}renderMaybeCard(i,t,e){var y;let s={recurrence:"once",releaseDate:(y=t.releaseDate)!=null?y:void 0},a=is(s,!0),n="wl-maybe-card";a.kind==="due"&&(n+=" wl-airtime-card-aired is-due");let r=i.createDiv({cls:n}),o=r.createDiv({cls:"wl-maybe-card-left"});o.createSpan({cls:"wl-maybe-card-title",text:t.title});let l=this.plugin.settings.types.find(v=>v.name===t.type),c=this.plugin.settings.coloredTypeBadges,d=o.createSpan({cls:c?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});c&&l&&(d.style.backgroundColor=N(t.type,l.color,this.plugin.settings.colorTheme));let u={"today-before":"wl-airtime-pill wl-airtime-pill-today-series",future:"wl-airtime-pill wl-airtime-pill-days",aired:"wl-airtime-pill wl-airtime-pill-aired",due:"wl-airtime-pill wl-airtime-pill-due"},h=a.kind==="future"&&a.label==="Tomorrow"?"wl-airtime-pill wl-airtime-pill-tomorrow":u[a.kind],p=r.createDiv({cls:"wl-maybe-card-right"});p.createDiv({cls:h,text:t.releaseDate?a.label:"\u2014"});let m=p.createEl("button",{cls:"wl-airtime-action-btn",text:"\u{1F310}"});m.title="Open page",m.addEventListener("click",v=>{v.stopPropagation(),t.externalLink?activeWindow.open(t.externalLink,"_blank"):new vt.Notice("No external link set.")});let f=p.createEl("button",{cls:"wl-airtime-action-btn wl-airtime-action-btn-delete wl-btn-danger",text:"\u2715"});f.title="Remove from maybe",f.addEventListener("click",v=>{v.stopPropagation(),new _(this.plugin.app,`Remove "${t.title}" from Maybe?`,()=>{this.dataManager.removeMaybeTitle(t.id).then(()=>this.render())}).open()})}renderSearch(){let t=this.container.createDiv({cls:"wl-search-wrap"}).createEl("input",{cls:"wl-search-input",attr:{type:"text",placeholder:"Search upcoming..."}});t.value=this.searchQuery;let e=null;t.addEventListener("input",()=>{this.searchQuery=t.value,e!==null&&window.clearTimeout(e),e=window.setTimeout(()=>{e=null,this.rerenderCards()},250)})}rerenderCards(){let i=this.container.querySelector(".wl-airtime-cards"),t=this.container.querySelector(".wl-empty-state");i&&i.remove(),t&&t.remove(),this.renderCards()}renderHeader(){let i=this.container.createDiv({cls:"wl-list-header"}),t=this.dataManager.getAirtimeEntries().filter(o=>this.resolveEntry(o)!==null).length;t>0&&i.createSpan({cls:"wl-list-count",text:String(t)});let e=i.createDiv({cls:"wl-header-controls"});if(this.selectionMode&&this.selectedItems.size>0&&this.renderActionBar(e),this.selectionMode){let o=this.selectedItems.size>0,l=e.createEl("button",{cls:"wl-btn wl-btn-sm",text:o?"None":"All"});l.title=o?"Deselect all":"Select all visible",l.addEventListener("click",()=>{if(this.selectedItems.size>0)this.selectedItems.clear();else for(let c of this.dataManager.getAirtimeEntries())this.selectedItems.add(c.id);this.render()})}let s=e.createDiv({cls:"wl-header-controls-right"});s.createEl("button",{cls:`wl-btn wl-btn-sm${this.selectionMode?" is-active":""}`,text:"Select"}).addEventListener("click",()=>{this.selectionMode=!this.selectionMode,this.selectedItems.clear(),this.render()}),s.createDiv({cls:"wl-add-btn-wrap"}).createEl("button",{cls:"wl-add-btn wl-btn-success",text:"+ add"}).addEventListener("click",o=>{o.stopPropagation(),this.openAddFlow()})}renderActionBar(i){let e=i.createDiv({cls:"wl-action-bar"}).createEl("button",{cls:"wl-group-action-btn wl-group-action-btn-delete wl-btn-danger",text:"\u2715"});e.title="Remove from upcoming",e.addEventListener("click",s=>{s.stopPropagation();let a=this.selectedItems.size;new _(this.plugin.app,`Remove ${a} selected item${a!==1?"s":""} from Upcoming? This cannot be undone.`,()=>{(async()=>(await this.dataManager.removeAirtimeEntriesBatch(Array.from(this.selectedItems)),this.selectedItems.clear(),this.render()))()}).open()})}openAddFlow(){let i=this.dataManager.getAirtimeEntries(),t=new Set(i.filter(a=>a.source!=="reading").map(a=>a.titleId)),e=new Set(i.filter(a=>a.source==="reading").map(a=>a.titleId)),s=[];for(let a of this.dataManager.getTitles())t.has(a.id)||s.push({source:"watchlist",id:a.id,title:a.title,typeLabel:a.type});for(let a of this.readingDataManager.getBooks())e.has(a.id)||s.push({source:"reading",kind:"book",id:a.id,title:a.title,typeLabel:"Book"});for(let a of this.readingDataManager.getMangaList())e.has(a.id)||s.push({source:"reading",kind:"manga",id:a.id,title:a.title,typeLabel:"Manga"});if(this.dataManager.getTitles().length===0&&this.readingDataManager.getBooks().length===0&&this.readingDataManager.getMangaList().length===0){new vt.Notice("No titles in your watchlog or reading library yet.");return}if(s.length===0){new vt.Notice("Everything is already in upcoming.");return}new ii(this.plugin.app,s,a=>{var n;if(a.source==="reading"){let r=(n=a.kind)!=null?n:"book",o=r==="book"?this.readingDataManager.getBook(a.id):this.readingDataManager.getManga(a.id);o&&this.startAddWithReading(o,r)}else{let r=this.dataManager.getTitle(a.id);r&&this.startAddWithTitle(r)}}).open()}startAddWithReading(i,t){let e=i.releaseDate&&/^\d{4}-\d{2}-\d{2}$/.test(i.releaseDate)?{recurrence:"once",releaseDate:i.releaseDate}:null;new Ee(this.plugin.app,i,t,e,null,null,null,null,async(s,a,n,r,o)=>{let l={id:this.dataManager.generateReadingAirtimeId(i.id),titleId:i.id,source:"reading",readingKind:t,schedule:s,currentSeason:a!=null?a:void 0,currentEpisode:n!=null?n:void 0,totalSeasons:r!=null?r:void 0,totalEpisodes:o!=null?o:void 0,dateAdded:new Date().toISOString()};await this.dataManager.addAirtimeEntry(l),await this.syncReadingItemFromSchedule(i.id,t,s,r,o),this.render()}).open()}async syncReadingItemFromSchedule(i,t,e,s,a){var n,r;if(t==="book"){let o=this.readingDataManager.getBook(i);if(!o)return;let l=!1;if(a!==null&&a!==o.totalChapters&&(o.totalChapters=a,l=!0),e.recurrence==="once"&&Lt(e.releaseDate)){let c=(n=e.releaseDate)!=null?n:null;o.releaseDate!==c&&(o.releaseDate=c,l=!0)}l&&await this.readingDataManager.updateBook(o)}else{let o=this.readingDataManager.getManga(i);if(!o)return;let l=!1;if(a!==null&&a!==o.totalChapters&&(o.totalChapters=a,l=!0),s!==null&&s!==o.totalVolumes&&(o.totalVolumes=s,l=!0),e.recurrence==="once"&&Lt(e.releaseDate)){let c=(r=e.releaseDate)!=null?r:null;o.releaseDate!==c&&(o.releaseDate=c,l=!0)}l&&await this.readingDataManager.updateManga(o)}}async revertToBeReleasedStatus(i,t){var e;if(t.source==="reading")if(((e=i.readingKind)!=null?e:"book")==="book"){let a=this.readingDataManager.getBook(i.titleId);a&&a.status==="To be released"&&(a.status="Plan to Read",await this.readingDataManager.updateBook(a))}else{let a=this.readingDataManager.getManga(i.titleId);a&&a.status==="To be released"&&(a.status="Plan to Read",await this.readingDataManager.updateManga(a))}else{let s=this.dataManager.getTitle(i.titleId);s&&s.status==="To be released"&&(s.status="Plan to watch",await this.dataManager.updateTitle(s))}}async startAddWithTitle(i){let t=null;if(i.type==="Anime"&&i.malId)try{let e=await this.plugin.apiService.getAnimeScheduleByMalId(i.malId);e&&(t={recurrence:"weekly",dayOfWeek:e.dayOfWeek,releaseTime:e.time},new vt.Notice("Schedule auto-filled from myanimelist."))}catch(e){}!t&&i.releaseDate&&/^\d{4}-\d{2}-\d{2}$/.test(i.releaseDate)&&(t={recurrence:"once",releaseDate:i.releaseDate}),new ai(this.plugin.app,i,t,null,null,null,null,async(e,s,a,n,r)=>{var c;let o={id:this.dataManager.generateAirtimeId(i.id),titleId:i.id,schedule:e,currentSeason:s!=null?s:void 0,currentEpisode:a!=null?a:void 0,totalSeasons:n!=null?n:void 0,totalEpisodes:r!=null?r:void 0,dateAdded:new Date().toISOString()};await this.dataManager.addAirtimeEntry(o);let l=this.dataManager.getTitle(i.id);if(l){let d=!1;if(r!==null&&r!==l.totalEpisodes&&(l.totalEpisodes=r,d=!0),e.recurrence==="once"){let u=(c=e.releaseDate)!=null?c:null;l.releaseDate!==u&&(l.releaseDate=u,d=!0)}d&&await this.dataManager.updateTitle(l)}this.render()}).open()}renderCards(){let i=this.dataManager.getAirtimeEntries();if(i.length===0){this.container.createDiv({cls:"wl-empty-state",text:"No titles in Upcoming. Click + Add to track airing schedules."});return}let t=this.searchQuery.trim().toLowerCase(),e=i.map(a=>{let n=this.resolveEntry(a);if(!n||t&&!n.title.toLowerCase().includes(t))return null;let r=is(a.schedule,n.isSingle,a.lastAcknowledgedDate);return{entry:a,r:n,countdown:r}}).filter(a=>a!==null).sort((a,n)=>{let r=c=>c==="aired"||c==="due"?0:c==="today-before"?1:2,o=r(a.countdown.kind),l=r(n.countdown.kind);return o!==l?o-l:a.countdown.daysUntil-n.countdown.daysUntil});if(e.length===0){this.container.createDiv({cls:"wl-empty-state",text:"No upcoming titles match your search."});return}let s=this.container.createDiv({cls:"wl-airtime-cards"});for(let{entry:a,r:n,countdown:r}of e)this.renderCard(s,a,n,r)}renderCard(i,t,e,s){let a=e.isSingle,n=e.totalUnits,r=!a&&t.currentEpisode!==void 0&&n>0&&t.currentEpisode>=n,o=a&&s.kind==="due"||!a&&s.kind==="aired",l="wl-airtime-card";(s.kind==="aired"||s.kind==="due")&&(l+=" wl-airtime-card-aired"),s.kind==="aired"&&(l+=" is-aired"),s.kind==="due"&&(l+=" is-due"),this.selectionMode&&this.selectedItems.has(t.id)&&(l+=" wl-row-selected");let c=i.createDiv({cls:l});if(this.selectionMode){let E=c.createEl("input",{attr:{type:"checkbox"}});E.addClass("wl-airtime-select-cb"),E.checked=this.selectedItems.has(t.id),E.addEventListener("click",D=>D.stopPropagation()),E.addEventListener("change",()=>{E.checked?this.selectedItems.add(t.id):this.selectedItems.delete(t.id),this.render()}),c.addEventListener("click",()=>{this.selectedItems.has(t.id)?this.selectedItems.delete(t.id):this.selectedItems.add(t.id),this.render()})}let d=c.createDiv({cls:"wl-airtime-card-left"});d.createDiv({cls:"wl-airtime-card-title",text:e.title});let u=d.createDiv({cls:"wl-airtime-card-meta"}),h=u.createSpan({cls:e.typeColor?"wl-badge wl-badge-sm":"wl-badge-plain",text:e.typeName});if(e.typeColor&&(h.style.backgroundColor=e.typeColor),u.createSpan({cls:"wl-airtime-schedule",text:ys(t.schedule)}),!a&&(t.currentSeason!==void 0||t.currentEpisode!==void 0)){let E=[];t.currentSeason!==void 0&&E.push(`${e.groupNounCap} ${t.currentSeason}`),t.currentEpisode!==void 0&&E.push(`${e.unitNounCap} ${t.currentEpisode}`),E.push(e.nextLabel);let D=r?"wl-ep-badge wl-ep-badge-final":"wl-ep-badge";d.createDiv({cls:D,text:E.join(" \xB7 ")})}let p=c.createDiv({cls:"wl-airtime-card-right"}),m={"today-before":"wl-airtime-pill wl-airtime-pill-today-series",future:"wl-airtime-pill wl-airtime-pill-days",aired:"wl-airtime-pill wl-airtime-pill-aired",due:"wl-airtime-pill wl-airtime-pill-due"},f=s.kind==="future"&&s.label==="Tomorrow"?"wl-airtime-pill wl-airtime-pill-tomorrow":m[s.kind];p.createDiv({cls:f,text:s.label});let y=p.createDiv({cls:"wl-airtime-actions"});if(o){let E=y.createEl("button",{cls:"wl-airtime-action-btn wl-airtime-action-btn-tick",text:"\u2713"});E.title=a?"Mark as released":r?`Final ${e.unitNoun} \u2014 mark done`:`Mark ${e.unitNoun} as aired`,E.addEventListener("click",D=>{var T;D.stopPropagation();let S=a?`"${e.title}" has been released. Remove from Upcoming and set status to ${e.planStatus}?`:r?`Final ${e.unitNoun} of "${e.title}". -Remove from Upcoming? (status unchanged)`:`${e.unitNounCap} ${(D=t.currentEpisode)!=null?D:""} of "${e.title}". -Mark and track next ${e.unitNoun}?`;new N(this.plugin.app,E,()=>{(async()=>{var T;let C=new Date,x=`${C.getFullYear()}-${String(C.getMonth()+1).padStart(2,"0")}-${String(C.getDate()).padStart(2,"0")}`;this.plugin.markAirtimeHandled(`${t.id}-${x}`),a?(await this.dataManager.removeAirtimeEntry(t.id),await this.revertToBeReleasedStatus(t,e)):r?await this.dataManager.removeAirtimeEntry(t.id):(t.currentEpisode=((T=t.currentEpisode)!=null?T:1)+1,t.lastAcknowledgedDate=x,await this.dataManager.updateAirtimeEntry(t)),this.render()})()}).open()})}let y=f.createEl("button",{cls:"wl-airtime-action-btn",text:"\u{1F310}"});y.title="Open page",y.addEventListener("click",S=>{S.stopPropagation(),e.externalLink?activeWindow.open(e.externalLink,"_blank"):new pt.Notice("No external link set for this title.")});let w=f.createEl("button",{cls:"wl-airtime-action-btn",text:"\u270F"});w.title="Edit schedule",w.addEventListener("click",S=>{S.stopPropagation(),e.source==="reading"?this.openEditReadingSchedule(t):this.openEditWatchSchedule(t)});let b=f.createEl("button",{cls:"wl-airtime-action-btn wl-airtime-action-btn-delete wl-btn-danger",text:"\u2715"});b.title="Remove from upcoming",b.addEventListener("click",S=>{S.stopPropagation(),new N(this.plugin.app,`Remove "${e.title}" from Upcoming?`,()=>{this.dataManager.removeAirtimeEntry(t.id).then(()=>this.render())}).open()})}openEditWatchSchedule(i){var e,s,a,n;let t=this.dataManager.getTitle(i.titleId);t&&new Ie(this.plugin.app,t,{...i.schedule},(e=i.currentSeason)!=null?e:null,(s=i.currentEpisode)!=null?s:null,(a=i.totalSeasons)!=null?a:null,(n=i.totalEpisodes)!=null?n:null,async(r,o,l,c,d)=>{var h;i.schedule=r,i.currentSeason=o!=null?o:void 0,i.currentEpisode=l!=null?l:void 0,i.totalSeasons=c!=null?c:void 0,i.totalEpisodes=d!=null?d:void 0,await this.dataManager.updateAirtimeEntry(i);let u=this.dataManager.getTitle(i.titleId);if(u){let p=!1;if(d!==null&&d!==u.totalEpisodes&&(u.totalEpisodes=d,p=!0),r.recurrence==="once"){let m=(h=r.releaseDate)!=null?h:null;u.releaseDate!==m&&(u.releaseDate=m,p=!0)}p&&await this.dataManager.updateTitle(u)}this.render()}).open()}openEditReadingSchedule(i){var s,a,n,r,o;let t=(s=i.readingKind)!=null?s:"book",e=t==="book"?this.readingDataManager.getBook(i.titleId):this.readingDataManager.getManga(i.titleId);e&&new se(this.plugin.app,e,t,{...i.schedule},(a=i.currentSeason)!=null?a:null,(n=i.currentEpisode)!=null?n:null,(r=i.totalSeasons)!=null?r:null,(o=i.totalEpisodes)!=null?o:null,async(l,c,d,u,h)=>{i.schedule=l,i.currentSeason=c!=null?c:void 0,i.currentEpisode=d!=null?d:void 0,i.totalSeasons=u!=null?u:void 0,i.totalEpisodes=h!=null?h:void 0,await this.dataManager.updateAirtimeEntry(i),await this.syncReadingItemFromSchedule(i.titleId,t,l,u,h),this.render()}).open()}},Ie=class extends pt.Modal{constructor(i,t,e,s,a,n,r,o){super(i),this.title=t;let l=t.totalEpisodes<=1;this.schedule=e?{...e}:{recurrence:l?"once":"weekly"},!this.schedule.releaseDate&&t.releaseDate&&/^\d{4}-\d{2}-\d{2}$/.test(t.releaseDate)&&(this.schedule.releaseDate=t.releaseDate),this.currentSeason=s,this.currentEpisode=a,this.totalSeasons=n!=null?n:t.seasons.length>0?t.seasons.length:null,this.totalEpisodes=r!=null?r:t.totalEpisodes>0?t.totalEpisodes:null,this.onSave=o}onOpen(){this.titleEl.setText("Set schedule"),this.contentEl.addClass("wl-add-modal"),this.renderForm()}onClose(){this.contentEl.empty()}localHHMMtoJST(i){if(!i||!/^\d{2}:\d{2}$/.test(i))return"\u2014";let[t,e]=i.split(":"),s=parseInt(t!=null?t:"0"),a=parseInt(e!=null?e:"0"),n=new Date,o=new Date(n.getFullYear(),n.getMonth(),n.getDate(),s,a,0,0).getTime()+9*60*60*1e3,l=new Date(o),c=l.getUTCHours().toString().padStart(2,"0"),d=l.getUTCMinutes().toString().padStart(2,"0");return`${c}:${d}`}renderForm(){this.contentEl.empty(),this.contentEl.addClass("wl-add-modal");let i=this.contentEl,t=this.title.totalEpisodes<=1,e=o=>{let l=i.createDiv({cls:"wl-modal-row"});return l.createSpan({cls:"wl-modal-label",text:o}),l},s=(o,l)=>{var p;let c=l.createDiv({cls:"wl-modal-row wl-modal-row-mt"});c.createSpan({cls:"wl-modal-label",text:o});let d=c.createEl("input",{cls:"wl-modal-input wl-time-input",attr:{type:"text",placeholder:"Hh:mm",maxlength:"5"}});d.value=(p=this.schedule.releaseTime)!=null?p:"";let u=c.createSpan({cls:"wl-jst-clock"}),h=()=>{u.textContent=d.value?`JST ${this.localHHMMtoJST(d.value)}`:"JST \u2014"};return h(),d.addEventListener("input",()=>{let m=d.value.trim();this.schedule.releaseTime=m||void 0,h()}),d};if(t){let l=e("Release date").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});l.value=this.schedule.releaseDate?this.schedule.releaseDate.split("-").reverse().join("/"):"",l.addEventListener("change",()=>{let c=j(l.value);c&&(this.schedule.recurrence="once",this.schedule.releaseDate=c)}),s("Time (optional)",i)}else{let l=e("Recurrence").createEl("select",{cls:"wl-select"}),c=[["once","Once"],["daily","Daily"],["weekly","Weekly"],["monthly","Monthly"]];for(let[S,k]of c){let E=l.createEl("option",{text:k,value:S});S===this.schedule.recurrence&&(E.selected=!0)}let d=i.createDiv(),u=()=>{var k;d.empty();let S=this.schedule.recurrence;if(S==="once"){let E=d.createDiv({cls:"wl-modal-row"});E.createSpan({cls:"wl-modal-label",text:"Date"});let D=E.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});D.value=this.schedule.releaseDate?this.schedule.releaseDate.split("-").reverse().join("/"):"",D.addEventListener("change",()=>{let C=j(D.value);C&&(this.schedule.releaseDate=C)})}if(S==="weekly"){let E=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],D=d.createDiv({cls:"wl-modal-row"});D.createSpan({cls:"wl-modal-label",text:"Day of week"});let C=D.createEl("select",{cls:"wl-select"});E.forEach((x,T)=>{var L;let M=C.createEl("option",{text:x,value:String(T)});T===((L=this.schedule.dayOfWeek)!=null?L:6)&&(M.selected=!0)}),C.addEventListener("change",()=>{this.schedule.dayOfWeek=parseInt(C.value)})}if(S==="monthly"){let E=d.createDiv({cls:"wl-modal-row"});E.createSpan({cls:"wl-modal-label",text:"Day of month"});let D=E.createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"1",max:"31",placeholder:"1"}});D.value=String((k=this.schedule.dayOfMonth)!=null?k:1),D.addEventListener("input",()=>{this.schedule.dayOfMonth=parseInt(D.value)||1})}s("Time (HH:MM)",d)};l.addEventListener("change",()=>{this.schedule.recurrence=l.value,u()}),u();let p=e("Current season").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"1",placeholder:"E.g. 2"}});this.currentSeason!==null&&(p.value=String(this.currentSeason)),p.addEventListener("input",()=>{this.currentSeason=parseInt(p.value)||null});let v=e("Current episode").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"1",placeholder:"E.g. 7"}});this.currentEpisode!==null&&(v.value=String(this.currentEpisode)),v.addEventListener("input",()=>{this.currentEpisode=parseInt(v.value)||null});let y=e("Total seasons").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"1",placeholder:"E.g. 3"}});this.totalSeasons!==null&&(y.value=String(this.totalSeasons)),y.addEventListener("input",()=>{this.totalSeasons=parseInt(y.value)||null});let b=e("Total episodes").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0",placeholder:"E.g. 13"}});this.totalEpisodes!==null&&(b.value=String(this.totalEpisodes)),b.addEventListener("input",()=>{this.totalEpisodes=parseInt(b.value)||null}),i.createDiv({cls:"wl-modal-info wl-schedule-hint",text:"Titles with 0 or 1 total episodes will be treated as a single release date, like a movie."})}let a=i.createDiv({cls:"wl-modal-btn-row"});a.createEl("button",{cls:"wl-btn wl-btn-mr",text:"Cancel"}).addEventListener("click",()=>this.close()),a.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",()=>{(async()=>{if(this.schedule.releaseTime&&!/^\d{2}:\d{2}$/.test(this.schedule.releaseTime)){new pt.Notice("Time must be in 24h format: hh:mm (e.g. 14:50)");return}await this.onSave(this.schedule,this.currentSeason,this.currentEpisode,this.totalSeasons,this.totalEpisodes),this.close()})()})}};var W=require("obsidian");var Ot=class{constructor(i,t){this.app=i;this.plugin=t;this.corruptLists=new Set;this.saveQueues=new Map}async saveSerialized(i,t){var a;let s=((a=this.saveQueues.get(i))!=null?a:Promise.resolve()).then(t).catch(n=>console.error("[WL] Save error for list:",i,n));this.saveQueues.set(i,s),await s}get folderPath(){return this.plugin.settings.customListsFolder||"WatchLog/CustomLists"}async ensureFolder(){let i=(0,W.normalizePath)(this.folderPath);if(!this.app.vault.getAbstractFileByPath(i))try{await this.app.vault.createFolder(i)}catch(t){}}listNames(){let i=(0,W.normalizePath)(this.folderPath);return this.app.vault.getFiles().filter(t=>{var s,a;return((a=(s=t.parent)==null?void 0:s.path)!=null?a:"")===i&&t.extension==="md"}).map(t=>t.basename).sort((t,e)=>t.localeCompare(e))}async loadList(i){let t=(0,W.normalizePath)(`${this.folderPath}/${i}.md`),e=this.app.vault.getAbstractFileByPath(t);if(!(e instanceof W.TFile))return null;try{let s=await this.app.vault.read(e);return this.parse(i,s)}catch(s){return console.warn("[WL] Failed to read custom list",i,s),null}}parse(i,t){var o;let e=t.match(/## Notes\n([\s\S]*?)(?=\n## |\s*$)/),s=((o=e==null?void 0:e[1])!=null?o:"").trim(),a=t.match(/## Data\n```json\n([\s\S]*?)\n```/),n=[],r=[];if(a!=null&&a[1])try{let l=JSON.parse(a[1]);Array.isArray(l.columns)&&(n=l.columns.filter(c=>typeof c=="object"&&c!==null&&"id"in c&&"label"in c&&"type"in c)),Array.isArray(l.rows)&&(r=l.rows.filter(c=>typeof c=="object"&&c!==null&&"id"in c))}catch(l){return console.warn("[WL] Custom list JSON parse failed for",i,l),new W.Notice(`Custom list "${i}" has corrupt data and cannot be loaded.`),this.corruptLists.add(i),null}return{name:i,columns:n,rows:r,notes:s}}async saveList(i){await this.saveSerialized(i.name,async()=>{if(this.corruptLists.has(i.name)){console.warn("[WL] Refusing to save corrupt custom list",i.name);return}await this.ensureFolder();let t=(0,W.normalizePath)(`${this.folderPath}/${i.name}.md`),e=this.serialize(i),s=this.app.vault.getAbstractFileByPath(t);try{s instanceof W.TFile?await this.app.vault.modify(s,e):await this.app.vault.create(t,e)}catch(a){console.error("WatchLog: failed to save custom list",a)}})}async saveNotes(i,t){await this.saveSerialized(i,async()=>{let e=(0,W.normalizePath)(`${this.folderPath}/${i}.md`),s=this.app.vault.getAbstractFileByPath(e);if(s instanceof W.TFile)try{let a=await this.app.vault.read(s),n=`## Notes +Remove from Upcoming? (status unchanged)`:`${e.unitNounCap} ${(T=t.currentEpisode)!=null?T:""} of "${e.title}". +Mark and track next ${e.unitNoun}?`;new _(this.plugin.app,S,()=>{(async()=>{var C;let M=new Date,x=`${M.getFullYear()}-${String(M.getMonth()+1).padStart(2,"0")}-${String(M.getDate()).padStart(2,"0")}`;this.plugin.markAirtimeHandled(`${t.id}-${x}`),a?(await this.dataManager.removeAirtimeEntry(t.id),await this.revertToBeReleasedStatus(t,e)):r?await this.dataManager.removeAirtimeEntry(t.id):(t.currentEpisode=((C=t.currentEpisode)!=null?C:1)+1,t.lastAcknowledgedDate=x,await this.dataManager.updateAirtimeEntry(t)),this.render()})()}).open()})}let v=y.createEl("button",{cls:"wl-airtime-action-btn",text:"\u{1F310}"});v.title="Open page",v.addEventListener("click",E=>{E.stopPropagation(),e.externalLink?activeWindow.open(e.externalLink,"_blank"):new vt.Notice("No external link set for this title.")});let w=y.createEl("button",{cls:"wl-airtime-action-btn",text:"\u270F"});w.title="Edit schedule",w.addEventListener("click",E=>{E.stopPropagation(),e.source==="reading"?this.openEditReadingSchedule(t):this.openEditWatchSchedule(t)});let b=y.createEl("button",{cls:"wl-airtime-action-btn wl-airtime-action-btn-delete wl-btn-danger",text:"\u2715"});b.title="Remove from upcoming",b.addEventListener("click",E=>{E.stopPropagation(),new _(this.plugin.app,`Remove "${e.title}" from Upcoming?`,()=>{this.dataManager.removeAirtimeEntry(t.id).then(()=>this.render())}).open()})}openEditWatchSchedule(i){var e,s,a,n;let t=this.dataManager.getTitle(i.titleId);t&&new ai(this.plugin.app,t,{...i.schedule},(e=i.currentSeason)!=null?e:null,(s=i.currentEpisode)!=null?s:null,(a=i.totalSeasons)!=null?a:null,(n=i.totalEpisodes)!=null?n:null,async(r,o,l,c,d)=>{var h;i.schedule=r,i.currentSeason=o!=null?o:void 0,i.currentEpisode=l!=null?l:void 0,i.totalSeasons=c!=null?c:void 0,i.totalEpisodes=d!=null?d:void 0,await this.dataManager.updateAirtimeEntry(i);let u=this.dataManager.getTitle(i.titleId);if(u){let p=!1;if(d!==null&&d!==u.totalEpisodes&&(u.totalEpisodes=d,p=!0),r.recurrence==="once"){let m=(h=r.releaseDate)!=null?h:null;u.releaseDate!==m&&(u.releaseDate=m,p=!0)}p&&await this.dataManager.updateTitle(u)}this.render()}).open()}openEditReadingSchedule(i){var s,a,n,r,o;let t=(s=i.readingKind)!=null?s:"book",e=t==="book"?this.readingDataManager.getBook(i.titleId):this.readingDataManager.getManga(i.titleId);e&&new Ee(this.plugin.app,e,t,{...i.schedule},(a=i.currentSeason)!=null?a:null,(n=i.currentEpisode)!=null?n:null,(r=i.totalSeasons)!=null?r:null,(o=i.totalEpisodes)!=null?o:null,async(l,c,d,u,h)=>{i.schedule=l,i.currentSeason=c!=null?c:void 0,i.currentEpisode=d!=null?d:void 0,i.totalSeasons=u!=null?u:void 0,i.totalEpisodes=h!=null?h:void 0,await this.dataManager.updateAirtimeEntry(i),await this.syncReadingItemFromSchedule(i.titleId,t,l,u,h),this.render()}).open()}},ai=class extends vt.Modal{constructor(i,t,e,s,a,n,r,o){super(i),this.title=t;let l=t.totalEpisodes<=1;this.schedule=e?{...e}:{recurrence:l?"once":"weekly"},!this.schedule.releaseDate&&t.releaseDate&&/^\d{4}-\d{2}-\d{2}$/.test(t.releaseDate)&&(this.schedule.releaseDate=t.releaseDate),this.currentSeason=s,this.currentEpisode=a,this.totalSeasons=n!=null?n:t.seasons.length>0?t.seasons.length:null,this.totalEpisodes=r!=null?r:t.totalEpisodes>0?t.totalEpisodes:null,this.onSave=o}onOpen(){this.titleEl.setText("Set schedule"),this.contentEl.addClass("wl-add-modal"),this.renderForm()}onClose(){this.contentEl.empty()}localHHMMtoJST(i){if(!i||!/^\d{2}:\d{2}$/.test(i))return"\u2014";let[t,e]=i.split(":"),s=parseInt(t!=null?t:"0"),a=parseInt(e!=null?e:"0"),n=new Date,o=new Date(n.getFullYear(),n.getMonth(),n.getDate(),s,a,0,0).getTime()+9*60*60*1e3,l=new Date(o),c=l.getUTCHours().toString().padStart(2,"0"),d=l.getUTCMinutes().toString().padStart(2,"0");return`${c}:${d}`}renderForm(){this.contentEl.empty(),this.contentEl.addClass("wl-add-modal");let i=this.contentEl,t=this.title.totalEpisodes<=1,e=o=>{let l=i.createDiv({cls:"wl-modal-row"});return l.createSpan({cls:"wl-modal-label",text:o}),l},s=(o,l)=>{var p;let c=l.createDiv({cls:"wl-modal-row wl-modal-row-mt"});c.createSpan({cls:"wl-modal-label",text:o});let d=c.createEl("input",{cls:"wl-modal-input wl-time-input",attr:{type:"text",placeholder:"Hh:mm",maxlength:"5"}});d.value=(p=this.schedule.releaseTime)!=null?p:"";let u=c.createSpan({cls:"wl-jst-clock"}),h=()=>{u.textContent=d.value?`JST ${this.localHHMMtoJST(d.value)}`:"JST \u2014"};return h(),d.addEventListener("input",()=>{let m=d.value.trim();this.schedule.releaseTime=m||void 0,h()}),d};if(t){let l=e("Release date").createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});l.value=this.schedule.releaseDate?this.schedule.releaseDate.split("-").reverse().join("/"):"",l.addEventListener("change",()=>{let c=q(l.value);c&&(this.schedule.recurrence="once",this.schedule.releaseDate=c)}),s("Time (optional)",i)}else{let l=e("Recurrence").createEl("select",{cls:"wl-select"}),c=[["once","Once"],["daily","Daily"],["weekly","Weekly"],["monthly","Monthly"]];for(let[E,D]of c){let S=l.createEl("option",{text:D,value:E});E===this.schedule.recurrence&&(S.selected=!0)}let d=i.createDiv(),u=()=>{var D;d.empty();let E=this.schedule.recurrence;if(E==="once"){let S=d.createDiv({cls:"wl-modal-row"});S.createSpan({cls:"wl-modal-label",text:"Date"});let T=S.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}});T.value=this.schedule.releaseDate?this.schedule.releaseDate.split("-").reverse().join("/"):"",T.addEventListener("change",()=>{let M=q(T.value);M&&(this.schedule.releaseDate=M)})}if(E==="weekly"){let S=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],T=d.createDiv({cls:"wl-modal-row"});T.createSpan({cls:"wl-modal-label",text:"Day of week"});let M=T.createEl("select",{cls:"wl-select"});S.forEach((x,C)=>{var I;let L=M.createEl("option",{text:x,value:String(C)});C===((I=this.schedule.dayOfWeek)!=null?I:6)&&(L.selected=!0)}),M.addEventListener("change",()=>{this.schedule.dayOfWeek=parseInt(M.value)})}if(E==="monthly"){let S=d.createDiv({cls:"wl-modal-row"});S.createSpan({cls:"wl-modal-label",text:"Day of month"});let T=S.createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"1",max:"31",placeholder:"1"}});T.value=String((D=this.schedule.dayOfMonth)!=null?D:1),T.addEventListener("input",()=>{this.schedule.dayOfMonth=parseInt(T.value)||1})}s("Time (HH:MM)",d)};l.addEventListener("change",()=>{this.schedule.recurrence=l.value,u()}),u();let p=e("Current season").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"1",placeholder:"E.g. 2"}});this.currentSeason!==null&&(p.value=String(this.currentSeason)),p.addEventListener("input",()=>{this.currentSeason=parseInt(p.value)||null});let f=e("Current episode").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"1",placeholder:"E.g. 7"}});this.currentEpisode!==null&&(f.value=String(this.currentEpisode)),f.addEventListener("input",()=>{this.currentEpisode=parseInt(f.value)||null});let v=e("Total seasons").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"1",placeholder:"E.g. 3"}});this.totalSeasons!==null&&(v.value=String(this.totalSeasons)),v.addEventListener("input",()=>{this.totalSeasons=parseInt(v.value)||null});let b=e("Total episodes").createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0",placeholder:"E.g. 13"}});this.totalEpisodes!==null&&(b.value=String(this.totalEpisodes)),b.addEventListener("input",()=>{this.totalEpisodes=parseInt(b.value)||null}),i.createDiv({cls:"wl-modal-info wl-schedule-hint",text:"Titles with 0 or 1 total episodes will be treated as a single release date, like a movie."})}let a=i.createDiv({cls:"wl-modal-btn-row"});a.createEl("button",{cls:"wl-btn wl-btn-mr",text:"Cancel"}).addEventListener("click",()=>this.close()),a.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",()=>{(async()=>{if(this.schedule.releaseTime&&!/^\d{2}:\d{2}$/.test(this.schedule.releaseTime)){new vt.Notice("Time must be in 24h format: hh:mm (e.g. 14:50)");return}await this.onSave(this.schedule,this.currentSeason,this.currentEpisode,this.totalSeasons,this.totalEpisodes),this.close()})()})}};var W=require("obsidian");function Vt(g){let i=(g!=null?g:"").trim().toLowerCase(),t=/^#([0-9a-f])([0-9a-f])([0-9a-f])$/.exec(i);return t?`#${t[1]}${t[1]}${t[2]}${t[2]}${t[3]}${t[3]}`:/^#[0-9a-f]{6}$/.test(i)?i:dt.toLowerCase()}function Tn(g){let i=Vt(g);return{r:parseInt(i.slice(1,3),16),g:parseInt(i.slice(3,5),16),b:parseInt(i.slice(5,7),16)}}function ss(g){return Math.max(0,Math.min(255,Math.round(g))).toString(16).padStart(2,"0")}function Cn(g,i){let{r:t,g:e,b:s}=Tn(g),a=n=>255*(1-i)+n*i;return`#${ss(a(t))}${ss(a(e))}${ss(a(s))}`}function Zt(g){let i=Vt(g);for(let{color600:t,color50:e}of Ie)if(Vt(t)===i)return e;return Cn(i,.12)}function Gt(g){return Vt(g)}function Se(g){let{anchor:i,container:t,current:e,allowCustom:s,onPick:a}=g;t.querySelectorAll(".wl-reading-col-palette").forEach(p=>p.remove());let n=i.getBoundingClientRect(),r=t.createDiv({cls:"wl-reading-col-palette"});r.style.top=`${n.bottom+4}px`,r.style.left=`${n.left}px`;let o=t.ownerDocument,l=Vt(e),c=p=>{!r.contains(p.target)&&p.target!==i&&(r.remove(),o.removeEventListener("mousedown",c,!0))},d=()=>{r.remove(),o.removeEventListener("mousedown",c,!0)},u=!1;for(let{color600:p,color50:m}of Ie){let f=r.createEl("button",{cls:"wl-reading-col-palette-swatch"});f.style.backgroundColor=m,f.style.borderColor=p,Vt(p)===l&&(f.addClass("is-active"),u=!0),f.title=p,f.addEventListener("click",y=>{y.stopPropagation(),d(),a(p)})}if(s){let p=r.createEl("button",{cls:"wl-reading-col-palette-swatch wl-color-custom-swatch"});p.title="Custom color\u2026",u?p.addClass("wl-color-custom-rainbow"):(p.addClass("is-active"),p.style.backgroundColor=Zt(l),p.style.borderColor=Gt(l));let m=p.createEl("input",{cls:"wl-color-custom-input",attr:{type:"color"}});m.value=l,p.addEventListener("click",f=>{f.stopPropagation(),m.click()}),m.addEventListener("change",f=>{f.stopPropagation();let y=Vt(m.value);d(),a(y)})}let h=r.createEl("button",{cls:"wl-reading-col-palette-swatch wl-color-clear-swatch"});h.title="No color (reset to default)",h.addEventListener("click",p=>{p.stopPropagation(),d(),a(null)}),window.setTimeout(()=>o.addEventListener("mousedown",c,!0),0)}var kn=60,as=140,te=class{constructor(i,t){this.app=i;this.plugin=t;this.corruptLists=new Set;this.saveQueues=new Map}async saveSerialized(i,t){var a;let s=((a=this.saveQueues.get(i))!=null?a:Promise.resolve()).then(t).catch(n=>console.error("[WL] Save error for list:",i,n));this.saveQueues.set(i,s),await s}get folderPath(){return this.plugin.settings.customListsFolder||"WatchLog/CustomLists"}async ensureFolder(){let i=(0,W.normalizePath)(this.folderPath);if(!this.app.vault.getAbstractFileByPath(i))try{await this.app.vault.createFolder(i)}catch(t){}}listNames(){let i=(0,W.normalizePath)(this.folderPath);return this.app.vault.getFiles().filter(t=>{var s,a;return((a=(s=t.parent)==null?void 0:s.path)!=null?a:"")===i&&t.extension==="md"}).map(t=>t.basename).sort((t,e)=>t.localeCompare(e))}async loadList(i){let t=(0,W.normalizePath)(`${this.folderPath}/${i}.md`),e=this.app.vault.getAbstractFileByPath(t);if(!(e instanceof W.TFile))return null;try{let s=await this.app.vault.read(e);return this.parse(i,s)}catch(s){return console.warn("[WL] Failed to read custom list",i,s),null}}async loadTabColors(i){let t=new Map;return await Promise.all(i.map(async e=>{let s=await this.loadList(e);s!=null&&s.tabColor&&t.set(e,s.tabColor)})),t}parse(i,t){var c;let e=t.match(/## Notes\n([\s\S]*?)(?=\n## |\s*$)/),s=((c=e==null?void 0:e[1])!=null?c:"").trim(),a=t.match(/## Data\n```json\n([\s\S]*?)\n```/),n=[],r=[],o,l;if(a!=null&&a[1])try{let d=JSON.parse(a[1]);typeof d.tabColor=="string"&&(o=d.tabColor),typeof d.nameWidth=="number"&&(l=d.nameWidth),Array.isArray(d.columns)&&(n=d.columns.filter(u=>typeof u=="object"&&u!==null&&"id"in u&&"label"in u&&"type"in u)),Array.isArray(d.rows)&&(r=d.rows.filter(u=>typeof u=="object"&&u!==null&&"id"in u))}catch(d){return console.warn("[WL] Custom list JSON parse failed for",i,d),new W.Notice(`Custom list "${i}" has corrupt data and cannot be loaded.`),this.corruptLists.add(i),null}return{name:i,columns:n,rows:r,notes:s,tabColor:o,nameWidth:l}}async saveList(i){await this.saveSerialized(i.name,async()=>{if(this.corruptLists.has(i.name)){console.warn("[WL] Refusing to save corrupt custom list",i.name);return}await this.ensureFolder();let t=(0,W.normalizePath)(`${this.folderPath}/${i.name}.md`),e=this.serialize(i),s=this.app.vault.getAbstractFileByPath(t);try{s instanceof W.TFile?await this.app.vault.modify(s,e):await this.app.vault.create(t,e)}catch(a){console.error("WatchLog: failed to save custom list",a)}})}async saveNotes(i,t){await this.saveSerialized(i,async()=>{let e=(0,W.normalizePath)(`${this.folderPath}/${i}.md`),s=this.app.vault.getAbstractFileByPath(e);if(s instanceof W.TFile)try{let a=await this.app.vault.read(s),n=`## Notes `,r=` ## Data `,o=a.indexOf(n);if(o===-1)return;let l=o+n.length,c=a.indexOf(r,l),d=c!==-1?a.slice(0,l)+t+a.slice(c):a.slice(0,l)+t+` -`;await this.app.vault.modify(s,d)}catch(a){console.error("WatchLog: failed to save notes",a)}})}serialize(i){let t=JSON.stringify({columns:i.columns,rows:i.rows},null,2);return`# ${i.name} +`;await this.app.vault.modify(s,d)}catch(a){console.error("WatchLog: failed to save notes",a)}})}serialize(i){let t=JSON.stringify({columns:i.columns,rows:i.rows,tabColor:i.tabColor,nameWidth:i.nameWidth},null,2);return`# ${i.name} ## Notes ${i.notes} @@ -101,19 +104,22 @@ ${i.notes} \`\`\`json ${t} \`\`\` -`}async deleteList(i){let t=(0,W.normalizePath)(`${this.folderPath}/${i}.md`),e=this.app.vault.getAbstractFileByPath(t);if(e instanceof W.TFile)try{await this.app.fileManager.trashFile(e)}catch(s){}}async renameList(i,t){let e=(0,W.normalizePath)(`${this.folderPath}/${t}.md`),s=(0,W.normalizePath)(`${this.folderPath}/${i}.md`),a=this.app.vault.getAbstractFileByPath(s);if(a instanceof W.TFile)try{await this.app.vault.rename(a,e)}catch(n){}}generateColId(i){let t=new Set(i.map(s=>s.id)),e=1;for(;t.has(`col_${e}`);)e++;return`col_${e}`}generateRowId(i){let t=new Set(i.map(s=>s.id)),e=1;for(;t.has(`row_${e}`);)e++;return`row_${e}`}};function os(g,i,t,e,s,a,n,r){g.empty(),g.addClass("wl-editcol-card-grid");let o=-1,l=c=>{let d=g.createDiv({cls:"wl-editcol-card wl-editcol-card-auto"});d.setAttribute("data-auto",c),d.createDiv({cls:"wl-editcol-card-name-wrap"}).createDiv({cls:"wl-editcol-card-name-label",text:c}),d.createDiv({cls:"wl-editcol-card-type-locked",text:"Auto"}),d.createDiv({cls:"wl-editcol-card-spacer"})};if(l("#"),l("Name"),i.forEach((c,d)=>{let u=g.createDiv({cls:"wl-editcol-card"}),h=u.createDiv({cls:"wl-editcol-card-handle",text:"\u283F"});h.title="Drag to reorder",h.addEventListener("mousedown",()=>u.setAttribute("draggable","true")),u.addEventListener("dragstart",f=>{var y;o=d,(y=f.dataTransfer)==null||y.setData("text/plain",String(d)),u.addClass("wl-cl-dragging")}),u.addEventListener("dragend",()=>{u.removeClass("wl-cl-dragging"),u.setAttribute("draggable","false")}),u.addEventListener("dragover",f=>{f.preventDefault(),u.addClass("wl-cl-drag-over")}),u.addEventListener("dragleave",()=>u.removeClass("wl-cl-drag-over")),u.addEventListener("drop",f=>{f.preventDefault(),u.removeClass("wl-cl-drag-over");let y=o,w=d;y!==w&&y>=0&&s(y,w)});let p=u.createEl("input",{cls:"wl-modal-input wl-editcol-card-name",attr:{type:"text",placeholder:"Column name",value:c.label}});p.addEventListener("input",()=>{c.label=p.value});let m=u.createEl("select",{cls:"wl-select wl-editcol-card-type"});for(let f of["text","number","select"]){let y=m.createEl("option",{value:f,text:f.charAt(0).toUpperCase()+f.slice(1)});c.type===f&&(y.selected=!0)}if(m.addEventListener("change",()=>{c.type=m.value,n()}),c.type==="text"||c.type==="number"){let f=u.createDiv({cls:"wl-editcol-card-toggles"}),y=f.createEl("button",{cls:`wl-btn wl-btn-sm wl-editcol-card-toggle wl-editcols-bold-btn${c.bold?" is-active":""}`,text:"B"});y.addEventListener("click",()=>{c.bold=!c.bold,y.toggleClass("is-active",!!c.bold)});let w=f.createEl("button",{cls:`wl-btn wl-btn-sm wl-editcol-card-toggle wl-editcols-italic-btn${c.italic?" is-active":""}`,text:"I"});if(w.addEventListener("click",()=>{c.italic=!c.italic,w.toggleClass("is-active",!!c.italic)}),c.type==="number"){let b=f.createEl("button",{cls:`wl-btn wl-btn-sm wl-editcol-card-toggle wl-editcols-autotime-btn${c.autoTime?" is-active":""}`,text:"\u23F1",attr:{title:"Auto-populate with remaining watch time from Watchlist"}});b.addEventListener("click",()=>{c.autoTime=!c.autoTime,b.toggleClass("is-active",!!c.autoTime)})}}let v=u.createEl("button",{cls:"wl-btn wl-btn-sm wl-editcol-card-del",text:"\xD7"});if(v.title="Delete this column",v.addEventListener("click",()=>{t.some(y=>{let w=y[c.id];return w!==void 0&&w!==""&&w!==null})?new N(e,`Delete column "${c.label}"? This will remove all data in this column.`,()=>{a(d)}).open():a(d)}),c.type==="select"){let f=u.createDiv({cls:"wl-editcol-card-opts"}),y=()=>{var b;f.empty(),((b=c.options)!=null?b:[]).forEach((S,k)=>{let E=f.createDiv({cls:"wl-editcol-card-opt-row"}),D=E.createEl("input",{cls:"wl-modal-input wl-editcol-card-opt-input",attr:{type:"text",value:S,placeholder:"Option"}});D.addEventListener("input",()=>{c.options||(c.options=[]),c.options[k]=D.value}),E.createEl("button",{cls:"wl-btn wl-btn-sm wl-editcol-card-opt-del",text:"\xD7",attr:{title:"Remove this option"}}).addEventListener("click",()=>{var x;(x=c.options)==null||x.splice(k,1),y()})}),f.createEl("button",{cls:"wl-btn wl-btn-sm wl-editcol-card-opt-add",text:"+ option"}).addEventListener("click",()=>{c.options||(c.options=[]),c.options.push(""),y()})};y()}}),r){let c=g.createDiv({cls:"wl-editcol-card wl-editcol-card-add"});c.createDiv({cls:"wl-editcol-card-add-label",text:"+ add column"}),c.addEventListener("click",()=>r())}}var Be=class extends W.Modal{constructor(i,t,e,s){super(i),this.list=t,this.manager=e,this.onSave=s,this.cols=t.columns.filter(a=>!a.locked).map(a=>({...a,options:a.options?[...a.options]:void 0}))}onOpen(){this.modalEl.addClass("wl-editcol-modal"),this.titleEl.setText(`Edit Columns \u2014 ${this.list.name}`),this.contentEl.addClass("wl-editcols-modal"),this.renderBody()}renderBody(){this.contentEl.empty(),this.contentEl.addClass("wl-editcols-modal"),this.listEl=this.contentEl.createDiv({cls:"wl-editcols-list"}),this.renderCols();let i=this.contentEl.createDiv({cls:"wl-modal-btn-row wl-editcols-footer"});i.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),i.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",()=>void this.handleSave())}renderCols(){os(this.listEl,this.cols,this.list.rows,this.app,(i,t)=>{let[e]=this.cols.splice(i,1);this.cols.splice(i{this.cols.splice(i,1),this.renderBody()},()=>this.renderBody(),()=>{this.cols.push({id:this.manager.generateColId([...this.list.columns.filter(i=>!i.locked),...this.cols]),label:"",type:"text",bold:!1,italic:!1}),this.renderBody()})}handleSave(){for(let i of this.cols){if(!i.label.trim()){new W.Notice("Column names cannot be empty.");return}if(i.type==="select"&&(!i.options||i.options.length===0)){new W.Notice(`Column "${i.label}" must have at least one option.`);return}}for(let i of this.cols)i.label=i.label.trim(),i.options&&(i.options=i.options.map(t=>t.trim()).filter(t=>t));this.onSave(this.cols).then(()=>this.close())}},Pe=class extends W.Modal{constructor(i,t){var e;super(i),this.plugin=t,this.manager=new Ot(i,t),this.cols=((e=t.settings.defaultCustomColumns)!=null?e:[]).map(s=>({...s,options:s.options?[...s.options]:void 0}))}onOpen(){this.modalEl.addClass("wl-editcol-modal"),this.titleEl.setText("Default columns"),this.contentEl.addClass("wl-editcols-modal"),this.renderBody()}renderBody(){this.contentEl.empty(),this.contentEl.addClass("wl-editcols-modal"),this.contentEl.createDiv({cls:"wl-settings-info",text:"These columns are pre-populated when creating a new list. The Name column is always added automatically."}),this.listEl=this.contentEl.createDiv({cls:"wl-editcols-list"}),this.renderCols();let i=this.contentEl.createDiv({cls:"wl-modal-btn-row wl-editcols-footer"});i.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),i.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",()=>void this.handleSave())}renderCols(){os(this.listEl,this.cols,[],this.app,(i,t)=>{let[e]=this.cols.splice(i,1);this.cols.splice(i{this.cols.splice(i,1),this.renderBody()},()=>this.renderBody(),()=>{this.cols.push({id:this.manager.generateColId(this.cols),label:"",type:"text",bold:!1,italic:!1}),this.renderBody()})}async handleSave(){for(let i of this.cols){if(!i.label.trim()){new W.Notice("Column names cannot be empty.");return}if(i.type==="select"&&(!i.options||i.options.length===0)){new W.Notice(`Column "${i.label}" must have at least one option.`);return}}for(let i of this.cols)i.label=i.label.trim(),i.options&&(i.options=i.options.map(t=>t.trim()).filter(t=>t));this.plugin.settings.defaultCustomColumns=this.cols,await this.plugin.saveSettings(),new W.Notice("Default columns saved."),this.close()}},hi=class extends W.Modal{constructor(t,e,s,a){super(t);this.listName=e;this.initialNotes=s;this.onSave=a;this.previewComponent=new W.Component}onOpen(){this.previewComponent.load(),this.titleEl.setText(`Notes \u2014 ${this.listName}`);let{contentEl:t}=this;t.addClass("wl-notes-modal");let e=t.createDiv({cls:"wl-notes-mode-bar"}),s=e.createEl("button",{cls:"wl-btn wl-btn-sm is-active",text:"Edit"}),a=e.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Preview"}),n=t.createDiv({cls:"wl-notes-edit-area"}),r=n.createEl("textarea",{cls:"wl-modal-textarea wl-notes-textarea",attr:{placeholder:"Add notes, links, or any text here..."}});r.value=this.initialNotes,window.setTimeout(()=>{r.focus(),r.setSelectionRange(r.value.length,r.value.length)},0);let o=t.createDiv({cls:"wl-notes-preview-area"});o.hide();let l=()=>{n.show(),o.hide(),s.addClass("is-active"),a.removeClass("is-active"),r.focus()},c=async()=>{n.hide(),o.show(),o.empty(),s.removeClass("is-active"),a.addClass("is-active");let p=r.value.trim()||"*No notes yet.*";await W.MarkdownRenderer.render(this.app,p,o,"",this.previewComponent)};s.addEventListener("click",l),a.addEventListener("click",()=>void c()),r.addEventListener("keydown",p=>{(p.ctrlKey||p.metaKey)&&p.key==="b"?(p.preventDefault(),rs(r,"**","**")):(p.ctrlKey||p.metaKey)&&p.key==="i"&&(p.preventDefault(),rs(r,"*","*"))});let d=t.createDiv({cls:"wl-modal-btn-row"});d.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),d.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",()=>void this.onSave(r.value).then(()=>this.close()))}onClose(){this.previewComponent.unload(),this.contentEl.empty()}};function rs(g,i,t){let e=g.selectionStart,s=g.selectionEnd,a=g.value.slice(e,s),n=i+a+t;g.setRangeText(n,e,s,"select"),e===s&&(g.selectionStart=e+i.length,g.selectionEnd=e+i.length)}var pi=class extends W.Modal{constructor(t,e,s){super(t);this.existingNames=e;this.onSubmit=s}onOpen(){this.titleEl.setText("New custom list");let{contentEl:t}=this,e="",s=t.createDiv({cls:"wl-cl-name-error"});s.hide(),new W.Setting(t).setName("List name").addText(r=>{r.setPlaceholder("E.g. Marvel movies").onChange(o=>{e=o,s.hide()}),window.setTimeout(()=>r.inputEl.focus(),0),r.inputEl.addEventListener("keydown",o=>{o.key==="Enter"&&(o.preventDefault(),a())})});let a=()=>{let r=e.trim();if(!r){s.textContent="Please enter a name.",s.show();return}if(this.existingNames.includes(r)){s.textContent=`A list named "${r}" already exists.`,s.show();return}this.close(),this.onSubmit(r)},n=t.createDiv({cls:"wl-modal-btn-row"});n.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),n.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Create"}).addEventListener("click",a)}onClose(){this.contentEl.empty()}},Fe=class{constructor(i,t,e){this.listNames=[];this.activeListName=null;this.currentList=null;this.sortCol=null;this.sortDir="asc";this.searchQuery="";this.duplicatedRowIds=new Set;this._escapeKeyHandler=null;this.activeCleanups=[];this.renderGeneration=0;this.saveQueues=new Map;this._countEl=null;this._tableContainer=null;this.container=i,this.plugin=t,this.dataManager=e,this.manager=new Ot(t.app,t)}applyTabOrder(i){var a;let e=((a=this.plugin.settings.customListTabOrder)!=null?a:[]).filter(n=>i.includes(n)),s=i.filter(n=>!e.includes(n));return[...e,...s]}destroy(){for(let i of this.activeCleanups)try{i()}catch(t){}if(this.activeCleanups=[],this._escapeKeyHandler){try{activeDocument.removeEventListener("keydown",this._escapeKeyHandler)}catch(i){}this._escapeKeyHandler=null}}addCleanup(i){this.activeCleanups.push(i)}saveSerialized(i,t){var a;let s=((a=this.saveQueues.get(i))!=null?a:Promise.resolve()).then(t).catch(n=>console.error("[WL] custom-list save failed:",n));return this.saveQueues.set(i,s),s}async render(){var e;let i=++this.renderGeneration;this.destroy(),this.container.empty(),this.container.addClass("wl-custom-lists");let t=this.manager.listNames();if(this.listNames=this.applyTabOrder(t),this.listNames.length===0){this.buildEmptyState();return}(!this.activeListName||!this.listNames.includes(this.activeListName))&&(this.activeListName=(e=this.listNames[0])!=null?e:null),this.activeListName&&(this.currentList=await this.manager.loadList(this.activeListName)),i===this.renderGeneration&&(this.container.empty(),this.buildSubTabs(),this.currentList&&this.buildListView(this.currentList))}buildEmptyState(){let i=this.container.createDiv({cls:"wl-cl-empty-state"});i.createDiv({cls:"wl-cl-empty-text",text:"No custom lists yet."}),i.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Create your first list"}).addEventListener("click",()=>this.promptCreateList())}buildSubTabs(){let i=this.container.createDiv({cls:"wl-cl-sub-tabs"}),t=null;for(let s of this.listNames){let a=i.createDiv({cls:`wl-cl-sub-tab${s===this.activeListName?" is-active":""}`});a.setAttribute("draggable","true");let n=a.createSpan({cls:"wl-cl-sub-tab-name",text:s});n.addEventListener("dblclick",o=>{o.stopPropagation(),this.startRenameTab(a,n,s)}),a.createSpan({cls:"wl-cl-sub-tab-del",text:"\xD7"}).addEventListener("click",o=>{o.stopPropagation(),this.deleteList(s)}),a.addEventListener("click",()=>{this.activeListName!==s&&(this.activeListName=s,this.sortCol=null,this.sortDir="asc",this.searchQuery="",this.duplicatedRowIds.clear(),this.render())}),a.addEventListener("dragstart",o=>{var l;t=s,(l=o.dataTransfer)==null||l.setData("text/plain",s),a.addClass("wl-cl-dragging")}),a.addEventListener("dragend",()=>a.removeClass("wl-cl-dragging")),a.addEventListener("dragover",o=>{o.preventDefault(),a.addClass("wl-cl-drag-over")}),a.addEventListener("dragleave",()=>a.removeClass("wl-cl-drag-over")),a.addEventListener("drop",o=>{if(o.preventDefault(),a.removeClass("wl-cl-drag-over"),!t||t===s)return;let l=this.listNames.indexOf(t),c=this.listNames.indexOf(s);l<0||c<0||(this.listNames.splice(l,1),this.listNames.splice(c,0,t),this.plugin.settings.customListTabOrder=[...this.listNames],this.plugin.saveSettings().then(()=>void this.render()))})}i.createEl("button",{cls:"wl-cl-sub-tab-add wl-btn-success",text:"+"}).addEventListener("click",()=>this.promptCreateList())}startRenameTab(i,t,e){t.hide();let s=i.createEl("input",{cls:"wl-cl-sub-tab-rename",attr:{type:"text",value:e}});s.focus(),s.select();let a=!1,n=async r=>{if(a||(a=!0,s.remove(),t.show(),!r))return;let o=s.value.trim();if(!(!o||o===e)){if(this.listNames.includes(o)){new W.Notice(`A list named "${o}" already exists.`);return}await this.manager.renameList(e,o),this.activeListName===e&&(this.activeListName=o),await this.render()}};s.addEventListener("keydown",r=>{r.key==="Enter"&&(r.preventDefault(),n(!0)),r.key==="Escape"&&n(!1)}),s.addEventListener("blur",()=>void n(!0))}promptCreateList(){new pi(this.plugin.app,this.listNames,i=>{var s;let t=((s=this.plugin.settings.defaultCustomColumns)!=null?s:[]).map(a=>({...a,id:a.id,options:a.options?[...a.options]:void 0})),e={name:i,columns:t,rows:[],notes:""};new Be(this.plugin.app,e,this.manager,async a=>{e.columns=a,await this.manager.saveList(e),this.activeListName=i,this.sortCol=null,this.sortDir="asc",this.searchQuery="",this.duplicatedRowIds.clear(),await this.render()}).open()}).open()}deleteList(i){new N(this.plugin.app,`Delete list "${i}"? This cannot be undone.`,()=>{(async()=>(await this.manager.deleteList(i),this.activeListName===i&&(this.activeListName=null,this.currentList=null),await this.render()))()}).open()}buildListView(i){let t=this.container.createDiv({cls:"wl-cl-list-view"}),e=t.createDiv({cls:"wl-cl-header"}),s=e.createSpan({cls:"wl-results-count wl-cl-count"}),a=e.createDiv({cls:"wl-cl-toolbar"});a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Notes"}).addEventListener("click",()=>{new hi(this.plugin.app,i.name,i.notes,async h=>{await this.manager.saveNotes(i.name,h),i.notes=h}).open()});let r=a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Sort"}),o=null;r.addEventListener("click",h=>{if(h.stopPropagation(),o){o.remove(),o=null;return}o=this.buildSortPanel(i,a,()=>{o=null}),activeDocument.addEventListener("click",()=>{o==null||o.remove(),o=null},{once:!0})}),a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Export"}).addEventListener("click",()=>void this.exportToClipboard(i)),a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Edit columns"}).addEventListener("click",()=>{new Be(this.plugin.app,i,this.manager,async h=>{let p=new Set(h.map(m=>m.id));for(let m of i.rows)for(let v of Object.keys(m))v!=="id"&&v!=="name"&&v!=="checked"&&!p.has(v)&&delete m[v];i.columns=h;for(let m of h)m.type==="number"&&m.autoTime&&this.autoPopulateTimeColumn(i,m);await this.manager.saveList(i),await this.render()}).open()});let c=t.createDiv({cls:"wl-search-wrap"}).createEl("input",{cls:"wl-search-input",attr:{type:"text",placeholder:"Search...",value:this.searchQuery}}),d=null;c.addEventListener("input",()=>{this.searchQuery=c.value,d!==null&&window.clearTimeout(d),d=window.setTimeout(()=>{d=null,this._tableContainer&&this._countEl&&(this._tableContainer.empty(),this.buildTable(this._tableContainer,i,this._countEl))},250)}),this.plugin.settings.showHintBanners&&t.createDiv({cls:"wl-cl-draft-banner",text:"\u26A0 This is a draft list. Titles here are not included in any stats or counts."});let u=t.createDiv({cls:"wl-cl-table-wrap"});this.buildTable(u,i,s)}buildSortPanel(i,t,e){let s=t.createDiv({cls:"wl-cl-sort-panel"}),a=s.createDiv({cls:"wl-filter-row"});a.createSpan({cls:"wl-filter-label",text:"Sort by"});let n=a.createEl("select",{cls:"wl-select"});n.createEl("option",{value:"name",text:"Name"});for(let c of i.columns.filter(d=>!d.locked))n.createEl("option",{value:c.id,text:c.label});this.sortCol&&(n.value=this.sortCol);let r=s.createDiv({cls:"wl-filter-row"});r.createSpan({cls:"wl-filter-label",text:"Direction"});let o=r.createEl("select",{cls:"wl-select"});o.createEl("option",{value:"asc",text:"A \u2192 z"}),o.createEl("option",{value:"desc",text:"Z \u2192 a"}),o.value=this.sortDir;let l=s.createDiv({cls:"wl-modal-btn-row"});return l.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Clear sort"}).addEventListener("click",c=>{c.stopPropagation(),this.sortCol=null,this.sortDir="asc",e(),this.render()}),l.createEl("button",{cls:"wl-btn wl-btn-sm wl-btn-primary",text:"Apply"}).addEventListener("click",c=>{c.stopPropagation(),this.sortCol=n.value,this.sortDir=o.value,e(),this.render()}),s.addEventListener("click",c=>c.stopPropagation()),s}async exportToClipboard(i){let t=i.columns.filter(r=>!r.locked),e=[{id:"#",label:"#"},{id:"name",label:"Name"},...t],s="| "+e.map(r=>r.label).join(" | ")+" |",a="| "+e.map(()=>"---").join(" | ")+" |",n=this.getFilteredSortedRows(i).map((r,o)=>"| "+e.map(c=>{if(c.id==="#")return String(o+1);let d=r[c.id];return d!=null?String(d):""}).join(" | ")+" |");try{await navigator.clipboard.writeText([s,a,...n].join(` -`)),new W.Notice("Copied to clipboard!")}catch(r){new W.Notice("Failed to copy to clipboard.")}}getFilteredSortedRows(i){let t=[...i.rows];if(this.searchQuery.trim()){let e=this.searchQuery.toLowerCase();t=t.filter(s=>{var a;return String((a=s.name)!=null?a:"").toLowerCase().includes(e)})}if(this.sortCol){let e=this.sortCol,s=this.sortDir;t.sort((a,n)=>{var l,c;let r=String((l=a[e])!=null?l:"").toLowerCase(),o=String((c=n[e])!=null?c:"").toLowerCase();return s==="asc"?r.localeCompare(o):o.localeCompare(r)})}return t}buildTable(i,t,e){this._countEl=e,this._tableContainer=i;let s=this.getFilteredSortedRows(t);e.textContent=`${s.length} title${s.length!==1?"s":""}`;let a=t.columns.filter(u=>!u.locked),n=i.createDiv({cls:"wl-cl-table"}),o=n.createDiv({cls:"wl-cl-thead"}).createDiv({cls:"wl-cl-tr wl-cl-tr-header"});o.createDiv({cls:"wl-cl-th wl-cl-th-tick"}),o.createDiv({cls:"wl-cl-th wl-cl-th-num",text:"#"}),o.createDiv({cls:"wl-cl-th",text:"Name"});for(let u of a){let h=o.createDiv({cls:"wl-cl-th"});if(h.createSpan({text:u.label}),u.type==="number"&&u.autoTime){let p=h.createSpan({cls:"wl-cl-autotime-refresh",text:"\u21BB"});p.title="Refresh remaining time values",p.addEventListener("click",m=>{m.stopPropagation(),this.autoPopulateTimeColumn(t,u),this.manager.saveList(t).then(()=>{i.empty(),this.buildTable(i,t,e)})})}}o.createDiv({cls:"wl-cl-th wl-cl-th-actions"});let l=n.createDiv({cls:"wl-cl-tbody"}),c=-1;s.forEach((u,h)=>{let p=u.checked===!0,m=l.createDiv({cls:`wl-cl-tr wl-cl-tr-body${p?" wl-cl-tr-checked":""}`});m.dataset.rowId=u.id;let f=m.createDiv({cls:"wl-cl-td wl-cl-td-tick"}).createDiv({cls:`wl-cl-tick-btn${p?" is-checked":""}`});f.title=p?"Uncheck row":"Check row",f.textContent=p?"\u2713":"\u25CB",f.addEventListener("click",()=>{let E=t.rows.find(D=>D.id===u.id);E&&(E.checked=!E.checked,this.manager.saveList(t).then(()=>{i.empty(),this.buildTable(i,t,e)}))}),m.createDiv({cls:"wl-cl-td wl-cl-td-num",text:String(h+1)});let y=m.createDiv({cls:"wl-cl-td wl-cl-td-name"});this.renderNameCell(y,u,t,e,a,i);for(let E of a){let D=m.createDiv({cls:"wl-cl-td"});this.renderCustomCell(D,u,E,t)}let w=m.createDiv({cls:"wl-cl-td wl-cl-td-actions"}),b=w.createDiv({cls:"wl-cl-row-action wl-cl-drag-handle",text:"\u283F"});b.title="Drag to reorder";let S=w.createDiv({cls:"wl-cl-row-action wl-cl-dup-btn",text:"\u29C9"});S.title="Duplicate row",S.addEventListener("click",()=>{let E=t.rows.findIndex(C=>C.id===u.id);if(E<0)return;let D={...t.rows[E],id:this.manager.generateRowId(t.rows)};t.rows.splice(E+1,0,D),this.duplicatedRowIds.add(D.id),this.manager.saveList(t).then(()=>{i.empty(),this.buildTable(i,t,e)})});let k=w.createDiv({cls:"wl-cl-row-action wl-cl-row-del",text:"\xD7"});k.title="Delete row",k.addEventListener("click",()=>{t.rows=t.rows.filter(E=>E.id!==u.id),this.duplicatedRowIds.delete(u.id),this.manager.saveList(t).then(()=>{i.empty(),this.buildTable(i,t,e)})}),m.setAttribute("draggable","false"),b.addEventListener("mousedown",()=>m.setAttribute("draggable","true")),m.addEventListener("dragstart",E=>{var D;c=t.rows.findIndex(C=>C.id===u.id),(D=E.dataTransfer)==null||D.setData("text/plain",u.id),m.addClass("wl-cl-dragging")}),m.addEventListener("dragend",()=>{m.removeClass("wl-cl-dragging"),m.setAttribute("draggable","false")}),m.addEventListener("dragover",E=>{E.preventDefault(),m.addClass("wl-cl-drag-over")}),m.addEventListener("dragleave",()=>m.removeClass("wl-cl-drag-over")),m.addEventListener("drop",E=>{E.preventDefault(),m.removeClass("wl-cl-drag-over");let D=t.rows.findIndex(C=>C.id===u.id);if(c!==D&&c>=0){let[C]=t.rows.splice(c,1);t.rows.splice(c{i.empty(),this.buildTable(i,t,e)})}})}),i.createDiv({cls:"wl-cl-add-row"}).createEl("button",{cls:"wl-btn wl-btn-sm wl-btn-success",text:"+ add row"}).addEventListener("click",()=>{let u={id:this.manager.generateRowId(t.rows),name:""};t.rows.push(u),this.manager.saveList(t).then(()=>{i.empty(),this.buildTable(i,t,e),window.setTimeout(()=>{var m;let h=i.querySelector(".wl-cl-tbody"),p=h==null?void 0:h.querySelector(".wl-cl-tr-body:last-child");(m=p==null?void 0:p.querySelector(".wl-cl-td-name"))==null||m.click()},0)})})}renderNameCell(i,t,e,s,a,n){var l;i.empty(),i.removeClass("wl-cl-editing");let r=String((l=t.name)!=null?l:""),o=this.duplicatedRowIds.has(t.id);if(r){let c=i.createSpan({cls:"wl-cl-cell-text",text:r});o&&c.addClass("wl-cl-dup-name")}else i.createSpan({cls:"wl-cl-cell-empty",text:"\u2014"});i.addEventListener("click",()=>{this.startNameEdit(i,t,e,s,a,n)},{once:!0})}startNameEdit(i,t,e,s,a,n){var y;let r=String((y=t.name)!=null?y:"");i.empty(),i.addClass("wl-cl-editing"),this._escapeKeyHandler=w=>{w.key==="Escape"&&(w.stopPropagation(),w.stopImmediatePropagation(),w.preventDefault())},activeDocument.addEventListener("keydown",this._escapeKeyHandler,!0),activeDocument.addEventListener("keyup",this._escapeKeyHandler,!0);let o=this._escapeKeyHandler;this.addCleanup(()=>{activeDocument.removeEventListener("keydown",o,!0),activeDocument.removeEventListener("keyup",o,!0)});let l=()=>{let w=activeDocument.activeElement;w&&w.scrollIntoView({behavior:"smooth",block:"center"})};window.visualViewport&&window.visualViewport.addEventListener("resize",l),this.addCleanup(()=>{window.visualViewport&&window.visualViewport.removeEventListener("resize",l)}),window.setTimeout(()=>i.scrollIntoView({block:"nearest",behavior:"smooth"}),50);let d=i.createDiv({cls:"wl-cl-autofill-wrap"}).createEl("input",{cls:"wl-cl-cell-input",attr:{type:"text",value:r}});d.focus(),d.select();let u=null,h=-1,p=()=>{u==null||u.remove(),u=null,h=-1};d.addEventListener("input",()=>{p();let w=d.value.toLowerCase();if(!w)return;let b=this.plugin.readingDataManager,S=[...this.dataManager.getTitles().map(E=>({title:E.title,meta:`${E.type} \xB7 ${E.status}`})),...b.getBooks().map(E=>({title:E.title,meta:`Book \xB7 ${E.status}`})),...b.getMangaList().map(E=>({title:E.title,meta:`Manga \xB7 ${E.status}`}))].filter(E=>E.title.toLowerCase().includes(w)).slice(0,10);if(!S.length)return;let k=d.getBoundingClientRect();u=activeDocument.body.createDiv({cls:"wl-cl-autofill-dropdown wl-pos-fixed"}),u.style.top=`${k.bottom}px`,u.style.left=`${k.left}px`,u.style.width=`${k.width}px`;for(let E of S){let D=u.createDiv({cls:"wl-result-item"});D.createDiv({cls:"wl-result-title",text:E.title}),D.createDiv({cls:"wl-result-meta",text:E.meta}),D.addEventListener("mousedown",C=>{C.preventDefault(),d.value=E.title,p()})}});let m=!1,v=null,f=async w=>{if(m)return;m=!0,window.visualViewport&&window.visualViewport.removeEventListener("resize",l),this._escapeKeyHandler&&(activeDocument.removeEventListener("keydown",this._escapeKeyHandler,!0),activeDocument.removeEventListener("keyup",this._escapeKeyHandler,!0),this._escapeKeyHandler=null),p();let b=d.value.trim();if(!w){let S=this.duplicatedRowIds.has(t.id);t.name=b,S&&b!==r&&this.duplicatedRowIds.delete(t.id),await this.manager.saveList(e)}this.renderNameCell(i,t,e,s,a,n),!w&&v&&this.navigateCell(i,v)};d.addEventListener("blur",()=>void f(!1)),d.addEventListener("keydown",w=>{var b,S,k;if(u){let E=Array.from(u.querySelectorAll(".wl-result-item"));if(w.key==="ArrowDown"){w.preventDefault(),h=Math.min(h+1,E.length-1),E.forEach((D,C)=>{C===h?D.addClass("wl-result-item-focused"):D.removeClass("wl-result-item-focused")});return}if(w.key==="ArrowUp"){w.preventDefault(),h=Math.max(h-1,0),E.forEach((D,C)=>{C===h?D.addClass("wl-result-item-focused"):D.removeClass("wl-result-item-focused")});return}if(w.key==="Enter"&&h>=0){w.preventDefault();let D=(k=(S=(b=E[h])==null?void 0:b.querySelector(".wl-result-title"))==null?void 0:S.textContent)!=null?k:"";D&&(d.value=D),p();return}if(w.key==="Escape"){w.preventDefault(),w.stopPropagation(),w.stopImmediatePropagation(),p();return}}w.key==="Tab"&&w.shiftKey?(w.preventDefault(),v="shift-tab",f(!1)):w.key==="Tab"?(w.preventDefault(),v="tab",f(!1)):w.key==="Enter"?(w.preventDefault(),v="enter",f(!1)):w.key==="Escape"&&(w.preventDefault(),w.stopPropagation(),w.stopImmediatePropagation(),f(!0))})}renderCustomCell(i,t,e,s){i.empty(),i.removeClass("wl-cl-editing");let a=t[e.id];if(e.type==="select"){let n=String(a!=null?a:"");n?i.createSpan({cls:"wl-cl-select-badge",text:n}):i.createSpan({cls:"wl-cl-cell-empty",text:"\u2014"})}else{let n=a!=null&&a!==""?String(a):"";if(n){let r=i.createSpan({cls:"wl-cl-cell-text",text:n});e.bold&&r.addClass("wl-cell-bold"),e.italic&&r.addClass("wl-cell-italic")}else i.createSpan({cls:"wl-cl-cell-empty",text:"\u2014"})}i.addEventListener("click",()=>this.startCustomEdit(i,t,e,s),{once:!0})}startCustomEdit(i,t,e,s){var d;let a=t[e.id];i.empty(),i.addClass("wl-cl-editing");let n=()=>{let u=activeDocument.activeElement;u&&u.scrollIntoView({behavior:"smooth",block:"center"})};window.visualViewport&&window.visualViewport.addEventListener("resize",n),this.addCleanup(()=>{window.visualViewport&&window.visualViewport.removeEventListener("resize",n)}),window.setTimeout(()=>i.scrollIntoView({block:"nearest",behavior:"smooth"}),50);let r,o=!1,l=null,c=async u=>{if(!o){if(o=!0,window.visualViewport&&window.visualViewport.removeEventListener("resize",n),this._escapeKeyHandler&&(activeDocument.removeEventListener("keydown",this._escapeKeyHandler,!0),activeDocument.removeEventListener("keyup",this._escapeKeyHandler,!0),this._escapeKeyHandler=null),i.removeClass("wl-cl-editing"),!u){let h=r();t[e.id]=h===""||h===void 0?void 0:h,await this.manager.saveList(s)}this.renderCustomCell(i,t,e,s),!u&&l&&this.navigateCell(i,l)}};if(e.type==="select"){let u=i.createEl("select",{cls:"wl-select wl-cl-cell-select"});u.createEl("option",{value:"",text:"\u2014"});for(let h of(d=e.options)!=null?d:[]){let p=u.createEl("option",{value:h,text:h});a===h&&(p.selected=!0)}r=()=>u.value,u.focus(),u.addEventListener("change",()=>void c(!1)),u.addEventListener("blur",()=>void c(!1)),u.addEventListener("keydown",h=>{h.key==="Escape"?(h.preventDefault(),h.stopPropagation(),c(!0)):h.key==="Tab"&&h.shiftKey?(h.preventDefault(),l="shift-tab",c(!1)):h.key==="Tab"&&(h.preventDefault(),l="tab",c(!1))})}else if(e.type==="number"){let u=i.createEl("input",{cls:"wl-cl-cell-input",attr:{type:"number",value:a!=null?String(a):""}});r=()=>{let h=parseFloat(u.value);return isNaN(h)?"":h},u.focus(),u.select(),u.addEventListener("blur",()=>void c(!1)),u.addEventListener("keydown",h=>{h.key==="Enter"?(h.preventDefault(),l="enter",c(!1)):h.key==="Tab"&&h.shiftKey?(h.preventDefault(),l="shift-tab",c(!1)):h.key==="Tab"?(h.preventDefault(),l="tab",c(!1)):h.key==="Escape"&&(h.preventDefault(),h.stopPropagation(),h.stopImmediatePropagation(),c(!0))})}else{let u=i.createEl("input",{cls:"wl-cl-cell-input",attr:{type:"text",value:a!=null?String(a):""}});r=()=>u.value,u.focus(),u.select(),u.addEventListener("blur",()=>void c(!1)),u.addEventListener("keydown",h=>{h.key==="Enter"?(h.preventDefault(),l="enter",c(!1)):h.key==="Tab"&&h.shiftKey?(h.preventDefault(),l="shift-tab",c(!1)):h.key==="Tab"?(h.preventDefault(),l="tab",c(!1)):h.key==="Escape"&&(h.preventDefault(),h.stopPropagation(),h.stopImmediatePropagation(),c(!0))})}}autoPopulateTimeColumn(i,t){var s;let e=this.dataManager.getTitles();for(let a of i.rows){let n=String((s=a.name)!=null?s:"").trim();if(!n)continue;let r=e.find(l=>l.title===n);if(!r){a[t.id]="Not found";continue}let o=this.dataManager.calcTimeRemainingForModal(r);a[t.id]=o}}getEditableCells(i){return Array.from(i.querySelectorAll(":scope > .wl-cl-td")).filter(t=>!t.classList.contains("wl-cl-td-num")&&!t.classList.contains("wl-cl-td-actions"))}navigateCell(i,t){let e=i.closest(".wl-cl-tr-body");if(!e)return;let s=e.parentElement;if(!s)return;let a=Array.from(s.querySelectorAll(":scope > .wl-cl-tr-body")),n=a.indexOf(e),r=this.getEditableCells(e),o=r.indexOf(i);if(t==="tab")if(o>=0&&o{var l;return(l=r[o+1])==null?void 0:l.click()},10);else if(n>=0&&n{var d;return(d=c[0])==null?void 0:d.click()},10)}}else this.addRowForNavigation(0);else if(t==="shift-tab"){if(o>0)window.setTimeout(()=>{var l;return(l=r[o-1])==null?void 0:l.click()},10);else if(n>0){let l=a[n-1];if(l){let c=this.getEditableCells(l);c.length&&window.setTimeout(()=>{var d;return(d=c[c.length-1])==null?void 0:d.click()},10)}}}else if(n>=0&&n=0?o:0,c.length-1);c.length&&window.setTimeout(()=>{var u;return(u=c[d])==null?void 0:u.click()},10)}}else this.addRowForNavigation(o>=0?o:0)}addRowForNavigation(i){let t=this.currentList,e=this._tableContainer,s=this._countEl;if(!t||!e||!s)return;let a={id:this.manager.generateRowId(t.rows),name:""};t.rows.push(a),this.manager.saveList(t).then(()=>{e.empty(),this.buildTable(e,t,s),window.setTimeout(()=>{let n=e.querySelector(".wl-cl-tbody");if(!n)return;let r=Array.from(n.querySelectorAll(".wl-cl-tr-body")),o=r[r.length-1];if(!o)return;let l=this.getEditableCells(o),c=l[Math.min(i,l.length-1)];c==null||c.click()},50)})}};function Dt(g){return Array.isArray?Array.isArray(g):ms(g)==="[object Array]"}function ua(g){if(typeof g=="string")return g;if(typeof g=="bigint")return g.toString();let i=g+"";return i=="0"&&1/g==-1/0?"-0":i}function gi(g){return g==null?"":ua(g)}function J(g){return typeof g=="string"}function We(g){return typeof g=="number"}function ha(g){return g===!0||g===!1||pa(g)&&ms(g)=="[object Boolean]"}function gs(g){return typeof g=="object"}function pa(g){return gs(g)&&g!==null}function Z(g){return g!=null}function $e(g){return!g.trim().length}function ms(g){return g==null?g===void 0?"[object Undefined]":"[object Null]":Object.prototype.toString.call(g)}var ga="Incorrect 'index' type",ma=g=>`Invalid value for key ${g}`,va=g=>`Pattern length exceeds max of ${g}.`,fa=g=>`Missing ${g} property in key`,wa=g=>`Property 'weight' in key '${g}' must be a positive integer`,ls=Object.prototype.hasOwnProperty,mi=class{constructor(i){this._keys=[],this._keyMap={};let t=0;i.forEach(e=>{let s=vs(e);this._keys.push(s),this._keyMap[s.id]=s,t+=s.weight}),this._keys.forEach(e=>{e.weight/=t})}get(i){return this._keyMap[i]}keys(){return this._keys}toJSON(){return JSON.stringify(this._keys)}};function vs(g){let i=null,t=null,e=null,s=1,a=null;if(J(g)||Dt(g))e=g,i=cs(g),t=vi(g);else{if(!ls.call(g,"name"))throw new Error(fa("name"));let n=g.name;if(e=n,ls.call(g,"weight")&&(s=g.weight,s<=0))throw new Error(wa(n));i=cs(n),t=vi(n),a=g.getFn}return{path:i,id:t,weight:s,src:e,getFn:a}}function cs(g){return Dt(g)?g:g.split(".")}function vi(g){return Dt(g)?g.join("."):g}function ya(g,i){let t=[],e=!1,s=(a,n,r,o)=>{if(Z(a))if(!n[r])t.push(o!==void 0?{v:a,i:o}:a);else{let l=n[r],c=a[l];if(!Z(c))return;if(r===n.length-1&&(J(c)||We(c)||ha(c)||typeof c=="bigint"))t.push(o!==void 0?{v:gi(c),i:o}:gi(c));else if(Dt(c)){e=!0;for(let d=0,u=c.length;dg.score===i.score?g.idx{this._keysMap[t.id]=e})}create(){this.isCreated||!this.docs.length||(this.isCreated=!0,J(this.docs[0])?this.docs.forEach((i,t)=>{this._addString(i,t)}):this.docs.forEach((i,t)=>{this._addObject(i,t)}),this.norm.clear())}add(i){let t=this.size();J(i)?this._addString(i,t):this._addObject(i,t)}removeAt(i){this.records.splice(i,1);for(let t=i,e=this.size();t=0;t-=1)this.records.splice(i[t],1);for(let t=0,e=this.records.length;t{let n=s.getFn?s.getFn(i):this.getFn(i,s.path);if(Z(n)){if(Dt(n)){let r=[];for(let o=0,l=n.length;ot),records:this.records}}};function fs(g,i,{getFn:t=B.getFn,fieldNormWeight:e=B.fieldNormWeight}={}){let s=new ae({getFn:t,fieldNormWeight:e});return s.setKeys(g.map(vs)),s.setSources(i),s.create(),s}function Ca(g,{getFn:i=B.getFn,fieldNormWeight:t=B.fieldNormWeight}={}){let{keys:e,records:s}=g,a=new ae({getFn:i,fieldNormWeight:t});return a.setKeys(e),a.setIndexRecords(s),a}function Ma(g=[],i=B.minMatchCharLength){let t=[],e=-1,s=-1,a=0;for(let n=g.length;a=i&&t.push([e,s]),e=-1)}return g[a-1]&&a-e>=i&&t.push([e,a-1]),t}var It=32;function xa(g,i,t,{location:e=B.location,distance:s=B.distance,threshold:a=B.threshold,findAllMatches:n=B.findAllMatches,minMatchCharLength:r=B.minMatchCharLength,includeMatches:o=B.includeMatches,ignoreLocation:l=B.ignoreLocation}={}){if(i.length>It)throw new Error(va(It));let c=i.length,d=g.length,u=Math.max(0,Math.min(e,d)),h=a,p=u,m=(D,C)=>{let x=D/c;if(l)return x;let T=Math.abs(u-C);return s?x+T/s:T?1:x},v=r>1||o,f=v?Array(d):[],y;for(;(y=g.indexOf(i,p))>-1;){let D=m(0,y);if(h=Math.min(D,h),p=y+c,v){let C=0;for(;C=T;A-=1){let P=A-1,I=t[g[P]];if(v&&(f[P]=+!!I),L[A]=(L[A+1]<<1|1)&I,D&&(L[A]|=(w[A+1]|w[A])<<1|1|w[A+1]),L[A]&k&&(b=m(D,P),b<=h)){if(h=b,p=P,p<=u)break;T=Math.max(1,2*u-p)}}if(m(D+1,u)>h)break;w=L}let E={isMatch:p>=0,score:Math.max(.001,b)};if(v){let D=Ma(f,r);D.length?o&&(E.indices=D):E.isMatch=!1}return E}function La(g){let i={};for(let t=0,e=g.length;tt[0]-e[0]||t[1]-e[1]);let i=[g[0]];for(let t=1,e=g.length;tg.normalize("NFD").replace(/[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F]/g,"").replace(Ra,i=>ws[i]):g=>g,re=class{constructor(i,{location:t=B.location,threshold:e=B.threshold,distance:s=B.distance,includeMatches:a=B.includeMatches,findAllMatches:n=B.findAllMatches,minMatchCharLength:r=B.minMatchCharLength,isCaseSensitive:o=B.isCaseSensitive,ignoreDiacritics:l=B.ignoreDiacritics,ignoreLocation:c=B.ignoreLocation}={}){if(this.options={location:t,threshold:e,distance:s,includeMatches:a,findAllMatches:n,minMatchCharLength:r,isCaseSensitive:o,ignoreDiacritics:l,ignoreLocation:c},i=o?i:i.toLowerCase(),i=l?ne(i):i,this.pattern=i,this.chunks=[],!this.pattern.length)return;let d=(h,p)=>{this.chunks.push({pattern:h,alphabet:La(h),startIndex:p})},u=this.pattern.length;if(u>It){let h=0,p=u%It,m=u-p;for(;h{let{isMatch:y,score:w,indices:b}=xa(i,m,v,{location:a+f,distance:n,threshold:r,findAllMatches:o,minMatchCharLength:l,includeMatches:s,ignoreLocation:c});y&&(h=!0),u+=w,y&&b&&d.push(...b)});let p={isMatch:h,score:h?u/this.chunks.length:1};return h&&s&&(p.indices=Ii(d)),p}},gt=class{constructor(i){this.pattern=i}static isMultiMatch(i){return ds(i,this.multiRegex)}static isSingleMatch(i){return ds(i,this.singleRegex)}search(i){return{isMatch:!1,score:1}}};function ds(g,i){let t=g.match(i);return t?t[1]:null}var fi=class extends gt{constructor(i){super(i)}static get type(){return"exact"}static get multiRegex(){return/^="(.*)"$/}static get singleRegex(){return/^=(.*)$/}search(i){let t=i===this.pattern;return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}},wi=class extends gt{constructor(i){super(i)}static get type(){return"inverse-exact"}static get multiRegex(){return/^!"(.*)"$/}static get singleRegex(){return/^!(.*)$/}search(i){let e=i.indexOf(this.pattern)===-1;return{isMatch:e,score:e?0:1,indices:[0,i.length-1]}}},yi=class extends gt{constructor(i){super(i)}static get type(){return"prefix-exact"}static get multiRegex(){return/^\^"(.*)"$/}static get singleRegex(){return/^\^(.*)$/}search(i){let t=i.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}},bi=class extends gt{constructor(i){super(i)}static get type(){return"inverse-prefix-exact"}static get multiRegex(){return/^!\^"(.*)"$/}static get singleRegex(){return/^!\^(.*)$/}search(i){let t=!i.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,i.length-1]}}},Ei=class extends gt{constructor(i){super(i)}static get type(){return"suffix-exact"}static get multiRegex(){return/^"(.*)"\$$/}static get singleRegex(){return/^(.*)\$$/}search(i){let t=i.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[i.length-this.pattern.length,i.length-1]}}},Si=class extends gt{constructor(i){super(i)}static get type(){return"inverse-suffix-exact"}static get multiRegex(){return/^!"(.*)"\$$/}static get singleRegex(){return/^!(.*)\$$/}search(i){let t=!i.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,i.length-1]}}},Oe=class extends gt{constructor(i,{location:t=B.location,threshold:e=B.threshold,distance:s=B.distance,includeMatches:a=B.includeMatches,findAllMatches:n=B.findAllMatches,minMatchCharLength:r=B.minMatchCharLength,isCaseSensitive:o=B.isCaseSensitive,ignoreDiacritics:l=B.ignoreDiacritics,ignoreLocation:c=B.ignoreLocation}={}){super(i),this._bitapSearch=new re(i,{location:t,threshold:e,distance:s,includeMatches:a,findAllMatches:n,minMatchCharLength:r,isCaseSensitive:o,ignoreDiacritics:l,ignoreLocation:c})}static get type(){return"fuzzy"}static get multiRegex(){return/^"(.*)"$/}static get singleRegex(){return/^(.*)$/}search(i){return this._bitapSearch.searchIn(i)}},He=class extends gt{constructor(i){super(i)}static get type(){return"include"}static get multiRegex(){return/^'"(.*)"$/}static get singleRegex(){return/^'(.*)$/}search(i){let t=0,e,s=[],a=this.pattern.length;for(;(e=i.indexOf(this.pattern,t))>-1;)t=e+a,s.push([e,t-1]);let n=!!s.length;return{isMatch:n,score:n?0:1,indices:s}}},Di=[fi,He,yi,bi,Si,Ei,wi,Oe],us=Di.length,Aa="\0",Ia="|";function Ba(g){let i=[],t=g.length,e=0;for(;e=t)break;let s=e;for(;s=t||g[a]===" "){s++;break}if(g[a]==="$"&&(a+1>=t||g[a+1]===" ")){s+=2;break}}s++}i.push(g.substring(e,s)),e=s}else{for(;s{let s=e.replace(/\u0000/g,"|"),a=Ba(s.trim()).filter(r=>r&&!!r.trim()),n=[];for(let r=0,o=a.length;r!!(g[_e.AND]||g[_e.OR]),$a=g=>!!g[Ci.PATH],Wa=g=>!Dt(g)&&gs(g)&&!Mi(g),hs=g=>({[_e.AND]:Object.keys(g).map(i=>({[i]:g[i]}))});function ys(g,i,{auto:t=!0}={}){let e=s=>{if(J(s)){let o={keyId:null,pattern:s};return t&&(o.searcher=Ne(s,i)),o}let a=Object.keys(s),n=$a(s);if(!n&&a.length>1&&!Mi(s))return e(hs(s));if(Wa(s)){let o=n?s[Ci.PATH]:a[0],l=n?s[Ci.PATTERN]:s[o];if(!J(l))throw new Error(ma(o));let c={keyId:vi(o),pattern:l};return t&&(c.searcher=Ne(l,i)),c}let r={children:[],operator:a[0]};return a.forEach(o=>{let l=s[o];Dt(l)&&l.forEach(c=>{r.children.push(e(c))})}),r};return Mi(g)||(g=hs(g)),e(g)}function xi(g,{ignoreFieldNorm:i=B.ignoreFieldNorm}){let t=1;return g.forEach(({key:e,norm:s,score:a})=>{let n=e?e.weight:null;t*=Math.pow(a===0&&n?Number.EPSILON:a,(n||1)*(i?1:s))}),t}function Oa(g,{ignoreFieldNorm:i=B.ignoreFieldNorm}){g.forEach(t=>{t.score=xi(t.matches,{ignoreFieldNorm:i})})}var Li=class{constructor(i){this.limit=i,this.heap=[]}get size(){return this.heap.length}shouldInsert(i){return this.size0;){let e=i-1>>1;if(t[i].score<=t[e].score)break;let s=t[i];t[i]=t[e],t[e]=s,i=e}}_sinkDown(i){let t=this.heap,e=t.length,s=i;do{i=s;let a=2*i+1,n=2*i+2;if(at[s].score&&(s=a),nt[s].score&&(s=n),s!==i){let r=t[i];t[i]=t[s],t[s]=r}}while(s!==i)}};function Ha(g,i){let t=g.matches;i.matches=[],Z(t)&&t.forEach(e=>{if(!Z(e.indices)||!e.indices.length)return;let{indices:s,value:a}=e,n={indices:s,value:a};e.key&&(n.key=e.key.src),e.idx>-1&&(n.refIndex=e.idx),i.matches.push(n)})}function Na(g,i){i.score=g.score}function _a(g,i,{includeMatches:t=B.includeMatches,includeScore:e=B.includeScore}={}){let s=[];return t&&s.push(Ha),e&&s.push(Na),g.map(a=>{let{idx:n}=a,r={item:i[n],refIndex:n};return s.length&&s.forEach(o=>{o(a,r)}),r})}var Ua=/\b\w+\b/g;function Ri({isCaseSensitive:g=!1,ignoreDiacritics:i=!1}={}){return{tokenize(t){return g||(t=t.toLowerCase()),i&&(t=ne(t)),t.match(Ua)||[]}}}function Va(g,i,t){var r;let e=new Map,s=new Map,a=0;function n(o,l,c,d){let u=t.tokenize(o);if(!u.length)return;a++;let h=new Map;for(let p of u)h.set(p,(h.get(p)||0)+1);for(let[p,m]of h){let v={docIdx:l,keyIdx:c,subIdx:d,tf:m},f=e.get(p);f||(f=[],e.set(p,f)),f.push(v),s.set(p,(s.get(p)||0)+1)}}for(let o of g){let{i:l,v:c,$:d}=o;if(c!==void 0){n(c,l,-1,-1);continue}if(d)for(let u=0;un.docIdx!==i),a=e.length-s.length;a>0&&(g.fieldCount-=a,g.df.set(t,(g.df.get(t)||0)-a),s.length===0?(g.terms.delete(t),g.df.delete(t)):g.terms.set(t,s))}}var et=class{constructor(i,t,e){this.options={...B,...t},this.options.useExtendedSearch,this.options.useTokenSearch,this._keyStore=new mi(this.options.keys),this._docs=i,this._myIndex=null,this._invertedIndex=null,this.setCollection(i,e),this._lastQuery=null,this._lastSearcher=null}_getSearcher(i){if(this._lastQuery===i)return this._lastSearcher;let t=this._invertedIndex?{...this.options,_invertedIndex:this._invertedIndex}:this.options,e=Ne(i,t);return this._lastQuery=i,this._lastSearcher=e,e}setCollection(i,t){if(this._docs=i,t&&!(t instanceof ae))throw new Error(ga);if(this._myIndex=t||fs(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight}),this.options.useTokenSearch){let e=Ri({isCaseSensitive:this.options.isCaseSensitive,ignoreDiacritics:this.options.ignoreDiacritics});this._invertedIndex=Va(this._myIndex.records,this._myIndex.keys.length,e)}}add(i){if(Z(i)&&(this._docs.push(i),this._myIndex.add(i),this._invertedIndex)){let t=this._myIndex.records[this._myIndex.records.length-1],e=Ri({isCaseSensitive:this.options.isCaseSensitive,ignoreDiacritics:this.options.ignoreDiacritics});Ga(this._invertedIndex,t,this._myIndex.keys.length,e)}}remove(i=()=>!1){let t=[],e=[];for(let s=0,a=this._docs.length;s=0;s-=1)this._docs.splice(e[s],1);this._myIndex.removeAll(e)}return t}removeAt(i){this._invertedIndex&&ps(this._invertedIndex,i);let t=this._docs.splice(i,1)[0];return this._myIndex.removeAt(i),t}getIndex(){return this._myIndex}search(i,t){let{limit:e=-1}=t||{},{includeMatches:s,includeScore:a,shouldSort:n,sortFn:r,ignoreFieldNorm:o}=this.options;if(J(i)&&!i.trim()){let d=this._docs.map((u,h)=>({item:u,refIndex:h}));return We(e)&&e>-1&&(d=d.slice(0,e)),d}let l=We(e)&&e>0&&J(i),c;if(l){let d=new Li(e);J(this._docs[0])?this._searchStringList(i,{heap:d,ignoreFieldNorm:o}):this._searchObjectList(i,{heap:d,ignoreFieldNorm:o}),c=d.extractSorted(r)}else c=J(i)?J(this._docs[0])?this._searchStringList(i):this._searchObjectList(i):this._searchLogical(i),Oa(c,{ignoreFieldNorm:o}),n&&c.sort(r),We(e)&&e>-1&&(c=c.slice(0,e));return _a(c,this._docs,{includeMatches:s,includeScore:a})}_searchStringList(i,{heap:t,ignoreFieldNorm:e}={}){let s=this._getSearcher(i),{records:a}=this._myIndex,n=t?null:[];return a.forEach(({v:r,i:o,n:l})=>{if(!Z(r))return;let{isMatch:c,score:d,indices:u}=s.searchIn(r);if(c){let h={item:r,idx:o,matches:[{score:d,value:r,norm:l,indices:u}]};t?(h.score=xi(h.matches,{ignoreFieldNorm:e}),t.shouldInsert(h.score)&&t.insert(h)):n.push(h)}}),n}_searchLogical(i){let t=ys(i,this.options),e=(r,o,l)=>{if(!("children"in r)){let{keyId:h,searcher:p}=r,m;return h===null?(m=[],this._myIndex.keys.forEach((v,f)=>{m.push(...this._findMatches({key:v,value:o[f],searcher:p}))})):m=this._findMatches({key:this._keyStore.get(h),value:this._myIndex.getValueForItemAtKeyId(o,h),searcher:p}),m&&m.length?[{idx:l,item:o,matches:m}]:[]}let{children:c,operator:d}=r,u=[];for(let h=0,p=c.length;h{if(Z(r)){let l=e(t,r,o);l.length&&(a.has(o)||(a.set(o,{idx:o,item:r,matches:[]}),n.push(a.get(o))),l.forEach(({matches:c})=>{a.get(o).matches.push(...c)}))}}),n}_searchObjectList(i,{heap:t,ignoreFieldNorm:e}={}){let s=this._getSearcher(i),{keys:a,records:n}=this._myIndex,r=t?null:[];return n.forEach(({$:o,i:l})=>{if(!Z(o))return;let c=[],d=!1,u=!1;if(a.forEach((h,p)=>{let m=this._findMatches({key:h,value:o[p],searcher:s});m.length?(c.push(...m),m[0].hasInverse&&(u=!0)):d=!0}),!(u&&d)&&c.length){let h={idx:l,item:o,matches:c};t?(h.score=xi(h.matches,{ignoreFieldNorm:e}),t.shouldInsert(h.score)&&t.insert(h)):r.push(h)}}),r}_findMatches({key:i,value:t,searcher:e}){if(!Z(t))return[];let s=[];if(Dt(t))t.forEach(({v:a,i:n,n:r})=>{if(!Z(a))return;let{isMatch:o,score:l,indices:c,hasInverse:d}=e.searchIn(a);o&&s.push({score:l,key:i,value:a,idx:n,norm:r,indices:c,hasInverse:d})});else{let{v:a,n}=t,{isMatch:r,score:o,indices:l,hasInverse:c}=e.searchIn(a);r&&s.push({score:o,key:i,value:a,norm:n,indices:l,hasInverse:c})}return s}},Ai=class{static condition(i,t){return t.useTokenSearch}constructor(i,t){this.options=t,this.analyzer=Ri({isCaseSensitive:t.isCaseSensitive,ignoreDiacritics:t.ignoreDiacritics});let e=this.analyzer.tokenize(i),s=t._invertedIndex,{df:a,fieldCount:n}=s;this.termSearchers=[],this.idfWeights=[];for(let r of e){this.termSearchers.push(new re(r,{location:t.location,threshold:t.threshold,distance:t.distance,includeMatches:t.includeMatches,findAllMatches:t.findAllMatches,minMatchCharLength:t.minMatchCharLength,isCaseSensitive:t.isCaseSensitive,ignoreDiacritics:t.ignoreDiacritics,ignoreLocation:!0}));let o=a.get(r)||0,l=Math.log(1+(n-o+.5)/(o+.5));this.idfWeights.push(l)}}searchIn(i){if(!this.termSearchers.length)return{isMatch:!1,score:1};let t=[],e=0,s=0,a=0;for(let o=0;o0?1-e/s:0,r={isMatch:!0,score:Math.max(.001,n)};return this.options.includeMatches&&t.length&&(r.indices=Ii(t)),r}};et.version="7.3.0";et.createIndex=fs;et.parseIndex=Ca;et.config=B;et.match=function(g,i,t){return Ne(g,{...B,...t}).searchIn(i)};et.parseQuery=ys;Bi(ki);Bi(Ai);et.use=function(...g){g.forEach(i=>Bi(i))};var ot=require("obsidian");function Ka(){return{title:"",author:"",status:"Plan to Read",rating:0,pagesRead:0,totalPages:0,chaptersRead:0,totalChapters:0,volumesRead:0,totalVolumes:0,coverUrl:"",googleBooksId:"",malId:"",vaultPage:"",dateStarted:null,dateFinished:null,releaseDate:null}}var Ue=class extends ot.FuzzySuggestModal{constructor(i,t,e){super(i),this.files=t,this.onPick=e,this.setPlaceholder("Pick a vault note...")}getItems(){return this.files}getItemText(i){return i.path}onChooseItem(i){this.onPick(i)}},Ht=class extends ot.Modal{constructor(t,e,s,a,n,r,o){var l;super(t);this.starsWrap=null;this.lookupResultsEl=null;this.formEl=null;this.openVaultBtn=null;this.linkVaultBtn=null;this.lookupSearchGen=0;this.selectGen=0;if(this.plugin=e,this.readingData=s,this.mode=a,this.state=r?{...r.state}:Ka(),!r){let c=s.getSettings().defaultStatus;c&&(this.state.status=c)}this.existingId=(l=r==null?void 0:r.id)!=null?l:null,this.onSaved=n,this.prefillSearch=o!=null?o:""}onOpen(){var e;let t=(e=this.plugin.settings.colorTheme)!=null?e:"default";this.modalEl.setAttribute("data-theme",t),this.contentEl.setAttribute("data-theme",t),this.contentEl.addClass("wl-view"),this.contentEl.addClass("wl-reading-modal"),this.contentEl.addClass(this.mode==="book"?"wl-reading-modal-book":"wl-reading-modal-manga"),this.titleEl.setText(this.headerTitle()),this.buildUI()}onClose(){this.contentEl.empty()}headerTitle(){return this.existingId?this.mode==="book"?"Edit book":"Edit manga":this.mode==="book"?"Add book":"Add manga"}buildUI(){let t=this.contentEl;t.empty(),this.renderHeaderRow(t),this.renderLookupBar(t),t.createDiv({cls:"wl-reading-modal-divider"}),this.formEl=t.createDiv({cls:"wl-reading-form-wrap"}),this.renderForm(this.formEl),this.renderFooter(t)}renderHeaderRow(t){let e=t.createDiv({cls:"wl-reading-modal-header"}),s=e.createDiv({cls:"wl-reading-modal-header-left"});s.createSpan({cls:"wl-reading-modal-header-icon",text:this.mode==="book"?"\u{1F4D6}":"\u{1F4D3}"}),s.createSpan({cls:"wl-reading-modal-header-title",text:this.headerTitle()});let a=e.createDiv({cls:"wl-reading-modal-header-actions"});this.openVaultBtn=a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Open"}),this.openVaultBtn.addEventListener("click",()=>this.openLinkedVaultPage()),this.refreshVaultButtons()}refreshVaultButtons(){if(this.linkVaultBtn&&(this.linkVaultBtn.textContent=this.state.vaultPage?"Change link":"Link",this.linkVaultBtn.title=this.state.vaultPage?`Linked: ${this.state.vaultPage}`:"Link a vault note to this entry"),this.openVaultBtn){let t=!!this.state.vaultPage;this.openVaultBtn.disabled=!t,this.openVaultBtn.toggleClass("is-hidden",!t)}}openLinkedVaultPage(){let t=this.state.vaultPage;if(!t)return;let e=this.plugin.app.vault.getAbstractFileByPath(t);e instanceof ot.TFile?(this.plugin.app.workspace.getLeaf("tab").openFile(e),this.close()):new ot.Notice("Linked vault page no longer exists.")}renderLookupBar(t){let e=t.createDiv({cls:"wl-reading-lookup"}),s=e.createEl("input",{cls:"wl-modal-input wl-reading-lookup-input",attr:{type:"text",placeholder:this.mode==="book"?"Search by title or ISBN...":"Search by title or MAL ID..."}}),a=e.createEl("button",{cls:"wl-btn wl-reading-lookup-btn",text:"Fetch"});this.lookupResultsEl=t.createDiv({cls:"wl-reading-lookup-results"}),this.prefillSearch&&(s.value=this.prefillSearch);let n=()=>{let r=s.value.trim();if(!r){new ot.Notice("Enter a search term first.");return}this.performLookup(r)};a.addEventListener("click",n),s.addEventListener("keydown",r=>{r.key==="Enter"&&(r.preventDefault(),n())})}async performLookup(t){let e=++this.lookupSearchGen;if(this.lookupResultsEl){this.lookupResultsEl.empty(),this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-loading",text:"Searching..."});try{if(this.mode==="book"){if(!this.plugin.apiService.hasGoogleBooksKey()){if(e!==this.lookupSearchGen)return;this.lookupResultsEl.empty(),this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-empty",text:"Google Books API key required \u2014 add one in Settings \u2192 API \u2192 Books."});return}let s=await this.plugin.apiService.searchGoogleBooks(t);if(e!==this.lookupSearchGen)return;this.renderBookLookupResults(s)}else{let s=/^\d+$/.test(t),a;if(s){let n=await this.plugin.apiService.getMangaByMalId(parseInt(t,10));if(e!==this.lookupSearchGen)return;a=n?[n]:[]}else if(a=await this.plugin.apiService.searchManga(t),e!==this.lookupSearchGen)return;this.renderMangaLookupResults(a)}}catch(s){if(e!==this.lookupSearchGen)return;this.lookupResultsEl.empty();let a=this.mode==="book"?Et(s):"Lookup failed. Check your connection.";this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-empty",text:a})}}}renderBookLookupResults(t){if(this.lookupResultsEl){if(this.lookupResultsEl.empty(),t.length===0){this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-empty",text:"No matches."});return}for(let e of t){let s=this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-item"});this.renderLookupItemTitle(s,e.title,e.url);let a=[e.author||"Unknown author",e.year?String(e.year):""].filter(Boolean).join(" \xB7 ");s.createDiv({cls:"wl-reading-lookup-item-meta",text:a}),s.addEventListener("click",()=>this.applyBookResult(e))}}}renderLookupItemTitle(t,e,s){let a=t.createDiv({cls:"wl-reading-lookup-item-title-row"});if(a.createDiv({cls:"wl-reading-lookup-item-title",text:e||"(untitled)"}),s){let n=a.createEl("a",{cls:"wl-acc-link-icon",text:"\u{1F310}"});n.href=s,n.title="Open external link",n.target="_blank",n.rel="noopener noreferrer",n.addEventListener("click",r=>r.stopPropagation())}}renderMangaLookupResults(t){if(this.lookupResultsEl){if(this.lookupResultsEl.empty(),t.length===0){this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-empty",text:"No matches."});return}for(let e of t){let s=this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-item"});this.renderLookupItemTitle(s,e.title,e.url);let a=[e.author||"Unknown author",e.year?String(e.year):""].filter(Boolean).join(" \xB7 ");s.createDiv({cls:"wl-reading-lookup-item-meta",text:a}),s.addEventListener("click",()=>this.applyMangaResult(e))}}}applyBookResult(t){var s;let e=++this.selectGen;this.state.title=t.title,this.state.author=t.author,this.state.totalPages=t.totalPages,this.state.coverUrl=t.coverUrl,this.state.googleBooksId=t.googleBooksId,this.state.releaseDate=(s=t.releaseDate)!=null?s:"",this.refreshForm(),t.googleBooksId&&(async()=>{try{let a=await this.plugin.apiService.getGoogleBookById(t.googleBooksId);if(e!==this.selectGen||!a)return;a.totalPages>0&&(this.state.totalPages=a.totalPages),a.coverUrl&&(this.state.coverUrl=a.coverUrl),this.refreshForm()}catch(a){}})()}applyMangaResult(t){var s;let e=++this.selectGen;this.state.title=t.title,this.state.author=t.author,this.state.totalChapters=t.totalChapters,this.state.totalVolumes=t.totalVolumes,this.state.coverUrl=t.coverUrl,this.state.malId=t.malId>0?String(t.malId):"",this.state.releaseDate=(s=t.releaseDate)!=null?s:"",this.refreshForm(),t.malId>0&&(async()=>{let a=await this.plugin.apiService.getMangaByMalId(t.malId);e!==this.selectGen||!a||(this.state.totalChapters=a.totalChapters>0?a.totalChapters:this.state.totalChapters,this.state.totalVolumes=a.totalVolumes>0?a.totalVolumes:this.state.totalVolumes,this.refreshForm())})()}refreshForm(){this.formEl&&(this.formEl.empty(),this.renderForm(this.formEl))}renderForm(t){let e=t.createDiv({cls:"wl-reading-form"});this.renderTextField(e,"Title","Book title",this.state.title,s=>{this.state.title=s}),this.renderTextField(e,"Author","Author name",this.state.author,s=>{this.state.author=s}),this.renderStatusRatingRow(e),this.renderProgressOptionalGrid(e)}renderProgressOptionalGrid(t){let e=t.createDiv({cls:"wl-reading-form-grid"}),s=e.createDiv({cls:"wl-reading-form-grid-col"});s.createDiv({cls:"wl-reading-section-label",text:"Progress"}),this.mode==="book"?(this.renderTwoNumberRow(s,{label:"Pages read",value:this.state.pagesRead,onChange:n=>{this.state.pagesRead=n}},{label:"Chapters read",value:this.state.chaptersRead,onChange:n=>{this.state.chaptersRead=n}}),this.renderTwoNumberRow(s,{label:"Total pages",value:this.state.totalPages,onChange:n=>{this.state.totalPages=n}},{label:"Total chapters",value:this.state.totalChapters,onChange:n=>{this.state.totalChapters=n}})):(this.renderTwoNumberRow(s,{label:"Chapters read",value:this.state.chaptersRead,onChange:n=>{this.state.chaptersRead=n}},{label:"Volumes read",value:this.state.volumesRead,onChange:n=>{this.state.volumesRead=n}}),this.renderTwoNumberRow(s,{label:"Total chapters",value:this.state.totalChapters,onChange:n=>{this.state.totalChapters=n}},{label:"Total volumes",value:this.state.totalVolumes,onChange:n=>{this.state.totalVolumes=n}}));let a=e.createDiv({cls:"wl-reading-form-grid-col"});a.createDiv({cls:"wl-reading-section-label",text:"Optional"}),this.renderTextField(a,"Cover URL","https://...",this.state.coverUrl,n=>{this.state.coverUrl=n}),this.renderDateField(a,"Start date",this.state.dateStarted,n=>{this.state.dateStarted=n}),this.renderDateField(a,"Release date",this.state.releaseDate,n=>{this.state.releaseDate=n})}renderTextField(t,e,s,a,n){let r=t.createDiv({cls:"wl-reading-row"});r.createSpan({cls:"wl-reading-label",text:e});let o=r.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:s}});o.value=a,o.addEventListener("input",()=>n(o.value))}renderStatusRatingRow(t){let e=t.createDiv({cls:"wl-reading-status-rating-row"}),s=e.createDiv({cls:"wl-reading-inline-group"});s.createSpan({cls:"wl-reading-label",text:"Status"});let a=s.createEl("select",{cls:"wl-select wl-reading-status-select"});for(let r of lt){let o=a.createEl("option",{text:r,value:r});r===this.state.status&&(o.selected=!0)}a.addEventListener("change",()=>{this.state.status=a.value});let n=e.createDiv({cls:"wl-reading-inline-group"});n.createSpan({cls:"wl-reading-label",text:"Rating"}),this.starsWrap=n.createDiv({cls:"wl-stars wl-reading-stars"}),this.renderStars()}renderStars(){if(this.starsWrap){this.starsWrap.empty();for(let t=1;t<=5;t++)this.starsWrap.createSpan({cls:`wl-star${this.state.rating>=t?" is-active":""}`,text:"\u2605"}).addEventListener("click",()=>{this.state.rating=this.state.rating===t?0:t,this.renderStars()})}}renderTwoNumberRow(t,e,s){let a=t.createDiv({cls:"wl-reading-row wl-reading-row-split"});this.renderNumberCol(a,e),this.renderNumberCol(a,s)}renderNumberCol(t,e){let s=t.createDiv({cls:"wl-reading-col"});s.createSpan({cls:"wl-reading-label",text:e.label});let a=s.createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0"}});a.value=String(e.value),a.addEventListener("input",()=>{let n=parseInt(a.value,10);e.onChange(isNaN(n)||n<0?0:n)})}renderDateField(t,e,s,a){let n=t.createDiv({cls:"wl-reading-row"});n.createSpan({cls:"wl-reading-label",text:e});let r=n.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"DD/MM/YYYY",maxlength:"10"}});r.value=s?Q(s):"",r.addEventListener("change",()=>{let o=r.value.trim();if(!o){r.removeClass("wl-input-error"),a(null);return}let l=j(o);l?(r.removeClass("wl-input-error"),a(l)):r.addClass("wl-input-error")})}renderFooter(t){let e=t.createDiv({cls:"wl-reading-modal-footer"});e.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),e.createEl("button",{cls:"wl-reading-add-btn wl-btn-success wl-reading-modal-save",text:this.saveButtonLabel()}).addEventListener("click",()=>void this.save())}saveButtonLabel(){return this.existingId?"Save changes":this.mode==="book"?"Add book":"Add manga"}async save(){let t=this.state.title.trim();if(!t){new ot.Notice("Please enter a title.");return}this.mode==="book"?await this.saveBook(t):await this.saveManga(t),this.onSaved(),this.close()}async saveBook(t){if(this.existingId){let e=this.readingData.getBook(this.existingId);if(!e){new ot.Notice("Original book no longer exists.");return}let s={...e,title:t,author:this.state.author.trim(),status:this.state.status,rating:this.state.rating,pagesRead:this.state.pagesRead,totalPages:this.state.totalPages,chaptersRead:this.state.chaptersRead,totalChapters:this.state.totalChapters,coverUrl:this.state.coverUrl.trim(),googleBooksId:this.state.googleBooksId.trim(),vaultPage:this.state.vaultPage,dateStarted:this.state.dateStarted,dateFinished:this.state.dateFinished,releaseDate:this.state.releaseDate};await this.readingData.updateBook(s)}else{let e=new Date().toISOString(),s={id:this.readingData.generateBookId(t),title:t,author:this.state.author.trim(),status:this.state.status,rating:this.state.rating,pagesRead:this.state.pagesRead,totalPages:this.state.totalPages,chaptersRead:this.state.chaptersRead,totalChapters:this.state.totalChapters,coverUrl:this.state.coverUrl.trim(),googleBooksId:this.state.googleBooksId.trim(),vaultPage:this.state.vaultPage,dateStarted:this.state.dateStarted,dateFinished:this.state.dateFinished,releaseDate:this.state.releaseDate,dateAdded:e,dateModified:e,customFields:{}};await this.readingData.addBook(s)}}async saveManga(t){if(this.existingId){let e=this.readingData.getManga(this.existingId);if(!e){new ot.Notice("Original manga no longer exists.");return}let s={...e,title:t,author:this.state.author.trim(),status:this.state.status,rating:this.state.rating,chaptersRead:this.state.chaptersRead,totalChapters:this.state.totalChapters,volumesRead:this.state.volumesRead,totalVolumes:this.state.totalVolumes,coverUrl:this.state.coverUrl.trim(),malId:this.state.malId.trim(),vaultPage:this.state.vaultPage,dateStarted:this.state.dateStarted,dateFinished:this.state.dateFinished,releaseDate:this.state.releaseDate};await this.readingData.updateManga(s)}else{let e=new Date().toISOString(),s={id:this.readingData.generateMangaId(t),title:t,author:this.state.author.trim(),status:this.state.status,rating:this.state.rating,chaptersRead:this.state.chaptersRead,totalChapters:this.state.totalChapters,volumesRead:this.state.volumesRead,totalVolumes:this.state.totalVolumes,coverUrl:this.state.coverUrl.trim(),malId:this.state.malId.trim(),vaultPage:this.state.vaultPage,dateStarted:this.state.dateStarted,dateFinished:this.state.dateFinished,releaseDate:this.state.releaseDate,dateAdded:e,dateModified:e,customFields:{}};await this.readingData.addManga(s)}}};var bs=require("obsidian"),Ve=class extends bs.Modal{constructor(t,e,s){super(t);this.draftText=e;this.onChoice=s}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("wl-draft-choice-modal"),this.titleEl.setText("Add draft"),t.createDiv({cls:"wl-draft-choice-subtitle",text:this.draftText});let e=t.createDiv({cls:"wl-draft-choice-grid"}),s=(a,n)=>{let r=e.createEl("button",{cls:"wl-draft-choice-btn"});r.createDiv({cls:"wl-draft-choice-label",text:a}),r.addEventListener("click",()=>{this.close(),this.onChoice(n)})};s("Add in Watchlist","watchlist"),s("Add book","book"),s("Add manga","manga")}onClose(){this.contentEl.empty()}};var oe=class g{constructor(i,t,e,s){this.eventRef=null;this.destroyed=!1;this.scanDebounceTimer=null;this.lastScanEntries=[];this.persistState={dismissed:[],added:[],firstSeen:{},titleDisplay:{}};this.containerEl=i,this.plugin=t,this.dataManager=e,this.onCountChange=s}async render(){if(this.destroyed=!1,await this.loadPersistState(),this.destroyed)return;let i=await this.scanVault();this.destroyed||(this.renderUI(i),this.registerChangeListener())}destroy(){this.destroyed=!0,this.scanDebounceTimer&&(window.clearTimeout(this.scanDebounceTimer),this.scanDebounceTimer=null),this.eventRef&&(this.plugin.app.metadataCache.offref(this.eventRef),this.eventRef=null)}async loadPersistState(){var e,s,a,n;let t=this.plugin.dataManager.getData().drafts;t&&(this.persistState={dismissed:(e=t.dismissed)!=null?e:[],added:(s=t.added)!=null?s:[],firstSeen:(a=t.firstSeen)!=null?a:{},titleDisplay:(n=t.titleDisplay)!=null?n:{}})}async savePersistState(){let i=this.plugin.dataManager.getData();i.drafts=this.persistState,this.plugin.dataManager.queueSave()}getTag(){var i;return(i=this.plugin.settings.draftsVaultTag)!=null?i:"#watchlog"}static async scanTaggedFiles(i,t){var a,n;let e=i.app.vault.getMarkdownFiles(),s=new Map;for(let r of e){let o=i.app.metadataCache.getFileCache(r);if((n=(a=o==null?void 0:o.tags)==null?void 0:a.some(c=>c.tag===t))!=null&&n)try{let d=(await i.app.vault.cachedRead(r)).split(` -`);for(let u of d){if(!u.includes(t))continue;let h=u.indexOf(t),p=u.slice(h+t.length).trim();if(!p)continue;let m=p.split(",");for(let v of m){let f=v.trim();if(!f||f.length>100)continue;let y=f.toLowerCase();s.has(y)||s.set(y,{sources:new Set,displayTitle:f}),s.get(y).sources.add(r.basename)}}}catch(c){}}return s}async scanVault(){var n,r;let i=this.getTag(),t=await g.scanTaggedFiles(this.plugin,i),e=!1,s=new Date().toISOString();for(let[o,{displayTitle:l}]of t)this.persistState.firstSeen[o]||(this.persistState.firstSeen[o]=s,e=!0),this.persistState.titleDisplay[o]||(this.persistState.titleDisplay[o]=l,e=!0);e&&await this.savePersistState();let a=[];for(let[o,{sources:l}]of t)this.persistState.dismissed.includes(o)||a.push({titleKey:o,titleDisplay:(n=this.persistState.titleDisplay[o])!=null?n:o,sources:Array.from(l),firstSeen:(r=this.persistState.firstSeen[o])!=null?r:s,added:this.persistState.added.includes(o)});return a.sort((o,l)=>o.firstSeen.localeCompare(l.firstSeen)),this.lastScanEntries=a,a}triggerDebouncedRender(){this.scanDebounceTimer&&window.clearTimeout(this.scanDebounceTimer),this.scanDebounceTimer=window.setTimeout(()=>{this.scanDebounceTimer=null,this.render()},500)}registerChangeListener(){this.eventRef&&this.plugin.app.metadataCache.offref(this.eventRef),this.eventRef=this.plugin.app.metadataCache.on("changed",i=>{this.triggerDebouncedRender()})}static buildFuse(i){return new et(i,{keys:["title"],threshold:.35,includeScore:!0})}static fuzzyMatchesWatchlist(i,t){var s,a;let e=t.search(i);return e.length>0&&((a=(s=e[0])==null?void 0:s.score)!=null?a:1)<=.35}static async computePendingCount(i,t){var u,h,p,m,v;let e=(u=i.settings.draftsVaultTag)!=null?u:"#watchlog",s=await g.scanTaggedFiles(i,e),n=i.dataManager.getData().drafts,r=new Set((h=n==null?void 0:n.dismissed)!=null?h:[]),o=new Set((p=n==null?void 0:n.added)!=null?p:[]),l=(m=n==null?void 0:n.titleDisplay)!=null?m:{},c=g.buildFuse(t.getTitles()),d=0;for(let[f,{displayTitle:y}]of s){if(r.has(f)||o.has(f))continue;let w=(v=l[f])!=null?v:y;g.fuzzyMatchesWatchlist(w,c)||d++}return d}renderUI(i){var c;let t=this.containerEl;t.empty();let e=this.getTag(),s=this.dataManager.getTitles(),a=g.buildFuse(s),n=new Map;for(let d of i)d.added?n.set(d.titleKey,!1):n.set(d.titleKey,g.fuzzyMatchesWatchlist(d.titleDisplay,a));let r=i.filter(d=>d.added?!1:!n.get(d.titleKey)).length;this.onCountChange(r),this.plugin.settings.showHintBanners&&t.createDiv({cls:"wl-drafts-notice",text:`\u26A0 Write ${e} Movie Name in any note and it appears here automatically. Hit Add when you're ready to add it to your Watchlist.`});let o=t.createDiv({cls:"wl-list-title-wrap"});if(o.createSpan({cls:"wl-list-count",text:String(r)}),o.createSpan({cls:"wl-drafts-count-label",text:` Pending draft${r!==1?"s":""}`}),i.length===0){t.createDiv({cls:"wl-drafts-empty",text:`No drafts found. Add ${e} followed by a title in any vault note.`});return}i.sort((d,u)=>{var m,v;let h=(m=n.get(d.titleKey))!=null?m:!1,p=(v=n.get(u.titleKey))!=null?v:!1;return h!==p?h?1:-1:d.firstSeen.localeCompare(u.firstSeen)});let l=t.createDiv({cls:"wl-drafts-cards"});for(let d of i)this.renderCard(l,d,(c=n.get(d.titleKey))!=null?c:!1)}renderCard(i,t,e){let s="wl-drafts-card";e&&(s+=" wl-drafts-card-watchlist"),t.added&&(s+=" wl-drafts-card-added");let a=i.createDiv({cls:s});a.createDiv({cls:"wl-drafts-card-title",text:t.titleDisplay});let n=a.createDiv({cls:"wl-drafts-card-source"});if(t.sources.length>0){let c=t.sources[0];n.createSpan({cls:"wl-drafts-source-link",text:`[[${c}]]`}).addEventListener("click",u=>{u.stopPropagation(),this.plugin.app.workspace.openLinkText(c,"")}),t.sources.length>1&&n.createSpan({cls:"wl-drafts-source-count",text:` (${t.sources.length})`,attr:{title:t.sources.join(` -`)}})}let r=a.createDiv({cls:"wl-drafts-card-dup"});e&&r.createSpan({text:"In Watchlist",attr:{title:"This title already exists in your Watchlist"}});let o=a.createDiv({cls:"wl-drafts-card-actions"});t.added||e?o.createSpan({cls:"wl-drafts-added-label",text:"Added"}):o.createEl("button",{cls:"wl-btn wl-btn-sm wl-btn-primary",text:"Add"}).addEventListener("click",()=>this.openAddModal(t)),o.createEl("button",{cls:"wl-btn wl-btn-sm wl-drafts-dismiss",text:"\u2715",attr:{title:"Dismiss"}}).addEventListener("click",()=>void this.dismissEntry(t.titleKey))}rerenderFromCache(){let i=this.lastScanEntries.filter(t=>!this.persistState.dismissed.includes(t.titleKey)).map(t=>({...t,added:this.persistState.added.includes(t.titleKey)}));this.renderUI(i)}async dismissEntry(i){this.persistState.dismissed.includes(i)||this.persistState.dismissed.push(i),this.persistState.added=this.persistState.added.filter(t=>t!==i),await this.savePersistState(),this.rerenderFromCache()}openAddModal(i){new Ve(this.plugin.app,i.titleDisplay,t=>{t==="watchlist"?this.openWatchlistAddModal(i):this.openReadingAddModal(i,t)}).open()}openWatchlistAddModal(i){new ht(this.plugin.app,this.plugin,this.dataManager,()=>void this.afterAdded(i.titleKey),{searchQuery:i.titleDisplay,title:i.titleDisplay,type:"Anime",episodes:0,duration:0,releaseDate:"",link:"",seasons:[]}).open()}openReadingAddModal(i,t){new Ht(this.plugin.app,this.plugin,this.plugin.readingDataManager,t,()=>void this.afterAdded(i.titleKey),void 0,i.titleDisplay).open()}async afterAdded(i){var e;((e=this.plugin.settings.draftsAfterAdding)!=null?e:"keep")==="remove"?await this.dismissEntry(i):(this.persistState.added.includes(i)||this.persistState.added.push(i),await this.savePersistState(),this.rerenderFromCache())}};var mt=require("obsidian");var it=require("obsidian");var Ge=require("obsidian");var Nt=class extends Ge.Modal{constructor(t,e,s,a,n){super(t);this.listEl=null;this.styleGroupEl=null;this.dragFromIndex=-1;this.plugin=e,this.readingData=s,this.kind=a,this.onChanged=n}onOpen(){var e;let t=(e=this.plugin.settings.colorTheme)!=null?e:"default";this.modalEl.setAttribute("data-theme",t),this.contentEl.setAttribute("data-theme",t),this.contentEl.addClass("wl-view"),this.contentEl.addClass("wl-reading-modal"),this.contentEl.addClass("wl-reading-manage-cols"),this.titleEl.setText(this.kind==="book"?"Manage book fields":"Manage manga fields"),this.build()}onClose(){this.contentEl.empty()}build(){let t=this.contentEl;t.empty();let e=t.createDiv({cls:"wl-reading-modal-header"});e.createSpan({cls:"wl-reading-modal-header-icon",text:this.kind==="book"?"\u{1F4D6}":"\u{1F4D3}"}),e.createSpan({cls:"wl-reading-modal-header-title",text:this.kind==="book"?"Manage book fields":"Manage manga fields"}),t.createDiv({cls:"wl-reading-manage-cols-desc",text:"Custom fields appear in the title detail modal. Changes save automatically."}),this.renderStyleToggle(t),this.listEl=t.createDiv({cls:"wl-reading-manage-cols-list"}),this.renderList(),t.createDiv({cls:"wl-reading-modal-divider"}),this.renderAddSection(t),t.createDiv({cls:"wl-reading-modal-footer"}).createEl("button",{cls:"wl-btn",text:"Close"}).addEventListener("click",()=>this.close())}renderStyleToggle(t){var n,r;let e=this.readingData.getSettings(),s=this.kind==="book"?(n=e.bookCustomFieldStyle)!=null?n:"fill":(r=e.mangaCustomFieldStyle)!=null?r:"fill",a=t.createDiv({cls:"wl-reading-cols-style-row"});a.createSpan({cls:"wl-reading-cols-style-label",text:"Display style:"}),this.styleGroupEl=a.createDiv({cls:"wl-reading-cols-style-group"});for(let o of["fill","border"]){let l=this.styleGroupEl.createEl("button",{cls:`wl-reading-cols-style-btn${s===o?" is-active":""}`,text:o.charAt(0).toUpperCase()+o.slice(1)});l.addEventListener("click",()=>{(async()=>{var d;let c=this.kind==="book"?"bookCustomFieldStyle":"mangaCustomFieldStyle";await this.readingData.updateSettings({[c]:o}),this.onChanged(),(d=this.styleGroupEl)==null||d.querySelectorAll(".wl-reading-cols-style-btn").forEach(u=>{u.removeClass("is-active")}),l.addClass("is-active")})()})}}getColumns(){return this.kind==="book"?this.readingData.getBookColumns():this.readingData.getMangaColumns()}renderList(){if(!this.listEl)return;this.listEl.empty();let t=this.getColumns();if(t.length===0){this.listEl.createDiv({cls:"wl-reading-manage-cols-empty",text:"No custom fields yet. Add one below."});return}t.forEach((e,s)=>{var u;let a=this.listEl.createDiv({cls:"wl-editcol-card wl-reading-col-card"}),n=a.createDiv({cls:"wl-editcol-card-handle",text:"\u283F"});n.title="Drag to reorder",n.addEventListener("mousedown",()=>a.setAttribute("draggable","true")),a.addEventListener("dragstart",h=>{var p;this.dragFromIndex=s,(p=h.dataTransfer)==null||p.setData("text/plain",String(s)),a.addClass("wl-cl-dragging")}),a.addEventListener("dragend",()=>{a.removeClass("wl-cl-dragging"),a.setAttribute("draggable","false")}),a.addEventListener("dragover",h=>{h.preventDefault(),a.addClass("wl-cl-drag-over")}),a.addEventListener("dragleave",()=>a.removeClass("wl-cl-drag-over")),a.addEventListener("drop",h=>{h.preventDefault(),a.removeClass("wl-cl-drag-over");let p=this.dragFromIndex,m=s;this.dragFromIndex=-1,!(p===m||p<0)&&this.reorder(p,m)});let r=a.createEl("input",{cls:"wl-modal-input wl-editcol-card-name",attr:{type:"text",placeholder:"Field name"}});r.value=e.name,r.addEventListener("change",()=>{let h=r.value.trim();if(!h){r.value=e.name;return}h!==e.name&&this.updateColumn({...e,name:h})});let o=a.createEl("select",{cls:"wl-select wl-editcol-card-type"});for(let h of["text","number","select"]){let p=o.createEl("option",{value:h,text:h.charAt(0).toUpperCase()+h.slice(1)});e.type===h&&(p.selected=!0)}let l=a.createEl("button",{cls:"wl-reading-col-color-dot"});l.style.backgroundColor=(u=e.color)!=null?u:Bt,l.title="Choose field color",l.addEventListener("click",h=>{h.stopPropagation(),this.openColorPalette(l,e)});let c=a.createEl("input",{cls:"wl-modal-input wl-reading-col-opts-input",attr:{type:"text",placeholder:"Comma-separated values"}});c.value=e.options.join(", "),c.style.visibility=e.type==="select"?"":"hidden",c.addEventListener("change",()=>{let h=c.value.split(",").map(p=>p.trim()).filter(Boolean);this.updateColumn({...e,options:h})}),o.addEventListener("change",()=>{let h=o.value;c.style.visibility=h==="select"?"":"hidden",this.updateColumn({...e,type:h})});let d=a.createEl("button",{cls:"wl-btn wl-btn-sm wl-editcol-card-del",text:"\u2715"});d.title="Delete this field",d.addEventListener("click",()=>{new N(this.plugin.app,`Delete field "${e.name}"? This removes its data from every ${this.kind==="book"?"book":"manga"} entry.`,()=>void this.deleteColumn(e.id)).open()})})}openColorPalette(t,e){var l;this.contentEl.querySelectorAll(".wl-reading-col-palette").forEach(c=>c.remove());let s=t.getBoundingClientRect(),a=this.contentEl.createDiv({cls:"wl-reading-col-palette"});a.style.top=`${s.bottom+4}px`,a.style.left=`${s.left}px`;let n=this.contentEl.ownerDocument,r=(l=e.color)!=null?l:Bt;for(let{color600:c,color50:d}of ei){let u=a.createEl("button",{cls:"wl-reading-col-palette-swatch"});u.style.backgroundColor=d,u.style.borderColor=c,r===c&&u.addClass("is-active"),u.title=c,u.addEventListener("click",h=>{h.stopPropagation(),a.remove(),this.updateColumn({...e,color:c})})}let o=c=>{!a.contains(c.target)&&c.target!==t&&(a.remove(),n.removeEventListener("mousedown",o,!0))};window.setTimeout(()=>n.addEventListener("mousedown",o,!0),0)}renderAddSection(t){let e=t.createDiv({cls:"wl-reading-add-col"});e.createDiv({cls:"wl-reading-section-label",text:"Add field"});let s=e.createDiv({cls:"wl-reading-add-col-row"}),a=s.createEl("input",{cls:"wl-modal-input wl-reading-add-col-name",attr:{type:"text",placeholder:"Field name"}}),n=s.createEl("select",{cls:"wl-select wl-reading-add-col-type"});for(let c of["text","number","select"])n.createEl("option",{value:c,text:c.charAt(0).toUpperCase()+c.slice(1)});let r=s.createEl("input",{cls:"wl-modal-input wl-reading-add-col-opts",attr:{type:"text",placeholder:"Options (comma-separated)"}}),o=()=>{r.style.display=n.value==="select"?"":"none"};n.addEventListener("change",o),o(),s.createEl("button",{cls:"wl-reading-add-btn wl-btn-success wl-reading-add-col-btn",text:"Add"}).addEventListener("click",()=>{let c=a.value.trim();if(!c){new Ge.Notice("Enter a field name first.");return}let d=n.value,u=d==="select"?r.value.split(",").map(p=>p.trim()).filter(Boolean):[],h={id:this.readingData.generateColumnId(this.kind,c),name:c,type:d,options:u,color:Bt};this.addColumn(h).then(()=>{a.value="",r.value="",n.value="text",o()})})}async addColumn(t){await this.readingData.addColumn(this.kind,t),this.renderList(),this.onChanged()}async updateColumn(t){await this.readingData.updateColumn(this.kind,t),this.renderList(),this.onChanged()}async deleteColumn(t){await this.readingData.removeColumn(this.kind,t),this.renderList(),this.onChanged()}async reorder(t,e){await this.readingData.reorderColumns(this.kind,t,e),this.renderList(),this.onChanged()}};function za(g){var r,o,l;let i=g.match(/(^|\n)## Quotes[ \t]*\r?\n([\s\S]*?)(?=\n## |\n# |$)/);if(!i)return[];let t=(r=i[2])!=null?r:"",e=[],s=t.split(/\r?\n/),a=null,n=()=>{if(a){let c=a.body.join(` -`).trim();c&&e.push({reference:a.reference,text:c})}a=null};for(let c of s){let d=c.match(/^>\s*\[!quote\](.*)$/i);if(d){n(),a={reference:((o=d[1])!=null?o:"").trim(),body:[]};continue}if(a){let u=c.match(/^>\s?(.*)$/);u?a.body.push((l=u[1])!=null?l:""):(c.trim(),n())}}return n(),e}var Ke=class extends it.Modal{constructor(t,e,s,a,n,r){super(t);this.starsWrapEl=null;this.plugin=e,this.readingData=s,this.mode=a,this.id=n,this.onChanged=r;let o=this.getItem();this.draft={pagesRead:o&&this.mode==="book"?o.pagesRead:0,chaptersRead:o?o.chaptersRead:0,volumesRead:o&&this.mode==="manga"?o.volumesRead:0},this.openSnapshot={...this.draft}}getItem(){return this.mode==="book"?this.readingData.getBook(this.id):this.readingData.getManga(this.id)}onOpen(){var e;let t=(e=this.plugin.settings.colorTheme)!=null?e:"default";this.modalEl.setAttribute("data-theme",t),this.contentEl.setAttribute("data-theme",t),this.contentEl.addClass("wl-view"),this.contentEl.addClass("wl-detail-modal"),this.contentEl.addClass("wl-reading-detail"),this.renderAll()}onClose(){this.commitOnClose(),this.contentEl.empty()}async commitOnClose(){if(!(this.draft.pagesRead!==this.openSnapshot.pagesRead||this.draft.chaptersRead!==this.openSnapshot.chaptersRead||this.draft.volumesRead!==this.openSnapshot.volumesRead))return;let e=this.getItem();if(e){if(this.mode==="book"){let a={...e,pagesRead:this.draft.pagesRead,chaptersRead:this.draft.chaptersRead};this.applyAutoComplete(a),await this.readingData.updateBook(a)}else{let a={...e,chaptersRead:this.draft.chaptersRead,volumesRead:this.draft.volumesRead};this.applyAutoComplete(a),await this.readingData.updateManga(a)}this.logProgressChange(e),this.onChanged()}}logProgressChange(t){var a,n,r,o;let e=this.openSnapshot,s=this.mode==="book"?"Book":"Manga";if(this.mode==="book"){let l=t;this.draft.pagesRead!==e.pagesRead&&l.totalPages>0&&((a=this.plugin.historyManager)==null||a.log(`${t.title} (${s}) At page ${this.draft.pagesRead} / ${l.totalPages}`,{source:"Reading",action:"watched",titleName:t.title})),this.draft.chaptersRead!==e.chaptersRead&&l.totalChapters>0&&((n=this.plugin.historyManager)==null||n.log(`${t.title} (${s}) At chapter ${this.draft.chaptersRead} / ${l.totalChapters}`,{source:"Reading",action:"watched",titleName:t.title}))}else{let l=t;this.draft.chaptersRead!==e.chaptersRead&&l.totalChapters>0&&((r=this.plugin.historyManager)==null||r.log(`${t.title} (${s}) At chapter ${this.draft.chaptersRead} / ${l.totalChapters}`,{source:"Reading",action:"watched",titleName:t.title})),this.draft.volumesRead!==e.volumesRead&&l.totalVolumes>0&&((o=this.plugin.historyManager)==null||o.log(`${t.title} (${s}) At volume ${this.draft.volumesRead} / ${l.totalVolumes}`,{source:"Reading",action:"watched",titleName:t.title}))}}renderAll(){this.contentEl.empty();let t=this.getItem();if(!t){this.contentEl.createDiv({text:"Item no longer exists."});return}this.renderHeader(t),this.renderProgressSection(t),this.renderDetailsSection(t),this.contentEl.createDiv({cls:"wl-reading-modal-divider"}),this.renderCustomFieldsSection(t),this.contentEl.createDiv({cls:"wl-reading-modal-divider"}),this.renderQuotesSection(t),this.renderFooter(t)}renderHeader(t){let e=this.contentEl.createDiv({cls:"wl-reading-detail-header"}),s=e.createDiv({cls:"wl-reading-detail-cover"});t.coverUrl?s.createEl("img",{cls:"wl-reading-detail-cover-img",attr:{src:t.coverUrl,alt:t.title}}):(s.style.backgroundColor=Pi(t.id),s.createSpan({cls:"wl-reading-detail-cover-icon",text:this.mode==="book"?"\u{1F4D6}":"\u{1F4D3}"}));let a=e.createDiv({cls:"wl-reading-detail-info"}),n=a.createDiv({cls:"wl-reading-detail-title-wrap"});this.renderTitleDisplay(n);let r=a.createDiv({cls:"wl-reading-detail-author-wrap"});this.renderAuthorDisplay(r);let o=a.createDiv({cls:"wl-reading-detail-meta-row"}),l=o.createSpan({cls:"wl-reading-detail-status-wrap"});this.renderStatusBadge(l),ke(this.plugin.app,o,this.readingData.noteFilePath(this.mode,t.title),()=>this.close()),this.starsWrapEl=o.createDiv({cls:"wl-stars wl-reading-detail-stars"}),this.renderStars();let c=a.createDiv({cls:"wl-reading-detail-actions"});this.renderExternalLinkActions(c);let d=a.createDiv({cls:"wl-reading-detail-vault-row"});this.renderVaultRow(d)}renderTitleDisplay(t){var a;t.empty();let e=this.getItem(),s=t.createEl("h2",{cls:"wl-reading-detail-title wl-reading-detail-editable-text",text:(a=e==null?void 0:e.title)!=null?a:""});s.title="Click to edit",s.addEventListener("click",()=>this.editTitle(t))}editTitle(t){var n;t.empty();let e=this.getItem(),s=t.createEl("input",{cls:"wl-modal-input wl-reading-detail-title-input",attr:{type:"text"}});s.value=(n=e==null?void 0:e.title)!=null?n:"";let a=()=>{let r=s.value.trim();if(!r){this.renderTitleDisplay(t);return}(async()=>{let o=this.getItem();o&&r!==o.title&&(this.mode==="book"?await this.readingData.updateBook({...o,title:r}):await this.readingData.updateManga({...o,title:r}),this.onChanged()),this.renderTitleDisplay(t)})()};s.addEventListener("blur",a),s.addEventListener("keydown",r=>{r.key==="Enter"?(r.preventDefault(),s.blur()):r.key==="Escape"&&(r.preventDefault(),this.renderTitleDisplay(t))}),s.focus(),s.select()}renderAuthorDisplay(t){t.empty();let e=this.getItem(),s=t.createDiv({cls:"wl-reading-detail-author wl-reading-detail-editable-text",text:(e==null?void 0:e.author)||"\u2014"});s.title="Click to edit",s.addEventListener("click",()=>this.editAuthor(t))}editAuthor(t){var n;t.empty();let e=this.getItem(),s=t.createEl("input",{cls:"wl-modal-input wl-reading-detail-author-input",attr:{type:"text"}});s.value=(n=e==null?void 0:e.author)!=null?n:"";let a=()=>{let r=s.value.trim();(async()=>{let o=this.getItem();o&&r!==o.author&&(this.mode==="book"?await this.readingData.updateBook({...o,author:r}):await this.readingData.updateManga({...o,author:r}),this.onChanged()),this.renderAuthorDisplay(t)})()};s.addEventListener("blur",a),s.addEventListener("keydown",r=>{r.key==="Enter"?(r.preventDefault(),s.blur()):r.key==="Escape"&&(r.preventDefault(),this.renderAuthorDisplay(t))}),s.focus(),s.select()}renderStatusBadge(t){var n;t.empty();let e=this.getItem(),s=(n=e==null?void 0:e.status)!=null?n:"Plan to Read",a=t.createSpan({cls:"wl-reading-detail-status",text:s});a.style.backgroundColor=le(s),a.title="Click to change status",a.addEventListener("click",r=>{r.stopPropagation(),this.openStatusDropdown(a,t)})}openStatusDropdown(t,e){this.contentEl.querySelectorAll(".wl-reading-status-dropdown").forEach(o=>o.remove());let s=t.getBoundingClientRect(),a=this.contentEl.createDiv({cls:"wl-reading-status-dropdown"});a.style.top=`${s.bottom+4}px`,a.style.left=`${s.left}px`;let n=this.contentEl.ownerDocument;for(let o of lt){let l=a.createDiv({cls:"wl-reading-status-option"}),c=l.createSpan({cls:"wl-reading-status-option-dot"});c.style.backgroundColor=le(o),l.createSpan({text:o}),l.addEventListener("click",()=>{a.remove(),n.removeEventListener("mousedown",r,!0),this.saveStatus(o).then(()=>this.renderStatusBadge(e))})}let r=o=>{a.contains(o.target)||(a.remove(),n.removeEventListener("mousedown",r,!0))};window.setTimeout(()=>n.addEventListener("mousedown",r,!0),0)}async saveStatus(t){let e=this.getItem();if(!e)return;let s={status:t};if(t==="Completed"&&!e.dateFinished){let a=new Date,n=a.getFullYear(),r=String(a.getMonth()+1).padStart(2,"0"),o=String(a.getDate()).padStart(2,"0");s.dateFinished=`${n}-${r}-${o}`}this.mode==="book"?await this.readingData.updateBook({...e,...s}):await this.readingData.updateManga({...e,...s}),this.onChanged()}renderExternalLinkActions(t){var n;t.empty();let e=this.getItem();if(!e)return;let s=!!e.externalLink;if(t.createEl("button",{cls:"wl-btn wl-btn-sm",text:s?"Change link":"External link"}).addEventListener("click",()=>{var u;t.empty();let r=t.createDiv({cls:"wl-reading-external-link-wrap"}),o=r.createEl("input",{cls:"wl-modal-input wl-reading-external-link-input",attr:{type:"url",placeholder:"https://\u2026"}});o.value=(u=e.externalLink)!=null?u:"";let l=r.createEl("button",{cls:"wl-reading-add-btn wl-btn-success",text:"Save"}),c=r.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Cancel"}),d=()=>{let h=o.value.trim();(async()=>{let p=this.getItem();p&&(this.mode==="book"?await this.readingData.updateBook({...p,externalLink:h}):await this.readingData.updateManga({...p,externalLink:h}),this.onChanged(),this.renderExternalLinkActions(t))})()};l.addEventListener("click",d),c.addEventListener("click",()=>this.renderExternalLinkActions(t)),o.addEventListener("keydown",h=>{h.key==="Enter"?(h.preventDefault(),d()):h.key==="Escape"&&(h.preventDefault(),this.renderExternalLinkActions(t))}),o.focus()}),s){let r=t.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Open"});r.title=(n=e.externalLink)!=null?n:"",r.addEventListener("click",()=>{let o=this.getItem();o!=null&&o.externalLink&&activeWindow.open(o.externalLink,"_blank","noopener,noreferrer")})}}renderVaultRow(t){t.empty();let e=this.getItem();if(!e)return;let s=t.createEl("button",{cls:"wl-btn wl-btn-sm",text:e.vaultPage?"Change":"Link"});if(s.title=e.vaultPage?`Linked: ${e.vaultPage}`:"Link a vault note to this entry",s.addEventListener("click",()=>{let a=this.plugin.app.vault.getMarkdownFiles();new Ue(this.plugin.app,a,n=>{this.updateVaultPage(n.path).then(()=>this.renderVaultRow(t))}).open()}),e.vaultPage){let a=t.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Open"});a.title="Open the linked vault page in a new tab",a.addEventListener("click",()=>this.openLinkedVaultPage())}if(t.createSpan({cls:"wl-reading-detail-vault-label",text:"Vault page:"}),e.vaultPage){let a=e.vaultPage.split("/").pop()||e.vaultPage,n=t.createSpan({cls:"wl-reading-detail-vault-path",text:a});n.title=e.vaultPage}else t.createSpan({cls:"wl-reading-detail-vault-empty",text:"not linked"})}async updateVaultPage(t){let e=this.getItem();if(e)if(this.mode==="book"){let s={...e,vaultPage:t};await this.readingData.updateBook(s)}else{let s={...e,vaultPage:t};await this.readingData.updateManga(s)}}openLinkedVaultPage(){let t=this.getItem();if(!t||!t.vaultPage)return;let e=this.plugin.app.vault.getAbstractFileByPath(t.vaultPage);e instanceof it.TFile?(this.plugin.app.workspace.getLeaf("tab").openFile(e),this.close()):new it.Notice("Linked vault page no longer exists.")}renderStars(){if(!this.starsWrapEl)return;this.starsWrapEl.empty();let t=this.getItem();if(t)for(let e=1;e<=5;e++)this.starsWrapEl.createSpan({cls:`wl-star${t.rating>=e?" is-active":""}`,text:"\u2605"}).addEventListener("click",()=>{let a=this.getItem();if(!a)return;let n=a.rating===e?0:e;(async()=>{if(this.mode==="book"){let r={...a,rating:n};await this.readingData.updateBook(r)}else{let r={...a,rating:n};await this.readingData.updateManga(r)}this.renderStars()})()})}renderProgressSection(t){let e=this.contentEl.createDiv({cls:"wl-reading-detail-progress"});e.createDiv({cls:"wl-reading-section-label",text:"Progress"});let s=e.createDiv({cls:"wl-reading-arc-row"});this.mode==="book"?(this.renderArcGauge(s,"pages","#8b5cf6",()=>this.draft.pagesRead,a=>{this.draft.pagesRead=a},()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.totalPages)!=null?n:0},a=>this.commitTotal("totalPages",a)),this.renderArcGauge(s,"chapters","#06b6d4",()=>this.draft.chaptersRead,a=>{this.draft.chaptersRead=a},()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.totalChapters)!=null?n:0},a=>this.commitTotal("totalChapters",a))):(this.renderArcGauge(s,"chapters","#06b6d4",()=>this.draft.chaptersRead,a=>{this.draft.chaptersRead=a},()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.totalChapters)!=null?n:0},a=>this.commitTotal("totalChapters",a)),this.renderArcGauge(s,"volumes","#f59e0b",()=>this.draft.volumesRead,a=>{this.draft.volumesRead=a},()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.totalVolumes)!=null?n:0},a=>this.commitTotal("totalVolumes",a)))}async commitTotal(t,e){let s=this.getItem();s&&(this.mode==="book"?await this.readingData.updateBook({...s,[t]:e}):await this.readingData.updateManga({...s,[t]:e}),this.onChanged())}renderArcGauge(t,e,s,a,n,r,o){let l=t.createDiv({cls:"wl-reading-arc-col"}),c=100,d=8,u=(c-d)/2,h=c/2,p=c/2,m=l.createDiv({cls:"wl-reading-arc-svg-wrap"}),v=activeDocument.createElementNS("http://www.w3.org/2000/svg","svg");v.setAttribute("viewBox",`0 0 ${c} ${c}`),v.setAttribute("class","wl-reading-arc-svg"),m.appendChild(v);let f=Math.PI*u,y=activeDocument.createElementNS("http://www.w3.org/2000/svg","path"),w=`M ${h-u} ${p} A ${u} ${u} 0 1 1 ${h+u} ${p}`;y.setAttribute("d",w),y.setAttribute("fill","none"),y.setAttribute("stroke","#2a2a2a"),y.setAttribute("stroke-width",String(d)),y.setAttribute("stroke-linecap","round"),v.appendChild(y);let b=activeDocument.createElementNS("http://www.w3.org/2000/svg","path");b.setAttribute("d",w),b.setAttribute("fill","none"),b.setAttribute("stroke",s),b.setAttribute("stroke-width",String(d)),b.setAttribute("stroke-linecap","round"),b.setAttribute("stroke-dasharray",String(f)),v.appendChild(b);let S=activeDocument.createElementNS("http://www.w3.org/2000/svg","text");S.setAttribute("x",String(h)),S.setAttribute("y",String(p+4)),S.setAttribute("text-anchor","middle"),S.setAttribute("class","wl-reading-arc-pct"),v.appendChild(S);let k=A=>{let P=r();return isNaN(A)||A<0?0:P>0&&A>P?P:A},E=l.createDiv({cls:"wl-reading-arc-controls"}),D=E.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-step-btn",text:"\u22121"}),C=E.createEl("input",{cls:"wl-modal-input wl-modal-input-sm wl-reading-arc-input",attr:{type:"number",min:"0",max:String(r())}}),x=E.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-step-btn",text:"+1"}),T=l.createDiv({cls:"wl-reading-arc-label"}),M=()=>{let A=r(),P=a();C.value=String(P),C.setAttribute("max",String(A));let I=A>0?Math.min(1,P/A):0,F=f*(1-I);b.setAttribute("stroke-dashoffset",String(F)),S.textContent=`${Math.round(I*100)}%`},L=()=>{T.empty(),T.createSpan({text:"of "});let A=T.createSpan({cls:"wl-reading-arc-total wl-reading-detail-editable-text",text:String(r())});A.title="Click to edit",A.addEventListener("click",()=>q()),T.createSpan({text:` ${e}`})},q=()=>{T.empty(),T.createSpan({text:"of "});let A=T.createEl("input",{cls:"wl-modal-input wl-modal-input-sm wl-reading-arc-total-input",attr:{type:"number",min:"0"}});A.value=String(r()),T.createSpan({text:` ${e}`});let P=!1,I=()=>{if(P)return;P=!0;let F=parseInt(A.value,10),_=isNaN(F)||F<0?0:F;(async()=>(_!==r()&&(await o(_),M()),L()))()};A.addEventListener("blur",I),A.addEventListener("keydown",F=>{F.key==="Enter"?(F.preventDefault(),A.blur()):F.key==="Escape"&&(F.preventDefault(),P=!0,L())}),A.focus(),A.select()};L(),M(),C.addEventListener("input",()=>{let A=k(parseInt(C.value,10));n(A),M()}),D.addEventListener("click",()=>{n(k(a()-1)),M()}),x.addEventListener("click",()=>{n(k(a()+1)),M()})}renderDetailsSection(t){let e=this.contentEl.createDiv({cls:"wl-reading-detail-details"});e.createDiv({cls:"wl-reading-section-label",text:"Details"});let s=e.createDiv({cls:"wl-reading-detail-grid"});this.renderIdCell(s,t),this.renderEditableDateCell(s,"Started",()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.dateStarted)!=null?n:null},async a=>{let n=this.getItem();n&&(this.mode==="book"?await this.readingData.updateBook({...n,dateStarted:a}):await this.readingData.updateManga({...n,dateStarted:a}),this.onChanged())}),this.renderAddedReleaseCell(s,t),this.renderEditableDateCell(s,"Finished",()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.dateFinished)!=null?n:null},async a=>{let n=this.getItem();n&&(this.mode==="book"?await this.readingData.updateBook({...n,dateFinished:a}):await this.readingData.updateManga({...n,dateFinished:a}),this.onChanged())})}renderIdCell(t,e){let s=this.mode==="book"?"Google Books ID":"MAL ID",a=this.makeDetailCell(t,s);a.addClass("wl-reading-detail-id-value"),this.fillIdValue(a,e)}idText(t){return this.mode==="book"?t.googleBooksId:t.malId}resolveItemLink(t){if(t.externalLink)return t.externalLink;if(this.mode==="manga"){let s=t.malId;return s?`https://myanimelist.net/manga/${encodeURIComponent(s)}`:""}let e=t.googleBooksId;return e?`https://books.google.com/books?id=${encodeURIComponent(e)}`:""}fillIdValue(t,e){t.empty();let s=this.idText(e),a=this.resolveItemLink(e);s?a?t.createEl("a",{cls:"wl-reading-detail-link",text:s,attr:{href:a,target:"_blank",rel:"noopener noreferrer"}}):t.createSpan({text:s}):t.createSpan({text:"\u2014"}),t.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-detail-id-edit",text:"\u270E",attr:{title:this.mode==="book"?"Edit Google Books ID":"Edit MAL ID"}}).addEventListener("click",()=>this.editIdLink(t,e))}editIdLink(t,e){t.empty();let s=t.createDiv({cls:"wl-reading-external-link-wrap"}),a=s.createEl("input",{cls:"wl-modal-input wl-reading-external-link-input",attr:{type:"text",placeholder:this.mode==="book"?"Google Books volume ID":"MAL manga ID"}});a.value=this.idText(e);let n=s.createEl("button",{cls:"wl-reading-add-btn wl-btn-success",text:"Save"}),r=s.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Cancel"}),o=()=>{let c=this.getItem();c&&this.fillIdValue(t,c)},l=()=>{let c=a.value.trim();(async()=>{let d=this.getItem();if(d){if(c===this.idText(d)){o();return}this.mode==="book"?await this.readingData.updateBook({...d,googleBooksId:c}):await this.readingData.updateManga({...d,malId:c}),this.onChanged(),o(),c&&await this.refetchCoverFromId(c)}})()};n.addEventListener("click",l),r.addEventListener("click",o),a.addEventListener("keydown",c=>{c.key==="Enter"?(c.preventDefault(),l()):c.key==="Escape"&&(c.preventDefault(),o())}),a.focus()}async refetchCoverFromId(t){try{if(this.mode==="book"){if(!this.plugin.apiService.hasGoogleBooksKey()){new it.Notice("Google Books API key required \u2014 add one in Settings \u2192 API \u2192 Books.");return}let e=await this.plugin.apiService.getGoogleBookById(t);if(!e||!e.coverUrl){new it.Notice("This volume doesn't have a cover \u2014 try a different edition's ID.");return}let s=this.getItem();if(!s)return;await this.readingData.updateBook({...s,coverUrl:e.coverUrl})}else{let e=await this.plugin.apiService.getMangaByMalId(Number(t));if(!e||!e.coverUrl){new it.Notice("This manga doesn't have a cover \u2014 try a different ID.");return}let s=this.getItem();if(!s)return;await this.readingData.updateManga({...s,coverUrl:e.coverUrl})}this.onChanged()}catch(e){new it.Notice(this.mode==="book"?Et(e):"Failed to fetch cover.")}}renderAddedReleaseCell(t,e){var l,c;let s=t.createDiv({cls:"wl-reading-detail-cell wl-reading-detail-cell-pair"}),a=s.createDiv({cls:"wl-reading-detail-pair-col"});a.createDiv({cls:"wl-reading-detail-cell-label",text:"Added"}),a.createDiv({cls:"wl-reading-detail-cell-value",text:Q(e.dateAdded.slice(0,10))});let n=s.createDiv({cls:"wl-reading-detail-pair-col"});n.createDiv({cls:"wl-reading-detail-cell-label",text:"Release"});let r=n.createEl("input",{cls:"wl-reading-detail-date-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}}),o=(c=(l=this.getItem())==null?void 0:l.releaseDate)!=null?c:null;r.value=o?Q(o):"",r.addEventListener("change",()=>{let d=r.value.trim(),u=null;if(d&&(u=j(d),!u)){r.addClass("wl-input-error");return}r.removeClass("wl-input-error"),(async()=>{let h=this.getItem();h&&(this.mode==="book"?await this.readingData.updateBook({...h,releaseDate:u}):await this.readingData.updateManga({...h,releaseDate:u}),this.onChanged(),this.renderAll())})()})}makeDetailCell(t,e){let s=t.createDiv({cls:"wl-reading-detail-cell"});return s.createDiv({cls:"wl-reading-detail-cell-label",text:e}),s.createDiv({cls:"wl-reading-detail-cell-value"})}renderEditableDateCell(t,e,s,a){let n=t.createDiv({cls:"wl-reading-detail-cell"});n.createDiv({cls:"wl-reading-detail-cell-label",text:e});let r=n.createDiv({cls:"wl-reading-detail-cell-date"}),o=r.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-detail-today-btn",text:"Today",attr:{title:"Fill with today's date"}}),l=r.createEl("input",{cls:"wl-reading-detail-date-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}}),c=s();l.value=c?Q(c):"";let d=()=>{o.toggleClass("is-dimmed",!!l.value.trim())};d(),o.addEventListener("click",()=>{if(l.value.trim())return;let u=new Date,h=String(u.getDate()).padStart(2,"0"),p=String(u.getMonth()+1).padStart(2,"0");l.value=`${h}/${p}/${u.getFullYear()}`,d(),l.dispatchEvent(new Event("change"))}),l.addEventListener("change",()=>{let u=l.value.trim();if(!u){l.removeClass("wl-input-error"),d(),a(null);return}let h=j(u);if(!h){l.addClass("wl-input-error");return}l.removeClass("wl-input-error"),d(),a(h)})}renderFooter(t){let e=this.contentEl.createDiv({cls:"wl-reading-detail-footer"});e.createDiv({cls:"wl-reading-detail-footer-left"}).createEl("button",{cls:"wl-delete-btn wl-btn-danger wl-reading-detail-delete",text:"Delete"}).addEventListener("click",()=>{new N(this.plugin.app,`Delete "${t.title}"?`,()=>{(async()=>(this.mode==="book"?await this.readingData.removeBook(t.id):await this.readingData.removeManga(t.id),this.onChanged(),this.close()))()}).open()}),e.createDiv({cls:"wl-reading-detail-footer-right"}).createEl("button",{cls:"wl-reading-add-btn wl-btn-success",text:"Update progress"}).addEventListener("click",()=>void this.commitDraft())}getColumns(){return this.mode==="book"?this.readingData.getBookColumns():this.readingData.getMangaColumns()}openManageColumns(){new Nt(this.plugin.app,this.plugin,this.readingData,this.mode,()=>this.renderAll()).open()}renderCustomFieldsSection(t){var d,u;let e=this.contentEl.createDiv({cls:"wl-reading-detail-custom"}),s=e.createDiv({cls:"wl-reading-detail-custom-heading"});s.createSpan({cls:"wl-reading-section-label",text:"Custom fields"}),s.createEl("a",{cls:"wl-reading-detail-custom-manage",text:"Manage"}).addEventListener("click",h=>{h.preventDefault(),this.openManageColumns()});let n=this.getColumns();if(n.length===0){let h=e.createDiv({cls:"wl-reading-detail-custom-empty"});h.createSpan({text:"No custom fields \u2014 add some via "}),h.createEl("a",{cls:"wl-reading-detail-custom-manage",text:"Manage"}).addEventListener("click",m=>{m.preventDefault(),this.openManageColumns()}),h.createSpan({text:"."});return}let r=this.readingData.getSettings(),l=(this.mode==="book"?(d=r.bookCustomFieldStyle)!=null?d:"fill":(u=r.mangaCustomFieldStyle)!=null?u:"fill")==="border"?"wl-reading-custom-table is-border-mode":"wl-reading-custom-table",c=e.createDiv({cls:l});for(let h of n)this.renderCustomFieldRow(c,t,h)}renderCustomFieldRow(t,e,s){var u,h,p,m,v;let a=t.createDiv({cls:"wl-reading-custom-row"}),n=a.createDiv({cls:"wl-reading-custom-label",text:s.name}),r=a.createDiv({cls:"wl-reading-custom-value"}),o=this.readingData.getSettings(),l=this.mode==="book"?(u=o.bookCustomFieldStyle)!=null?u:"fill":(h=o.mangaCustomFieldStyle)!=null?h:"fill",c=(p=s.color)!=null?p:Bt;if(l==="fill"){let f=(m=_i[c])!=null?m:"#F1EFE8";n.setCssProps({"--wl-field-bg":f})}else n.setCssProps({"--wl-field-border":c});let d=(v=e.customFields)==null?void 0:v[s.id];this.renderCustomValueDisplay(r,e,s,d)}renderCustomValueDisplay(t,e,s,a){t.empty();let n=a!=null&&a!=="";t.createSpan({cls:`wl-reading-custom-display${n?"":" is-placeholder"}`,text:n?String(a):"\u2014"}).addEventListener("click",()=>{this.renderCustomValueEditor(t,e,s,a)})}renderCustomValueEditor(t,e,s,a){if(t.empty(),s.type==="select"){let o=t.createEl("select",{cls:"wl-select wl-reading-custom-input"}),l=o.createEl("option",{value:"",text:"\u2014"});(a==null||a==="")&&(l.selected=!0);for(let d of s.options){let u=o.createEl("option",{value:d,text:d});String(a!=null?a:"")===d&&(u.selected=!0)}let c=()=>{let d=o.value;this.saveCustomField(e,s,d===""?null:d).then(()=>{var h;let u=this.getItem();this.renderCustomValueDisplay(t,u!=null?u:e,s,(h=u==null?void 0:u.customFields)==null?void 0:h[s.id])})};o.addEventListener("change",c),o.addEventListener("blur",c),o.focus();return}let n=t.createEl("input",{cls:"wl-modal-input wl-reading-custom-input",attr:{type:s.type==="number"?"number":"text",placeholder:"Enter value\u2026"}});a!=null&&(n.value=String(a));let r=()=>{let o=n.value.trim(),l;if(o==="")l=null;else if(s.type==="number"){let c=Number(o);l=isNaN(c)?null:c}else l=o;this.saveCustomField(e,s,l).then(()=>{var d;let c=this.getItem();this.renderCustomValueDisplay(t,c!=null?c:e,s,(d=c==null?void 0:c.customFields)==null?void 0:d[s.id])})};n.addEventListener("blur",r),n.addEventListener("keydown",o=>{var l;if(o.key==="Enter")o.preventDefault(),n.blur();else if(o.key==="Escape"){o.preventDefault();let c=this.getItem();this.renderCustomValueDisplay(t,c!=null?c:e,s,(l=c==null?void 0:c.customFields)==null?void 0:l[s.id])}}),n.focus(),n.select()}async saveCustomField(t,e,s){await this.readingData.setCustomField(this.mode,t.id,e.id,s)}async renderQuotesSection(t){let e=this.contentEl.createDiv({cls:"wl-reading-detail-quotes"}),s=e.createDiv({cls:"wl-reading-detail-quotes-heading"});s.createSpan({cls:"wl-reading-section-label",text:"Favorite quotes"});let a=s.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-detail-quotes-add",text:"Add quote"}),n=e.createDiv({cls:"wl-reading-quote-list"}),r=e.createDiv({cls:"wl-reading-quote-form-host"}),o=async()=>{n.empty();try{let l=await this.readingData.readReadingNote(this.mode,t),c=l?za(l):[];if(c.length===0)n.createDiv({cls:"wl-reading-quote-empty",text:"No quotes yet."});else for(let d of c)this.renderQuoteCard(n,d)}catch(l){console.warn("[WL] quotes read failed:",l)}};a.addEventListener("click",()=>{r.empty(),this.renderAddQuoteForm(r,t,async()=>{await o()})}),o()}renderQuoteCard(t,e){let s=t.createDiv({cls:"wl-reading-quote-card"});s.createDiv({cls:"wl-reading-quote-text",text:e.text}),e.reference&&s.createDiv({cls:"wl-reading-quote-ref",text:e.reference})}renderAddQuoteForm(t,e,s){t.empty();let a=t.createDiv({cls:"wl-reading-quote-form"}),n=a.createEl("textarea",{cls:"wl-modal-input wl-reading-quote-textarea",attr:{placeholder:"Quote text\u2026",rows:"3"}}),r=a.createEl("input",{cls:"wl-modal-input wl-reading-quote-ref-input",attr:{type:"text",placeholder:"p. 123 or ch. 5 (optional)"}}),o=a.createDiv({cls:"wl-reading-quote-form-actions"});o.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Cancel"}).addEventListener("click",()=>t.empty()),o.createEl("button",{cls:"wl-reading-add-btn wl-btn-success wl-reading-quote-save",text:"Save quote"}).addEventListener("click",()=>{let d=n.value.trim();if(!d){new it.Notice("Enter the quote text first.");return}(async()=>{try{await this.readingData.appendQuote(this.mode,e,d,r.value),t.empty(),await s()}catch(u){console.warn("[WL] appendQuote failed:",u),new it.Notice("Could not save quote.")}})()}),n.focus()}async commitDraft(){let t=this.getItem();if(t){if(this.mode==="book"){let s={...t,pagesRead:this.draft.pagesRead,chaptersRead:this.draft.chaptersRead};this.applyAutoComplete(s),await this.readingData.updateBook(s)}else{let s={...t,chaptersRead:this.draft.chaptersRead,volumesRead:this.draft.volumesRead};this.applyAutoComplete(s),await this.readingData.updateManga(s)}this.logProgressChange(t),this.openSnapshot={...this.draft},new it.Notice("Progress updated."),this.onChanged(),this.close()}}applyAutoComplete(t){if((this.mode==="book"?this.isBookComplete(t):this.isMangaComplete(t))&&t.status!=="Completed"&&(t.status="Completed"),t.status==="Completed"&&!t.dateFinished){let s=new Date,a=s.getFullYear(),n=String(s.getMonth()+1).padStart(2,"0"),r=String(s.getDate()).padStart(2,"0");t.dateFinished=`${a}-${n}-${r}`}}isBookComplete(t){return t.totalPages>0&&t.pagesRead>=t.totalPages||t.totalChapters>0&&t.chaptersRead>=t.totalChapters}isMangaComplete(t){return t.totalChapters>0&&t.chaptersRead>=t.totalChapters}};var Es="__has__",Ss="__none__";function ja(g,i){var e;let t=(e=g.customFields)==null?void 0:e[i];return t!=null&&t!==""}function Fi(){return{statusExclude:[],ratingMode:"all",customExclude:{}}}function Ds(){return{key:"dateAdded",dir:"desc",secondKey:"none",secondDir:"asc"}}function qa(g){var t,e;let i=0;g.statusExclude.length>0&&i++,g.ratingMode!=="all"&&i++;for(let s of Object.keys(g.customExclude))((e=(t=g.customExclude[s])==null?void 0:t.length)!=null?e:0)>0&&i++;return i}function le(g){switch(g){case"Reading":return"#1D9E75";case"Completed":return"#7F77DD";case"Plan to Read":return"#E8873A";case"To be released":return"#3A86C8";case"Dropped":return"#E24B4A";default:return"#888780"}}var ks=["#3a4a6b","#4a3a6b","#6b3a4a","#6b5a3a","#3a6b5a","#5a6b3a","#3a5a6b","#6b3a5a"];function Pi(g){var t;let i=0;for(let e=0;e>>0;return(t=ks[i%ks.length])!=null?t:"#3a4a6b"}function Ts(g){return g.totalPages>0?Math.min(100,g.pagesRead/g.totalPages*100):0}function Cs(g){return g.totalChapters>0?Math.min(100,g.chaptersRead/g.totalChapters*100):0}var st=class st{constructor(i,t,e){this.searchQuery="";this.contentEl=null;this.filterBtn=null;this.sortBtn=null;this.resetBtn=null;this.savedFilterActive=!1;this.savedFilterBtnEl=null;this.openPopover=null;this.popoverCleanup=null;this.activeCleanups=[];this.selectionMode=!1;this.selectedIds=new Set;this.toolbarExpanded=!1;this.vsScrollContainer=null;this.vsScrollSpacer=null;this.vsGridEl=null;this.vsDisplayItems=[];this.vsScrollHandler=null;this.vsScrollRAF=null;this.vsResizeObserver=null;this.vsLastFirst=-1;this.vsLastLast=-1;this.vsLastScrollTop=0;this.vsPersistentScrollTop=0;this.vsRowHeight=0;this.coverObserver=null;this.observedCovers=new Set;this.coverFetchFailed=new Set;this.container=i,this.plugin=t,this.readingData=e,this.dataChangeListener=()=>this.renderContent(),this.readingData.onChange(this.dataChangeListener)}get activeSubTab(){var i;return st.sessionSubTab!==null?st.sessionSubTab:(i=this.readingData.getSettings().defaultSubTab)!=null?i:"books"}set activeSubTab(i){st.sessionSubTab=i}get filters(){return st.sessionFilters[this.activeSubTab]}get sort(){return st.sessionSort[this.activeSubTab]}activeColumns(){return this.activeSubTab==="books"?this.readingData.getBookColumns():this.readingData.getMangaColumns()}destroy(){this.readingData.offChange(this.dataChangeListener),this.closePopover(),this.destroyVirtualScroll();for(let i of this.activeCleanups)i();this.activeCleanups=[]}render(){this.container.empty(),this.container.addClass("wl-reading-tab"),this.renderSubTabs(),this.renderToolbar(),this.contentEl=this.container.createDiv({cls:"wl-reading-content"}),this.renderContent()}renderSubTabs(){let i=this.container.createDiv({cls:"wl-reading-subtabs"}),t=i.createEl("button",{cls:`wl-reading-subtab${this.activeSubTab==="books"?" is-active":""}`,text:"Books"}),e=i.createEl("button",{cls:`wl-reading-subtab${this.activeSubTab==="manga"?" is-active":""}`,text:"Manga"});t.addEventListener("click",()=>{this.activeSubTab!=="books"&&(this.activeSubTab="books",this.searchQuery="",this.render())}),e.addEventListener("click",()=>{this.activeSubTab!=="manga"&&(this.activeSubTab="manga",this.searchQuery="",this.render())})}renderToolbar(){let i=this.container.createDiv({cls:"wl-reading-toolbar"});De({controls:i,renderSearch:t=>this.renderReadingSearch(t),renderActions:t=>this.renderReadingActions(t),expanded:this.toolbarExpanded,onToggleChange:t=>{this.toolbarExpanded=t}})}renderReadingSearch(i){let t=i.createDiv({cls:"wl-reading-search-wrap"}),e=this.activeSubTab==="books"?"Search books...":"Search manga...",s=t.createEl("input",{cls:"wl-reading-search-input",attr:{type:"text",placeholder:e}});s.value=this.searchQuery;let a=0;s.addEventListener("input",()=>{this.searchQuery=s.value,window.clearTimeout(a),a=window.setTimeout(()=>this.renderContent(),200)})}renderReadingActions(i){let t=this.getSavedFilter();if(t){this.savedFilterActive=this.filtersMatchSaved(t);let r=i.createEl("button",{cls:`wl-btn wl-btn-sm${this.savedFilterActive?" wl-btn-preset-active":""}`,text:"Saved filter"});this.savedFilterBtnEl=r,r.addEventListener("click",()=>{st.sessionFilters[this.activeSubTab]={statusExclude:wt.filter(o=>!t.statusInclude.includes(o)),ratingMode:t.ratingMode,customExclude:{}},this.savedFilterActive=!0,r.addClass("wl-btn-preset-active"),this.refreshFilterButtonBadge(),this.render()})}else this.savedFilterBtnEl=null;if(this.filterBtn=i.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-filter-btn",text:"Filter"}),this.refreshFilterButtonBadge(),this.filterBtn.addEventListener("click",r=>{r.stopPropagation(),this.toggleFilterPopover()}),this.resetBtn=i.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-reset-btn",text:"Reset"}),this.resetBtn.addEventListener("click",()=>{var r;st.sessionFilters[this.activeSubTab]=Fi(),this.deactivateSavedFilter(),this.closePopover(),(r=this.filterBtn)==null||r.removeClass("is-popover-open"),this.refreshFilterButtonBadge(),this.renderContent()}),this.refreshFilterButtonBadge(),this.sortBtn=i.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-sort-btn",text:"Sort"}),this.sortBtn.addEventListener("click",r=>{r.stopPropagation(),this.toggleSortPopover()}),this.selectionMode&&this.selectedIds.size>0&&this.renderSelectionActionBar(i),this.selectionMode){let r=this.selectedIds.size>0,o=i.createEl("button",{cls:"wl-btn wl-btn-sm",text:r?"None":"All"});o.title=r?"Deselect all":"Select all visible",o.addEventListener("click",()=>{if(this.selectedIds.size>0)this.selectedIds.clear();else for(let l of this.vsDisplayItems)this.selectedIds.add(l.id);this.render()})}i.createEl("button",{cls:`wl-btn wl-btn-sm${this.selectionMode?" is-active":""}`,text:"Select"}).addEventListener("click",()=>{this.selectionMode=!this.selectionMode,this.selectedIds.clear(),this.render()});let s=i.createDiv({cls:"wl-reading-toolbar-right"});s.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-manage-btn",attr:{"aria-label":"Manage columns",title:"Manage columns"},text:"\u2699"}).addEventListener("click",()=>this.openManageColumns()),s.createEl("button",{cls:"wl-reading-add-btn wl-btn-success",text:this.activeSubTab==="books"?"+ Add book":"+ Add manga"}).addEventListener("click",()=>this.openAddModal())}renderSelectionActionBar(i){let t=i.createDiv({cls:"wl-reading-action-bar"}),e=t.createEl("button",{cls:"wl-group-action-btn wl-group-action-btn-delete wl-btn-danger",text:"\u2715"});e.title="Delete selected",e.addEventListener("click",a=>{a.stopPropagation();let n=this.selectedIds.size;new N(this.plugin.app,`Delete ${n} selected item${n!==1?"s":""}? This cannot be undone.`,()=>{(async()=>{let r=Array.from(this.selectedIds);this.activeSubTab==="books"?await this.readingData.removeBooksBatch(r):await this.readingData.removeMangaBatch(r),this.selectedIds.clear(),this.selectionMode=!1,this.render()})()}).open()});let s=t.createEl("select",{cls:"wl-select wl-select-sm"});s.createEl("option",{text:"Status\u2026",value:""});for(let a of lt)s.createEl("option",{text:a,value:a});s.addEventListener("change",()=>{(async()=>{let a=s.value;if(!a)return;let n=this.activeSubTab==="books";for(let r of this.selectedIds)if(n){let o=this.readingData.getBook(r);o&&this.readingData.updateBookSilent({...o,status:a})}else{let o=this.readingData.getManga(r);o&&this.readingData.updateMangaSilent({...o,status:a})}await this.readingData.saveAndNotify(),s.value="",this.selectedIds.clear(),this.selectionMode=!1,this.render()})()})}refreshFilterButtonBadge(){if(!this.filterBtn)return;let i=qa(this.filters);this.filterBtn.empty(),this.filterBtn.createSpan({text:"Filter"}),i>0&&this.filterBtn.createSpan({cls:"wl-reading-filter-badge",text:String(i)}),this.resetBtn&&(this.resetBtn.style.display=i>0?"":"none")}closePopover(){this.openPopover&&(this.openPopover.remove(),this.openPopover=null),this.popoverCleanup&&(this.popoverCleanup(),this.popoverCleanup=null)}openPopoverAt(i,t,e){this.closePopover();let s=this.container.createDiv({cls:`${t} wl-popover-anchored`}),a=i.getBoundingClientRect(),n=this.container.getBoundingClientRect();s.setCssProps({top:`${a.bottom-n.top+4}px`,left:`${a.left-n.left}px`}),e(s),this.openPopover=s;let r=l=>{s.contains(l.target)||this.closePopover()},o=l=>{l.key==="Escape"&&this.closePopover()};window.setTimeout(()=>activeDocument.addEventListener("click",r),0),activeDocument.addEventListener("keydown",o),this.popoverCleanup=()=>{activeDocument.removeEventListener("click",r),activeDocument.removeEventListener("keydown",o)}}toggleFilterPopover(){var i,t,e;if(this.openPopover&&((i=this.filterBtn)!=null&&i.hasClass("is-popover-open"))){this.closePopover(),this.filterBtn.removeClass("is-popover-open");return}(t=this.sortBtn)==null||t.removeClass("is-popover-open"),(e=this.filterBtn)==null||e.addClass("is-popover-open"),this.openPopoverAt(this.filterBtn,"wl-dropdown wl-filters-panel",s=>this.buildFilterPopover(s))}toggleSortPopover(){var i,t,e;if(this.openPopover&&((i=this.sortBtn)!=null&&i.hasClass("is-popover-open"))){this.closePopover(),this.sortBtn.removeClass("is-popover-open");return}(t=this.filterBtn)==null||t.removeClass("is-popover-open"),(e=this.sortBtn)==null||e.addClass("is-popover-open"),this.openPopoverAt(this.sortBtn,"wl-dropdown wl-sorting-panel",s=>this.buildSortPopover(s))}getSavedFilter(){var i,t;return(t=(i=this.readingData.getSettings().savedFilters)==null?void 0:i[this.activeSubTab])!=null?t:null}filtersMatchSaved(i){let t=this.filters;if(Object.values(t.customExclude).some(a=>a.length>0))return!1;let e=new Set(wt.filter(a=>!i.statusInclude.includes(a))),s=new Set(t.statusExclude);if(s.size!==e.size)return!1;for(let a of s)if(!e.has(a))return!1;return t.ratingMode===i.ratingMode}deactivateSavedFilter(){var i;this.savedFilterActive&&(this.savedFilterActive=!1,(i=this.savedFilterBtnEl)==null||i.removeClass("wl-btn-preset-active"))}buildFilterPopover(i){var s;let t={statusExclude:new Set(this.filters.statusExclude),ratingMode:this.filters.ratingMode,customExclude:new Map};for(let a of this.activeColumns())t.customExclude.set(a.id,new Set((s=this.filters.customExclude[a.id])!=null?s:[]));let e={};this.renderFilterPopoverBody(i,t,e)}addFilterSection(i,t,e,s,a){var c,d;let n=i.createDiv({cls:"wl-filter-section"}),r=n.createDiv({cls:"wl-filter-section-header"});r.createSpan({cls:"wl-filter-label",text:s});let o=r.createSpan({cls:"wl-filter-chevron",text:(c=t[e])==null||c?"\u25BC":"\u25B2"}),l=n.createDiv({cls:"wl-filter-section-content"});l.toggleClass("wl-hidden",(d=t[e])!=null?d:!0),r.addEventListener("click",u=>{var p;u.stopPropagation();let h=!((p=t[e])==null||p);t[e]=h,l.toggleClass("wl-hidden",h),o.textContent=h?"\u25BC":"\u25B2"}),a(l)}addMultiSelectBody(i,t,e){let s=[],a=i.createDiv({cls:"wl-filter-checkbox-row"}),n=a.createEl("input",{attr:{type:"checkbox"}});a.createSpan({cls:"wl-filter-all-toggle",text:"\u25C6 All"});let r=()=>{n.checked=s.length>0&&s.every(l=>l.checked)};for(let l of t){let c=i.createDiv({cls:"wl-filter-checkbox-row"}),d=c.createEl("input",{attr:{type:"checkbox"}});d.checked=!e.has(l),c.createSpan({text:l}),s.push(d),d.addEventListener("change",()=>{d.checked?e.delete(l):e.add(l),r()})}r();let o=()=>{if(s.length>0&&s.every(c=>c.checked)){for(let c of s)c.checked=!1;for(let c of t)e.add(c)}else{for(let c of s)c.checked=!0;e.clear()}r()};return n.addEventListener("click",l=>{l.stopPropagation(),o()}),a.addEventListener("click",l=>{l.target!==n&&(l.stopPropagation(),o())}),{selectAll:()=>{for(let l of s)l.checked=!0;e.clear(),r()},deselectAll:()=>{for(let l of s)l.checked=!1;for(let l of t)e.add(l);r()}}}addHasValueBody(i,t){let e=[];for(let[s,a]of[[Es,"Has value"],[Ss,"No value"]]){let n=i.createDiv({cls:"wl-filter-checkbox-row"}),r=n.createEl("input",{attr:{type:"checkbox"}});r.checked=!t.has(s),n.createSpan({text:a}),r.addEventListener("change",()=>{r.checked?t.delete(s):t.add(s)}),e.push({key:s,cb:r})}return{selectAll:()=>{for(let s of e)s.cb.checked=!0,t.delete(s.key)},deselectAll:()=>{for(let s of e)s.cb.checked=!1,t.add(s.key)}}}renderFilterPopoverBody(i,t,e){var d;i.empty();let s=[],a=i.createDiv({cls:"wl-filter-global-btns"});a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Select all"}).addEventListener("click",u=>{u.stopPropagation();for(let h of s)h.selectAll()}),a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Deselect all"}).addEventListener("click",u=>{u.stopPropagation();for(let h of s)h.deselectAll()});let o=a.createEl("button",{cls:"wl-btn wl-btn-sm",text:this.getSavedFilter()?"Delete":"Save"});o.addEventListener("click",u=>{u.stopPropagation(),(async()=>{var p,m;let h={...(p=this.readingData.getSettings().savedFilters)!=null?p:{}};o.textContent==="Save"?(h[this.activeSubTab]={name:"Saved filter",statusInclude:wt.filter(v=>!t.statusExclude.has(v)),ratingMode:t.ratingMode},await this.readingData.updateSettings({savedFilters:h})):(delete h[this.activeSubTab],await this.readingData.updateSettings({savedFilters:h}),this.savedFilterActive=!1),this.closePopover(),(m=this.filterBtn)==null||m.removeClass("is-popover-open"),this.render()})()}),this.addFilterSection(i,e,"Status","Status",u=>{s.push(this.addMultiSelectBody(u,wt,t.statusExclude))}),this.addFilterSection(i,e,"Rating","Rating",u=>{let h=[{key:"all",label:"All"},{key:"has",label:"Has rating"},{key:"none",label:"No rating"}],p=`wl-reading-rating-${Date.now()}`;for(let m of h){let v=u.createDiv({cls:"wl-filter-checkbox-row"}),f=v.createEl("input",{attr:{type:"radio",name:p}});f.checked=t.ratingMode===m.key,v.createSpan({text:m.label}),f.addEventListener("change",()=>{f.checked&&(t.ratingMode=m.key)})}});for(let u of this.activeColumns()){let h=(d=t.customExclude.get(u.id))!=null?d:new Set;t.customExclude.set(u.id,h),this.addFilterSection(i,e,`custom:${u.id}`,u.name,p=>{u.type==="select"?s.push(this.addMultiSelectBody(p,u.options,h)):s.push(this.addHasValueBody(p,h))})}i.createDiv({cls:"wl-filter-apply-wrap"}).createEl("button",{cls:"wl-btn wl-btn-sm wl-filter-apply-btn",text:"Apply"}).addEventListener("click",u=>{var p;u.stopPropagation();let h={};for(let[m,v]of t.customExclude)v.size>0&&(h[m]=Array.from(v));st.sessionFilters[this.activeSubTab]={statusExclude:Array.from(t.statusExclude),ratingMode:t.ratingMode,customExclude:h},this.deactivateSavedFilter(),this.refreshFilterButtonBadge(),this.closePopover(),(p=this.filterBtn)==null||p.removeClass("is-popover-open"),this.renderContent()})}buildSortPopover(i){let t=[{key:"dateAdded",label:"Date added"},{key:"title",label:"Title"},{key:"author",label:"Author"},{key:"rating",label:"Rating"},{key:"progress",label:"Progress"},{key:"status",label:"Status"},{key:"dateStarted",label:"Date started"},{key:"dateFinished",label:"Date finished"}];for(let s of this.activeColumns())t.push({key:`custom:${s.id}`,label:s.name});let e=(s,a,n,r)=>{let o=i.createDiv({cls:"wl-filter-row"});o.createSpan({cls:"wl-filter-label",text:s});let l=o.createEl("select",{cls:"wl-select"});if(!r){let d=l.createEl("option",{text:"None",value:"none"});a==="none"&&(d.selected=!0)}for(let d of t){let u=l.createEl("option",{text:d.label,value:d.key});d.key===a&&(u.selected=!0)}let c=o.createEl("button",{cls:"wl-btn wl-btn-sm wl-sort-dir-btn",text:n==="asc"?"\u2191":"\u2193"});c.title=n==="asc"?"Ascending \u2014 click to switch to descending":"Descending \u2014 click to switch to ascending",l.addEventListener("change",()=>{var d;r?this.sort.key=l.value:this.sort.secondKey=l.value==="none"?"none":l.value,this.closePopover(),(d=this.sortBtn)==null||d.removeClass("is-popover-open"),this.renderContent()}),c.addEventListener("click",d=>{var u;d.stopPropagation(),r?this.sort.dir=this.sort.dir==="asc"?"desc":"asc":this.sort.secondDir=this.sort.secondDir==="asc"?"desc":"asc",this.closePopover(),(u=this.sortBtn)==null||u.removeClass("is-popover-open"),this.renderContent()})};e("Sort by",this.sort.key,this.sort.dir,!0),e("Then by",this.sort.secondKey,this.sort.secondDir,!1)}applyFilters(i){let t=this.filters,e=this.activeColumns();return i.filter(s=>{var a;if(t.statusExclude.includes(s.status)||t.ratingMode==="has"&&!(s.rating>0)||t.ratingMode==="none"&&s.rating>0)return!1;for(let n of e){let r=t.customExclude[n.id];if(!(!r||r.length===0))if(n.type==="select"){let o=(a=s.customFields)==null?void 0:a[n.id],l=o==null?"":String(o);if(l!==""&&r.includes(l))return!1}else{let o=ja(s,n.id);if(o&&r.includes(Es)||!o&&r.includes(Ss))return!1}}return!0})}applySearch(i){let t=this.searchQuery.trim();return t?new et(i,{keys:["title","author"],threshold:.4,ignoreLocation:!0}).search(t).map(s=>s.item):i}compareBySortKey(i,t,e,s,a){var n,r,o,l;if(e.startsWith("custom:"))return this.compareCustom(i,t,e.slice(7),s);switch(e){case"title":return i.title.localeCompare(t.title)*s;case"author":return(i.author||"").localeCompare(t.author||"")*s;case"rating":return(i.rating-t.rating)*s;case"dateAdded":return i.dateAdded.localeCompare(t.dateAdded)*s;case"dateStarted":return((n=i.dateStarted)!=null?n:"").localeCompare((r=t.dateStarted)!=null?r:"")*s;case"dateFinished":return((o=i.dateFinished)!=null?o:"").localeCompare((l=t.dateFinished)!=null?l:"")*s;case"status":return i.status.localeCompare(t.status)*s;case"progress":{let c=a?Ts(i):Cs(i),d=a?Ts(t):Cs(t);return(c-d)*s}default:return 0}}compareCustom(i,t,e,s){var c,d;let a=this.activeColumns().find(u=>u.id===e),n=(c=i.customFields)==null?void 0:c[e],r=(d=t.customFields)==null?void 0:d[e],o=n==null||n==="",l=r==null||r==="";return o&&l?0:o?1:l?-1:(a==null?void 0:a.type)==="number"?(Number(n)-Number(r))*s:String(n).localeCompare(String(r))*s}applySort(i){let{key:t,dir:e,secondKey:s,secondDir:a}=this.sort,n=this.activeSubTab==="books",r=e==="asc"?1:-1,o=a==="asc"?1:-1;return[...i].sort((l,c)=>{let d=this.compareBySortKey(l,c,t,r,n);return d!==0||s==="none"?d:this.compareBySortKey(l,c,s,o,n)})}renderContent(){if(!this.contentEl)return;this.destroyVirtualScroll();for(let n of this.activeCleanups)n();this.activeCleanups=[],this.contentEl.empty();let t=this.activeSubTab==="books"?this.readingData.getBooks():this.readingData.getMangaList();if(t.length===0){this.renderEmptyState();return}let e=this.applyFilters(t),s=this.applySearch(e),a=this.applySort(s);if(a.length===0){let n=this.searchQuery.trim();this.contentEl.createDiv({cls:"wl-reading-empty-search",text:n?`No matches for "${n}".`:"No items match the current filters."});return}this.renderResultsCount(a.length),this.vsDisplayItems=a,this.renderVirtualGrid()}renderResultsCount(i){if(!this.contentEl)return;let t=this.contentEl.createDiv({cls:"wl-results-count"});t.textContent=`${i} title${i!==1?"s":""}`}destroyVirtualScroll(){this.destroyCoverObserver(),this.vsScrollRAF!==null&&(window.cancelAnimationFrame(this.vsScrollRAF),this.vsScrollRAF=null),this.vsResizeObserver&&(this.vsResizeObserver.disconnect(),this.vsResizeObserver=null),this.vsScrollContainer&&this.vsScrollHandler&&this.vsScrollContainer.removeEventListener("scroll",this.vsScrollHandler),this.vsScrollHandler=null,this.vsScrollContainer=null,this.vsScrollSpacer=null,this.vsGridEl=null,this.vsDisplayItems=[],this.vsLastFirst=-1,this.vsLastLast=-1,this.vsLastScrollTop=0,this.vsRowHeight=0}renderVirtualGrid(){if(!this.contentEl)return;let i=this.contentEl.createDiv({cls:"wl-reading-scroll-container"}),t=i.createDiv({cls:"wl-reading-scroll-spacer"}),e=t.createDiv({cls:"wl-reading-grid wl-reading-grid-virtual"});this.vsScrollContainer=i,this.vsScrollSpacer=t,this.vsGridEl=e,this.vsLastFirst=-1,this.vsLastLast=-1,this.vsScrollHandler=()=>{let s=i.scrollTop;this.vsPersistentScrollTop=s;let a=this.vsRowHeight>0?this.vsRowHeight/2:50;Math.abs(s-this.vsLastScrollTop){this.vsScrollRAF=null,this.renderVisibleCards()})))},i.addEventListener("scroll",this.vsScrollHandler,{passive:!0}),this.vsResizeObserver=new ResizeObserver(()=>{this.renderVisibleCards()}),this.vsResizeObserver.observe(i),this.vsPersistentScrollTop>0&&(this.renderVisibleCards(),i.scrollTop=this.vsPersistentScrollTop,this.vsLastScrollTop=this.vsPersistentScrollTop,this.renderVisibleCards())}getGridMetrics(i){let s=Math.max(1,Math.floor((i+12)/152)),a=(i-12*(s-1))/s,r=a*1.5+72,o=r+12;return{cols:s,cardWidth:a,cardHeight:r,rowHeight:o}}renderVisibleCards(){let i=this.vsScrollContainer,t=this.vsScrollSpacer,e=this.vsGridEl;if(!i||!t||!e)return;let s=i.scrollTop,a=i.clientHeight,n=i.clientWidth;if(n<=0||a<=0)return;let{cols:r,cardHeight:o,rowHeight:l}=this.getGridMetrics(n);this.vsRowHeight=l;let c=this.vsDisplayItems.length,d=Math.ceil(c/r),u=Math.max(0,Math.floor(s/l)-2),h=Math.min(d-1,Math.ceil((s+a)/l)+2),p=u*r,m=Math.min(c-1,(h+1)*r-1);t.style.height=`${d*l}px`,e.style.transform=`translateY(${u*l}px)`,e.style.setProperty("--wl-reading-cols",String(r)),e.style.setProperty("--wl-reading-card-height",`${o}px`);let v=this.vsLastFirst,f=this.vsLastLast;if(p===v&&m===f)return;this.vsLastFirst=p,this.vsLastLast=m,e.empty();let y=this.activeSubTab==="books",w=activeDocument.createDocumentFragment();for(let b=p;b<=m;b++){let S=this.vsDisplayItems[b];if(!S)continue;let k=activeDocument.createElement("div");y?this.renderBookCard(k,S):this.renderMangaCard(k,S);let E=k.firstElementChild;E&&w.appendChild(E)}e.appendChild(w),this.setupCoverObserver()}setupCoverObserver(){let i=this.vsScrollContainer,t=this.vsGridEl;!i||!t||(this.coverObserver||(this.coverObserver=new IntersectionObserver(e=>this.handleCoverIntersection(e),{root:i,rootMargin:"0px",threshold:0})),this.observedCovers.clear(),t.querySelectorAll('.wl-reading-card[data-needs-cover="true"]').forEach(e=>{let s=e;this.observedCovers.has(s)||(this.coverObserver.observe(s),this.observedCovers.add(s))}))}handleCoverIntersection(i){var e;let t=this.activeSubTab==="books"?"book":"manga";for(let s of i){if(!s.isIntersecting)continue;let a=s.target;(e=this.coverObserver)==null||e.unobserve(a),this.observedCovers.delete(a);let n=a.dataset.itemId;if(!n)continue;let r=t==="book"?this.readingData.getBook(n):this.readingData.getManga(n);if(!r||r.coverUrl||this.coverFetchFailed.has(n))continue;let o=a.querySelector(".wl-reading-card-cover");o==null||o.addClass("is-loading"),this.resolveCover(t,r).then(({url:l,sourceId:c})=>{o==null||o.removeClass("is-loading"),l?(c?this.readingData.updateCoverAndSource(t,n,l,c):this.readingData.updateCoverUrl(t,n,l),this.applyCoverToCard(a,l,r.title)):this.coverFetchFailed.add(n)})}}async resolveCover(i,t){var e,s;try{if(i==="book"){let o=t.googleBooksId;if(o){let u=await this.plugin.apiService.getGoogleBookById(o);return{url:(e=u==null?void 0:u.coverUrl)!=null?e:"",sourceId:""}}let l=t.author?`${t.title} ${t.author}`:t.title,d=(await this.plugin.apiService.searchGoogleBooks(l))[0];return!d||!d.coverUrl||!d.googleBooksId?{url:"",sourceId:""}:{url:d.coverUrl,sourceId:d.googleBooksId}}let a=t.malId;if(a){let o=await this.plugin.apiService.getMangaByMalId(Number(a));return{url:(s=o==null?void 0:o.coverUrl)!=null?s:"",sourceId:""}}let r=(await this.plugin.apiService.searchManga(t.title))[0];return!r||!r.coverUrl||!r.malId?{url:"",sourceId:""}:{url:r.coverUrl,sourceId:String(r.malId)}}catch(a){return{url:"",sourceId:""}}}applyCoverToCard(i,t,e){let s=i.querySelector(".wl-reading-card-cover");if(!s)return;let a=s.querySelector(".wl-reading-card-cover-icon"),n=activeDocument.createElement("img");n.className="wl-reading-card-cover-img",n.alt=e,n.loading="lazy",n.onload=()=>{s.style.removeProperty("background-color"),a==null||a.remove()},n.onerror=()=>{n.remove()},s.insertBefore(n,s.firstChild),n.src=t,delete i.dataset.needsCover}destroyCoverObserver(){this.coverObserver&&(this.coverObserver.disconnect(),this.coverObserver=null),this.observedCovers.clear()}renderBookCard(i,t){let e=this.renderCardShell(i,t,"\u{1F4D6}"),s=t.totalPages>0?Math.min(100,Math.round(t.pagesRead/t.totalPages*100)):0;this.renderProgressBar(e,s,t.status);let a=e.createDiv({cls:"wl-reading-card-progress-text"});t.totalPages>0?a.textContent=`${t.pagesRead} / ${t.totalPages} pages`:t.pagesRead>0?a.textContent=`${t.pagesRead} pages`:a.textContent="No progress",this.bindCardClick(e,"book",t.id)}renderMangaCard(i,t){let e=this.renderCardShell(i,t,"\u{1F4D3}"),s=t.totalChapters>0?Math.min(100,Math.round(t.chaptersRead/t.totalChapters*100)):0;this.renderProgressBar(e,s,t.status);let a=e.createDiv({cls:"wl-reading-card-progress-text"}),n=t.totalChapters>0?`Ch. ${t.chaptersRead}/${t.totalChapters}`:t.chaptersRead>0?`Ch. ${t.chaptersRead}`:"",r=t.totalVolumes>0?`Vol. ${t.volumesRead}/${t.totalVolumes}`:t.volumesRead>0?`Vol. ${t.volumesRead}`:"";n&&a.createSpan({cls:"wl-reading-card-progress-piece",text:n}),r&&a.createSpan({cls:"wl-reading-card-progress-piece",text:r}),!n&&!r&&(a.textContent="No progress"),this.bindCardClick(e,"manga",t.id)}bindCardClick(i,t,e){this.selectionMode?(this.selectedIds.has(e)&&i.addClass("is-selected"),i.addEventListener("click",s=>{s.stopPropagation(),this.selectedIds.has(e)?(this.selectedIds.delete(e),i.removeClass("is-selected")):(this.selectedIds.add(e),i.addClass("is-selected")),this.render()})):i.addEventListener("click",()=>this.openDetailModal(t,e))}renderCardShell(i,t,e){let s=i.createDiv({cls:"wl-reading-card"}),a=s.createDiv({cls:"wl-reading-card-cover"});t.coverUrl?a.createEl("img",{cls:"wl-reading-card-cover-img",attr:{src:t.coverUrl,alt:t.title,loading:"lazy"}}):(a.style.backgroundColor=Pi(t.id),a.createSpan({cls:"wl-reading-card-cover-icon",text:e}),this.coverFetchFailed.has(t.id)||(s.dataset.needsCover="true",s.dataset.itemId=t.id));let n=a.createSpan({cls:"wl-reading-card-status-badge",text:t.status});n.style.backgroundColor=le(t.status);let r=s.createEl("button",{cls:"wl-reading-card-menu-btn",text:"\u22EE"});r.setAttr("aria-label","More actions"),r.addEventListener("click",c=>{c.stopPropagation(),this.openCardContextMenu(s,r,t)});let o=s.createDiv({cls:"wl-reading-card-title",text:t.title});o.title=t.title;let l=s.createDiv({cls:"wl-reading-card-author",text:t.author||"\u2014"});return l.title=t.author||"",s}openCardContextMenu(i,t,e){this.container.querySelectorAll(".wl-reading-card-context-menu").forEach(d=>d.remove());let s=i.createDiv({cls:"wl-reading-card-context-menu"}),a=s.createDiv({cls:"wl-reading-card-context-item",text:"Refresh cover"}),n=i.getBoundingClientRect(),r=this.container.getBoundingClientRect();n.right>r.right-180&&s.classList.add("is-right-aligned");let o=i.ownerDocument,l=()=>{s.remove(),o.removeEventListener("click",c,!0)},c=d=>{!s.contains(d.target)&&d.target!==t&&l()};window.setTimeout(()=>o.addEventListener("click",c,!0),0),this.activeCleanups.push(()=>o.removeEventListener("click",c,!0)),a.addEventListener("click",d=>{d.stopPropagation(),l(),this.refreshCover(e)})}refreshCover(i){if((this.activeSubTab==="books"?"book":"manga")==="book"){let s=i;if(!s.googleBooksId){new mt.Notice("No Google Books ID \u2014 cannot refresh cover.");return}if(!this.plugin.apiService.hasGoogleBooksKey()){new mt.Notice("Google Books API key required \u2014 add one in Settings \u2192 API \u2192 Books.");return}(async()=>{try{let a=await this.plugin.apiService.getGoogleBookById(s.googleBooksId);if(!a||!a.coverUrl){new mt.Notice("Could not fetch cover from API.");return}let n=this.readingData.getBook(s.id);if(!n)return;await this.readingData.updateBook({...n,coverUrl:a.coverUrl}),new mt.Notice("Cover refreshed.")}catch(a){new mt.Notice(Et(a))}})()}else{let s=i;if(!s.malId){new mt.Notice("No MAL ID \u2014 cannot refresh cover.");return}(async()=>{try{let a=await this.plugin.apiService.getMangaByMalId(Number(s.malId));if(!a||!a.coverUrl){new mt.Notice("Could not fetch cover from API.");return}let n=this.readingData.getManga(s.id);if(!n)return;await this.readingData.updateManga({...n,coverUrl:a.coverUrl}),new mt.Notice("Cover refreshed.")}catch(a){new mt.Notice("Failed to refresh cover.")}})()}}renderProgressBar(i,t,e){let a=i.createDiv({cls:"wl-reading-card-progress-bar"}).createDiv({cls:"wl-reading-card-progress-fill"});a.style.width=`${t}%`,a.style.backgroundColor=le(e)}renderEmptyState(){if(!this.contentEl)return;let i=this.contentEl.createDiv({cls:"wl-reading-empty"}),t=this.activeSubTab==="books";i.createSpan({cls:"wl-reading-empty-icon",text:t?"\u{1F4D6}":"\u{1F4D3}"});let e=i.createDiv({cls:"wl-reading-empty-msg"});e.createSpan({text:t?"No books yet \u2014 ":"No manga yet \u2014 "}),e.createEl("a",{cls:"wl-reading-empty-link",text:t?"add your first book":"add your first manga"}).addEventListener("click",a=>{a.preventDefault(),this.openAddModal()})}openAddModal(){new Ht(this.plugin.app,this.plugin,this.readingData,this.activeSubTab==="books"?"book":"manga",()=>this.renderContent()).open()}openManageColumns(){new Nt(this.plugin.app,this.plugin,this.readingData,this.activeSubTab==="books"?"book":"manga",()=>this.renderContent()).open()}openDetailModal(i,t){new Ke(this.plugin.app,this.plugin,this.readingData,i,t,()=>this.renderContent()).open()}};st.sessionSubTab=null,st.sessionFilters={books:Fi(),manga:Fi()},st.sessionSort={books:Ds(),manga:Ds()};var ze=st;var Qa=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],Ya=["January","February","March","April","May","June","July","August","September","October","November","December"],Ja={completed:"#1D9E75",watched:"#1D9E75",added:"#378ADD",deleted:"#E24B4A",status:"#BA7517",rating:"#BA7517"},Xa={Reading:"#1D9E75",Watchlist:"#378ADD"};function xs(g){if(g.action)return g.action;let i=g.message.toLowerCase();return i.includes("was added")?"added":i.includes("was deleted")?"deleted":i.includes("was reviewed")||i.includes("rating changed")?"rating":i.includes("episode")&&i.includes("watched")?"watched":i.includes("was marked as watched")||i.includes("completed")?"completed":i.includes("status")?"status":"added"}function Ms(g){return g.source?g.source:"Watchlist"}function Za(g){let i=xs(g),t=g.message;switch(i){case"added":return"Added";case"deleted":return"Deleted";case"rating":{let e=t.match(/Rating → (\d+\/5)/);return e?`Rating \u2192 ${e[1]}`:"Rating changed"}case"status":{let e=t.match(/status changed to (.+)$/);return e?`Status \u2192 ${e[1]}`:"Status changed"}case"completed":return"Completed";case"watched":{let e=t.match(/At (page|chapter|volume) (\d+) \/ (\d+)/i);if(e)return`At ${e[1]} ${e[2]} / ${e[3]}`;let s=t.match(/\)\s+(.+?)\s+was fully watched on/i);if(s)return`${s[1]} watched`;let a=t.match(/episode (\d+)/i);return a?`Episode ${a[1]} watched`:"Watched"}}return"Updated"}function tn(g){let i=g.message.match(/\(([^)]+)\)/);return i?i[1]:""}function en(g){let i;if(g.titleName)i=g.titleName;else{let e=g.message.match(/^(.+?)\s*\(/);i=e?e[1]:g.message}let t=tn(g);return t?`${i} (${t})`:i}function sn(g){let i=new Date(g+"T12:00:00");return`${Qa[i.getDay()]}, ${i.getDate()} ${Ya[i.getMonth()]} ${i.getFullYear()}`}function an(g){let i=new Date(g);return`${String(i.getHours()).padStart(2,"0")}:${String(i.getMinutes()).padStart(2,"0")}`}function nn(g){let i=new Date(g);return`${i.getFullYear()}-${String(i.getMonth()+1).padStart(2,"0")}-${String(i.getDate()).padStart(2,"0")}`}var $i=32,Wi=40,je=class{constructor(i,t){this.sourceFilter="all";this.scrollContainer=null;this.spacer=null;this.viewport=null;this.rows=[];this.rowOffsets=[];this.totalHeight=0;this.scrollHandler=null;this.scrollRAF=null;this.resizeObserver=null;this.lastFirst=-1;this.lastLast=-1;this.renderedNodes=new Map;this.container=i,this.plugin=t}destroy(){this.destroyVirtualScroll()}render(){var e,s;this.destroyVirtualScroll(),this.container.empty(),this.container.addClass("wl-log-tab"),this.renderFilterBar();let i=(s=(e=this.plugin.historyManager)==null?void 0:e.getEntries())!=null?s:[],t=this.sourceFilter==="all"?i:i.filter(a=>Ms(a)===this.sourceFilter);if(t.length===0){this.container.createDiv({cls:"wl-log-empty",text:this.sourceFilter==="all"?"No events yet. Actions from Watchlist and Reading will appear here.":`No ${this.sourceFilter} events yet.`});return}this.buildVirtualRows(t),this.renderVirtualTimeline()}renderFilterBar(){let i=this.container.createDiv({cls:"wl-log-filter-bar"}),t=[{label:"All",value:"all"},{label:"Watchlist",value:"Watchlist"},{label:"Reading",value:"Reading"}];for(let e of t)i.createEl("button",{cls:`wl-log-filter-btn${this.sourceFilter===e.value?" is-active":""}`,text:e.label}).addEventListener("click",()=>{this.sourceFilter!==e.value&&(this.sourceFilter=e.value,this.render())})}buildVirtualRows(i){this.rows=[],this.rowOffsets=[];let t=new Map;for(let a of i){let n=nn(a.timestamp),r=t.get(n);r||(r=[],t.set(n,r)),r.push(a)}let e=[];for(let[a,n]of t)e.push({date:a,entries:n});let s=0;for(let a of e){this.rows.push({type:"header",date:a.date}),this.rowOffsets.push(s),s+=Wi;for(let n=0;n{this.scrollRAF===null&&(this.scrollRAF=window.requestAnimationFrame(()=>{this.scrollRAF=null,this.renderVisibleRows()}))},i.addEventListener("scroll",this.scrollHandler,{passive:!0}),this.resizeObserver=new ResizeObserver(()=>{this.renderedNodes.clear(),this.viewport&&this.viewport.empty(),this.lastFirst=-1,this.lastLast=-1,this.renderVisibleRows()}),this.resizeObserver.observe(i),this.renderVisibleRows()}renderVisibleRows(){var r;let i=this.scrollContainer,t=this.viewport;if(!i||!t)return;let e=i.scrollTop,s=i.clientHeight;if(s<=0)return;let a=this.findFirstVisible(e),n=this.findLastVisible(e+s);if(!(a===this.lastFirst&&n===this.lastLast)){this.lastFirst=a,this.lastLast=n;for(let[o,l]of this.renderedNodes)(on)&&(l.remove(),this.renderedNodes.delete(o));for(let o=a;o<=n;o++){if(this.renderedNodes.has(o))continue;let l=this.rows[o];if(!l)continue;let c;l.type==="header"?(c=activeDocument.createElement("div"),c.className="wl-log-day-header",c.setCssProps({height:`${Wi}px`}),c.textContent=sn(l.date)):c=this.buildEntryRow(l);let d=(r=this.rowOffsets[o])!=null?r:0;c.setCssProps({top:`${d}px`}),t.appendChild(c),this.renderedNodes.set(o,c)}}}buildEntryRow(i){var f,y;let t=i.entry,e=xs(t),s=(f=Ja[e])!=null?f:"#888780",a=Ms(t),n=(y=Xa[a])!=null?y:"#888780",r=activeDocument.createElement("div");r.className="wl-log-entry",r.setCssProps({height:`${$i}px`});let o=activeDocument.createElement("div");o.className="wl-log-dot-col";let l=activeDocument.createElement("div");if(l.className="wl-log-dot",l.style.backgroundColor=n,o.appendChild(l),!i.isLastInGroup){let w=activeDocument.createElement("div");w.className="wl-log-connector",o.appendChild(w)}r.appendChild(o);let c=activeDocument.createElement("div");c.className="wl-log-content";let d=activeDocument.createElement("span");d.className="wl-log-source",d.textContent=a,c.appendChild(d);let u=activeDocument.createElement("span");u.className="wl-log-sep",u.textContent=" \xB7 ",c.appendChild(u);let h=activeDocument.createElement("span");h.className="wl-log-title",h.textContent=en(t),c.appendChild(h);let p=activeDocument.createElement("span");p.className="wl-log-sep",p.textContent=" \u2014 ",c.appendChild(p);let m=activeDocument.createElement("span");m.className="wl-log-action",m.textContent=Za(t),m.style.color=s,c.appendChild(m),r.appendChild(c);let v=activeDocument.createElement("div");return v.className="wl-log-time",v.textContent=an(t.timestamp),r.appendChild(v),r}findFirstVisible(i){let t=0,e=this.rows.length-1;for(;t>>1;this.rowOffsets[s]+(this.rows[s].type==="header"?Wi:$i)<=i?t=s+1:e=s}return Math.max(0,t-2)}findLastVisible(i){let t=0,e=this.rows.length-1;for(;t>>1;this.rowOffsets[s]>=i?e=s-1:t=s}return Math.min(this.rows.length-1,t+2)}destroyVirtualScroll(){this.scrollRAF!==null&&(window.cancelAnimationFrame(this.scrollRAF),this.scrollRAF=null),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.scrollContainer&&this.scrollHandler&&this.scrollContainer.removeEventListener("scroll",this.scrollHandler),this.scrollHandler=null,this.scrollContainer=null,this.spacer=null,this.viewport=null,this.renderedNodes.clear(),this.lastFirst=-1,this.lastLast=-1}};var ce="watchlog-view",Ls=["wl-dashboard","wl-list","wl-airtime","wl-reading-tab","wl-custom-lists","wl-log-tab"],kt=class extends _t.ItemView{constructor(t,e,s){super(t);this.dashboardTab=null;this.listTab=null;this.airtimeTab=null;this.readingTab=null;this.customListsTab=null;this.draftsTab=null;this.logTab=null;this.airtimeBtn=null;this.draftsBtn=null;this.tabButtons={};this.tabContentEl=null;this.mobileResizeObserver=null;this.mobileSizerRaf=null;this.lastAppliedTabHeight=-1;this.editPinActive=!1;this.smallestEditHeight=-1;this.pinReleaseTimer=null;this.focusListenersBound=!1;this.overflowObserver=null;this.plugin=e,this.dataManager=s,this.activeTab="dashboard",this.dataChangeListener=()=>{this.refreshActiveTab()}}getViewType(){return ce}getDisplayText(){return"Watchlog"}getIcon(){return"tv"}async onOpen(){await super.onOpen(),this.dataManager.onChange(this.dataChangeListener),this.buildUI(),_t.Platform.isMobile&&this.setupTabContentSizer()}setupTabContentSizer(){var t;(t=this.mobileResizeObserver)==null||t.disconnect(),this.mobileResizeObserver=new ResizeObserver(()=>{this.mobileSizerRaf===null&&(this.mobileSizerRaf=window.requestAnimationFrame(()=>{this.mobileSizerRaf=null,this.applyTabContentHeight()}))}),this.mobileResizeObserver.observe(this.contentEl),this.focusListenersBound||(this.registerDomEvent(this.contentEl,"focusin",e=>this.onScrollerFocusIn(e)),this.registerDomEvent(this.contentEl,"focusout",e=>this.onScrollerFocusOut(e)),this.focusListenersBound=!0)}isEditorInScroller(t){let e=t;if(!e||typeof e.tagName!="string")return!1;let s=this.contentEl.querySelector(":scope > .wl-tab-content");if(!s||!s.contains(e))return!1;let a=e.tagName.toLowerCase();return a==="input"||a==="textarea"||e.isContentEditable===!0}onScrollerFocusIn(t){!_t.Platform.isMobile||!this.isEditorInScroller(t.target)||(this.pinReleaseTimer!==null&&(window.clearTimeout(this.pinReleaseTimer),this.pinReleaseTimer=null),this.editPinActive||(this.smallestEditHeight=-1),this.editPinActive=!0,this.lastAppliedTabHeight=-1,this.applyTabContentHeight())}onScrollerFocusOut(t){this.isEditorInScroller(t.target)&&(this.pinReleaseTimer!==null&&window.clearTimeout(this.pinReleaseTimer),this.pinReleaseTimer=window.setTimeout(()=>{this.pinReleaseTimer=null;let e=this.contentEl.ownerDocument.activeElement;this.isEditorInScroller(e)||this.releaseEditPin()},250))}releaseEditPin(){if(!this.editPinActive)return;this.editPinActive=!1,this.smallestEditHeight=-1;let t=this.contentEl.querySelector(":scope > .wl-tab-content");t==null||t.removeClass("wl-tab-content-pinned"),this.lastAppliedTabHeight=-1,this.applyTabContentHeight()}applyTabContentHeight(){let t=this.contentEl;if(!t)return;let e=t.querySelector(":scope > .wl-tab-bar"),s=t.querySelector(":scope > .wl-tab-content");if(!s)return;let a=t.clientHeight,n=e?e.offsetHeight:0,r=a-n;if(!(r<=0)){if(this.editPinActive){if(!this.isEditorInScroller(this.contentEl.ownerDocument.activeElement)){this.releaseEditPin();return}(this.smallestEditHeight<0||r{this.activeTab!=="dashboard"&&(this.destroyDraftsTab(),this.activeTab="dashboard",l.forEach(c=>c.removeClass("is-active")),s.addClass("is-active"),this.renderTabContent())}),a.addEventListener("click",()=>{this.activeTab!=="watchlist"&&(this.destroyDraftsTab(),this.activeTab="watchlist",l.forEach(c=>c.removeClass("is-active")),a.addClass("is-active"),this.renderTabContent())}),this.airtimeBtn.addEventListener("click",()=>{this.activeTab!=="upcoming"&&(this.destroyDraftsTab(),this.activeTab="upcoming",l.forEach(c=>c.removeClass("is-active")),this.airtimeBtn.addClass("is-active"),this.renderTabContent())}),n.addEventListener("click",()=>{this.activeTab!=="reading"&&(this.destroyDraftsTab(),this.activeTab="reading",l.forEach(c=>c.removeClass("is-active")),n.addClass("is-active"),this.renderTabContent())}),r.addEventListener("click",()=>{this.activeTab!=="custom-lists"&&(this.destroyDraftsTab(),this.activeTab="custom-lists",l.forEach(c=>c.removeClass("is-active")),r.addClass("is-active"),this.renderTabContent())}),this.draftsBtn.addEventListener("click",()=>{this.activeTab!=="drafts"&&(this.activeTab="drafts",l.forEach(c=>c.removeClass("is-active")),this.draftsBtn.addClass("is-active"),this.renderTabContent())}),o.addEventListener("click",()=>{this.activeTab!=="log"&&(this.destroyDraftsTab(),this.activeTab="log",l.forEach(c=>c.removeClass("is-active")),o.addClass("is-active"),this.renderTabContent())}),this.tabContentEl=t.createDiv({cls:"wl-tab-content"}),this.renderTabContent(),this.updateUpcomingBadge(),this.updateDraftsBadge(),this.registerEvent(this.plugin.app.metadataCache.on("resolved",()=>{this.updateDraftsBadge()}))}setActiveTab(t){var e;if(this.activeTab!==t){if(!this.tabContentEl){this.activeTab=t;return}t!=="drafts"&&this.destroyDraftsTab(),this.activeTab=t;for(let s of Object.values(this.tabButtons))s==null||s.removeClass("is-active");(e=this.tabButtons[t])==null||e.addClass("is-active"),this.renderTabContent()}}renderTabContent(){var t,e,s,a,n;if(this.tabContentEl){(t=this.customListsTab)==null||t.destroy(),this.activeTab!=="reading"&&((e=this.readingTab)==null||e.destroy(),this.readingTab=null),this.activeTab!=="log"&&((s=this.logTab)==null||s.destroy(),this.logTab=null),this.tabContentEl.empty();for(let r of Ls)this.tabContentEl.removeClass(r);this.activeTab==="dashboard"?(this.dashboardTab=new we(this.tabContentEl,this.plugin,this.dataManager,this.plugin.readingDataManager),this.dashboardTab.render()):this.activeTab==="watchlist"?((a=this.listTab)==null||a.destroy(),this.listTab=new Ce(this.tabContentEl,this.plugin,this.dataManager),this.listTab.render()):this.activeTab==="upcoming"?(this.airtimeTab=new vt(this.tabContentEl,this.plugin,this.dataManager,r=>{this.airtimeBtn&&(this.airtimeBtn.textContent=r>0?`Upcoming (${r})`:"Upcoming")}),this.airtimeTab.render()):this.activeTab==="reading"?((n=this.readingTab)==null||n.destroy(),this.readingTab=new ze(this.tabContentEl,this.plugin,this.plugin.readingDataManager),this.readingTab.render()):this.activeTab==="drafts"?(this.draftsTab=new oe(this.tabContentEl,this.plugin,this.dataManager,r=>this.setDraftsBadge(r)),this.draftsTab.render()):this.activeTab==="log"?(this.logTab=new je(this.tabContentEl,this.plugin),this.logTab.render()):(this.customListsTab=new Fe(this.tabContentEl,this.plugin,this.dataManager),this.customListsTab.render()),this.guardOverflow(),this.refreshMobileLayout()}}refreshActiveTab(){if(this.applyColorTheme(this.contentEl),this.tabContentEl)for(let t of Ls)this.tabContentEl.removeClass(t);if(this.activeTab==="watchlist"&&this.listTab)this.listTab.render();else if(this.activeTab==="dashboard"&&this.dashboardTab)this.dashboardTab.render();else if(this.activeTab==="upcoming"&&this.airtimeTab)this.airtimeTab.render();else if(this.activeTab==="reading"&&this.readingTab)this.readingTab.render();else if(this.activeTab==="custom-lists"&&this.customListsTab)this.customListsTab.render();else if(this.activeTab==="drafts"&&this.draftsTab)this.draftsTab.render();else if(this.activeTab==="log"&&this.logTab)this.logTab.render();else{this.renderTabContent();return}this.guardOverflow(),this.updateUpcomingBadge()}guardOverflow(){var s;if(!this.tabContentEl)return;(s=this.overflowObserver)==null||s.disconnect();let t=this.tabContentEl,e=Date.now();this.overflowObserver=new MutationObserver(()=>{if(Date.now()-e>300)return;window.getComputedStyle(t).overflow==="hidden"&&t.setCssProps({overflow:"auto"})}),this.overflowObserver.observe(t,{attributes:!0,attributeFilter:["style","class"]})}updateUpcomingBadge(){if(!this.airtimeBtn)return;let t=vt.getAiredDueCount(this.dataManager,this.plugin.readingDataManager)+vt.getMaybeDueCount(this.dataManager);this.airtimeBtn.textContent=t>0?`Upcoming (${t})`:"Upcoming"}setDraftsBadge(t){this.draftsBtn&&(this.draftsBtn.textContent=t>0?`Drafts (${t})`:"Drafts")}async updateDraftsBadge(){if(!this.draftsBtn)return;let t=await oe.computePendingCount(this.plugin,this.dataManager);this.setDraftsBadge(t)}};var R=require("obsidian");var Tt=require("obsidian"),Rs=["title","type","status","priority","rating","totalEpisodes","episodeDuration","dateStarted","dateFinished","releaseDate","dateAdded","externalLink","notes"];function rn(g){let i=String(g!=null?g:"");return i.includes(",")||i.includes('"')||i.includes(` -`)?`"${i.replace(/"/g,'""')}"`:i}function on(g){let i=Rs.join(","),t=g.map(e=>Rs.map(s=>rn(e[s])).join(","));return[i,...t].join(` -`)}function ln(g){let i=[],t=[],e="",s=!1,a=g.replace(/\r\n?/g,` +`}async deleteList(i){let t=(0,W.normalizePath)(`${this.folderPath}/${i}.md`),e=this.app.vault.getAbstractFileByPath(t);if(e instanceof W.TFile)try{await this.app.fileManager.trashFile(e)}catch(s){}}async renameList(i,t){let e=(0,W.normalizePath)(`${this.folderPath}/${t}.md`),s=(0,W.normalizePath)(`${this.folderPath}/${i}.md`),a=this.app.vault.getAbstractFileByPath(s);if(a instanceof W.TFile)try{await this.app.vault.rename(a,e)}catch(n){}}generateColId(i){let t=new Set(i.map(s=>s.id)),e=1;for(;t.has(`col_${e}`);)e++;return`col_${e}`}generateRowId(i){let t=new Set(i.map(s=>s.id)),e=1;for(;t.has(`row_${e}`);)e++;return`row_${e}`}};function Js(g){var e;if(g.type!=="select"){delete g.optionColors;return}if(!g.optionColors)return;let i=new Set((e=g.options)!=null?e:[]),t={};for(let[s,a]of Object.entries(g.optionColors)){let n=s.trim();i.has(n)&&(t[n]=a)}Object.keys(t).length?g.optionColors=t:delete g.optionColors}function Xs(g,i,t,e,s,a,n,r,o){g.empty(),g.addClass("wl-editcol-card-grid");let l=-1,c=d=>{let u=g.createDiv({cls:"wl-editcol-card wl-editcol-card-auto"});u.setAttribute("data-auto",d),u.createDiv({cls:"wl-editcol-card-name-wrap"}).createDiv({cls:"wl-editcol-card-name-label",text:d}),u.createDiv({cls:"wl-editcol-card-type-locked",text:"Auto"}),u.createDiv({cls:"wl-editcol-card-spacer"})};if(c("#"),c("Name"),i.forEach((d,u)=>{let h=g.createDiv({cls:"wl-editcol-card"}),p=h.createDiv({cls:"wl-editcol-card-handle",text:"\u283F"});p.title="Drag to reorder",p.addEventListener("mousedown",()=>h.setAttribute("draggable","true")),h.addEventListener("dragstart",v=>{var w;l=u,(w=v.dataTransfer)==null||w.setData("text/plain",String(u)),h.addClass("wl-cl-dragging")}),h.addEventListener("dragend",()=>{h.removeClass("wl-cl-dragging"),h.setAttribute("draggable","false")}),h.addEventListener("dragover",v=>{v.preventDefault(),h.addClass("wl-cl-drag-over")}),h.addEventListener("dragleave",()=>h.removeClass("wl-cl-drag-over")),h.addEventListener("drop",v=>{v.preventDefault(),h.removeClass("wl-cl-drag-over");let w=l,b=u;w!==b&&w>=0&&s(w,b)});let m=h.createEl("input",{cls:"wl-modal-input wl-editcol-card-name",attr:{type:"text",placeholder:"Column name",value:d.label}});m.addEventListener("input",()=>{d.label=m.value});let f=h.createEl("select",{cls:"wl-select wl-editcol-card-type"});for(let v of["text","number","select"]){let w=f.createEl("option",{value:v,text:v.charAt(0).toUpperCase()+v.slice(1)});d.type===v&&(w.selected=!0)}if(f.addEventListener("change",()=>{let v=f.value;if(v==="select"){let w=new Set,b=[];for(let E of t){let D=E[d.id];if(typeof D!="string"&&typeof D!="number")continue;let S=String(D).trim();!S||w.has(S)||(w.add(S),b.push(S))}d.options=b}d.type=v,n()}),d.type==="text"||d.type==="number"){let v=h.createDiv({cls:"wl-editcol-card-toggles"}),w=v.createEl("button",{cls:`wl-btn wl-btn-sm wl-editcol-card-toggle wl-editcols-bold-btn${d.bold?" is-active":""}`,text:"B"});w.addEventListener("click",()=>{d.bold=!d.bold,w.toggleClass("is-active",!!d.bold)});let b=v.createEl("button",{cls:`wl-btn wl-btn-sm wl-editcol-card-toggle wl-editcols-italic-btn${d.italic?" is-active":""}`,text:"I"});if(b.addEventListener("click",()=>{d.italic=!d.italic,b.toggleClass("is-active",!!d.italic)}),d.type==="number"){let E=v.createEl("button",{cls:`wl-btn wl-btn-sm wl-editcol-card-toggle wl-editcols-autotime-btn${d.autoTime?" is-active":""}`,text:"\u23F1",attr:{title:"Auto-populate with remaining watch time from Watchlist"}});E.addEventListener("click",()=>{d.autoTime=!d.autoTime,E.toggleClass("is-active",!!d.autoTime)})}}let y=h.createEl("button",{cls:"wl-btn wl-btn-sm wl-editcol-card-del",text:"\xD7"});if(y.title="Delete this column",y.addEventListener("click",()=>{t.some(w=>{let b=w[d.id];return b!==void 0&&b!==""&&b!==null})?new _(e,`Delete column "${d.label}"? This will remove all data in this column.`,()=>{a(u)}).open():a(u)}),d.type==="select"){let v=h.createDiv({cls:"wl-editcol-card-opts"}),w=()=>{var E;v.empty(),((E=d.options)!=null?E:[]).forEach((D,S)=>{let T=v.createDiv({cls:"wl-editcol-card-opt-row"}),M=T.createEl("button",{cls:"wl-reading-col-color-dot wl-editcol-opt-color-dot"});M.title="Option color";let x=()=>{var k,R,P;let H=(P=d.optionColors)==null?void 0:P[(R=(k=d.options)==null?void 0:k[S])!=null?R:""];H?(M.removeClass("is-unset"),M.setCssProps({"background-color":Zt(H),"border-color":Gt(H)})):(M.addClass("is-unset"),M.setCssProps({"background-color":"","border-color":""}))};x(),M.addEventListener("click",H=>{var R,P,B,K;H.stopPropagation();let k=(P=(R=d.options)==null?void 0:R[S])!=null?P:"";k&&Se({anchor:M,container:g,current:(K=(B=d.optionColors)==null?void 0:B[k])!=null?K:dt,allowCustom:!0,onPick:U=>{U===null?d.optionColors&&delete d.optionColors[k]:(d.optionColors||(d.optionColors={}),d.optionColors[k]=U),x()}})});let C=T.createEl("input",{cls:"wl-modal-input wl-editcol-card-opt-input",attr:{type:"text",value:D,placeholder:"Option"}}),L=D;C.addEventListener("input",()=>{d.options||(d.options=[]);let H=C.value;if(H!==L){if(d.optionColors){let k=d.optionColors[L];k!==void 0&&(H&&(d.optionColors[H]=k),delete d.optionColors[L])}o==null||o(d.id,L,H)}d.options[S]=H,L=H}),T.createEl("button",{cls:"wl-btn wl-btn-sm wl-editcol-card-opt-del",text:"\xD7",attr:{title:"Remove this option"}}).addEventListener("click",()=>{var k,R;let H=(k=d.options)==null?void 0:k[S];(R=d.options)==null||R.splice(S,1),H&&d.optionColors&&delete d.optionColors[H],w()})}),v.createEl("button",{cls:"wl-btn wl-btn-sm wl-editcol-card-opt-add",text:"+ option"}).addEventListener("click",()=>{d.options||(d.options=[]),d.options.push(""),w()})};w()}}),r){let d=g.createDiv({cls:"wl-editcol-card wl-editcol-card-add"});d.createDiv({cls:"wl-editcol-card-add-label",text:"+ add column"}),d.addEventListener("click",()=>r())}}var ni=class extends W.Modal{constructor(t,e,s,a){super(t);this.optionRenames=new Map;this.list=e,this.manager=s,this.onSave=a,this.tabColor=e.tabColor,this.cols=e.columns.filter(n=>!n.locked).map(n=>({...n,options:n.options?[...n.options]:void 0,optionColors:n.optionColors?{...n.optionColors}:void 0}))}onOpen(){this.modalEl.addClass("wl-editcol-modal"),this.titleEl.setText(`Table settings \u2014 ${this.list.name}`),this.contentEl.addClass("wl-editcols-modal"),this.renderBody()}renderBody(){this.contentEl.empty(),this.contentEl.addClass("wl-editcols-modal"),this.renderTabColorRow(this.contentEl),this.listEl=this.contentEl.createDiv({cls:"wl-editcols-list"}),this.renderCols();let t=this.contentEl.createDiv({cls:"wl-modal-btn-row wl-editcols-footer"});t.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),t.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",()=>void this.handleSave())}renderTabColorRow(t){let e=t.createDiv({cls:"wl-editcols-tabcolor-row"});e.createSpan({cls:"wl-editcols-tabcolor-label",text:"Tab color"});let s=e.createEl("button",{cls:"wl-reading-col-color-dot wl-editcols-tabcolor-dot"}),a=()=>{this.tabColor?(s.removeClass("is-unset"),s.setCssProps({"background-color":this.tabColor})):(s.addClass("is-unset"),s.setCssProps({"background-color":""}))};a(),s.title="Choose tab color",s.addEventListener("click",n=>{var r;n.stopPropagation(),Se({anchor:s,container:this.contentEl,current:(r=this.tabColor)!=null?r:dt,allowCustom:!0,onPick:o=>{this.tabColor=o!=null?o:void 0,a()}})})}renderCols(){Xs(this.listEl,this.cols,this.list.rows,this.app,(t,e)=>{let[s]=this.cols.splice(t,1);this.cols.splice(t{this.cols.splice(t,1),this.renderBody()},()=>this.renderBody(),()=>{this.cols.push({id:this.manager.generateColId([...this.list.columns.filter(t=>!t.locked),...this.cols]),label:"",type:"text",bold:!1,italic:!1}),this.renderBody()},(t,e,s)=>this.recordOptionRename(t,e,s))}recordOptionRename(t,e,s){let a=this.optionRenames.get(t);a||(a=new Map,this.optionRenames.set(t,a));let n=null;for(let[r,o]of a)if(o===e){n=r;break}a.set(n!=null?n:e,s)}applyOptionRenamesToRows(){for(let[t,e]of this.optionRenames)for(let[s,a]of e)if(!(s===""||s===a))for(let n of this.list.rows)n[t]===s&&(n[t]=a)}handleSave(){for(let t of this.cols){if(!t.label.trim()){new W.Notice("Column names cannot be empty.");return}if(t.type==="select"&&(!t.options||t.options.length===0)){new W.Notice(`Column "${t.label}" must have at least one option.`);return}}for(let t of this.cols)t.label=t.label.trim(),t.options&&(t.options=t.options.map(e=>e.trim()).filter(e=>e)),Js(t);this.applyOptionRenamesToRows(),this.list.tabColor=this.tabColor,this.onSave(this.cols).then(()=>this.close())}},ri=class extends W.Modal{constructor(i,t){var e;super(i),this.plugin=t,this.manager=new te(i,t),this.cols=((e=t.settings.defaultCustomColumns)!=null?e:[]).map(s=>({...s,options:s.options?[...s.options]:void 0,optionColors:s.optionColors?{...s.optionColors}:void 0}))}onOpen(){this.modalEl.addClass("wl-editcol-modal"),this.titleEl.setText("Default columns"),this.contentEl.addClass("wl-editcols-modal"),this.renderBody()}renderBody(){this.contentEl.empty(),this.contentEl.addClass("wl-editcols-modal"),this.contentEl.createDiv({cls:"wl-settings-info",text:"These columns are pre-populated when creating a new list. The Name column is always added automatically."}),this.listEl=this.contentEl.createDiv({cls:"wl-editcols-list"}),this.renderCols();let i=this.contentEl.createDiv({cls:"wl-modal-btn-row wl-editcols-footer"});i.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),i.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",()=>void this.handleSave())}renderCols(){Xs(this.listEl,this.cols,[],this.app,(i,t)=>{let[e]=this.cols.splice(i,1);this.cols.splice(i{this.cols.splice(i,1),this.renderBody()},()=>this.renderBody(),()=>{this.cols.push({id:this.manager.generateColId(this.cols),label:"",type:"text",bold:!1,italic:!1}),this.renderBody()})}async handleSave(){for(let i of this.cols){if(!i.label.trim()){new W.Notice("Column names cannot be empty.");return}if(i.type==="select"&&(!i.options||i.options.length===0)){new W.Notice(`Column "${i.label}" must have at least one option.`);return}}for(let i of this.cols)i.label=i.label.trim(),i.options&&(i.options=i.options.map(t=>t.trim()).filter(t=>t)),Js(i);this.plugin.settings.defaultCustomColumns=this.cols,await this.plugin.saveSettings(),new W.Notice("Default columns saved."),this.close()}},ns=class extends W.Modal{constructor(t,e,s,a){super(t);this.listName=e;this.initialNotes=s;this.onSave=a;this.previewComponent=new W.Component}onOpen(){this.previewComponent.load(),this.titleEl.setText(`Notes \u2014 ${this.listName}`);let{contentEl:t}=this;t.addClass("wl-notes-modal");let e=t.createDiv({cls:"wl-notes-mode-bar"}),s=e.createEl("button",{cls:"wl-btn wl-btn-sm is-active",text:"Edit"}),a=e.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Preview"}),n=t.createDiv({cls:"wl-notes-edit-area"}),r=n.createEl("textarea",{cls:"wl-modal-textarea wl-notes-textarea",attr:{placeholder:"Add notes, links, or any text here..."}});r.value=this.initialNotes,window.setTimeout(()=>{r.focus(),r.setSelectionRange(r.value.length,r.value.length)},0);let o=t.createDiv({cls:"wl-notes-preview-area"});o.hide();let l=()=>{n.show(),o.hide(),s.addClass("is-active"),a.removeClass("is-active"),r.focus()},c=async()=>{n.hide(),o.show(),o.empty(),s.removeClass("is-active"),a.addClass("is-active");let p=r.value.trim()||"*No notes yet.*";await W.MarkdownRenderer.render(this.app,p,o,"",this.previewComponent)};s.addEventListener("click",l),a.addEventListener("click",()=>void c()),r.addEventListener("keydown",p=>{(p.ctrlKey||p.metaKey)&&p.key==="b"?(p.preventDefault(),Ys(r,"**","**")):(p.ctrlKey||p.metaKey)&&p.key==="i"&&(p.preventDefault(),Ys(r,"*","*"))});let d=t.createDiv({cls:"wl-modal-btn-row"});d.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),d.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Save"}).addEventListener("click",()=>void this.onSave(r.value).then(()=>this.close()))}onClose(){this.previewComponent.unload(),this.contentEl.empty()}};function Ys(g,i,t){let e=g.selectionStart,s=g.selectionEnd,a=g.value.slice(e,s),n=i+a+t;g.setRangeText(n,e,s,"select"),e===s&&(g.selectionStart=e+i.length,g.selectionEnd=e+i.length)}var rs=class extends W.Modal{constructor(t,e,s){super(t);this.existingNames=e;this.onSubmit=s}onOpen(){this.titleEl.setText("New custom list");let{contentEl:t}=this,e="",s=t.createDiv({cls:"wl-cl-name-error"});s.hide(),new W.Setting(t).setName("List name").addText(r=>{r.setPlaceholder("E.g. Marvel movies").onChange(o=>{e=o,s.hide()}),window.setTimeout(()=>r.inputEl.focus(),0),r.inputEl.addEventListener("keydown",o=>{o.key==="Enter"&&(o.preventDefault(),a())})});let a=()=>{let r=e.trim();if(!r){s.textContent="Please enter a name.",s.show();return}if(this.existingNames.includes(r)){s.textContent=`A list named "${r}" already exists.`,s.show();return}this.close(),this.onSubmit(r)},n=t.createDiv({cls:"wl-modal-btn-row"});n.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),n.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Create"}).addEventListener("click",a)}onClose(){this.contentEl.empty()}},oi=class{constructor(i,t,e){this.listNames=[];this.activeListName=null;this.currentList=null;this.sortCol=null;this.sortDir="asc";this.searchQuery="";this.duplicatedRowIds=new Set;this._escapeKeyHandler=null;this.activeCleanups=[];this.renderGeneration=0;this.saveQueues=new Map;this._countEl=null;this._tableContainer=null;this.container=i,this.plugin=t,this.dataManager=e,this.manager=new te(t.app,t)}applyTabOrder(i){var a;let e=((a=this.plugin.settings.customListTabOrder)!=null?a:[]).filter(n=>i.includes(n)),s=i.filter(n=>!e.includes(n));return[...e,...s]}destroy(){for(let i of this.activeCleanups)try{i()}catch(t){}if(this.activeCleanups=[],this._escapeKeyHandler){try{activeDocument.removeEventListener("keydown",this._escapeKeyHandler)}catch(i){}this._escapeKeyHandler=null}}addCleanup(i){this.activeCleanups.push(i)}saveSerialized(i,t){var a;let s=((a=this.saveQueues.get(i))!=null?a:Promise.resolve()).then(t).catch(n=>console.error("[WL] custom-list save failed:",n));return this.saveQueues.set(i,s),s}async render(){var s;let i=++this.renderGeneration;this.destroy(),this.container.empty(),this.container.addClass("wl-custom-lists");let t=this.manager.listNames();if(this.listNames=this.applyTabOrder(t),this.listNames.length===0){this.buildEmptyState();return}(!this.activeListName||!this.listNames.includes(this.activeListName))&&(this.activeListName=(s=this.listNames[0])!=null?s:null),this.activeListName&&(this.currentList=await this.manager.loadList(this.activeListName));let e=await this.manager.loadTabColors(this.listNames);i===this.renderGeneration&&(this.container.empty(),this.buildSubTabs(e),this.currentList&&this.buildListView(this.currentList))}buildEmptyState(){let i=this.container.createDiv({cls:"wl-cl-empty-state"});i.createDiv({cls:"wl-cl-empty-text",text:"No custom lists yet."}),i.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Create your first list"}).addEventListener("click",()=>this.promptCreateList())}buildSubTabs(i){let t=this.container.createDiv({cls:"wl-cl-sub-tabs"}),e=null;for(let a of this.listNames){let n=t.createDiv({cls:`wl-cl-sub-tab${a===this.activeListName?" is-active":""}`});n.setAttribute("draggable","true");let r=n.createSpan({cls:"wl-cl-sub-tab-name",text:a}),o=i.get(a);o&&(r.style.color=o),r.addEventListener("dblclick",c=>{c.stopPropagation(),this.startRenameTab(n,r,a)}),n.createSpan({cls:"wl-cl-sub-tab-del",text:"\xD7"}).addEventListener("click",c=>{c.stopPropagation(),this.deleteList(a)}),n.addEventListener("click",()=>{this.activeListName!==a&&(this.activeListName=a,this.sortCol=null,this.sortDir="asc",this.searchQuery="",this.duplicatedRowIds.clear(),this.render())}),n.addEventListener("dragstart",c=>{var d;e=a,(d=c.dataTransfer)==null||d.setData("text/plain",a),n.addClass("wl-cl-dragging")}),n.addEventListener("dragend",()=>n.removeClass("wl-cl-dragging")),n.addEventListener("dragover",c=>{c.preventDefault(),n.addClass("wl-cl-drag-over")}),n.addEventListener("dragleave",()=>n.removeClass("wl-cl-drag-over")),n.addEventListener("drop",c=>{if(c.preventDefault(),n.removeClass("wl-cl-drag-over"),!e||e===a)return;let d=this.listNames.indexOf(e),u=this.listNames.indexOf(a);d<0||u<0||(this.listNames.splice(d,1),this.listNames.splice(u,0,e),this.plugin.settings.customListTabOrder=[...this.listNames],this.plugin.saveSettings().then(()=>void this.render()))})}t.createEl("button",{cls:"wl-cl-sub-tab-add wl-btn-success",text:"+"}).addEventListener("click",()=>this.promptCreateList())}startRenameTab(i,t,e){t.hide();let s=i.createEl("input",{cls:"wl-cl-sub-tab-rename",attr:{type:"text",value:e}});s.focus(),s.select();let a=!1,n=async r=>{if(a||(a=!0,s.remove(),t.show(),!r))return;let o=s.value.trim();if(!(!o||o===e)){if(this.listNames.includes(o)){new W.Notice(`A list named "${o}" already exists.`);return}await this.manager.renameList(e,o),this.activeListName===e&&(this.activeListName=o),await this.render()}};s.addEventListener("keydown",r=>{r.key==="Enter"&&(r.preventDefault(),n(!0)),r.key==="Escape"&&n(!1)}),s.addEventListener("blur",()=>void n(!0))}promptCreateList(){new rs(this.plugin.app,this.listNames,i=>{var s;let t=((s=this.plugin.settings.defaultCustomColumns)!=null?s:[]).map(a=>({...a,id:a.id,options:a.options?[...a.options]:void 0,optionColors:a.optionColors?{...a.optionColors}:void 0})),e={name:i,columns:t,rows:[],notes:""};new ni(this.plugin.app,e,this.manager,async a=>{e.columns=a,await this.manager.saveList(e),this.activeListName=i,this.sortCol=null,this.sortDir="asc",this.searchQuery="",this.duplicatedRowIds.clear(),await this.render()}).open()}).open()}deleteList(i){new _(this.plugin.app,`Delete list "${i}"? This cannot be undone.`,()=>{(async()=>(await this.manager.deleteList(i),this.activeListName===i&&(this.activeListName=null,this.currentList=null),await this.render()))()}).open()}buildListView(i){let t=this.container.createDiv({cls:"wl-cl-list-view"}),e=t.createDiv({cls:"wl-cl-header"}),s=e.createSpan({cls:"wl-results-count wl-cl-count"}),a=e.createDiv({cls:"wl-cl-toolbar"});a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Notes"}).addEventListener("click",()=>{new ns(this.plugin.app,i.name,i.notes,async h=>{await this.manager.saveNotes(i.name,h),i.notes=h}).open()});let r=a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Sort"}),o=null;r.addEventListener("click",h=>{if(h.stopPropagation(),o){o.remove(),o=null;return}o=this.buildSortPanel(i,a,()=>{o=null}),activeDocument.addEventListener("click",()=>{o==null||o.remove(),o=null},{once:!0})}),a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Export"}).addEventListener("click",()=>this.exportToClipboard(i)),a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Import"}).addEventListener("click",()=>this.openImport(i)),a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Table settings"}).addEventListener("click",()=>{new ni(this.plugin.app,i,this.manager,async h=>{let p=new Set(h.map(m=>m.id));for(let m of i.rows)for(let f of Object.keys(m))f!=="id"&&f!=="name"&&f!=="checked"&&!p.has(f)&&delete m[f];i.columns=h;for(let m of h)m.type==="number"&&m.autoTime&&this.autoPopulateTimeColumn(i,m);await this.manager.saveList(i),await this.render()}).open()});let c=t.createDiv({cls:"wl-search-wrap"}).createEl("input",{cls:"wl-search-input",attr:{type:"text",placeholder:"Search...",value:this.searchQuery}}),d=null;c.addEventListener("input",()=>{this.searchQuery=c.value,d!==null&&window.clearTimeout(d),d=window.setTimeout(()=>{d=null,this._tableContainer&&this._countEl&&(this._tableContainer.empty(),this.buildTable(this._tableContainer,i,this._countEl))},250)}),this.plugin.settings.showHintBanners&&t.createDiv({cls:"wl-cl-draft-banner",text:"\u26A0 This is a draft list. Titles here are not included in any stats or counts."});let u=t.createDiv({cls:"wl-cl-table-wrap"});this.buildTable(u,i,s)}buildSortPanel(i,t,e){let s=t.createDiv({cls:"wl-cl-sort-panel"}),a=s.createDiv({cls:"wl-filter-row"});a.createSpan({cls:"wl-filter-label",text:"Sort by"});let n=a.createEl("select",{cls:"wl-select"});n.createEl("option",{value:"name",text:"Name"});for(let c of i.columns.filter(d=>!d.locked))n.createEl("option",{value:c.id,text:c.label});this.sortCol&&(n.value=this.sortCol);let r=s.createDiv({cls:"wl-filter-row"});r.createSpan({cls:"wl-filter-label",text:"Direction"});let o=r.createEl("select",{cls:"wl-select"});o.createEl("option",{value:"asc",text:"A \u2192 z"}),o.createEl("option",{value:"desc",text:"Z \u2192 a"}),o.value=this.sortDir;let l=s.createDiv({cls:"wl-modal-btn-row"});return l.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Clear sort"}).addEventListener("click",c=>{c.stopPropagation(),this.sortCol=null,this.sortDir="asc",e(),this.render()}),l.createEl("button",{cls:"wl-btn wl-btn-sm wl-btn-primary",text:"Apply"}).addEventListener("click",c=>{c.stopPropagation(),this.sortCol=n.value,this.sortDir=o.value,e(),this.render()}),s.addEventListener("click",c=>c.stopPropagation()),s}gatherExportData(i){let t=i.columns.filter(n=>!n.locked),e=[{id:"#",label:"#"},{id:"name",label:"Name"},...t],s=e.map(n=>n.label),a=this.getFilteredSortedRows(i).map((n,r)=>e.map(o=>{if(o.id==="#")return String(r+1);let l=n[o.id];return l!=null?String(l):""}));return{headers:s,rows:a}}buildMarkdown(i){let t="| "+i.headers.join(" | ")+" |",e="| "+i.headers.map(()=>"---").join(" | ")+" |",s=i.rows.map(a=>"| "+a.join(" | ")+" |");return[t,e,...s].join(` +`)}buildTsv(i){return[i.headers,...i.rows].map(t=>t.join(" ")).join(` +`)}exportToClipboard(i){new os(this.plugin.app,t=>{let e=this.gatherExportData(i),s=t==="tsv"?this.buildTsv(e):this.buildMarkdown(e);navigator.clipboard.writeText(s).then(()=>new W.Notice("Copied to clipboard!")).catch(()=>new W.Notice("Failed to copy to clipboard."))}).open()}openImport(i){new ls(this.plugin.app,i,this.manager,async()=>{await this.manager.saveList(i),await this.render()}).open()}getFilteredSortedRows(i){let t=[...i.rows];if(this.searchQuery.trim()){let e=this.searchQuery.toLowerCase();t=t.filter(s=>{var a;return String((a=s.name)!=null?a:"").toLowerCase().includes(e)})}if(this.sortCol){let e=this.sortCol,s=this.sortDir;t.sort((a,n)=>{var l,c;let r=String((l=a[e])!=null?l:"").toLowerCase(),o=String((c=n[e])!=null?c:"").toLowerCase();return s==="asc"?r.localeCompare(o):o.localeCompare(r)})}return t}buildTable(i,t,e){this._countEl=e,this._tableContainer=i;let s=this.getFilteredSortedRows(t);e.textContent=`${s.length} title${s.length!==1?"s":""}`;let a=t.columns.filter(f=>!f.locked),n=i.createDiv({cls:"wl-cl-table"}),o=n.createDiv({cls:"wl-cl-thead"}).createDiv({cls:"wl-cl-tr wl-cl-tr-header"}),l=o.createDiv({cls:"wl-cl-th wl-cl-th-tick"}),c=s.length>0&&s.every(f=>f.checked===!0),d=l.createDiv({cls:`wl-cl-tick-btn${c?" is-checked":""}`});d.title=c?"Uncheck all visible rows":"Check all visible rows",d.textContent=c?"\u2713":"\u25CB",d.addEventListener("click",()=>{let f=new Set(s.map(v=>v.id)),y=!c;for(let v of t.rows)f.has(v.id)&&(v.checked=y);this.manager.saveList(t).then(()=>{i.empty(),this.buildTable(i,t,e)})}),o.createDiv({cls:"wl-cl-th wl-cl-th-num",text:"#"});let u=o.createDiv({cls:"wl-cl-th",text:"Name"});u.dataset.wlCol="__name",this.addResizeHandle(u,"__name",t,n);for(let f of a){let y=o.createDiv({cls:"wl-cl-th"});if(y.dataset.wlCol=f.id,y.createSpan({text:f.label}),this.addResizeHandle(y,f.id,t,n),f.type==="number"&&f.autoTime){let v=y.createSpan({cls:"wl-cl-autotime-refresh",text:"\u21BB"});v.title="Refresh remaining time values",v.addEventListener("click",w=>{w.stopPropagation(),this.autoPopulateTimeColumn(t,f),this.manager.saveList(t).then(()=>{i.empty(),this.buildTable(i,t,e)})})}}o.createDiv({cls:"wl-cl-th wl-cl-th-actions"});let h=n.createDiv({cls:"wl-cl-tbody"}),p=-1;s.forEach((f,y)=>{let v=f.checked===!0,w=h.createDiv({cls:`wl-cl-tr wl-cl-tr-body${v?" wl-cl-tr-checked":""}`});w.dataset.rowId=f.id;let E=w.createDiv({cls:"wl-cl-td wl-cl-td-tick"}).createDiv({cls:`wl-cl-tick-btn${v?" is-checked":""}`});E.title=v?"Uncheck row":"Check row",E.textContent=v?"\u2713":"\u25CB",E.addEventListener("click",()=>{let C=t.rows.find(L=>L.id===f.id);C&&(C.checked=!C.checked,this.manager.saveList(t).then(()=>{i.empty(),this.buildTable(i,t,e)}))}),w.createDiv({cls:"wl-cl-td wl-cl-td-num",text:String(y+1)});let D=w.createDiv({cls:"wl-cl-td wl-cl-td-name"});D.dataset.wlCol="__name",this.renderNameCell(D,f,t,e,a,i);for(let C of a){let L=w.createDiv({cls:"wl-cl-td"});L.dataset.wlCol=C.id,this.renderCustomCell(L,f,C,t)}let S=w.createDiv({cls:"wl-cl-td wl-cl-td-actions"}),T=S.createDiv({cls:"wl-cl-row-action wl-cl-drag-handle",text:"\u283F"});T.title="Drag to reorder";let M=S.createDiv({cls:"wl-cl-row-action wl-cl-dup-btn",text:"\u29C9"});M.title="Duplicate row",M.addEventListener("click",()=>{let C=t.rows.findIndex(I=>I.id===f.id);if(C<0)return;let L={...t.rows[C],id:this.manager.generateRowId(t.rows)};t.rows.splice(C+1,0,L),this.duplicatedRowIds.add(L.id),this.manager.saveList(t).then(()=>{i.empty(),this.buildTable(i,t,e)})});let x=S.createDiv({cls:"wl-cl-row-action wl-cl-row-del",text:"\xD7"});x.title="Delete row",x.addEventListener("click",()=>{t.rows=t.rows.filter(C=>C.id!==f.id),this.duplicatedRowIds.delete(f.id),this.manager.saveList(t).then(()=>{i.empty(),this.buildTable(i,t,e)})}),w.setAttribute("draggable","false"),T.addEventListener("mousedown",()=>w.setAttribute("draggable","true")),w.addEventListener("dragstart",C=>{var L;p=t.rows.findIndex(I=>I.id===f.id),(L=C.dataTransfer)==null||L.setData("text/plain",f.id),w.addClass("wl-cl-dragging")}),w.addEventListener("dragend",()=>{w.removeClass("wl-cl-dragging"),w.setAttribute("draggable","false")}),w.addEventListener("dragover",C=>{C.preventDefault(),w.addClass("wl-cl-drag-over")}),w.addEventListener("dragleave",()=>w.removeClass("wl-cl-drag-over")),w.addEventListener("drop",C=>{C.preventDefault(),w.removeClass("wl-cl-drag-over");let L=t.rows.findIndex(I=>I.id===f.id);if(p!==L&&p>=0){let[I]=t.rows.splice(p,1);t.rows.splice(p{i.empty(),this.buildTable(i,t,e)})}})}),this.applyColumnWidths(n,t),i.createDiv({cls:"wl-cl-add-row"}).createEl("button",{cls:"wl-btn wl-btn-sm wl-btn-success",text:"+ add row"}).addEventListener("click",()=>{let f={id:this.manager.generateRowId(t.rows),name:""};t.rows.push(f),this.manager.saveList(t).then(()=>{i.empty(),this.buildTable(i,t,e),window.setTimeout(()=>{var w;let y=i.querySelector(".wl-cl-tbody"),v=y==null?void 0:y.querySelector(".wl-cl-tr-body:last-child");(w=v==null?void 0:v.querySelector(".wl-cl-td-name"))==null||w.click()},0)})})}isTableResizable(i){return i.nameWidth!==void 0||i.columns.some(t=>!t.locked&&t.width!==void 0)}getColWidth(i,t){var e;return t==="__name"?i.nameWidth:(e=i.columns.find(s=>s.id===t))==null?void 0:e.width}setColWidth(i,t,e){if(t==="__name"){i.nameWidth=e;return}let s=i.columns.find(a=>a.id===t);s&&(s.width=e)}applyColumnWidths(i,t){if(!this.isTableResizable(t)){i.removeClass("wl-cl-table-resizable");return}i.addClass("wl-cl-table-resizable");let e=(s,a)=>{let n=a!=null?a:as;i.querySelectorAll(`[data-wl-col="${s}"]`).forEach(r=>{r.addClass("wl-cl-col-fixed"),r.setCssProps({"--wl-cl-cw":`${n}px`})})};e("__name",t.nameWidth);for(let s of t.columns)s.locked||e(s.id,s.width)}pinCurrentWidths(i,t){let e=s=>{let a=i.querySelector(`.wl-cl-th[data-wl-col="${s}"]`);return a?Math.round(a.getBoundingClientRect().width):as};t.nameWidth===void 0&&(t.nameWidth=e("__name"));for(let s of t.columns)s.locked||s.width!==void 0||(s.width=e(s.id))}addResizeHandle(i,t,e,s){if(W.Platform.isMobile)return;i.addClass("wl-cl-th-resizable"),i.createDiv({cls:"wl-cl-col-resize"}).addEventListener("mousedown",n=>{var d;n.preventDefault(),n.stopPropagation(),this.pinCurrentWidths(s,e),this.applyColumnWidths(s,e);let r=n.clientX,o=(d=this.getColWidth(e,t))!=null?d:as,l=u=>{let h=Math.max(kn,Math.round(o+(u.clientX-r)));this.setColWidth(e,t,h),s.querySelectorAll(`[data-wl-col="${t}"]`).forEach(p=>{p.setCssProps({"--wl-cl-cw":`${h}px`})})},c=()=>{activeDocument.removeEventListener("mousemove",l),activeDocument.removeEventListener("mouseup",c),activeDocument.body.removeClass("wl-cl-col-resizing"),this.manager.saveList(e)};activeDocument.addEventListener("mousemove",l),activeDocument.addEventListener("mouseup",c),activeDocument.body.addClass("wl-cl-col-resizing")})}renderNameCell(i,t,e,s,a,n){var l;i.empty(),i.removeClass("wl-cl-editing");let r=String((l=t.name)!=null?l:""),o=this.duplicatedRowIds.has(t.id);if(r){let c=i.createSpan({cls:"wl-cl-cell-text",text:r});o&&c.addClass("wl-cl-dup-name")}else i.createSpan({cls:"wl-cl-cell-empty",text:"\u2014"});i.addEventListener("click",()=>{this.startNameEdit(i,t,e,s,a,n)},{once:!0})}startNameEdit(i,t,e,s,a,n){var v;let r=String((v=t.name)!=null?v:"");i.empty(),i.addClass("wl-cl-editing"),this._escapeKeyHandler=w=>{w.key==="Escape"&&(w.stopPropagation(),w.stopImmediatePropagation(),w.preventDefault())},activeDocument.addEventListener("keydown",this._escapeKeyHandler,!0),activeDocument.addEventListener("keyup",this._escapeKeyHandler,!0);let o=this._escapeKeyHandler;this.addCleanup(()=>{activeDocument.removeEventListener("keydown",o,!0),activeDocument.removeEventListener("keyup",o,!0)});let l=()=>{let w=activeDocument.activeElement;w&&w.scrollIntoView({behavior:"smooth",block:"center"})};window.visualViewport&&window.visualViewport.addEventListener("resize",l),this.addCleanup(()=>{window.visualViewport&&window.visualViewport.removeEventListener("resize",l)}),window.setTimeout(()=>i.scrollIntoView({block:"nearest",behavior:"smooth"}),50);let d=i.createDiv({cls:"wl-cl-autofill-wrap"}).createEl("input",{cls:"wl-cl-cell-input",attr:{type:"text",value:r}});d.focus(),d.select();let u=null,h=-1,p=()=>{u==null||u.remove(),u=null,h=-1};d.addEventListener("input",()=>{p();let w=d.value.toLowerCase();if(!w)return;let b=this.plugin.readingDataManager,E=[...this.dataManager.getTitles().map(S=>({title:S.title,meta:`${S.type} \xB7 ${S.status}`})),...b.getBooks().map(S=>({title:S.title,meta:`Book \xB7 ${S.status}`})),...b.getMangaList().map(S=>({title:S.title,meta:`Manga \xB7 ${S.status}`}))].filter(S=>S.title.toLowerCase().includes(w)).slice(0,10);if(!E.length)return;let D=d.getBoundingClientRect();u=activeDocument.body.createDiv({cls:"wl-cl-autofill-dropdown wl-pos-fixed"}),u.style.top=`${D.bottom}px`,u.style.left=`${D.left}px`,u.style.width=`${D.width}px`;for(let S of E){let T=u.createDiv({cls:"wl-result-item"});T.createDiv({cls:"wl-result-title",text:S.title}),T.createDiv({cls:"wl-result-meta",text:S.meta}),T.addEventListener("mousedown",M=>{M.preventDefault(),d.value=S.title,p()})}});let m=!1,f=null,y=async w=>{if(m)return;m=!0,window.visualViewport&&window.visualViewport.removeEventListener("resize",l),this._escapeKeyHandler&&(activeDocument.removeEventListener("keydown",this._escapeKeyHandler,!0),activeDocument.removeEventListener("keyup",this._escapeKeyHandler,!0),this._escapeKeyHandler=null),p();let b=d.value.trim();if(!w){let E=this.duplicatedRowIds.has(t.id);t.name=b,E&&b!==r&&this.duplicatedRowIds.delete(t.id),await this.manager.saveList(e)}this.renderNameCell(i,t,e,s,a,n),!w&&f&&this.navigateCell(i,f)};d.addEventListener("blur",()=>void y(!1)),d.addEventListener("keydown",w=>{var b,E,D;if(u){let S=Array.from(u.querySelectorAll(".wl-result-item"));if(w.key==="ArrowDown"){w.preventDefault(),h=Math.min(h+1,S.length-1),S.forEach((T,M)=>{M===h?T.addClass("wl-result-item-focused"):T.removeClass("wl-result-item-focused")});return}if(w.key==="ArrowUp"){w.preventDefault(),h=Math.max(h-1,0),S.forEach((T,M)=>{M===h?T.addClass("wl-result-item-focused"):T.removeClass("wl-result-item-focused")});return}if(w.key==="Enter"&&h>=0){w.preventDefault();let T=(D=(E=(b=S[h])==null?void 0:b.querySelector(".wl-result-title"))==null?void 0:E.textContent)!=null?D:"";T&&(d.value=T),p();return}if(w.key==="Escape"){w.preventDefault(),w.stopPropagation(),w.stopImmediatePropagation(),p();return}}w.key==="Tab"&&w.shiftKey?(w.preventDefault(),f="shift-tab",y(!1)):w.key==="Tab"?(w.preventDefault(),f="tab",y(!1)):w.key==="Enter"?(w.preventDefault(),f="enter",y(!1)):w.key==="Escape"&&(w.preventDefault(),w.stopPropagation(),w.stopImmediatePropagation(),y(!0))})}renderCustomCell(i,t,e,s){var n;i.empty(),i.removeClass("wl-cl-editing");let a=t[e.id];if(e.type==="select"){let r=String(a!=null?a:"");if(r){let o=i.createSpan({cls:"wl-cl-select-badge",text:r}),l=(n=e.optionColors)==null?void 0:n[r];l&&(o.style.backgroundColor=Zt(l),o.style.borderColor=Gt(l),o.style.color=Gt(l))}else i.createSpan({cls:"wl-cl-cell-empty",text:"\u2014"})}else{let r=a!=null&&a!==""?String(a):"";if(r){let o=i.createSpan({cls:"wl-cl-cell-text",text:r});e.bold&&o.addClass("wl-cell-bold"),e.italic&&o.addClass("wl-cell-italic")}else i.createSpan({cls:"wl-cl-cell-empty",text:"\u2014"})}i.addEventListener("click",()=>{e.type==="select"?this.openSelectDropdown(i,t,e,s):this.startCustomEdit(i,t,e,s)},{once:!0})}openSelectDropdown(i,t,e,s){var r,o;let a=String((r=t[e.id])!=null?r:""),n=[{value:"",label:"\u2014"},...((o=e.options)!=null?o:[]).map(l=>({value:l,label:l}))];Xt({anchor:i,container:activeDocument.body,options:n,getOptionColor:l=>{var c,d;return(d=(c=e.optionColors)==null?void 0:c[l])!=null?d:null},onSelect:l=>{l!==a?(t[e.id]=l===""?void 0:l,this.manager.saveList(s).then(()=>this.renderCustomCell(i,t,e,s))):this.renderCustomCell(i,t,e,s)},onClose:()=>this.renderCustomCell(i,t,e,s)})}startCustomEdit(i,t,e,s){let a=t[e.id];i.empty(),i.addClass("wl-cl-editing");let n=()=>{let d=activeDocument.activeElement;d&&d.scrollIntoView({behavior:"smooth",block:"center"})};window.visualViewport&&window.visualViewport.addEventListener("resize",n),this.addCleanup(()=>{window.visualViewport&&window.visualViewport.removeEventListener("resize",n)}),window.setTimeout(()=>i.scrollIntoView({block:"nearest",behavior:"smooth"}),50);let r,o=!1,l=null,c=async d=>{if(!o){if(o=!0,window.visualViewport&&window.visualViewport.removeEventListener("resize",n),this._escapeKeyHandler&&(activeDocument.removeEventListener("keydown",this._escapeKeyHandler,!0),activeDocument.removeEventListener("keyup",this._escapeKeyHandler,!0),this._escapeKeyHandler=null),i.removeClass("wl-cl-editing"),!d){let u=r();t[e.id]=u===""||u===void 0?void 0:u,await this.manager.saveList(s)}this.renderCustomCell(i,t,e,s),!d&&l&&this.navigateCell(i,l)}};if(e.type==="number"){let d=i.createEl("input",{cls:"wl-cl-cell-input",attr:{type:"number",value:a!=null?String(a):""}});r=()=>{let u=parseFloat(d.value);return isNaN(u)?"":u},d.focus(),d.select(),d.addEventListener("blur",()=>void c(!1)),d.addEventListener("keydown",u=>{u.key==="Enter"?(u.preventDefault(),l="enter",c(!1)):u.key==="Tab"&&u.shiftKey?(u.preventDefault(),l="shift-tab",c(!1)):u.key==="Tab"?(u.preventDefault(),l="tab",c(!1)):u.key==="Escape"&&(u.preventDefault(),u.stopPropagation(),u.stopImmediatePropagation(),c(!0))})}else{let d=i.createEl("input",{cls:"wl-cl-cell-input",attr:{type:"text",value:a!=null?String(a):""}});r=()=>d.value,d.focus(),d.select(),d.addEventListener("blur",()=>void c(!1)),d.addEventListener("keydown",u=>{u.key==="Enter"?(u.preventDefault(),l="enter",c(!1)):u.key==="Tab"&&u.shiftKey?(u.preventDefault(),l="shift-tab",c(!1)):u.key==="Tab"?(u.preventDefault(),l="tab",c(!1)):u.key==="Escape"&&(u.preventDefault(),u.stopPropagation(),u.stopImmediatePropagation(),c(!0))})}}autoPopulateTimeColumn(i,t){var s;let e=this.dataManager.getTitles();for(let a of i.rows){let n=String((s=a.name)!=null?s:"").trim();if(!n)continue;let r=e.find(l=>l.title===n);if(!r){a[t.id]="Not found";continue}let o=this.dataManager.calcTimeRemainingForModal(r);a[t.id]=o}}getEditableCells(i){return Array.from(i.querySelectorAll(":scope > .wl-cl-td")).filter(t=>!t.classList.contains("wl-cl-td-num")&&!t.classList.contains("wl-cl-td-actions"))}navigateCell(i,t){let e=i.closest(".wl-cl-tr-body");if(!e)return;let s=e.parentElement;if(!s)return;let a=Array.from(s.querySelectorAll(":scope > .wl-cl-tr-body")),n=a.indexOf(e),r=this.getEditableCells(e),o=r.indexOf(i);if(t==="tab")if(o>=0&&o{var l;return(l=r[o+1])==null?void 0:l.click()},10);else if(n>=0&&n{var d;return(d=c[0])==null?void 0:d.click()},10)}}else this.addRowForNavigation(0);else if(t==="shift-tab"){if(o>0)window.setTimeout(()=>{var l;return(l=r[o-1])==null?void 0:l.click()},10);else if(n>0){let l=a[n-1];if(l){let c=this.getEditableCells(l);c.length&&window.setTimeout(()=>{var d;return(d=c[c.length-1])==null?void 0:d.click()},10)}}}else if(n>=0&&n=0?o:0,c.length-1);c.length&&window.setTimeout(()=>{var u;return(u=c[d])==null?void 0:u.click()},10)}}else this.addRowForNavigation(o>=0?o:0)}addRowForNavigation(i){let t=this.currentList,e=this._tableContainer,s=this._countEl;if(!t||!e||!s)return;let a={id:this.manager.generateRowId(t.rows),name:""};t.rows.push(a),this.manager.saveList(t).then(()=>{e.empty(),this.buildTable(e,t,s),window.setTimeout(()=>{let n=e.querySelector(".wl-cl-tbody");if(!n)return;let r=Array.from(n.querySelectorAll(".wl-cl-tr-body")),o=r[r.length-1];if(!o)return;let l=this.getEditableCells(o),c=l[Math.min(i,l.length-1)];c==null||c.click()},50)})}},os=class extends W.Modal{constructor(i,t){super(i),this.onChoose=t}onOpen(){this.titleEl.setText("Export list"),this.contentEl.addClass("wl-export-modal"),this.contentEl.createDiv({cls:"wl-settings-info",text:"TSV pastes into spreadsheets as columns. Markdown produces a table you can paste into notes."});let i=this.contentEl.createDiv({cls:"wl-modal-btn-row"});i.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Copy as TSV"}).addEventListener("click",()=>{this.close(),this.onChoose("tsv")}),i.createEl("button",{cls:"wl-btn",text:"Copy as Markdown"}).addEventListener("click",()=>{this.close(),this.onChoose("md")})}onClose(){this.contentEl.empty()}},ls=class extends W.Modal{constructor(t,e,s,a){super(t);this.firstRowIsHeader=!0;this.list=e,this.manager=s,this.onApplied=a}onOpen(){this.titleEl.setText("Import rows"),this.contentEl.addClass("wl-import-modal"),this.contentEl.createDiv({cls:"wl-settings-info",text:"Paste tab-separated values copied from a spreadsheet (Google Sheets / Excel). Rows are appended to the end of the list. Do not include an index/# column \u2014 rows are numbered automatically."}),this.textarea=this.contentEl.createEl("textarea",{cls:"wl-modal-textarea wl-import-textarea",attr:{placeholder:"Paste here\u2026",rows:"8"}}),this.textarea.addEventListener("input",()=>this.refreshPreview());let t=this.contentEl.createDiv({cls:"wl-import-header-toggle"}),e=t.createEl("input",{cls:"wl-import-header-checkbox",attr:{type:"checkbox",id:"wl-import-header-cb"}});e.checked=this.firstRowIsHeader,t.createEl("label",{text:"First row is a header (column names, not imported as data)",attr:{for:"wl-import-header-cb"}}),e.addEventListener("change",()=>{this.firstRowIsHeader=e.checked,this.refreshPreview()}),this.previewEl=this.contentEl.createDiv({cls:"wl-import-preview"});let s=this.contentEl.createDiv({cls:"wl-modal-btn-row"});this.addBtn=s.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Add"}),this.addBtn.addEventListener("click",()=>void this.apply()),s.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),this.refreshPreview()}onClose(){this.contentEl.empty()}parse(){let t=this.textarea.value.replace(/\r\n?/g,` +`).split(` +`).filter(a=>a.length>0);if(t.length===0)return null;if(!this.firstRowIsHeader)return{header:[],dataRows:t.map(a=>a.split(" ").map(n=>n.trim()))};let[e,...s]=t;return{header:e.split(" ").map(a=>a.trim()),dataRows:s.map(a=>a.split(" ").map(n=>n.trim()))}}nonLockedColumns(){return this.list.columns.filter(t=>!t.locked)}analyse(){var l;let t=this.parse();if(!t||t.dataRows.length===0)return null;let e=this.nonLockedColumns(),s=1+e.length,a=Math.max(t.header.length,...t.dataRows.map(c=>c.length)),n=Math.max(0,a-s),r=new Set,o=new Map;for(let c of t.dataRows)for(let d=1;d({label:c.label,values:[...c.values]})),numberConflicts:[...r]}}refreshPreview(){this.previewEl.empty();let t=this.analyse();if(!t){this.addBtn.disabled=!0,this.previewEl.createDiv({cls:"wl-import-counts",text:"Paste TSV data to preview the import."});return}this.previewEl.createDiv({cls:"wl-import-counts",text:`${t.rowCount} row${t.rowCount===1?"":"s"} \xD7 ${t.totalCols} column${t.totalCols===1?"":"s"} detected.`});let e=t.numberConflicts.length>0;t.newColCount>0&&this.previewEl.createDiv({cls:"wl-import-banner",text:`\u26A0 ${t.newColCount} new text column${t.newColCount===1?"":"s"} will be created to match the pasted data.`});for(let s of t.selectAdditions)this.previewEl.createDiv({cls:"wl-import-banner",text:`\u26A0 Select column "${s.label}" will gain ${s.values.length} new option${s.values.length===1?"":"s"}: ${s.values.join(", ")}.`});t.totalCols0)return;let e=this.list,s=this.nonLockedColumns(),a=[];for(let c=t.existingCount;c(u.label||"(unnamed)")===c.label&&u.type==="select");if(d){d.options=[...(o=d.options)!=null?o:[]];for(let u of c.values)d.options.includes(u)||d.options.push(u)}}for(let c of t.dataRows){let d={id:this.manager.generateRowId(e.rows),name:""};e.rows.push(d);for(let u=0;uthis.openLinkedVaultPage()),this.refreshVaultButtons()}refreshVaultButtons(){if(this.linkVaultBtn&&(this.linkVaultBtn.textContent=this.state.vaultPage?"Change link":"Link",this.linkVaultBtn.title=this.state.vaultPage?`Linked: ${this.state.vaultPage}`:"Link a vault note to this entry"),this.openVaultBtn){let t=!!this.state.vaultPage;this.openVaultBtn.disabled=!t,this.openVaultBtn.toggleClass("is-hidden",!t)}}openLinkedVaultPage(){let t=this.state.vaultPage;if(!t)return;let e=this.plugin.app.vault.getAbstractFileByPath(t);e instanceof lt.TFile?(this.plugin.app.workspace.getLeaf("tab").openFile(e),this.close()):new lt.Notice("Linked vault page no longer exists.")}renderLookupBar(t){let e=t.createDiv({cls:"wl-reading-lookup"}),s=e.createEl("input",{cls:"wl-modal-input wl-reading-lookup-input",attr:{type:"text",placeholder:this.mode==="book"?"Search by title or ISBN...":"Search by title or MAL ID..."}}),a=e.createEl("button",{cls:"wl-btn wl-reading-lookup-btn",text:"Fetch"});this.lookupResultsEl=t.createDiv({cls:"wl-reading-lookup-results"}),this.prefillSearch&&(s.value=this.prefillSearch);let n=()=>{let r=s.value.trim();if(!r){new lt.Notice("Enter a search term first.");return}this.performLookup(r)};a.addEventListener("click",n),s.addEventListener("keydown",r=>{r.key==="Enter"&&(r.preventDefault(),n())})}async performLookup(t){let e=++this.lookupSearchGen;if(this.lookupResultsEl){this.lookupResultsEl.empty(),this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-loading",text:"Searching..."});try{if(this.mode==="book"){if(!this.plugin.apiService.hasGoogleBooksKey()){if(e!==this.lookupSearchGen)return;this.lookupResultsEl.empty(),this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-empty",text:"Google Books API key required \u2014 add one in Settings \u2192 API \u2192 Books."});return}let s=await this.plugin.apiService.searchGoogleBooks(t);if(e!==this.lookupSearchGen)return;this.renderBookLookupResults(s)}else{let s=/^\d+$/.test(t),a;if(s){let n=await this.plugin.apiService.getMangaByMalId(parseInt(t,10));if(e!==this.lookupSearchGen)return;a=n?[n]:[]}else if(a=await this.plugin.apiService.searchManga(t),e!==this.lookupSearchGen)return;this.renderMangaLookupResults(a)}}catch(s){if(e!==this.lookupSearchGen)return;this.lookupResultsEl.empty();let a=this.mode==="book"?It(s):"Lookup failed. Check your connection.";this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-empty",text:a})}}}renderBookLookupResults(t){if(this.lookupResultsEl){if(this.lookupResultsEl.empty(),t.length===0){this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-empty",text:"No matches."});return}for(let e of t){let s=this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-item"});ve(s,e.coverUrl,e.title,"\u{1F4D6}");let a=s.createDiv({cls:"wl-reading-lookup-item-text"});this.renderLookupItemTitle(a,e.title,e.url);let n=[e.author||"Unknown author",e.year?String(e.year):""].filter(Boolean).join(" \xB7 ");a.createDiv({cls:"wl-reading-lookup-item-meta",text:n}),s.addEventListener("click",()=>this.applyBookResult(e))}}}renderLookupItemTitle(t,e,s){let a=t.createDiv({cls:"wl-reading-lookup-item-title-row"});if(a.createDiv({cls:"wl-reading-lookup-item-title",text:e||"(untitled)"}),s){let n=a.createEl("a",{cls:"wl-acc-link-icon",text:"\u{1F310}"});n.href=s,n.title="Open external link",n.target="_blank",n.rel="noopener noreferrer",n.addEventListener("click",r=>r.stopPropagation())}}renderMangaLookupResults(t){if(this.lookupResultsEl){if(this.lookupResultsEl.empty(),t.length===0){this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-empty",text:"No matches."});return}for(let e of t){let s=this.lookupResultsEl.createDiv({cls:"wl-reading-lookup-item"});ve(s,e.coverUrl,e.title,"\u{1F4D3}");let a=s.createDiv({cls:"wl-reading-lookup-item-text"});this.renderLookupItemTitle(a,e.title,e.url);let n=[e.author||"Unknown author",e.year?String(e.year):""].filter(Boolean).join(" \xB7 ");a.createDiv({cls:"wl-reading-lookup-item-meta",text:n}),s.addEventListener("click",()=>this.applyMangaResult(e))}}}applyBookResult(t){var s;let e=++this.selectGen;this.state.title=t.title,this.state.author=t.author,this.state.totalPages=t.totalPages,this.state.coverUrl=t.coverUrl,this.state.googleBooksId=t.googleBooksId,this.state.releaseDate=(s=t.releaseDate)!=null?s:"",this.refreshForm(),t.googleBooksId&&(async()=>{try{let a=await this.plugin.apiService.getGoogleBookById(t.googleBooksId);if(e!==this.selectGen||!a)return;a.totalPages>0&&(this.state.totalPages=a.totalPages),a.coverUrl&&(this.state.coverUrl=a.coverUrl),this.refreshForm()}catch(a){}})()}applyMangaResult(t){var s;let e=++this.selectGen;this.state.title=t.title,this.state.author=t.author,this.state.totalChapters=t.totalChapters,this.state.totalVolumes=t.totalVolumes,this.state.coverUrl=t.coverUrl,this.state.malId=t.malId>0?String(t.malId):"",this.state.releaseDate=(s=t.releaseDate)!=null?s:"",this.refreshForm(),t.malId>0&&(async()=>{let a=await this.plugin.apiService.getMangaByMalId(t.malId);e!==this.selectGen||!a||(this.state.totalChapters=a.totalChapters>0?a.totalChapters:this.state.totalChapters,this.state.totalVolumes=a.totalVolumes>0?a.totalVolumes:this.state.totalVolumes,this.refreshForm())})()}refreshForm(){this.formEl&&(this.formEl.empty(),this.renderForm(this.formEl))}renderForm(t){let e=t.createDiv({cls:"wl-reading-form"});this.renderTextField(e,"Title","Book title",this.state.title,s=>{this.state.title=s}),this.renderTextField(e,"Author","Author name",this.state.author,s=>{this.state.author=s}),this.renderStatusRatingRow(e),this.renderProgressOptionalGrid(e)}renderProgressOptionalGrid(t){let e=t.createDiv({cls:"wl-reading-form-grid"}),s=e.createDiv({cls:"wl-reading-form-grid-col"});s.createDiv({cls:"wl-reading-section-label",text:"Progress"}),this.mode==="book"?(this.renderTwoNumberRow(s,{label:"Pages read",value:this.state.pagesRead,onChange:n=>{this.state.pagesRead=n}},{label:"Chapters read",value:this.state.chaptersRead,onChange:n=>{this.state.chaptersRead=n}}),this.renderTwoNumberRow(s,{label:"Total pages",value:this.state.totalPages,onChange:n=>{this.state.totalPages=n}},{label:"Total chapters",value:this.state.totalChapters,onChange:n=>{this.state.totalChapters=n}})):(this.renderTwoNumberRow(s,{label:"Chapters read",value:this.state.chaptersRead,onChange:n=>{this.state.chaptersRead=n}},{label:"Volumes read",value:this.state.volumesRead,onChange:n=>{this.state.volumesRead=n}}),this.renderTwoNumberRow(s,{label:"Total chapters",value:this.state.totalChapters,onChange:n=>{this.state.totalChapters=n}},{label:"Total volumes",value:this.state.totalVolumes,onChange:n=>{this.state.totalVolumes=n}}));let a=e.createDiv({cls:"wl-reading-form-grid-col"});a.createDiv({cls:"wl-reading-section-label",text:"Optional"}),this.renderTextField(a,"Cover URL","https://...",this.state.coverUrl,n=>{this.state.coverUrl=n}),this.renderDateField(a,"Start date",this.state.dateStarted,n=>{this.state.dateStarted=n}),this.renderDateField(a,"Release date",this.state.releaseDate,n=>{this.state.releaseDate=n})}renderTextField(t,e,s,a,n){let r=t.createDiv({cls:"wl-reading-row"});r.createSpan({cls:"wl-reading-label",text:e});let o=r.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:s}});o.value=a,o.addEventListener("input",()=>n(o.value))}renderStatusRatingRow(t){let e=t.createDiv({cls:"wl-reading-status-rating-row"}),s=e.createDiv({cls:"wl-reading-inline-group"});s.createSpan({cls:"wl-reading-label",text:"Status"});let a=s.createEl("select",{cls:"wl-select wl-reading-status-select"});for(let r of ct){let o=a.createEl("option",{text:r,value:r});r===this.state.status&&(o.selected=!0)}a.addEventListener("change",()=>{this.state.status=a.value});let n=e.createDiv({cls:"wl-reading-inline-group"});n.createSpan({cls:"wl-reading-label",text:"Rating"}),this.starsWrap=n.createDiv({cls:"wl-stars wl-reading-stars"}),this.renderStars()}renderStars(){if(this.starsWrap){this.starsWrap.empty();for(let t=1;t<=5;t++)this.starsWrap.createSpan({cls:`wl-star${this.state.rating>=t?" is-active":""}`,text:"\u2605"}).addEventListener("click",()=>{this.state.rating=this.state.rating===t?0:t,this.renderStars()})}}renderTwoNumberRow(t,e,s){let a=t.createDiv({cls:"wl-reading-row wl-reading-row-split"});this.renderNumberCol(a,e),this.renderNumberCol(a,s)}renderNumberCol(t,e){let s=t.createDiv({cls:"wl-reading-col"});s.createSpan({cls:"wl-reading-label",text:e.label});let a=s.createEl("input",{cls:"wl-modal-input wl-modal-input-sm",attr:{type:"number",min:"0"}});a.value=String(e.value),a.addEventListener("input",()=>{let n=parseInt(a.value,10);e.onChange(isNaN(n)||n<0?0:n)})}renderDateField(t,e,s,a){let n=t.createDiv({cls:"wl-reading-row"});n.createSpan({cls:"wl-reading-label",text:e});let r=n.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"DD/MM/YYYY",maxlength:"10"}});r.value=s?Q(s):"",r.addEventListener("change",()=>{let o=r.value.trim();if(!o){r.removeClass("wl-input-error"),a(null);return}let l=q(o);l?(r.removeClass("wl-input-error"),a(l)):r.addClass("wl-input-error")})}renderFooter(t){let e=t.createDiv({cls:"wl-reading-modal-footer"});e.createEl("button",{cls:"wl-btn",text:"Cancel"}).addEventListener("click",()=>this.close()),e.createEl("button",{cls:"wl-reading-add-btn wl-btn-success wl-reading-modal-save",text:this.saveButtonLabel()}).addEventListener("click",()=>void this.save())}saveButtonLabel(){return this.existingId?"Save changes":this.mode==="book"?"Add book":"Add manga"}async save(){let t=this.state.title.trim();if(!t){new lt.Notice("Please enter a title.");return}this.mode==="book"?await this.saveBook(t):await this.saveManga(t),this.onSaved(),this.close()}async saveBook(t){if(this.existingId){let e=this.readingData.getBook(this.existingId);if(!e){new lt.Notice("Original book no longer exists.");return}let s={...e,title:t,author:this.state.author.trim(),status:this.state.status,rating:this.state.rating,pagesRead:this.state.pagesRead,totalPages:this.state.totalPages,chaptersRead:this.state.chaptersRead,totalChapters:this.state.totalChapters,coverUrl:this.state.coverUrl.trim(),googleBooksId:this.state.googleBooksId.trim(),vaultPage:this.state.vaultPage,dateStarted:this.state.dateStarted,dateFinished:this.state.dateFinished,releaseDate:this.state.releaseDate};await this.readingData.updateBook(s)}else{let e=new Date().toISOString(),s={id:this.readingData.generateBookId(t),title:t,author:this.state.author.trim(),status:this.state.status,rating:this.state.rating,pagesRead:this.state.pagesRead,totalPages:this.state.totalPages,chaptersRead:this.state.chaptersRead,totalChapters:this.state.totalChapters,coverUrl:this.state.coverUrl.trim(),googleBooksId:this.state.googleBooksId.trim(),vaultPage:this.state.vaultPage,dateStarted:this.state.dateStarted,dateFinished:this.state.dateFinished,releaseDate:this.state.releaseDate,dateAdded:e,dateModified:e,customFields:{}};await this.readingData.addBook(s)}}async saveManga(t){if(this.existingId){let e=this.readingData.getManga(this.existingId);if(!e){new lt.Notice("Original manga no longer exists.");return}let s={...e,title:t,author:this.state.author.trim(),status:this.state.status,rating:this.state.rating,chaptersRead:this.state.chaptersRead,totalChapters:this.state.totalChapters,volumesRead:this.state.volumesRead,totalVolumes:this.state.totalVolumes,coverUrl:this.state.coverUrl.trim(),malId:this.state.malId.trim(),vaultPage:this.state.vaultPage,dateStarted:this.state.dateStarted,dateFinished:this.state.dateFinished,releaseDate:this.state.releaseDate};await this.readingData.updateManga(s)}else{let e=new Date().toISOString(),s={id:this.readingData.generateMangaId(t),title:t,author:this.state.author.trim(),status:this.state.status,rating:this.state.rating,chaptersRead:this.state.chaptersRead,totalChapters:this.state.totalChapters,volumesRead:this.state.volumesRead,totalVolumes:this.state.totalVolumes,coverUrl:this.state.coverUrl.trim(),malId:this.state.malId.trim(),vaultPage:this.state.vaultPage,dateStarted:this.state.dateStarted,dateFinished:this.state.dateFinished,releaseDate:this.state.releaseDate,dateAdded:e,dateModified:e,customFields:{}};await this.readingData.addManga(s)}}};var Zs=require("obsidian"),ci=class extends Zs.Modal{constructor(t,e,s){super(t);this.draftText=e;this.onChoice=s}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("wl-draft-choice-modal"),this.titleEl.setText("Add draft"),t.createDiv({cls:"wl-draft-choice-subtitle",text:this.draftText});let e=t.createDiv({cls:"wl-draft-choice-grid"}),s=(a,n)=>{let r=e.createEl("button",{cls:"wl-draft-choice-btn"});r.createDiv({cls:"wl-draft-choice-label",text:a}),r.addEventListener("click",()=>{this.close(),this.onChoice(n)})};s("Add in Watchlist","watchlist"),s("Add book","book"),s("Add manga","manga")}onClose(){this.contentEl.empty()}};var De=class g{constructor(i,t,e,s){this.eventRef=null;this.destroyed=!1;this.scanDebounceTimer=null;this.lastScanEntries=[];this.persistState={dismissed:[],added:[],firstSeen:{},titleDisplay:{}};this.containerEl=i,this.plugin=t,this.dataManager=e,this.onCountChange=s}async render(){if(this.destroyed=!1,await this.loadPersistState(),this.destroyed)return;let i=await this.scanVault();this.destroyed||(this.renderUI(i),this.registerChangeListener())}destroy(){this.destroyed=!0,this.scanDebounceTimer&&(window.clearTimeout(this.scanDebounceTimer),this.scanDebounceTimer=null),this.eventRef&&(this.plugin.app.metadataCache.offref(this.eventRef),this.eventRef=null)}async loadPersistState(){var e,s,a,n;let t=this.plugin.dataManager.getData().drafts;t&&(this.persistState={dismissed:(e=t.dismissed)!=null?e:[],added:(s=t.added)!=null?s:[],firstSeen:(a=t.firstSeen)!=null?a:{},titleDisplay:(n=t.titleDisplay)!=null?n:{}})}async savePersistState(){let i=this.plugin.dataManager.getData();i.drafts=this.persistState,this.plugin.dataManager.queueSave()}getTag(){var i;return(i=this.plugin.settings.draftsVaultTag)!=null?i:"#watchlog"}static async scanTaggedFiles(i,t){var a,n;let e=i.app.vault.getMarkdownFiles(),s=new Map;for(let r of e){let o=i.app.metadataCache.getFileCache(r);if((n=(a=o==null?void 0:o.tags)==null?void 0:a.some(c=>c.tag===t))!=null&&n)try{let d=(await i.app.vault.cachedRead(r)).split(` +`);for(let u of d){if(!u.includes(t))continue;let h=u.indexOf(t),p=u.slice(h+t.length).trim();if(!p)continue;let m=p.split(",");for(let f of m){let y=f.trim();if(!y||y.length>100)continue;let v=y.toLowerCase();s.has(v)||s.set(v,{sources:new Set,displayTitle:y}),s.get(v).sources.add(r.basename)}}}catch(c){}}return s}async scanVault(){var n,r;let i=this.getTag(),t=await g.scanTaggedFiles(this.plugin,i),e=!1,s=new Date().toISOString();for(let[o,{displayTitle:l}]of t)this.persistState.firstSeen[o]||(this.persistState.firstSeen[o]=s,e=!0),this.persistState.titleDisplay[o]||(this.persistState.titleDisplay[o]=l,e=!0);e&&await this.savePersistState();let a=[];for(let[o,{sources:l}]of t)this.persistState.dismissed.includes(o)||a.push({titleKey:o,titleDisplay:(n=this.persistState.titleDisplay[o])!=null?n:o,sources:Array.from(l),firstSeen:(r=this.persistState.firstSeen[o])!=null?r:s,added:this.persistState.added.includes(o)});return a.sort((o,l)=>o.firstSeen.localeCompare(l.firstSeen)),this.lastScanEntries=a,a}triggerDebouncedRender(){this.scanDebounceTimer&&window.clearTimeout(this.scanDebounceTimer),this.scanDebounceTimer=window.setTimeout(()=>{this.scanDebounceTimer=null,this.render()},500)}registerChangeListener(){this.eventRef&&this.plugin.app.metadataCache.offref(this.eventRef),this.eventRef=this.plugin.app.metadataCache.on("changed",i=>{this.triggerDebouncedRender()})}static buildFuse(i){return new X(i,{keys:["title"],threshold:.35,includeScore:!0})}static fuzzyMatchesWatchlist(i,t){var s,a;let e=t.search(i);return e.length>0&&((a=(s=e[0])==null?void 0:s.score)!=null?a:1)<=.35}static async computePendingCount(i,t){var u,h,p,m,f;let e=(u=i.settings.draftsVaultTag)!=null?u:"#watchlog",s=await g.scanTaggedFiles(i,e),n=i.dataManager.getData().drafts,r=new Set((h=n==null?void 0:n.dismissed)!=null?h:[]),o=new Set((p=n==null?void 0:n.added)!=null?p:[]),l=(m=n==null?void 0:n.titleDisplay)!=null?m:{},c=g.buildFuse(t.getTitles()),d=0;for(let[y,{displayTitle:v}]of s){if(r.has(y)||o.has(y))continue;let w=(f=l[y])!=null?f:v;g.fuzzyMatchesWatchlist(w,c)||d++}return d}renderUI(i){var c;let t=this.containerEl;t.empty();let e=this.getTag(),s=this.dataManager.getTitles(),a=g.buildFuse(s),n=new Map;for(let d of i)d.added?n.set(d.titleKey,!1):n.set(d.titleKey,g.fuzzyMatchesWatchlist(d.titleDisplay,a));let r=i.filter(d=>d.added?!1:!n.get(d.titleKey)).length;this.onCountChange(r),this.plugin.settings.showHintBanners&&t.createDiv({cls:"wl-drafts-notice",text:`\u26A0 Write ${e} Movie Name in any note and it appears here automatically. Hit Add when you're ready to add it to your Watchlist.`});let o=t.createDiv({cls:"wl-list-title-wrap"});if(o.createSpan({cls:"wl-list-count",text:String(r)}),o.createSpan({cls:"wl-drafts-count-label",text:` Pending draft${r!==1?"s":""}`}),i.length===0){t.createDiv({cls:"wl-drafts-empty",text:`No drafts found. Add ${e} followed by a title in any vault note.`});return}i.sort((d,u)=>{var m,f;let h=(m=n.get(d.titleKey))!=null?m:!1,p=(f=n.get(u.titleKey))!=null?f:!1;return h!==p?h?1:-1:d.firstSeen.localeCompare(u.firstSeen)});let l=t.createDiv({cls:"wl-drafts-cards"});for(let d of i)this.renderCard(l,d,(c=n.get(d.titleKey))!=null?c:!1)}renderCard(i,t,e){let s="wl-drafts-card";e&&(s+=" wl-drafts-card-watchlist"),t.added&&(s+=" wl-drafts-card-added");let a=i.createDiv({cls:s});a.createDiv({cls:"wl-drafts-card-title",text:t.titleDisplay});let n=a.createDiv({cls:"wl-drafts-card-source"});if(t.sources.length>0){let c=t.sources[0];n.createSpan({cls:"wl-drafts-source-link",text:`[[${c}]]`}).addEventListener("click",u=>{u.stopPropagation(),this.plugin.app.workspace.openLinkText(c,"")}),t.sources.length>1&&n.createSpan({cls:"wl-drafts-source-count",text:` (${t.sources.length})`,attr:{title:t.sources.join(` +`)}})}let r=a.createDiv({cls:"wl-drafts-card-dup"});e&&r.createSpan({text:"In Watchlist",attr:{title:"This title already exists in your Watchlist"}});let o=a.createDiv({cls:"wl-drafts-card-actions"});t.added||e?o.createSpan({cls:"wl-drafts-added-label",text:"Added"}):o.createEl("button",{cls:"wl-btn wl-btn-sm wl-btn-primary",text:"Add"}).addEventListener("click",()=>this.openAddModal(t)),o.createEl("button",{cls:"wl-btn wl-btn-sm wl-drafts-dismiss",text:"\u2715",attr:{title:"Dismiss"}}).addEventListener("click",()=>void this.dismissEntry(t.titleKey))}rerenderFromCache(){let i=this.lastScanEntries.filter(t=>!this.persistState.dismissed.includes(t.titleKey)).map(t=>({...t,added:this.persistState.added.includes(t.titleKey)}));this.renderUI(i)}async dismissEntry(i){this.persistState.dismissed.includes(i)||this.persistState.dismissed.push(i),this.persistState.added=this.persistState.added.filter(t=>t!==i),await this.savePersistState(),this.rerenderFromCache()}openAddModal(i){new ci(this.plugin.app,i.titleDisplay,t=>{t==="watchlist"?this.openWatchlistAddModal(i):this.openReadingAddModal(i,t)}).open()}openWatchlistAddModal(i){new ft(this.plugin.app,this.plugin,this.dataManager,()=>void this.afterAdded(i.titleKey),{searchQuery:i.titleDisplay,title:i.titleDisplay,type:"Anime",episodes:0,duration:0,releaseDate:"",link:"",seasons:[]}).open()}openReadingAddModal(i,t){new ee(this.plugin.app,this.plugin,this.plugin.readingDataManager,t,()=>void this.afterAdded(i.titleKey),void 0,i.titleDisplay).open()}async afterAdded(i){var e;((e=this.plugin.settings.draftsAfterAdding)!=null?e:"keep")==="remove"?await this.dismissEntry(i):(this.persistState.added.includes(i)||this.persistState.added.push(i),await this.savePersistState(),this.rerenderFromCache())}};var wt=require("obsidian");var nt=require("obsidian");var di=require("obsidian");var ie=class extends di.Modal{constructor(t,e,s,a,n){super(t);this.listEl=null;this.styleGroupEl=null;this.dragFromIndex=-1;this.plugin=e,this.readingData=s,this.kind=a,this.onChanged=n}onOpen(){var e;let t=(e=this.plugin.settings.colorTheme)!=null?e:"default";this.modalEl.setAttribute("data-theme",t),this.contentEl.setAttribute("data-theme",t),this.contentEl.addClass("wl-view"),this.contentEl.addClass("wl-reading-modal"),this.contentEl.addClass("wl-reading-manage-cols"),this.titleEl.setText(this.kind==="book"?"Manage book fields":"Manage manga fields"),this.build()}onClose(){this.contentEl.empty()}build(){let t=this.contentEl;t.empty();let e=t.createDiv({cls:"wl-reading-modal-header"});e.createSpan({cls:"wl-reading-modal-header-icon",text:this.kind==="book"?"\u{1F4D6}":"\u{1F4D3}"}),e.createSpan({cls:"wl-reading-modal-header-title",text:this.kind==="book"?"Manage book fields":"Manage manga fields"}),t.createDiv({cls:"wl-reading-manage-cols-desc",text:"Custom fields appear in the title detail modal. Changes save automatically."}),this.renderStyleToggle(t),this.listEl=t.createDiv({cls:"wl-reading-manage-cols-list"}),this.renderList(),t.createDiv({cls:"wl-reading-modal-divider"}),this.renderAddSection(t),t.createDiv({cls:"wl-reading-modal-footer"}).createEl("button",{cls:"wl-btn",text:"Close"}).addEventListener("click",()=>this.close())}renderStyleToggle(t){var n,r;let e=this.readingData.getSettings(),s=this.kind==="book"?(n=e.bookCustomFieldStyle)!=null?n:"fill":(r=e.mangaCustomFieldStyle)!=null?r:"fill",a=t.createDiv({cls:"wl-reading-cols-style-row"});a.createSpan({cls:"wl-reading-cols-style-label",text:"Display style:"}),this.styleGroupEl=a.createDiv({cls:"wl-reading-cols-style-group"});for(let o of["fill","border"]){let l=this.styleGroupEl.createEl("button",{cls:`wl-reading-cols-style-btn${s===o?" is-active":""}`,text:o.charAt(0).toUpperCase()+o.slice(1)});l.addEventListener("click",()=>{(async()=>{var d;let c=this.kind==="book"?"bookCustomFieldStyle":"mangaCustomFieldStyle";await this.readingData.updateSettings({[c]:o}),this.onChanged(),(d=this.styleGroupEl)==null||d.querySelectorAll(".wl-reading-cols-style-btn").forEach(u=>{u.removeClass("is-active")}),l.addClass("is-active")})()})}}getColumns(){return this.kind==="book"?this.readingData.getBookColumns():this.readingData.getMangaColumns()}renderList(){if(!this.listEl)return;this.listEl.empty();let t=this.getColumns();if(t.length===0){this.listEl.createDiv({cls:"wl-reading-manage-cols-empty",text:"No custom fields yet. Add one below."});return}t.forEach((e,s)=>{var u;let a=this.listEl.createDiv({cls:"wl-editcol-card wl-reading-col-card"}),n=a.createDiv({cls:"wl-editcol-card-handle",text:"\u283F"});n.title="Drag to reorder",n.addEventListener("mousedown",()=>a.setAttribute("draggable","true")),a.addEventListener("dragstart",h=>{var p;this.dragFromIndex=s,(p=h.dataTransfer)==null||p.setData("text/plain",String(s)),a.addClass("wl-cl-dragging")}),a.addEventListener("dragend",()=>{a.removeClass("wl-cl-dragging"),a.setAttribute("draggable","false")}),a.addEventListener("dragover",h=>{h.preventDefault(),a.addClass("wl-cl-drag-over")}),a.addEventListener("dragleave",()=>a.removeClass("wl-cl-drag-over")),a.addEventListener("drop",h=>{h.preventDefault(),a.removeClass("wl-cl-drag-over");let p=this.dragFromIndex,m=s;this.dragFromIndex=-1,!(p===m||p<0)&&this.reorder(p,m)});let r=a.createEl("input",{cls:"wl-modal-input wl-editcol-card-name",attr:{type:"text",placeholder:"Field name"}});r.value=e.name,r.addEventListener("change",()=>{let h=r.value.trim();if(!h){r.value=e.name;return}h!==e.name&&this.updateColumn({...e,name:h})});let o=a.createEl("select",{cls:"wl-select wl-editcol-card-type"});for(let h of["text","number","select"]){let p=o.createEl("option",{value:h,text:h.charAt(0).toUpperCase()+h.slice(1)});e.type===h&&(p.selected=!0)}let l=a.createEl("button",{cls:"wl-reading-col-color-dot"});l.style.backgroundColor=(u=e.color)!=null?u:dt,l.title="Choose field color",l.addEventListener("click",h=>{h.stopPropagation(),this.openColorPalette(l,e)});let c=a.createEl("input",{cls:"wl-modal-input wl-reading-col-opts-input",attr:{type:"text",placeholder:"Comma-separated values"}});c.value=e.options.join(", "),c.style.visibility=e.type==="select"?"":"hidden",c.addEventListener("change",()=>{let h=c.value.split(",").map(p=>p.trim()).filter(Boolean);this.updateColumn({...e,options:h})}),o.addEventListener("change",()=>{let h=o.value;c.style.visibility=h==="select"?"":"hidden",this.updateColumn({...e,type:h})});let d=a.createEl("button",{cls:"wl-btn wl-btn-sm wl-editcol-card-del",text:"\u2715"});d.title="Delete this field",d.addEventListener("click",()=>{new _(this.plugin.app,`Delete field "${e.name}"? This removes its data from every ${this.kind==="book"?"book":"manga"} entry.`,()=>void this.deleteColumn(e.id)).open()})})}openColorPalette(t,e){var s;Se({anchor:t,container:this.contentEl,current:(s=e.color)!=null?s:dt,allowCustom:!0,onPick:a=>{this.updateColumn({...e,color:a!=null?a:void 0})}})}renderAddSection(t){let e=t.createDiv({cls:"wl-reading-add-col"});e.createDiv({cls:"wl-reading-section-label",text:"Add field"});let s=e.createDiv({cls:"wl-reading-add-col-row"}),a=s.createEl("input",{cls:"wl-modal-input wl-reading-add-col-name",attr:{type:"text",placeholder:"Field name"}}),n=s.createEl("select",{cls:"wl-select wl-reading-add-col-type"});for(let c of["text","number","select"])n.createEl("option",{value:c,text:c.charAt(0).toUpperCase()+c.slice(1)});let r=s.createEl("input",{cls:"wl-modal-input wl-reading-add-col-opts",attr:{type:"text",placeholder:"Options (comma-separated)"}}),o=()=>{r.style.display=n.value==="select"?"":"none"};n.addEventListener("change",o),o(),s.createEl("button",{cls:"wl-reading-add-btn wl-btn-success wl-reading-add-col-btn",text:"Add"}).addEventListener("click",()=>{let c=a.value.trim();if(!c){new di.Notice("Enter a field name first.");return}let d=n.value,u=d==="select"?r.value.split(",").map(p=>p.trim()).filter(Boolean):[],h={id:this.readingData.generateColumnId(this.kind,c),name:c,type:d,options:u,color:dt};this.addColumn(h).then(()=>{a.value="",r.value="",n.value="text",o()})})}async addColumn(t){await this.readingData.addColumn(this.kind,t),this.renderList(),this.onChanged()}async updateColumn(t){await this.readingData.updateColumn(this.kind,t),this.renderList(),this.onChanged()}async deleteColumn(t){await this.readingData.removeColumn(this.kind,t),this.renderList(),this.onChanged()}async reorder(t,e){await this.readingData.reorderColumns(this.kind,t,e),this.renderList(),this.onChanged()}};function xn(g){var r,o,l;let i=g.match(/(^|\n)## Quotes[ \t]*\r?\n([\s\S]*?)(?=\n## |\n# |$)/);if(!i)return[];let t=(r=i[2])!=null?r:"",e=[],s=t.split(/\r?\n/),a=null,n=()=>{if(a){let c=a.body.join(` +`).trim();c&&e.push({reference:a.reference,text:c})}a=null};for(let c of s){let d=c.match(/^>\s*\[!quote\](.*)$/i);if(d){n(),a={reference:((o=d[1])!=null?o:"").trim(),body:[]};continue}if(a){let u=c.match(/^>\s?(.*)$/);u?a.body.push((l=u[1])!=null?l:""):(c.trim(),n())}}return n(),e}var ui=class extends nt.Modal{constructor(t,e,s,a,n,r){super(t);this.starsWrapEl=null;this.plugin=e,this.readingData=s,this.mode=a,this.id=n,this.onChanged=r;let o=this.getItem();this.draft={pagesRead:o&&this.mode==="book"?o.pagesRead:0,chaptersRead:o?o.chaptersRead:0,volumesRead:o&&this.mode==="manga"?o.volumesRead:0},this.openSnapshot={...this.draft}}getItem(){return this.mode==="book"?this.readingData.getBook(this.id):this.readingData.getManga(this.id)}onOpen(){var e;let t=(e=this.plugin.settings.colorTheme)!=null?e:"default";this.modalEl.setAttribute("data-theme",t),this.contentEl.setAttribute("data-theme",t),this.contentEl.addClass("wl-view"),this.contentEl.addClass("wl-detail-modal"),this.contentEl.addClass("wl-reading-detail"),this.renderAll()}onClose(){this.commitOnClose(),this.contentEl.empty()}async commitOnClose(){if(!(this.draft.pagesRead!==this.openSnapshot.pagesRead||this.draft.chaptersRead!==this.openSnapshot.chaptersRead||this.draft.volumesRead!==this.openSnapshot.volumesRead))return;let e=this.getItem();if(e){if(this.mode==="book"){let a={...e,pagesRead:this.draft.pagesRead,chaptersRead:this.draft.chaptersRead};this.applyAutoComplete(a),await this.readingData.updateBook(a)}else{let a={...e,chaptersRead:this.draft.chaptersRead,volumesRead:this.draft.volumesRead};this.applyAutoComplete(a),await this.readingData.updateManga(a)}this.logProgressChange(e),this.onChanged()}}logProgressChange(t){var a,n,r,o;let e=this.openSnapshot,s=this.mode==="book"?"Book":"Manga";if(this.mode==="book"){let l=t;this.draft.pagesRead!==e.pagesRead&&l.totalPages>0&&((a=this.plugin.historyManager)==null||a.log(`${t.title} (${s}) At page ${this.draft.pagesRead} / ${l.totalPages}`,{source:"Reading",action:"watched",titleName:t.title})),this.draft.chaptersRead!==e.chaptersRead&&l.totalChapters>0&&((n=this.plugin.historyManager)==null||n.log(`${t.title} (${s}) At chapter ${this.draft.chaptersRead} / ${l.totalChapters}`,{source:"Reading",action:"watched",titleName:t.title}))}else{let l=t;this.draft.chaptersRead!==e.chaptersRead&&l.totalChapters>0&&((r=this.plugin.historyManager)==null||r.log(`${t.title} (${s}) At chapter ${this.draft.chaptersRead} / ${l.totalChapters}`,{source:"Reading",action:"watched",titleName:t.title})),this.draft.volumesRead!==e.volumesRead&&l.totalVolumes>0&&((o=this.plugin.historyManager)==null||o.log(`${t.title} (${s}) At volume ${this.draft.volumesRead} / ${l.totalVolumes}`,{source:"Reading",action:"watched",titleName:t.title}))}}renderAll(){this.contentEl.empty();let t=this.getItem();if(!t){this.contentEl.createDiv({text:"Item no longer exists."});return}this.renderHeader(t),this.renderProgressSection(t),this.renderDetailsSection(t),this.contentEl.createDiv({cls:"wl-reading-modal-divider"}),this.renderCustomFieldsSection(t),this.contentEl.createDiv({cls:"wl-reading-modal-divider"}),this.renderQuotesSection(t),this.renderFooter(t)}renderHeader(t){let e=this.contentEl.createDiv({cls:"wl-reading-detail-header"}),s=e.createDiv({cls:"wl-reading-detail-cover"});t.coverUrl?s.createEl("img",{cls:"wl-reading-detail-cover-img",attr:{src:t.coverUrl,alt:t.title}}):(s.style.backgroundColor=cs(t.id),s.createSpan({cls:"wl-reading-detail-cover-icon",text:this.mode==="book"?"\u{1F4D6}":"\u{1F4D3}"}));let a=e.createDiv({cls:"wl-reading-detail-info"}),n=a.createDiv({cls:"wl-reading-detail-title-wrap"});this.renderTitleDisplay(n);let r=a.createDiv({cls:"wl-reading-detail-author-wrap"});this.renderAuthorDisplay(r);let o=a.createDiv({cls:"wl-reading-detail-meta-row"}),l=o.createSpan({cls:"wl-reading-detail-status-wrap"});this.renderStatusBadge(l),Ye(this.plugin.app,o,this.readingData.noteFilePath(this.mode,t.title),()=>this.close()),this.starsWrapEl=o.createDiv({cls:"wl-stars wl-reading-detail-stars"}),this.renderStars();let c=a.createDiv({cls:"wl-reading-detail-actions"});this.renderExternalLinkActions(c);let d=a.createDiv({cls:"wl-reading-detail-vault-row"});this.renderVaultRow(d)}renderTitleDisplay(t){var a;t.empty();let e=this.getItem(),s=t.createEl("h2",{cls:"wl-reading-detail-title wl-reading-detail-editable-text",text:(a=e==null?void 0:e.title)!=null?a:""});s.title="Click to edit",s.addEventListener("click",()=>this.editTitle(t))}editTitle(t){var n;t.empty();let e=this.getItem(),s=t.createEl("input",{cls:"wl-modal-input wl-reading-detail-title-input",attr:{type:"text"}});s.value=(n=e==null?void 0:e.title)!=null?n:"";let a=()=>{let r=s.value.trim();if(!r){this.renderTitleDisplay(t);return}(async()=>{let o=this.getItem();o&&r!==o.title&&(this.mode==="book"?await this.readingData.updateBook({...o,title:r}):await this.readingData.updateManga({...o,title:r}),this.onChanged()),this.renderTitleDisplay(t)})()};s.addEventListener("blur",a),s.addEventListener("keydown",r=>{r.key==="Enter"?(r.preventDefault(),s.blur()):r.key==="Escape"&&(r.preventDefault(),this.renderTitleDisplay(t))}),s.focus(),s.select()}renderAuthorDisplay(t){t.empty();let e=this.getItem(),s=t.createDiv({cls:"wl-reading-detail-author wl-reading-detail-editable-text",text:(e==null?void 0:e.author)||"\u2014"});s.title="Click to edit",s.addEventListener("click",()=>this.editAuthor(t))}editAuthor(t){var n;t.empty();let e=this.getItem(),s=t.createEl("input",{cls:"wl-modal-input wl-reading-detail-author-input",attr:{type:"text"}});s.value=(n=e==null?void 0:e.author)!=null?n:"";let a=()=>{let r=s.value.trim();(async()=>{let o=this.getItem();o&&r!==o.author&&(this.mode==="book"?await this.readingData.updateBook({...o,author:r}):await this.readingData.updateManga({...o,author:r}),this.onChanged()),this.renderAuthorDisplay(t)})()};s.addEventListener("blur",a),s.addEventListener("keydown",r=>{r.key==="Enter"?(r.preventDefault(),s.blur()):r.key==="Escape"&&(r.preventDefault(),this.renderAuthorDisplay(t))}),s.focus(),s.select()}renderStatusBadge(t){var n;t.empty();let e=this.getItem(),s=(n=e==null?void 0:e.status)!=null?n:"Plan to Read",a=t.createSpan({cls:"wl-reading-detail-status",text:s});a.style.backgroundColor=Te(s),a.title="Click to change status",a.addEventListener("click",r=>{r.stopPropagation(),this.openStatusDropdown(a,t)})}openStatusDropdown(t,e){Xt({anchor:t,container:this.contentEl,options:[...ct],getOptionColor:s=>Te(s),onSelect:s=>void this.saveStatus(s).then(()=>this.renderStatusBadge(e))})}async saveStatus(t){let e=this.getItem();if(!e)return;let s={status:t};if(t==="Completed"&&!e.dateFinished){let a=new Date,n=a.getFullYear(),r=String(a.getMonth()+1).padStart(2,"0"),o=String(a.getDate()).padStart(2,"0");s.dateFinished=`${n}-${r}-${o}`}this.mode==="book"?await this.readingData.updateBook({...e,...s}):await this.readingData.updateManga({...e,...s}),this.onChanged()}renderExternalLinkActions(t){var n;t.empty();let e=this.getItem();if(!e)return;let s=!!e.externalLink;if(t.createEl("button",{cls:"wl-btn wl-btn-sm",text:s?"Change link":"External link"}).addEventListener("click",()=>{var u;t.empty();let r=t.createDiv({cls:"wl-reading-external-link-wrap"}),o=r.createEl("input",{cls:"wl-modal-input wl-reading-external-link-input",attr:{type:"url",placeholder:"https://\u2026"}});o.value=(u=e.externalLink)!=null?u:"";let l=r.createEl("button",{cls:"wl-reading-add-btn wl-btn-success",text:"Save"}),c=r.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Cancel"}),d=()=>{let h=o.value.trim();(async()=>{let p=this.getItem();p&&(this.mode==="book"?await this.readingData.updateBook({...p,externalLink:h}):await this.readingData.updateManga({...p,externalLink:h}),this.onChanged(),this.renderExternalLinkActions(t))})()};l.addEventListener("click",d),c.addEventListener("click",()=>this.renderExternalLinkActions(t)),o.addEventListener("keydown",h=>{h.key==="Enter"?(h.preventDefault(),d()):h.key==="Escape"&&(h.preventDefault(),this.renderExternalLinkActions(t))}),o.focus()}),s){let r=t.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Open"});r.title=(n=e.externalLink)!=null?n:"",r.addEventListener("click",()=>{let o=this.getItem();o!=null&&o.externalLink&&activeWindow.open(o.externalLink,"_blank","noopener,noreferrer")})}}renderVaultRow(t){t.empty();let e=this.getItem();if(!e)return;let s=t.createEl("button",{cls:"wl-btn wl-btn-sm",text:e.vaultPage?"Change":"Link"});if(s.title=e.vaultPage?`Linked: ${e.vaultPage}`:"Link a vault note to this entry",s.addEventListener("click",()=>{let a=this.plugin.app.vault.getMarkdownFiles();new li(this.plugin.app,a,n=>{this.updateVaultPage(n.path).then(()=>this.renderVaultRow(t))}).open()}),e.vaultPage){let a=t.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Open"});a.title="Open the linked vault page in a new tab",a.addEventListener("click",()=>this.openLinkedVaultPage())}if(t.createSpan({cls:"wl-reading-detail-vault-label",text:"Vault page:"}),e.vaultPage){let a=e.vaultPage.split("/").pop()||e.vaultPage,n=t.createSpan({cls:"wl-reading-detail-vault-path",text:a});n.title=e.vaultPage}else t.createSpan({cls:"wl-reading-detail-vault-empty",text:"not linked"})}async updateVaultPage(t){let e=this.getItem();if(e)if(this.mode==="book"){let s={...e,vaultPage:t};await this.readingData.updateBook(s)}else{let s={...e,vaultPage:t};await this.readingData.updateManga(s)}}openLinkedVaultPage(){let t=this.getItem();if(!t||!t.vaultPage)return;let e=this.plugin.app.vault.getAbstractFileByPath(t.vaultPage);e instanceof nt.TFile?(this.plugin.app.workspace.getLeaf("tab").openFile(e),this.close()):new nt.Notice("Linked vault page no longer exists.")}renderStars(){if(!this.starsWrapEl)return;this.starsWrapEl.empty();let t=this.getItem();if(t)for(let e=1;e<=5;e++)this.starsWrapEl.createSpan({cls:`wl-star${t.rating>=e?" is-active":""}`,text:"\u2605"}).addEventListener("click",()=>{let a=this.getItem();if(!a)return;let n=a.rating===e?0:e;(async()=>{if(this.mode==="book"){let r={...a,rating:n};await this.readingData.updateBook(r)}else{let r={...a,rating:n};await this.readingData.updateManga(r)}this.renderStars()})()})}renderProgressSection(t){let e=this.contentEl.createDiv({cls:"wl-reading-detail-progress"});e.createDiv({cls:"wl-reading-section-label",text:"Progress"});let s=e.createDiv({cls:"wl-reading-arc-row"});this.mode==="book"?(this.renderArcGauge(s,"pages","#8b5cf6",()=>this.draft.pagesRead,a=>{this.draft.pagesRead=a},()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.totalPages)!=null?n:0},a=>this.commitTotal("totalPages",a)),this.renderArcGauge(s,"chapters","#06b6d4",()=>this.draft.chaptersRead,a=>{this.draft.chaptersRead=a},()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.totalChapters)!=null?n:0},a=>this.commitTotal("totalChapters",a))):(this.renderArcGauge(s,"chapters","#06b6d4",()=>this.draft.chaptersRead,a=>{this.draft.chaptersRead=a},()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.totalChapters)!=null?n:0},a=>this.commitTotal("totalChapters",a)),this.renderArcGauge(s,"volumes","#f59e0b",()=>this.draft.volumesRead,a=>{this.draft.volumesRead=a},()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.totalVolumes)!=null?n:0},a=>this.commitTotal("totalVolumes",a)))}async commitTotal(t,e){let s=this.getItem();s&&(this.mode==="book"?await this.readingData.updateBook({...s,[t]:e}):await this.readingData.updateManga({...s,[t]:e}),this.onChanged())}renderArcGauge(t,e,s,a,n,r,o){let l=t.createDiv({cls:"wl-reading-arc-col"}),c=100,d=8,u=(c-d)/2,h=c/2,p=c/2,m=l.createDiv({cls:"wl-reading-arc-svg-wrap"}),f=activeDocument.createElementNS("http://www.w3.org/2000/svg","svg");f.setAttribute("viewBox",`0 0 ${c} ${c}`),f.setAttribute("class","wl-reading-arc-svg"),m.appendChild(f);let y=Math.PI*u,v=activeDocument.createElementNS("http://www.w3.org/2000/svg","path"),w=`M ${h-u} ${p} A ${u} ${u} 0 1 1 ${h+u} ${p}`;v.setAttribute("d",w),v.setAttribute("fill","none"),v.setAttribute("stroke","#2a2a2a"),v.setAttribute("stroke-width",String(d)),v.setAttribute("stroke-linecap","round"),f.appendChild(v);let b=activeDocument.createElementNS("http://www.w3.org/2000/svg","path");b.setAttribute("d",w),b.setAttribute("fill","none"),b.setAttribute("stroke",s),b.setAttribute("stroke-width",String(d)),b.setAttribute("stroke-linecap","round"),b.setAttribute("stroke-dasharray",String(y)),f.appendChild(b);let E=activeDocument.createElementNS("http://www.w3.org/2000/svg","text");E.setAttribute("x",String(h)),E.setAttribute("y",String(p+4)),E.setAttribute("text-anchor","middle"),E.setAttribute("class","wl-reading-arc-pct"),f.appendChild(E);let D=k=>{let R=r();return isNaN(k)||k<0?0:R>0&&k>R?R:k},S=l.createDiv({cls:"wl-reading-arc-controls"}),T=S.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-step-btn",text:"\u22121"}),M=S.createEl("input",{cls:"wl-modal-input wl-modal-input-sm wl-reading-arc-input",attr:{type:"number",min:"0",max:String(r())}}),x=S.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-step-btn",text:"+1"}),C=l.createDiv({cls:"wl-reading-arc-label"}),L=()=>{let k=r(),R=a();M.value=String(R),M.setAttribute("max",String(k));let P=k>0?Math.min(1,R/k):0,B=y*(1-P);b.setAttribute("stroke-dashoffset",String(B)),E.textContent=`${Math.round(P*100)}%`},I=()=>{C.empty(),C.createSpan({text:"of "});let k=C.createSpan({cls:"wl-reading-arc-total wl-reading-detail-editable-text",text:String(r())});k.title="Click to edit",k.addEventListener("click",()=>H()),C.createSpan({text:` ${e}`})},H=()=>{C.empty(),C.createSpan({text:"of "});let k=C.createEl("input",{cls:"wl-modal-input wl-modal-input-sm wl-reading-arc-total-input",attr:{type:"number",min:"0"}});k.value=String(r()),C.createSpan({text:` ${e}`});let R=!1,P=()=>{if(R)return;R=!0;let B=parseInt(k.value,10),K=isNaN(B)||B<0?0:B;(async()=>(K!==r()&&(await o(K),L()),I()))()};k.addEventListener("blur",P),k.addEventListener("keydown",B=>{B.key==="Enter"?(B.preventDefault(),k.blur()):B.key==="Escape"&&(B.preventDefault(),R=!0,I())}),k.focus(),k.select()};I(),L(),M.addEventListener("input",()=>{let k=D(parseInt(M.value,10));n(k),L()}),T.addEventListener("click",()=>{n(D(a()-1)),L()}),x.addEventListener("click",()=>{n(D(a()+1)),L()})}renderDetailsSection(t){let e=this.contentEl.createDiv({cls:"wl-reading-detail-details"});e.createDiv({cls:"wl-reading-section-label",text:"Details"});let s=e.createDiv({cls:"wl-reading-detail-grid"});this.renderIdCell(s,t),this.renderEditableDateCell(s,"Started",()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.dateStarted)!=null?n:null},async a=>{let n=this.getItem();n&&(this.mode==="book"?await this.readingData.updateBook({...n,dateStarted:a}):await this.readingData.updateManga({...n,dateStarted:a}),this.onChanged())}),this.renderAddedReleaseCell(s,t),this.renderEditableDateCell(s,"Finished",()=>{var a,n;return(n=(a=this.getItem())==null?void 0:a.dateFinished)!=null?n:null},async a=>{let n=this.getItem();n&&(this.mode==="book"?await this.readingData.updateBook({...n,dateFinished:a}):await this.readingData.updateManga({...n,dateFinished:a}),this.onChanged())})}renderIdCell(t,e){let s=this.mode==="book"?"Google Books ID":"MAL ID",a=this.makeDetailCell(t,s);a.addClass("wl-reading-detail-id-value"),this.fillIdValue(a,e)}idText(t){return this.mode==="book"?t.googleBooksId:t.malId}resolveItemLink(t){if(t.externalLink)return t.externalLink;if(this.mode==="manga"){let s=t.malId;return s?`https://myanimelist.net/manga/${encodeURIComponent(s)}`:""}let e=t.googleBooksId;return e?`https://books.google.com/books?id=${encodeURIComponent(e)}`:""}fillIdValue(t,e){t.empty();let s=this.idText(e),a=this.resolveItemLink(e);s?a?t.createEl("a",{cls:"wl-reading-detail-link",text:s,attr:{href:a,target:"_blank",rel:"noopener noreferrer"}}):t.createSpan({text:s}):t.createSpan({text:"\u2014"}),t.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-detail-id-edit",text:"\u270E",attr:{title:this.mode==="book"?"Edit Google Books ID":"Edit MAL ID"}}).addEventListener("click",()=>this.editIdLink(t,e))}editIdLink(t,e){t.empty();let s=t.createDiv({cls:"wl-reading-external-link-wrap"}),a=s.createEl("input",{cls:"wl-modal-input wl-reading-external-link-input",attr:{type:"text",placeholder:this.mode==="book"?"Google Books volume ID":"MAL manga ID"}});a.value=this.idText(e);let n=s.createEl("button",{cls:"wl-reading-add-btn wl-btn-success",text:"Save"}),r=s.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Cancel"}),o=()=>{let c=this.getItem();c&&this.fillIdValue(t,c)},l=()=>{let c=a.value.trim();(async()=>{let d=this.getItem();if(d){if(c===this.idText(d)){o();return}this.mode==="book"?await this.readingData.updateBook({...d,googleBooksId:c}):await this.readingData.updateManga({...d,malId:c}),this.onChanged(),o(),c&&await this.refetchCoverFromId(c)}})()};n.addEventListener("click",l),r.addEventListener("click",o),a.addEventListener("keydown",c=>{c.key==="Enter"?(c.preventDefault(),l()):c.key==="Escape"&&(c.preventDefault(),o())}),a.focus()}async refetchCoverFromId(t){try{if(this.mode==="book"){if(!this.plugin.apiService.hasGoogleBooksKey()){new nt.Notice("Google Books API key required \u2014 add one in Settings \u2192 API \u2192 Books.");return}let e=await this.plugin.apiService.getGoogleBookById(t);if(!e||!e.coverUrl){new nt.Notice("This volume doesn't have a cover \u2014 try a different edition's ID.");return}let s=this.getItem();if(!s)return;await this.readingData.updateBook({...s,coverUrl:e.coverUrl})}else{let e=await this.plugin.apiService.getMangaByMalId(Number(t));if(!e||!e.coverUrl){new nt.Notice("This manga doesn't have a cover \u2014 try a different ID.");return}let s=this.getItem();if(!s)return;await this.readingData.updateManga({...s,coverUrl:e.coverUrl})}this.onChanged()}catch(e){new nt.Notice(this.mode==="book"?It(e):"Failed to fetch cover.")}}renderAddedReleaseCell(t,e){var l,c;let s=t.createDiv({cls:"wl-reading-detail-cell wl-reading-detail-cell-pair"}),a=s.createDiv({cls:"wl-reading-detail-pair-col"});a.createDiv({cls:"wl-reading-detail-cell-label",text:"Added"}),a.createDiv({cls:"wl-reading-detail-cell-value",text:Q(e.dateAdded.slice(0,10))});let n=s.createDiv({cls:"wl-reading-detail-pair-col"});n.createDiv({cls:"wl-reading-detail-cell-label",text:"Release"});let r=n.createEl("input",{cls:"wl-reading-detail-date-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}}),o=(c=(l=this.getItem())==null?void 0:l.releaseDate)!=null?c:null;r.value=o?Q(o):"",r.addEventListener("change",()=>{let d=r.value.trim(),u=null;if(d&&(u=q(d),!u)){r.addClass("wl-input-error");return}r.removeClass("wl-input-error"),(async()=>{let h=this.getItem();h&&(this.mode==="book"?await this.readingData.updateBook({...h,releaseDate:u}):await this.readingData.updateManga({...h,releaseDate:u}),this.onChanged(),this.renderAll())})()})}makeDetailCell(t,e){let s=t.createDiv({cls:"wl-reading-detail-cell"});return s.createDiv({cls:"wl-reading-detail-cell-label",text:e}),s.createDiv({cls:"wl-reading-detail-cell-value"})}renderEditableDateCell(t,e,s,a){let n=t.createDiv({cls:"wl-reading-detail-cell"});n.createDiv({cls:"wl-reading-detail-cell-label",text:e});let r=n.createDiv({cls:"wl-reading-detail-cell-date"}),o=r.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-detail-today-btn",text:"Today",attr:{title:"Fill with today's date"}}),l=r.createEl("input",{cls:"wl-reading-detail-date-input",attr:{type:"text",placeholder:"Dd/mm/yyyy",maxlength:"10"}}),c=s();l.value=c?Q(c):"";let d=()=>{o.toggleClass("is-dimmed",!!l.value.trim())};d(),o.addEventListener("click",()=>{if(l.value.trim())return;let u=new Date,h=String(u.getDate()).padStart(2,"0"),p=String(u.getMonth()+1).padStart(2,"0");l.value=`${h}/${p}/${u.getFullYear()}`,d(),l.dispatchEvent(new Event("change"))}),l.addEventListener("change",()=>{let u=l.value.trim();if(!u){l.removeClass("wl-input-error"),d(),a(null);return}let h=q(u);if(!h){l.addClass("wl-input-error");return}l.removeClass("wl-input-error"),d(),a(h)})}renderFooter(t){let e=this.contentEl.createDiv({cls:"wl-reading-detail-footer"});e.createDiv({cls:"wl-reading-detail-footer-left"}).createEl("button",{cls:"wl-delete-btn wl-btn-danger wl-reading-detail-delete",text:"Delete"}).addEventListener("click",()=>{new _(this.plugin.app,`Delete "${t.title}"?`,()=>{(async()=>(this.mode==="book"?await this.readingData.removeBook(t.id):await this.readingData.removeManga(t.id),this.onChanged(),this.close()))()}).open()}),e.createDiv({cls:"wl-reading-detail-footer-right"}).createEl("button",{cls:"wl-reading-add-btn wl-btn-success",text:"Update progress"}).addEventListener("click",()=>void this.commitDraft())}getColumns(){return this.mode==="book"?this.readingData.getBookColumns():this.readingData.getMangaColumns()}openManageColumns(){new ie(this.plugin.app,this.plugin,this.readingData,this.mode,()=>this.renderAll()).open()}renderCustomFieldsSection(t){var d,u;let e=this.contentEl.createDiv({cls:"wl-reading-detail-custom"}),s=e.createDiv({cls:"wl-reading-detail-custom-heading"});s.createSpan({cls:"wl-reading-section-label",text:"Custom fields"}),s.createEl("a",{cls:"wl-reading-detail-custom-manage",text:"Manage"}).addEventListener("click",h=>{h.preventDefault(),this.openManageColumns()});let n=this.getColumns();if(n.length===0){let h=e.createDiv({cls:"wl-reading-detail-custom-empty"});h.createSpan({text:"No custom fields \u2014 add some via "}),h.createEl("a",{cls:"wl-reading-detail-custom-manage",text:"Manage"}).addEventListener("click",m=>{m.preventDefault(),this.openManageColumns()}),h.createSpan({text:"."});return}let r=this.readingData.getSettings(),l=(this.mode==="book"?(d=r.bookCustomFieldStyle)!=null?d:"fill":(u=r.mangaCustomFieldStyle)!=null?u:"fill")==="border"?"wl-reading-custom-table is-border-mode":"wl-reading-custom-table",c=e.createDiv({cls:l});for(let h of n)this.renderCustomFieldRow(c,t,h)}renderCustomFieldRow(t,e,s){var u,h,p,m;let a=t.createDiv({cls:"wl-reading-custom-row"}),n=a.createDiv({cls:"wl-reading-custom-label",text:s.name}),r=a.createDiv({cls:"wl-reading-custom-value"}),o=this.readingData.getSettings(),l=this.mode==="book"?(u=o.bookCustomFieldStyle)!=null?u:"fill":(h=o.mangaCustomFieldStyle)!=null?h:"fill",c=(p=s.color)!=null?p:dt;l==="fill"?n.setCssProps({"--wl-field-bg":Zt(c)}):n.setCssProps({"--wl-field-border":Gt(c)});let d=(m=e.customFields)==null?void 0:m[s.id];this.renderCustomValueDisplay(r,e,s,d)}renderCustomValueDisplay(t,e,s,a){t.empty();let n=a!=null&&a!=="";t.createSpan({cls:`wl-reading-custom-display${n?"":" is-placeholder"}`,text:n?String(a):"\u2014"}).addEventListener("click",()=>{this.renderCustomValueEditor(t,e,s,a)})}renderCustomValueEditor(t,e,s,a){if(t.empty(),s.type==="select"){let o=t.createEl("select",{cls:"wl-select wl-reading-custom-input"}),l=o.createEl("option",{value:"",text:"\u2014"});(a==null||a==="")&&(l.selected=!0);for(let d of s.options){let u=o.createEl("option",{value:d,text:d});String(a!=null?a:"")===d&&(u.selected=!0)}let c=()=>{let d=o.value;this.saveCustomField(e,s,d===""?null:d).then(()=>{var h;let u=this.getItem();this.renderCustomValueDisplay(t,u!=null?u:e,s,(h=u==null?void 0:u.customFields)==null?void 0:h[s.id])})};o.addEventListener("change",c),o.addEventListener("blur",c),o.focus();return}let n=t.createEl("input",{cls:"wl-modal-input wl-reading-custom-input",attr:{type:s.type==="number"?"number":"text",placeholder:"Enter value\u2026"}});a!=null&&(n.value=String(a));let r=()=>{let o=n.value.trim(),l;if(o==="")l=null;else if(s.type==="number"){let c=Number(o);l=isNaN(c)?null:c}else l=o;this.saveCustomField(e,s,l).then(()=>{var d;let c=this.getItem();this.renderCustomValueDisplay(t,c!=null?c:e,s,(d=c==null?void 0:c.customFields)==null?void 0:d[s.id])})};n.addEventListener("blur",r),n.addEventListener("keydown",o=>{var l;if(o.key==="Enter")o.preventDefault(),n.blur();else if(o.key==="Escape"){o.preventDefault();let c=this.getItem();this.renderCustomValueDisplay(t,c!=null?c:e,s,(l=c==null?void 0:c.customFields)==null?void 0:l[s.id])}}),n.focus(),n.select()}async saveCustomField(t,e,s){await this.readingData.setCustomField(this.mode,t.id,e.id,s)}async renderQuotesSection(t){let e=this.contentEl.createDiv({cls:"wl-reading-detail-quotes"}),s=e.createDiv({cls:"wl-reading-detail-quotes-heading"});s.createSpan({cls:"wl-reading-section-label",text:"Favorite quotes"});let a=s.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-detail-quotes-add",text:"Add quote"}),n=e.createDiv({cls:"wl-reading-quote-list"}),r=e.createDiv({cls:"wl-reading-quote-form-host"}),o=async()=>{n.empty();try{let l=await this.readingData.readReadingNote(this.mode,t),c=l?xn(l):[];if(c.length===0)n.createDiv({cls:"wl-reading-quote-empty",text:"No quotes yet."});else for(let d of c)this.renderQuoteCard(n,d)}catch(l){console.warn("[WL] quotes read failed:",l)}};a.addEventListener("click",()=>{r.empty(),this.renderAddQuoteForm(r,t,async()=>{await o()})}),o()}renderQuoteCard(t,e){let s=t.createDiv({cls:"wl-reading-quote-card"});s.createDiv({cls:"wl-reading-quote-text",text:e.text}),e.reference&&s.createDiv({cls:"wl-reading-quote-ref",text:e.reference})}renderAddQuoteForm(t,e,s){t.empty();let a=t.createDiv({cls:"wl-reading-quote-form"}),n=a.createEl("textarea",{cls:"wl-modal-input wl-reading-quote-textarea",attr:{placeholder:"Quote text\u2026",rows:"3"}}),r=a.createEl("input",{cls:"wl-modal-input wl-reading-quote-ref-input",attr:{type:"text",placeholder:"p. 123 or ch. 5 (optional)"}}),o=a.createDiv({cls:"wl-reading-quote-form-actions"});o.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Cancel"}).addEventListener("click",()=>t.empty()),o.createEl("button",{cls:"wl-reading-add-btn wl-btn-success wl-reading-quote-save",text:"Save quote"}).addEventListener("click",()=>{let d=n.value.trim();if(!d){new nt.Notice("Enter the quote text first.");return}(async()=>{try{await this.readingData.appendQuote(this.mode,e,d,r.value),t.empty(),await s()}catch(u){console.warn("[WL] appendQuote failed:",u),new nt.Notice("Could not save quote.")}})()}),n.focus()}async commitDraft(){let t=this.getItem();if(t){if(this.mode==="book"){let s={...t,pagesRead:this.draft.pagesRead,chaptersRead:this.draft.chaptersRead};this.applyAutoComplete(s),await this.readingData.updateBook(s)}else{let s={...t,chaptersRead:this.draft.chaptersRead,volumesRead:this.draft.volumesRead};this.applyAutoComplete(s),await this.readingData.updateManga(s)}this.logProgressChange(t),this.openSnapshot={...this.draft},new nt.Notice("Progress updated."),this.onChanged(),this.close()}}applyAutoComplete(t){if((this.mode==="book"?this.isBookComplete(t):this.isMangaComplete(t))&&t.status!=="Completed"&&(t.status="Completed"),t.status==="Completed"&&!t.dateFinished){let s=new Date,a=s.getFullYear(),n=String(s.getMonth()+1).padStart(2,"0"),r=String(s.getDate()).padStart(2,"0");t.dateFinished=`${a}-${n}-${r}`}}isBookComplete(t){return t.totalPages>0&&t.pagesRead>=t.totalPages||t.totalChapters>0&&t.chaptersRead>=t.totalChapters}isMangaComplete(t){return t.totalChapters>0&&t.chaptersRead>=t.totalChapters}};var ta="__has__",ea="__none__";function Ln(g,i){var e;let t=(e=g.customFields)==null?void 0:e[i];return t!=null&&t!==""}function ds(){return{statusExclude:[],ratingMode:"all",customExclude:{}}}function ia(){return{key:"dateAdded",dir:"desc",secondKey:"none",secondDir:"asc"}}function Rn(g){var t,e;let i=0;g.statusExclude.length>0&&i++,g.ratingMode!=="all"&&i++;for(let s of Object.keys(g.customExclude))((e=(t=g.customExclude[s])==null?void 0:t.length)!=null?e:0)>0&&i++;return i}function Te(g){switch(g){case"Reading":return"#1D9E75";case"Completed":return"#7F77DD";case"Plan to Read":return"#E8873A";case"To be released":return"#3A86C8";case"Dropped":return"#E24B4A";default:return"#888780"}}var sa=["#3a4a6b","#4a3a6b","#6b3a4a","#6b5a3a","#3a6b5a","#5a6b3a","#3a5a6b","#6b3a5a"];function cs(g){var t;let i=0;for(let e=0;e>>0;return(t=sa[i%sa.length])!=null?t:"#3a4a6b"}function aa(g){return g.totalPages>0?Math.min(100,g.pagesRead/g.totalPages*100):0}function na(g){return g.totalChapters>0?Math.min(100,g.chaptersRead/g.totalChapters*100):0}var rt=class rt{constructor(i,t,e){this.searchQuery="";this.contentEl=null;this.filterBtn=null;this.sortBtn=null;this.resetBtn=null;this.savedFilterActive=!1;this.savedFilterBtnEl=null;this.openPopover=null;this.popoverCleanup=null;this.activeCleanups=[];this.selectionMode=!1;this.selectedIds=new Set;this.toolbarExpanded=!1;this.vsScrollContainer=null;this.vsScrollSpacer=null;this.vsGridEl=null;this.vsDisplayItems=[];this.vsScrollHandler=null;this.vsScrollRAF=null;this.vsResizeObserver=null;this.vsLastFirst=-1;this.vsLastLast=-1;this.vsLastScrollTop=0;this.vsPersistentScrollTop=0;this.vsRowHeight=0;this.coverObserver=null;this.observedCovers=new Set;this.coverFetchFailed=new Set;this.container=i,this.plugin=t,this.readingData=e,this.dataChangeListener=()=>this.renderContent(),this.readingData.onChange(this.dataChangeListener)}get activeSubTab(){var i;return rt.sessionSubTab!==null?rt.sessionSubTab:(i=this.readingData.getSettings().defaultSubTab)!=null?i:"books"}set activeSubTab(i){rt.sessionSubTab=i}get filters(){return rt.sessionFilters[this.activeSubTab]}get sort(){return rt.sessionSort[this.activeSubTab]}activeColumns(){return this.activeSubTab==="books"?this.readingData.getBookColumns():this.readingData.getMangaColumns()}destroy(){this.readingData.offChange(this.dataChangeListener),this.closePopover(),this.destroyVirtualScroll();for(let i of this.activeCleanups)i();this.activeCleanups=[]}render(){this.container.empty(),this.container.addClass("wl-reading-tab"),this.renderSubTabs(),this.renderToolbar(),this.contentEl=this.container.createDiv({cls:"wl-reading-content"}),this.renderContent()}renderSubTabs(){let i=this.container.createDiv({cls:"wl-reading-subtabs"}),t=i.createEl("button",{cls:`wl-reading-subtab${this.activeSubTab==="books"?" is-active":""}`,text:"Books"}),e=i.createEl("button",{cls:`wl-reading-subtab${this.activeSubTab==="manga"?" is-active":""}`,text:"Manga"});t.addEventListener("click",()=>{this.activeSubTab!=="books"&&(this.activeSubTab="books",this.searchQuery="",this.render())}),e.addEventListener("click",()=>{this.activeSubTab!=="manga"&&(this.activeSubTab="manga",this.searchQuery="",this.render())})}renderToolbar(){let i=this.container.createDiv({cls:"wl-reading-toolbar"});Qe({controls:i,renderSearch:t=>this.renderReadingSearch(t),renderActions:t=>this.renderReadingActions(t),expanded:this.toolbarExpanded,onToggleChange:t=>{this.toolbarExpanded=t}})}renderReadingSearch(i){let t=i.createDiv({cls:"wl-reading-search-wrap"}),e=this.activeSubTab==="books"?"Search books...":"Search manga...",s=t.createEl("input",{cls:"wl-reading-search-input",attr:{type:"text",placeholder:e}});s.value=this.searchQuery;let a=0;s.addEventListener("input",()=>{this.searchQuery=s.value,window.clearTimeout(a),a=window.setTimeout(()=>this.renderContent(),200)})}renderReadingActions(i){let t=this.getSavedFilter();if(t){this.savedFilterActive=this.filtersMatchSaved(t);let r=i.createEl("button",{cls:`wl-btn wl-btn-sm${this.savedFilterActive?" wl-btn-preset-active":""}`,text:"Saved filter"});this.savedFilterBtnEl=r,r.addEventListener("click",()=>{rt.sessionFilters[this.activeSubTab]={statusExclude:Mt.filter(o=>!t.statusInclude.includes(o)),ratingMode:t.ratingMode,customExclude:{}},this.savedFilterActive=!0,r.addClass("wl-btn-preset-active"),this.refreshFilterButtonBadge(),this.render()})}else this.savedFilterBtnEl=null;if(this.filterBtn=i.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-filter-btn",text:"Filter"}),this.refreshFilterButtonBadge(),this.filterBtn.addEventListener("click",r=>{r.stopPropagation(),this.toggleFilterPopover()}),this.resetBtn=i.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-reset-btn",text:"Reset"}),this.resetBtn.addEventListener("click",()=>{var r;rt.sessionFilters[this.activeSubTab]=ds(),this.deactivateSavedFilter(),this.closePopover(),(r=this.filterBtn)==null||r.removeClass("is-popover-open"),this.refreshFilterButtonBadge(),this.renderContent()}),this.refreshFilterButtonBadge(),this.sortBtn=i.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-sort-btn",text:"Sort"}),this.sortBtn.addEventListener("click",r=>{r.stopPropagation(),this.toggleSortPopover()}),this.selectionMode&&this.selectedIds.size>0&&this.renderSelectionActionBar(i),this.selectionMode){let r=this.selectedIds.size>0,o=i.createEl("button",{cls:"wl-btn wl-btn-sm",text:r?"None":"All"});o.title=r?"Deselect all":"Select all visible",o.addEventListener("click",()=>{if(this.selectedIds.size>0)this.selectedIds.clear();else for(let l of this.vsDisplayItems)this.selectedIds.add(l.id);this.render()})}i.createEl("button",{cls:`wl-btn wl-btn-sm${this.selectionMode?" is-active":""}`,text:"Select"}).addEventListener("click",()=>{this.selectionMode=!this.selectionMode,this.selectedIds.clear(),this.render()});let s=i.createDiv({cls:"wl-reading-toolbar-right"});s.createEl("button",{cls:"wl-btn wl-btn-sm wl-reading-manage-btn",attr:{"aria-label":"Manage columns",title:"Manage columns"},text:"\u2699"}).addEventListener("click",()=>this.openManageColumns()),s.createEl("button",{cls:"wl-reading-add-btn wl-btn-success",text:this.activeSubTab==="books"?"+ Add book":"+ Add manga"}).addEventListener("click",()=>this.openAddModal())}renderSelectionActionBar(i){let t=i.createDiv({cls:"wl-reading-action-bar"}),e=t.createEl("button",{cls:"wl-group-action-btn wl-group-action-btn-delete wl-btn-danger",text:"\u2715"});e.title="Delete selected",e.addEventListener("click",a=>{a.stopPropagation();let n=this.selectedIds.size;new _(this.plugin.app,`Delete ${n} selected item${n!==1?"s":""}? This cannot be undone.`,()=>{(async()=>{let r=Array.from(this.selectedIds);this.activeSubTab==="books"?await this.readingData.removeBooksBatch(r):await this.readingData.removeMangaBatch(r),this.selectedIds.clear(),this.selectionMode=!1,this.render()})()}).open()});let s=t.createEl("select",{cls:"wl-select wl-select-sm"});s.createEl("option",{text:"Status\u2026",value:""});for(let a of ct)s.createEl("option",{text:a,value:a});s.addEventListener("change",()=>{(async()=>{let a=s.value;if(!a)return;let n=this.activeSubTab==="books";for(let r of this.selectedIds)if(n){let o=this.readingData.getBook(r);o&&this.readingData.updateBookSilent({...o,status:a})}else{let o=this.readingData.getManga(r);o&&this.readingData.updateMangaSilent({...o,status:a})}await this.readingData.saveAndNotify(),s.value="",this.selectedIds.clear(),this.selectionMode=!1,this.render()})()})}refreshFilterButtonBadge(){if(!this.filterBtn)return;let i=Rn(this.filters);this.filterBtn.empty(),this.filterBtn.createSpan({text:"Filter"}),i>0&&this.filterBtn.createSpan({cls:"wl-reading-filter-badge",text:String(i)}),this.resetBtn&&(this.resetBtn.style.display=i>0?"":"none")}closePopover(){this.openPopover&&(this.openPopover.remove(),this.openPopover=null),this.popoverCleanup&&(this.popoverCleanup(),this.popoverCleanup=null)}openPopoverAt(i,t,e){this.closePopover();let s=this.container.createDiv({cls:`${t} wl-popover-anchored`}),a=i.getBoundingClientRect(),n=this.container.getBoundingClientRect();s.setCssProps({top:`${a.bottom-n.top+4}px`,left:`${a.left-n.left}px`}),e(s),this.openPopover=s;let r=l=>{s.contains(l.target)||this.closePopover()},o=l=>{l.key==="Escape"&&this.closePopover()};window.setTimeout(()=>activeDocument.addEventListener("click",r),0),activeDocument.addEventListener("keydown",o),this.popoverCleanup=()=>{activeDocument.removeEventListener("click",r),activeDocument.removeEventListener("keydown",o)}}toggleFilterPopover(){var i,t,e;if(this.openPopover&&((i=this.filterBtn)!=null&&i.hasClass("is-popover-open"))){this.closePopover(),this.filterBtn.removeClass("is-popover-open");return}(t=this.sortBtn)==null||t.removeClass("is-popover-open"),(e=this.filterBtn)==null||e.addClass("is-popover-open"),this.openPopoverAt(this.filterBtn,"wl-dropdown wl-filters-panel",s=>this.buildFilterPopover(s))}toggleSortPopover(){var i,t,e;if(this.openPopover&&((i=this.sortBtn)!=null&&i.hasClass("is-popover-open"))){this.closePopover(),this.sortBtn.removeClass("is-popover-open");return}(t=this.filterBtn)==null||t.removeClass("is-popover-open"),(e=this.sortBtn)==null||e.addClass("is-popover-open"),this.openPopoverAt(this.sortBtn,"wl-dropdown wl-sorting-panel",s=>this.buildSortPopover(s))}getSavedFilter(){var i,t;return(t=(i=this.readingData.getSettings().savedFilters)==null?void 0:i[this.activeSubTab])!=null?t:null}filtersMatchSaved(i){let t=this.filters;if(Object.values(t.customExclude).some(a=>a.length>0))return!1;let e=new Set(Mt.filter(a=>!i.statusInclude.includes(a))),s=new Set(t.statusExclude);if(s.size!==e.size)return!1;for(let a of s)if(!e.has(a))return!1;return t.ratingMode===i.ratingMode}deactivateSavedFilter(){var i;this.savedFilterActive&&(this.savedFilterActive=!1,(i=this.savedFilterBtnEl)==null||i.removeClass("wl-btn-preset-active"))}buildFilterPopover(i){var s;let t={statusExclude:new Set(this.filters.statusExclude),ratingMode:this.filters.ratingMode,customExclude:new Map};for(let a of this.activeColumns())t.customExclude.set(a.id,new Set((s=this.filters.customExclude[a.id])!=null?s:[]));let e={};this.renderFilterPopoverBody(i,t,e)}addFilterSection(i,t,e,s,a){var c,d;let n=i.createDiv({cls:"wl-filter-section"}),r=n.createDiv({cls:"wl-filter-section-header"});r.createSpan({cls:"wl-filter-label",text:s});let o=r.createSpan({cls:"wl-filter-chevron",text:(c=t[e])==null||c?"\u25BC":"\u25B2"}),l=n.createDiv({cls:"wl-filter-section-content"});l.toggleClass("wl-hidden",(d=t[e])!=null?d:!0),r.addEventListener("click",u=>{var p;u.stopPropagation();let h=!((p=t[e])==null||p);t[e]=h,l.toggleClass("wl-hidden",h),o.textContent=h?"\u25BC":"\u25B2"}),a(l)}addMultiSelectBody(i,t,e){let s=[],a=i.createDiv({cls:"wl-filter-checkbox-row"}),n=a.createEl("input",{attr:{type:"checkbox"}});a.createSpan({cls:"wl-filter-all-toggle",text:"\u25C6 All"});let r=()=>{n.checked=s.length>0&&s.every(l=>l.checked)};for(let l of t){let c=i.createDiv({cls:"wl-filter-checkbox-row"}),d=c.createEl("input",{attr:{type:"checkbox"}});d.checked=!e.has(l),c.createSpan({text:l}),s.push(d),d.addEventListener("change",()=>{d.checked?e.delete(l):e.add(l),r()})}r();let o=()=>{if(s.length>0&&s.every(c=>c.checked)){for(let c of s)c.checked=!1;for(let c of t)e.add(c)}else{for(let c of s)c.checked=!0;e.clear()}r()};return n.addEventListener("click",l=>{l.stopPropagation(),o()}),a.addEventListener("click",l=>{l.target!==n&&(l.stopPropagation(),o())}),{selectAll:()=>{for(let l of s)l.checked=!0;e.clear(),r()},deselectAll:()=>{for(let l of s)l.checked=!1;for(let l of t)e.add(l);r()}}}addHasValueBody(i,t){let e=[];for(let[s,a]of[[ta,"Has value"],[ea,"No value"]]){let n=i.createDiv({cls:"wl-filter-checkbox-row"}),r=n.createEl("input",{attr:{type:"checkbox"}});r.checked=!t.has(s),n.createSpan({text:a}),r.addEventListener("change",()=>{r.checked?t.delete(s):t.add(s)}),e.push({key:s,cb:r})}return{selectAll:()=>{for(let s of e)s.cb.checked=!0,t.delete(s.key)},deselectAll:()=>{for(let s of e)s.cb.checked=!1,t.add(s.key)}}}renderFilterPopoverBody(i,t,e){var d;i.empty();let s=[],a=i.createDiv({cls:"wl-filter-global-btns"});a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Select all"}).addEventListener("click",u=>{u.stopPropagation();for(let h of s)h.selectAll()}),a.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Deselect all"}).addEventListener("click",u=>{u.stopPropagation();for(let h of s)h.deselectAll()});let o=a.createEl("button",{cls:"wl-btn wl-btn-sm",text:this.getSavedFilter()?"Delete":"Save"});o.addEventListener("click",u=>{u.stopPropagation(),(async()=>{var p,m;let h={...(p=this.readingData.getSettings().savedFilters)!=null?p:{}};o.textContent==="Save"?(h[this.activeSubTab]={name:"Saved filter",statusInclude:Mt.filter(f=>!t.statusExclude.has(f)),ratingMode:t.ratingMode},await this.readingData.updateSettings({savedFilters:h})):(delete h[this.activeSubTab],await this.readingData.updateSettings({savedFilters:h}),this.savedFilterActive=!1),this.closePopover(),(m=this.filterBtn)==null||m.removeClass("is-popover-open"),this.render()})()}),this.addFilterSection(i,e,"Status","Status",u=>{s.push(this.addMultiSelectBody(u,Mt,t.statusExclude))}),this.addFilterSection(i,e,"Rating","Rating",u=>{let h=[{key:"all",label:"All"},{key:"has",label:"Has rating"},{key:"none",label:"No rating"}],p=`wl-reading-rating-${Date.now()}`;for(let m of h){let f=u.createDiv({cls:"wl-filter-checkbox-row"}),y=f.createEl("input",{attr:{type:"radio",name:p}});y.checked=t.ratingMode===m.key,f.createSpan({text:m.label}),y.addEventListener("change",()=>{y.checked&&(t.ratingMode=m.key)})}});for(let u of this.activeColumns()){let h=(d=t.customExclude.get(u.id))!=null?d:new Set;t.customExclude.set(u.id,h),this.addFilterSection(i,e,`custom:${u.id}`,u.name,p=>{u.type==="select"?s.push(this.addMultiSelectBody(p,u.options,h)):s.push(this.addHasValueBody(p,h))})}i.createDiv({cls:"wl-filter-apply-wrap"}).createEl("button",{cls:"wl-btn wl-btn-sm wl-filter-apply-btn",text:"Apply"}).addEventListener("click",u=>{var p;u.stopPropagation();let h={};for(let[m,f]of t.customExclude)f.size>0&&(h[m]=Array.from(f));rt.sessionFilters[this.activeSubTab]={statusExclude:Array.from(t.statusExclude),ratingMode:t.ratingMode,customExclude:h},this.deactivateSavedFilter(),this.refreshFilterButtonBadge(),this.closePopover(),(p=this.filterBtn)==null||p.removeClass("is-popover-open"),this.renderContent()})}buildSortPopover(i){let t=[{key:"dateAdded",label:"Date added"},{key:"title",label:"Title"},{key:"author",label:"Author"},{key:"rating",label:"Rating"},{key:"progress",label:"Progress"},{key:"status",label:"Status"},{key:"dateStarted",label:"Date started"},{key:"dateFinished",label:"Date finished"}];for(let s of this.activeColumns())t.push({key:`custom:${s.id}`,label:s.name});let e=(s,a,n,r)=>{let o=i.createDiv({cls:"wl-filter-row"});o.createSpan({cls:"wl-filter-label",text:s});let l=o.createEl("select",{cls:"wl-select"});if(!r){let d=l.createEl("option",{text:"None",value:"none"});a==="none"&&(d.selected=!0)}for(let d of t){let u=l.createEl("option",{text:d.label,value:d.key});d.key===a&&(u.selected=!0)}let c=o.createEl("button",{cls:"wl-btn wl-btn-sm wl-sort-dir-btn",text:n==="asc"?"\u2191":"\u2193"});c.title=n==="asc"?"Ascending \u2014 click to switch to descending":"Descending \u2014 click to switch to ascending",l.addEventListener("change",()=>{var d;r?this.sort.key=l.value:this.sort.secondKey=l.value==="none"?"none":l.value,this.closePopover(),(d=this.sortBtn)==null||d.removeClass("is-popover-open"),this.renderContent()}),c.addEventListener("click",d=>{var u;d.stopPropagation(),r?this.sort.dir=this.sort.dir==="asc"?"desc":"asc":this.sort.secondDir=this.sort.secondDir==="asc"?"desc":"asc",this.closePopover(),(u=this.sortBtn)==null||u.removeClass("is-popover-open"),this.renderContent()})};e("Sort by",this.sort.key,this.sort.dir,!0),e("Then by",this.sort.secondKey,this.sort.secondDir,!1)}applyFilters(i){let t=this.filters,e=this.activeColumns();return i.filter(s=>{var a;if(t.statusExclude.includes(s.status)||t.ratingMode==="has"&&!(s.rating>0)||t.ratingMode==="none"&&s.rating>0)return!1;for(let n of e){let r=t.customExclude[n.id];if(!(!r||r.length===0))if(n.type==="select"){let o=(a=s.customFields)==null?void 0:a[n.id],l=o==null?"":String(o);if(l!==""&&r.includes(l))return!1}else{let o=Ln(s,n.id);if(o&&r.includes(ta)||!o&&r.includes(ea))return!1}}return!0})}applySearch(i){let t=this.searchQuery.trim();return t?new X(i,{keys:["title","author"],threshold:.4,ignoreLocation:!0}).search(t).map(s=>s.item):i}compareBySortKey(i,t,e,s,a){var n,r,o,l;if(e.startsWith("custom:"))return this.compareCustom(i,t,e.slice(7),s);switch(e){case"title":return i.title.localeCompare(t.title)*s;case"author":return(i.author||"").localeCompare(t.author||"")*s;case"rating":return(i.rating-t.rating)*s;case"dateAdded":return i.dateAdded.localeCompare(t.dateAdded)*s;case"dateStarted":return((n=i.dateStarted)!=null?n:"").localeCompare((r=t.dateStarted)!=null?r:"")*s;case"dateFinished":return((o=i.dateFinished)!=null?o:"").localeCompare((l=t.dateFinished)!=null?l:"")*s;case"status":return i.status.localeCompare(t.status)*s;case"progress":{let c=a?aa(i):na(i),d=a?aa(t):na(t);return(c-d)*s}default:return 0}}compareCustom(i,t,e,s){var c,d;let a=this.activeColumns().find(u=>u.id===e),n=(c=i.customFields)==null?void 0:c[e],r=(d=t.customFields)==null?void 0:d[e],o=n==null||n==="",l=r==null||r==="";return o&&l?0:o?1:l?-1:(a==null?void 0:a.type)==="number"?(Number(n)-Number(r))*s:String(n).localeCompare(String(r))*s}applySort(i){let{key:t,dir:e,secondKey:s,secondDir:a}=this.sort,n=this.activeSubTab==="books",r=e==="asc"?1:-1,o=a==="asc"?1:-1;return[...i].sort((l,c)=>{let d=this.compareBySortKey(l,c,t,r,n);return d!==0||s==="none"?d:this.compareBySortKey(l,c,s,o,n)})}renderContent(){if(!this.contentEl)return;this.destroyVirtualScroll();for(let n of this.activeCleanups)n();this.activeCleanups=[],this.contentEl.empty();let t=this.activeSubTab==="books"?this.readingData.getBooks():this.readingData.getMangaList();if(t.length===0){this.renderEmptyState();return}let e=this.applyFilters(t),s=this.applySearch(e),a=this.applySort(s);if(a.length===0){let n=this.searchQuery.trim();this.contentEl.createDiv({cls:"wl-reading-empty-search",text:n?`No matches for "${n}".`:"No items match the current filters."});return}this.renderResultsCount(a.length),this.vsDisplayItems=a,this.renderVirtualGrid()}renderResultsCount(i){if(!this.contentEl)return;let t=this.contentEl.createDiv({cls:"wl-results-count"});t.textContent=`${i} title${i!==1?"s":""}`}destroyVirtualScroll(){this.destroyCoverObserver(),this.vsScrollRAF!==null&&(window.cancelAnimationFrame(this.vsScrollRAF),this.vsScrollRAF=null),this.vsResizeObserver&&(this.vsResizeObserver.disconnect(),this.vsResizeObserver=null),this.vsScrollContainer&&this.vsScrollHandler&&this.vsScrollContainer.removeEventListener("scroll",this.vsScrollHandler),this.vsScrollHandler=null,this.vsScrollContainer=null,this.vsScrollSpacer=null,this.vsGridEl=null,this.vsDisplayItems=[],this.vsLastFirst=-1,this.vsLastLast=-1,this.vsLastScrollTop=0,this.vsRowHeight=0}renderVirtualGrid(){if(!this.contentEl)return;let i=this.contentEl.createDiv({cls:"wl-reading-scroll-container"}),t=i.createDiv({cls:"wl-reading-scroll-spacer"}),e=t.createDiv({cls:"wl-reading-grid wl-reading-grid-virtual"});this.vsScrollContainer=i,this.vsScrollSpacer=t,this.vsGridEl=e,this.vsLastFirst=-1,this.vsLastLast=-1,this.vsScrollHandler=()=>{let s=i.scrollTop;this.vsPersistentScrollTop=s;let a=this.vsRowHeight>0?this.vsRowHeight/2:50;Math.abs(s-this.vsLastScrollTop){this.vsScrollRAF=null,this.renderVisibleCards()})))},i.addEventListener("scroll",this.vsScrollHandler,{passive:!0}),this.vsResizeObserver=new ResizeObserver(()=>{this.renderVisibleCards()}),this.vsResizeObserver.observe(i),this.vsPersistentScrollTop>0&&(this.renderVisibleCards(),i.scrollTop=this.vsPersistentScrollTop,this.vsLastScrollTop=this.vsPersistentScrollTop,this.renderVisibleCards())}getGridMetrics(i){let s=Math.max(1,Math.floor((i+12)/152)),a=(i-12*(s-1))/s,r=a*1.5+72,o=r+12;return{cols:s,cardWidth:a,cardHeight:r,rowHeight:o}}renderVisibleCards(){let i=this.vsScrollContainer,t=this.vsScrollSpacer,e=this.vsGridEl;if(!i||!t||!e)return;let s=i.scrollTop,a=i.clientHeight,n=i.clientWidth;if(n<=0||a<=0)return;let{cols:r,cardHeight:o,rowHeight:l}=this.getGridMetrics(n);this.vsRowHeight=l;let c=this.vsDisplayItems.length,d=Math.ceil(c/r),u=Math.max(0,Math.floor(s/l)-2),h=Math.min(d-1,Math.ceil((s+a)/l)+2),p=u*r,m=Math.min(c-1,(h+1)*r-1);t.style.height=`${d*l}px`,e.style.transform=`translateY(${u*l}px)`,e.style.setProperty("--wl-reading-cols",String(r)),e.style.setProperty("--wl-reading-card-height",`${o}px`);let f=this.vsLastFirst,y=this.vsLastLast;if(p===f&&m===y)return;this.vsLastFirst=p,this.vsLastLast=m,e.empty();let v=this.activeSubTab==="books",w=activeDocument.createDocumentFragment();for(let b=p;b<=m;b++){let E=this.vsDisplayItems[b];if(!E)continue;let D=activeDocument.createElement("div");v?this.renderBookCard(D,E):this.renderMangaCard(D,E);let S=D.firstElementChild;S&&w.appendChild(S)}e.appendChild(w),this.setupCoverObserver()}setupCoverObserver(){let i=this.vsScrollContainer,t=this.vsGridEl;!i||!t||(this.coverObserver||(this.coverObserver=new IntersectionObserver(e=>this.handleCoverIntersection(e),{root:i,rootMargin:"0px",threshold:0})),this.observedCovers.clear(),t.querySelectorAll('.wl-reading-card[data-needs-cover="true"]').forEach(e=>{let s=e;this.observedCovers.has(s)||(this.coverObserver.observe(s),this.observedCovers.add(s))}))}handleCoverIntersection(i){var e;let t=this.activeSubTab==="books"?"book":"manga";for(let s of i){if(!s.isIntersecting)continue;let a=s.target;(e=this.coverObserver)==null||e.unobserve(a),this.observedCovers.delete(a);let n=a.dataset.itemId;if(!n)continue;let r=t==="book"?this.readingData.getBook(n):this.readingData.getManga(n);if(!r||r.coverUrl||this.coverFetchFailed.has(n))continue;let o=a.querySelector(".wl-reading-card-cover");o==null||o.addClass("is-loading"),this.resolveCover(t,r).then(({url:l,sourceId:c})=>{o==null||o.removeClass("is-loading"),l?(c?this.readingData.updateCoverAndSource(t,n,l,c):this.readingData.updateCoverUrl(t,n,l),this.applyCoverToCard(a,l,r.title)):this.coverFetchFailed.add(n)})}}async resolveCover(i,t){var e,s;try{if(i==="book"){let o=t.googleBooksId;if(o){let u=await this.plugin.apiService.getGoogleBookById(o);return{url:(e=u==null?void 0:u.coverUrl)!=null?e:"",sourceId:""}}let l=t.author?`${t.title} ${t.author}`:t.title,d=(await this.plugin.apiService.searchGoogleBooks(l))[0];return!d||!d.coverUrl||!d.googleBooksId?{url:"",sourceId:""}:{url:d.coverUrl,sourceId:d.googleBooksId}}let a=t.malId;if(a){let o=await this.plugin.apiService.getMangaByMalId(Number(a));return{url:(s=o==null?void 0:o.coverUrl)!=null?s:"",sourceId:""}}let r=(await this.plugin.apiService.searchManga(t.title))[0];return!r||!r.coverUrl||!r.malId?{url:"",sourceId:""}:{url:r.coverUrl,sourceId:String(r.malId)}}catch(a){return{url:"",sourceId:""}}}applyCoverToCard(i,t,e){let s=i.querySelector(".wl-reading-card-cover");if(!s)return;let a=s.querySelector(".wl-reading-card-cover-icon"),n=activeDocument.createElement("img");n.className="wl-reading-card-cover-img",n.alt=e,n.loading="lazy",n.onload=()=>{s.style.removeProperty("background-color"),a==null||a.remove()},n.onerror=()=>{n.remove()},s.insertBefore(n,s.firstChild),n.src=t,delete i.dataset.needsCover}destroyCoverObserver(){this.coverObserver&&(this.coverObserver.disconnect(),this.coverObserver=null),this.observedCovers.clear()}renderBookCard(i,t){let e=this.renderCardShell(i,t,"\u{1F4D6}"),s=t.totalPages>0?Math.min(100,Math.round(t.pagesRead/t.totalPages*100)):0;this.renderProgressBar(e,s,t.status);let a=e.createDiv({cls:"wl-reading-card-progress-text"});t.totalPages>0?a.textContent=`${t.pagesRead} / ${t.totalPages} pages`:t.pagesRead>0?a.textContent=`${t.pagesRead} pages`:a.textContent="No progress",this.bindCardClick(e,"book",t.id)}renderMangaCard(i,t){let e=this.renderCardShell(i,t,"\u{1F4D3}"),s=t.totalChapters>0?Math.min(100,Math.round(t.chaptersRead/t.totalChapters*100)):0;this.renderProgressBar(e,s,t.status);let a=e.createDiv({cls:"wl-reading-card-progress-text"}),n=t.totalChapters>0?`Ch. ${t.chaptersRead}/${t.totalChapters}`:t.chaptersRead>0?`Ch. ${t.chaptersRead}`:"",r=t.totalVolumes>0?`Vol. ${t.volumesRead}/${t.totalVolumes}`:t.volumesRead>0?`Vol. ${t.volumesRead}`:"";n&&a.createSpan({cls:"wl-reading-card-progress-piece",text:n}),r&&a.createSpan({cls:"wl-reading-card-progress-piece",text:r}),!n&&!r&&(a.textContent="No progress"),this.bindCardClick(e,"manga",t.id)}bindCardClick(i,t,e){this.selectionMode?(this.selectedIds.has(e)&&i.addClass("is-selected"),i.addEventListener("click",s=>{s.stopPropagation(),this.selectedIds.has(e)?(this.selectedIds.delete(e),i.removeClass("is-selected")):(this.selectedIds.add(e),i.addClass("is-selected")),this.render()})):i.addEventListener("click",()=>this.openDetailModal(t,e))}renderCardShell(i,t,e){let s=i.createDiv({cls:"wl-reading-card"}),a=s.createDiv({cls:"wl-reading-card-cover"});t.coverUrl?a.createEl("img",{cls:"wl-reading-card-cover-img",attr:{src:t.coverUrl,alt:t.title,loading:"lazy"}}):(a.style.backgroundColor=cs(t.id),a.createSpan({cls:"wl-reading-card-cover-icon",text:e}),this.coverFetchFailed.has(t.id)||(s.dataset.needsCover="true",s.dataset.itemId=t.id));let n=a.createSpan({cls:"wl-reading-card-status-badge",text:t.status});n.style.backgroundColor=Te(t.status);let r=s.createEl("button",{cls:"wl-reading-card-menu-btn",text:"\u22EE"});r.setAttr("aria-label","More actions"),r.addEventListener("click",c=>{c.stopPropagation(),this.openCardContextMenu(s,r,t)});let o=s.createDiv({cls:"wl-reading-card-title",text:t.title});o.title=t.title;let l=s.createDiv({cls:"wl-reading-card-author",text:t.author||"\u2014"});return l.title=t.author||"",s}openCardContextMenu(i,t,e){this.container.querySelectorAll(".wl-reading-card-context-menu").forEach(d=>d.remove());let s=i.createDiv({cls:"wl-reading-card-context-menu"}),a=s.createDiv({cls:"wl-reading-card-context-item",text:"Refresh cover"}),n=i.getBoundingClientRect(),r=this.container.getBoundingClientRect();n.right>r.right-180&&s.classList.add("is-right-aligned");let o=i.ownerDocument,l=()=>{s.remove(),o.removeEventListener("click",c,!0)},c=d=>{!s.contains(d.target)&&d.target!==t&&l()};window.setTimeout(()=>o.addEventListener("click",c,!0),0),this.activeCleanups.push(()=>o.removeEventListener("click",c,!0)),a.addEventListener("click",d=>{d.stopPropagation(),l(),this.refreshCover(e)})}refreshCover(i){if((this.activeSubTab==="books"?"book":"manga")==="book"){let s=i;if(!s.googleBooksId){new wt.Notice("No Google Books ID \u2014 cannot refresh cover.");return}if(!this.plugin.apiService.hasGoogleBooksKey()){new wt.Notice("Google Books API key required \u2014 add one in Settings \u2192 API \u2192 Books.");return}(async()=>{try{let a=await this.plugin.apiService.getGoogleBookById(s.googleBooksId);if(!a||!a.coverUrl){new wt.Notice("Could not fetch cover from API.");return}let n=this.readingData.getBook(s.id);if(!n)return;await this.readingData.updateBook({...n,coverUrl:a.coverUrl}),new wt.Notice("Cover refreshed.")}catch(a){new wt.Notice(It(a))}})()}else{let s=i;if(!s.malId){new wt.Notice("No MAL ID \u2014 cannot refresh cover.");return}(async()=>{try{let a=await this.plugin.apiService.getMangaByMalId(Number(s.malId));if(!a||!a.coverUrl){new wt.Notice("Could not fetch cover from API.");return}let n=this.readingData.getManga(s.id);if(!n)return;await this.readingData.updateManga({...n,coverUrl:a.coverUrl}),new wt.Notice("Cover refreshed.")}catch(a){new wt.Notice("Failed to refresh cover.")}})()}}renderProgressBar(i,t,e){let a=i.createDiv({cls:"wl-reading-card-progress-bar"}).createDiv({cls:"wl-reading-card-progress-fill"});a.style.width=`${t}%`,a.style.backgroundColor=Te(e)}renderEmptyState(){if(!this.contentEl)return;let i=this.contentEl.createDiv({cls:"wl-reading-empty"}),t=this.activeSubTab==="books";i.createSpan({cls:"wl-reading-empty-icon",text:t?"\u{1F4D6}":"\u{1F4D3}"});let e=i.createDiv({cls:"wl-reading-empty-msg"});e.createSpan({text:t?"No books yet \u2014 ":"No manga yet \u2014 "}),e.createEl("a",{cls:"wl-reading-empty-link",text:t?"add your first book":"add your first manga"}).addEventListener("click",a=>{a.preventDefault(),this.openAddModal()})}openAddModal(){new ee(this.plugin.app,this.plugin,this.readingData,this.activeSubTab==="books"?"book":"manga",()=>this.renderContent()).open()}openManageColumns(){new ie(this.plugin.app,this.plugin,this.readingData,this.activeSubTab==="books"?"book":"manga",()=>this.renderContent()).open()}openDetailModal(i,t){new ui(this.plugin.app,this.plugin,this.readingData,i,t,()=>this.renderContent()).open()}};rt.sessionSubTab=null,rt.sessionFilters={books:ds(),manga:ds()},rt.sessionSort={books:ia(),manga:ia()};var hi=rt;var An=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],In=["January","February","March","April","May","June","July","August","September","October","November","December"],Pn={completed:"#1D9E75",watched:"#1D9E75",added:"#378ADD",deleted:"#E24B4A",status:"#BA7517",rating:"#BA7517"},Bn={Reading:"#1D9E75",Watchlist:"#378ADD"};function oa(g){if(g.action)return g.action;let i=g.message.toLowerCase();return i.includes("was added")?"added":i.includes("was deleted")?"deleted":i.includes("was reviewed")||i.includes("rating changed")?"rating":i.includes("episode")&&i.includes("watched")?"watched":i.includes("was marked as watched")||i.includes("completed")?"completed":i.includes("status")?"status":"added"}function ra(g){return g.source?g.source:"Watchlist"}function Fn(g){let i=oa(g),t=g.message;switch(i){case"added":return"Added";case"deleted":return"Deleted";case"rating":{let e=t.match(/Rating → (\d+\/5)/);return e?`Rating \u2192 ${e[1]}`:"Rating changed"}case"status":{let e=t.match(/status changed to (.+)$/);return e?`Status \u2192 ${e[1]}`:"Status changed"}case"completed":return"Completed";case"watched":{let e=t.match(/At (page|chapter|volume) (\d+) \/ (\d+)/i);if(e)return`At ${e[1]} ${e[2]} / ${e[3]}`;let s=t.match(/\)\s+(.+?)\s+was fully watched on/i);if(s)return`${s[1]} watched`;let a=t.match(/episode (\d+)/i);return a?`Episode ${a[1]} watched`:"Watched"}}return"Updated"}function $n(g){let i=g.message.match(/\(([^)]+)\)/);return i?i[1]:""}function Wn(g){let i;if(g.titleName)i=g.titleName;else{let e=g.message.match(/^(.+?)\s*\(/);i=e?e[1]:g.message}let t=$n(g);return t?`${i} (${t})`:i}function On(g){let i=new Date(g+"T12:00:00");return`${An[i.getDay()]}, ${i.getDate()} ${In[i.getMonth()]} ${i.getFullYear()}`}function Hn(g){let i=new Date(g);return`${String(i.getHours()).padStart(2,"0")}:${String(i.getMinutes()).padStart(2,"0")}`}function Nn(g){let i=new Date(g);return`${i.getFullYear()}-${String(i.getMonth()+1).padStart(2,"0")}-${String(i.getDate()).padStart(2,"0")}`}var us=32,hs=40,pi=class{constructor(i,t){this.sourceFilter="all";this.scrollContainer=null;this.spacer=null;this.viewport=null;this.rows=[];this.rowOffsets=[];this.totalHeight=0;this.scrollHandler=null;this.scrollRAF=null;this.resizeObserver=null;this.lastFirst=-1;this.lastLast=-1;this.renderedNodes=new Map;this.container=i,this.plugin=t}destroy(){this.destroyVirtualScroll()}render(){var e,s;this.destroyVirtualScroll(),this.container.empty(),this.container.addClass("wl-log-tab"),this.renderFilterBar();let i=(s=(e=this.plugin.historyManager)==null?void 0:e.getEntries())!=null?s:[],t=this.sourceFilter==="all"?i:i.filter(a=>ra(a)===this.sourceFilter);if(t.length===0){this.container.createDiv({cls:"wl-log-empty",text:this.sourceFilter==="all"?"No events yet. Actions from Watchlist and Reading will appear here.":`No ${this.sourceFilter} events yet.`});return}this.buildVirtualRows(t),this.renderVirtualTimeline()}renderFilterBar(){let i=this.container.createDiv({cls:"wl-log-filter-bar"}),t=[{label:"All",value:"all"},{label:"Watchlist",value:"Watchlist"},{label:"Reading",value:"Reading"}];for(let e of t)i.createEl("button",{cls:`wl-log-filter-btn${this.sourceFilter===e.value?" is-active":""}`,text:e.label}).addEventListener("click",()=>{this.sourceFilter!==e.value&&(this.sourceFilter=e.value,this.render())})}buildVirtualRows(i){this.rows=[],this.rowOffsets=[];let t=new Map;for(let a of i){let n=Nn(a.timestamp),r=t.get(n);r||(r=[],t.set(n,r)),r.push(a)}let e=[];for(let[a,n]of t)e.push({date:a,entries:n});let s=0;for(let a of e){this.rows.push({type:"header",date:a.date}),this.rowOffsets.push(s),s+=hs;for(let n=0;n{this.scrollRAF===null&&(this.scrollRAF=window.requestAnimationFrame(()=>{this.scrollRAF=null,this.renderVisibleRows()}))},i.addEventListener("scroll",this.scrollHandler,{passive:!0}),this.resizeObserver=new ResizeObserver(()=>{this.renderedNodes.clear(),this.viewport&&this.viewport.empty(),this.lastFirst=-1,this.lastLast=-1,this.renderVisibleRows()}),this.resizeObserver.observe(i),this.renderVisibleRows()}renderVisibleRows(){var r;let i=this.scrollContainer,t=this.viewport;if(!i||!t)return;let e=i.scrollTop,s=i.clientHeight;if(s<=0)return;let a=this.findFirstVisible(e),n=this.findLastVisible(e+s);if(!(a===this.lastFirst&&n===this.lastLast)){this.lastFirst=a,this.lastLast=n;for(let[o,l]of this.renderedNodes)(on)&&(l.remove(),this.renderedNodes.delete(o));for(let o=a;o<=n;o++){if(this.renderedNodes.has(o))continue;let l=this.rows[o];if(!l)continue;let c;l.type==="header"?(c=activeDocument.createElement("div"),c.className="wl-log-day-header",c.setCssProps({height:`${hs}px`}),c.textContent=On(l.date)):c=this.buildEntryRow(l);let d=(r=this.rowOffsets[o])!=null?r:0;c.setCssProps({top:`${d}px`}),t.appendChild(c),this.renderedNodes.set(o,c)}}}buildEntryRow(i){var y,v;let t=i.entry,e=oa(t),s=(y=Pn[e])!=null?y:"#888780",a=ra(t),n=(v=Bn[a])!=null?v:"#888780",r=activeDocument.createElement("div");r.className="wl-log-entry",r.setCssProps({height:`${us}px`});let o=activeDocument.createElement("div");o.className="wl-log-dot-col";let l=activeDocument.createElement("div");if(l.className="wl-log-dot",l.style.backgroundColor=n,o.appendChild(l),!i.isLastInGroup){let w=activeDocument.createElement("div");w.className="wl-log-connector",o.appendChild(w)}r.appendChild(o);let c=activeDocument.createElement("div");c.className="wl-log-content";let d=activeDocument.createElement("span");d.className="wl-log-source",d.textContent=a,c.appendChild(d);let u=activeDocument.createElement("span");u.className="wl-log-sep",u.textContent=" \xB7 ",c.appendChild(u);let h=activeDocument.createElement("span");h.className="wl-log-title",h.textContent=Wn(t),c.appendChild(h);let p=activeDocument.createElement("span");p.className="wl-log-sep",p.textContent=" \u2014 ",c.appendChild(p);let m=activeDocument.createElement("span");m.className="wl-log-action",m.textContent=Fn(t),m.style.color=s,c.appendChild(m),r.appendChild(c);let f=activeDocument.createElement("div");return f.className="wl-log-time",f.textContent=Hn(t.timestamp),r.appendChild(f),r}findFirstVisible(i){let t=0,e=this.rows.length-1;for(;t>>1;this.rowOffsets[s]+(this.rows[s].type==="header"?hs:us)<=i?t=s+1:e=s}return Math.max(0,t-2)}findLastVisible(i){let t=0,e=this.rows.length-1;for(;t>>1;this.rowOffsets[s]>=i?e=s-1:t=s}return Math.min(this.rows.length-1,t+2)}destroyVirtualScroll(){this.scrollRAF!==null&&(window.cancelAnimationFrame(this.scrollRAF),this.scrollRAF=null),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.scrollContainer&&this.scrollHandler&&this.scrollContainer.removeEventListener("scroll",this.scrollHandler),this.scrollHandler=null,this.scrollContainer=null,this.spacer=null,this.viewport=null,this.renderedNodes.clear(),this.lastFirst=-1,this.lastLast=-1}};var Ce="watchlog-view",la=["wl-dashboard","wl-list","wl-airtime","wl-reading-tab","wl-custom-lists","wl-log-tab"],Ft=class extends ut.ItemView{constructor(t,e,s){super(t);this.dashboardTab=null;this.listTab=null;this.airtimeTab=null;this.readingTab=null;this.customListsTab=null;this.draftsTab=null;this.logTab=null;this.airtimeBtn=null;this.draftsBtn=null;this.tabButtons={};this.tabContentEl=null;this.mobileResizeObserver=null;this.mobileSizerRaf=null;this.lastAppliedTabHeight=-1;this.editPinActive=!1;this.smallestEditHeight=-1;this.pinReleaseTimer=null;this.focusListenersBound=!1;this.overflowObserver=null;this.plugin=e,this.dataManager=s,this.activeTab="dashboard",this.dataChangeListener=()=>{this.refreshActiveTab()}}getViewType(){return Ce}getDisplayText(){return"Watchlog"}getIcon(){return"tv"}async onOpen(){await super.onOpen(),this.dataManager.onChange(this.dataChangeListener),this.buildUI(),ut.Platform.isMobile&&this.setupTabContentSizer()}setupTabContentSizer(){var t;(t=this.mobileResizeObserver)==null||t.disconnect(),this.mobileResizeObserver=new ResizeObserver(()=>{this.mobileSizerRaf===null&&(this.mobileSizerRaf=window.requestAnimationFrame(()=>{this.mobileSizerRaf=null,this.applyTabContentHeight()}))}),this.mobileResizeObserver.observe(this.contentEl),this.focusListenersBound||(this.registerDomEvent(this.contentEl,"focusin",e=>this.onScrollerFocusIn(e)),this.registerDomEvent(this.contentEl,"focusout",e=>this.onScrollerFocusOut(e)),this.focusListenersBound=!0)}isEditorInScroller(t){let e=t;if(!e||typeof e.tagName!="string")return!1;let s=this.contentEl.querySelector(":scope > .wl-tab-content");if(!s||!s.contains(e))return!1;let a=e.tagName.toLowerCase();return a==="input"||a==="textarea"||e.isContentEditable===!0}onScrollerFocusIn(t){!ut.Platform.isMobile||!this.isEditorInScroller(t.target)||(this.pinReleaseTimer!==null&&(window.clearTimeout(this.pinReleaseTimer),this.pinReleaseTimer=null),this.editPinActive||(this.smallestEditHeight=-1),this.editPinActive=!0,this.lastAppliedTabHeight=-1,this.applyTabContentHeight())}onScrollerFocusOut(t){this.isEditorInScroller(t.target)&&(this.pinReleaseTimer!==null&&window.clearTimeout(this.pinReleaseTimer),this.pinReleaseTimer=window.setTimeout(()=>{this.pinReleaseTimer=null;let e=this.contentEl.ownerDocument.activeElement;this.isEditorInScroller(e)||this.releaseEditPin()},250))}releaseEditPin(){if(!this.editPinActive)return;this.editPinActive=!1,this.smallestEditHeight=-1;let t=this.contentEl.querySelector(":scope > .wl-tab-content");t==null||t.removeClass("wl-tab-content-pinned"),this.lastAppliedTabHeight=-1,this.applyTabContentHeight()}applyTabContentHeight(){let t=this.contentEl;if(!t)return;let e=t.querySelector(":scope > .wl-tab-bar"),s=t.querySelector(":scope > .wl-tab-content");if(!s)return;let a=t.clientHeight,n=e?e.offsetHeight:0,r=a-n;if(!(r<=0)){if(this.editPinActive){if(!this.isEditorInScroller(this.contentEl.ownerDocument.activeElement)){this.releaseEditPin();return}(this.smallestEditHeight<0||r{this.activeTab!=="dashboard"&&(this.destroyDraftsTab(),this.activeTab="dashboard",l.forEach(c=>c.removeClass("is-active")),s.addClass("is-active"),this.renderTabContent())}),a.addEventListener("click",()=>{this.activeTab!=="watchlist"&&(this.destroyDraftsTab(),this.activeTab="watchlist",l.forEach(c=>c.removeClass("is-active")),a.addClass("is-active"),this.renderTabContent())}),this.airtimeBtn.addEventListener("click",()=>{this.activeTab!=="upcoming"&&(this.destroyDraftsTab(),this.activeTab="upcoming",l.forEach(c=>c.removeClass("is-active")),this.airtimeBtn.addClass("is-active"),this.renderTabContent())}),n.addEventListener("click",()=>{this.activeTab!=="reading"&&(this.destroyDraftsTab(),this.activeTab="reading",l.forEach(c=>c.removeClass("is-active")),n.addClass("is-active"),this.renderTabContent())}),r.addEventListener("click",()=>{this.activeTab!=="custom-lists"&&(this.destroyDraftsTab(),this.activeTab="custom-lists",l.forEach(c=>c.removeClass("is-active")),r.addClass("is-active"),this.renderTabContent())}),this.draftsBtn.addEventListener("click",()=>{this.activeTab!=="drafts"&&(this.activeTab="drafts",l.forEach(c=>c.removeClass("is-active")),this.draftsBtn.addClass("is-active"),this.renderTabContent())}),o.addEventListener("click",()=>{this.activeTab!=="log"&&(this.destroyDraftsTab(),this.activeTab="log",l.forEach(c=>c.removeClass("is-active")),o.addClass("is-active"),this.renderTabContent())}),this.tabContentEl=t.createDiv({cls:"wl-tab-content"}),this.renderTabContent(),this.updateUpcomingBadge(),this.updateDraftsBadge(),this.registerEvent(this.plugin.app.metadataCache.on("resolved",()=>{this.updateDraftsBadge()}))}makeTabBtn(t,e,s,a){let n=t.createEl("button",{cls:`wl-tab-btn${this.activeTab===e?" is-active":""}`});return ut.Platform.isMobile?(n.addClass("wl-tab-btn-icon"),(0,ut.setIcon)(n,a),n.setAttribute("aria-label",s)):n.setText(s),n}setTabBadge(t,e,s){t&&(ut.Platform.isMobile?t.toggleClass("wl-tab-has-badge",s>0):t.textContent=s>0?`${e} (${s})`:e)}setActiveTab(t){var e;if(this.activeTab!==t){if(!this.tabContentEl){this.activeTab=t;return}t!=="drafts"&&this.destroyDraftsTab(),this.activeTab=t;for(let s of Object.values(this.tabButtons))s==null||s.removeClass("is-active");(e=this.tabButtons[t])==null||e.addClass("is-active"),this.renderTabContent()}}renderTabContent(){var t,e,s,a,n;if(this.tabContentEl){(t=this.customListsTab)==null||t.destroy(),this.activeTab!=="reading"&&((e=this.readingTab)==null||e.destroy(),this.readingTab=null),this.activeTab!=="log"&&((s=this.logTab)==null||s.destroy(),this.logTab=null),this.tabContentEl.empty();for(let r of la)this.tabContentEl.removeClass(r);this.activeTab==="dashboard"?(this.dashboardTab=new Oe(this.tabContentEl,this.plugin,this.dataManager,this.plugin.readingDataManager),this.dashboardTab.render()):this.activeTab==="watchlist"?((a=this.listTab)==null||a.destroy(),this.listTab=new Xe(this.tabContentEl,this.plugin,this.dataManager),this.listTab.render()):this.activeTab==="upcoming"?(this.airtimeTab=new Dt(this.tabContentEl,this.plugin,this.dataManager,r=>{this.setTabBadge(this.airtimeBtn,"Upcoming",r)}),this.airtimeTab.render()):this.activeTab==="reading"?((n=this.readingTab)==null||n.destroy(),this.readingTab=new hi(this.tabContentEl,this.plugin,this.plugin.readingDataManager),this.readingTab.render()):this.activeTab==="drafts"?(this.draftsTab=new De(this.tabContentEl,this.plugin,this.dataManager,r=>this.setDraftsBadge(r)),this.draftsTab.render()):this.activeTab==="log"?(this.logTab=new pi(this.tabContentEl,this.plugin),this.logTab.render()):(this.customListsTab=new oi(this.tabContentEl,this.plugin,this.dataManager),this.customListsTab.render()),this.guardOverflow(),this.refreshMobileLayout()}}refreshActiveTab(){if(this.applyColorTheme(this.contentEl),this.tabContentEl)for(let t of la)this.tabContentEl.removeClass(t);if(this.activeTab==="watchlist"&&this.listTab)this.listTab.render();else if(this.activeTab==="dashboard"&&this.dashboardTab)this.dashboardTab.render();else if(this.activeTab==="upcoming"&&this.airtimeTab)this.airtimeTab.render();else if(this.activeTab==="reading"&&this.readingTab)this.readingTab.render();else if(this.activeTab==="custom-lists"&&this.customListsTab)this.customListsTab.render();else if(this.activeTab==="drafts"&&this.draftsTab)this.draftsTab.render();else if(this.activeTab==="log"&&this.logTab)this.logTab.render();else{this.renderTabContent();return}this.guardOverflow(),this.updateUpcomingBadge()}guardOverflow(){var s;if(!this.tabContentEl)return;(s=this.overflowObserver)==null||s.disconnect();let t=this.tabContentEl,e=Date.now();this.overflowObserver=new MutationObserver(()=>{if(Date.now()-e>300)return;window.getComputedStyle(t).overflow==="hidden"&&t.setCssProps({overflow:"auto"})}),this.overflowObserver.observe(t,{attributes:!0,attributeFilter:["style","class"]})}updateUpcomingBadge(){if(!this.airtimeBtn)return;let t=Dt.getAiredDueCount(this.dataManager,this.plugin.readingDataManager)+Dt.getMaybeDueCount(this.dataManager);this.setTabBadge(this.airtimeBtn,"Upcoming",t)}setDraftsBadge(t){this.setTabBadge(this.draftsBtn,"Drafts",t)}async updateDraftsBadge(){if(!this.draftsBtn)return;let t=await De.computePendingCount(this.plugin,this.dataManager);this.setDraftsBadge(t)}};var A=require("obsidian");var $t=require("obsidian"),ca=["title","type","status","priority","rating","totalEpisodes","episodeDuration","dateStarted","dateFinished","releaseDate","dateAdded","externalLink","notes"];function _n(g){let i=String(g!=null?g:"");return i.includes(",")||i.includes('"')||i.includes(` +`)?`"${i.replace(/"/g,'""')}"`:i}function Un(g){let i=ca.join(","),t=g.map(e=>ca.map(s=>_n(e[s])).join(","));return[i,...t].join(` +`)}function Vn(g){let i=[],t=[],e="",s=!1,a=g.replace(/\r\n?/g,` `);for(let n=0;n0||t.length>0)&&(t.push(e),i.push(t));i.length>0&&i[i.length-1].every(n=>n==="");)i.pop();return i}var As={jan:1,feb:2,mar:3,apr:4,may:5,jun:6,jul:7,aug:8,sep:9,oct:10,nov:11,dec:12};function Oi(g){let i=g.trim();if(!i)return null;try{if(/^\d{4}-\d{2}-\d{2}$/.test(i))return i;let t=i.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);if(t){let r=parseInt(t[1]),o=parseInt(t[2]),l=parseInt(t[3]),c,d;return r>12?(c=r,d=o):o>12?(d=r,c=o):(c=r,d=o),d<1||d>12||c<1||c>31?null:`${l}-${String(d).padStart(2,"0")}-${String(c).padStart(2,"0")}`}let e=i.match(/^(\d{1,2})\s+([A-Za-z]{3,})\s+(\d{4})$/);if(e){let r=As[e[2].toLowerCase().slice(0,3)],o=parseInt(e[1]),l=parseInt(e[3]);if(r)return`${l}-${String(r).padStart(2,"0")}-${String(o).padStart(2,"0")}`}let s=i.match(/^([A-Za-z]{3,})\s+(\d{1,2}),?\s+(\d{4})$/);if(s){let r=As[s[1].toLowerCase().slice(0,3)],o=parseInt(s[2]),l=parseInt(s[3]);if(r)return`${l}-${String(r).padStart(2,"0")}-${String(o).padStart(2,"0")}`}let a=i.match(/^(\d{1,2})[.-](\d{1,2})[.-](\d{4})$/);if(a){let r=parseInt(a[1]),o=parseInt(a[2]),l=parseInt(a[3]);if(o>=1&&o<=12&&r>=1&&r<=31)return`${l}-${String(o).padStart(2,"0")}-${String(r).padStart(2,"0")}`}let n=new Date(i);if(!isNaN(n.getTime())){let r=n.getDate(),o=n.getMonth()+1;return`${n.getFullYear()}-${String(o).padStart(2,"0")}-${String(r).padStart(2,"0")}`}return null}catch(t){return null}}var Hi=[{key:"title",label:"Name",autoDetect:["title","name"]},{key:"type",label:"Type",autoDetect:["type"]},{key:"status",label:"Status",autoDetect:["status"]},{key:"priority",label:"Priority",autoDetect:["priority"]},{key:"rating",label:"Rating",autoDetect:["rating","score"]},{key:"totalEpisodes",label:"Episodes",autoDetect:["episodes","totalepisodes","total episodes","episode count","ep count"]},{key:"episodeDuration",label:"Duration (min)",autoDetect:["duration","episodeduration","episode duration","minutes","runtime"]},{key:"dateStarted",label:"Date Started",autoDetect:["started","datestarted","date started","date_started","start date"]},{key:"dateFinished",label:"Date Finished",autoDetect:["finished","datefinished","date finished","date_finished","end date","finish date","completed date"]},{key:"releaseDate",label:"Release Date",autoDetect:["releasedate","release date","release_date","air date","airdate"]},{key:"externalLink",label:"Link",autoDetect:["link","externallink","external link","external_link","url"]},{key:"notes",label:"Notes",autoDetect:["notes","note","comment","comments"]}];function cn(g){let i={};for(let t of Hi){let e=g.find(s=>t.autoDetect.includes(s.toLowerCase()));i[t.key]=e!=null?e:""}return i}function dn(g,i,t){var a;if(g.length<2)return[];let e=((a=g[0])!=null?a:[]).map(n=>n.trim()),s=t.getTitles();return g.slice(1).filter(n=>n.some(r=>r.trim())).map(n=>{var E;let r=D=>{var T;let C=i[D];if(!C)return"";let x=e.indexOf(C);return x>=0?((T=n[x])!=null?T:"").trim():""},o={},l=r("title");l&&(o.title=l);let c=r("type");c&&(o.type=c);let d=r("status");d&&(o.status=d);let u=r("priority");u&&(o.priority=u);let h=r("rating");if(h){let D=parseFloat(h)||0;o.rating=Math.max(0,Math.min(5,D))}let p=r("totalEpisodes");p&&(o.totalEpisodes=parseInt(p)||0);let m=r("episodeDuration");m&&(o.episodeDuration=parseInt(m)||0);let v=r("dateStarted");if(v){let D=Oi(v);D&&(o.dateStarted=D)}let f=r("dateFinished");if(f){let D=Oi(f);D&&(o.dateFinished=D)}let y=r("releaseDate");if(y){let D=Oi(y);D&&(o.releaseDate=D)}let w=r("externalLink");w&&(o.externalLink=w);let b=r("notes");if(b&&(o.notes=b),!((E=o.title)!=null&&E.trim())&&!o.type&&!o.status&&!o.rating&&!o.totalEpisodes&&!o.episodeDuration&&!o.dateStarted&&!o.dateFinished&&!o.releaseDate&&!o.externalLink&&!o.notes)return null;let k=!!s.find(D=>{var C;return D.title.toLowerCase()===((C=o.title)!=null?C:"").toLowerCase()});return{entry:o,isDuplicate:k}}).filter(n=>n!==null)}var qe="__create__",Is={default:["#6366F1","#8B5CF6","#EC4899","#14B8A6","#F59E0B","#10B981","#3B82F6","#EF4444"],nightfall:["#7B2CBF","#9D4EDD","#C77DFF","#5A189A","#E040FB","#B388FF","#CE93D8","#9C27B0"],bluez:["#2C7DA0","#468FAF","#61A5C2","#1B6A8A","#0077B6","#00B4D8","#48CAE4","#90E0EF"]};function un(g){var t,e;let i=(t=Is[g])!=null?t:Is.default;return(e=i[Math.floor(Math.random()*i.length)])!=null?e:"#888780"}var de=class extends Tt.Modal{constructor(t,e,s,a){super(t);this.selectedIds=new Set;this.csvRows=[];this.csvHeaders=[];this.columnMapping={};this.importRows=[];this.statusValueMap={};this.typeValueMap={};this.ratingValueMap={};this.stepUpload=null;this.stepMapping=null;this.stepValueMap=null;this.stepPreview=null;this.importBtn=null;this.cancelBtn=null;this.isImporting=!1;this.importCancelled=!1;this.progressWrap=null;this.progressBarFill=null;this.progressText=null;this.plugin=e,this.dataManager=s,this.mode=a}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("wl-csv-modal"),this.mode==="export"?this.renderExport(t):this.renderImport(t)}onClose(){this.contentEl.empty()}renderExport(t){t.createEl("h2",{cls:"wl-modal-title",text:"Export to CSV"});let e=this.dataManager.getTitles();e.forEach(p=>this.selectedIds.add(p.id));let s=t.createDiv({cls:"wl-csv-ctrl-row"}),a=s.createEl("button",{cls:"wl-btn",text:"Select all"}),n=s.createEl("button",{cls:"wl-btn",text:"Select none"}),r=s.createSpan({cls:"wl-csv-count",text:`${e.length} selected`}),o=t.createDiv({cls:"wl-csv-list"}),l=[],c=()=>{r.textContent=`${this.selectedIds.size} selected`};for(let p of e){let m=o.createDiv({cls:"wl-csv-row"}),v=m.createEl("input",{attr:{type:"checkbox"}});v.checked=!0,l.push(v),m.createSpan({cls:"wl-csv-row-title",text:p.title}),m.createSpan({cls:"wl-csv-row-meta",text:`${p.type} \xB7 ${p.status}`}),v.addEventListener("change",()=>{v.checked?this.selectedIds.add(p.id):this.selectedIds.delete(p.id),c()})}a.addEventListener("click",()=>{e.forEach(p=>this.selectedIds.add(p.id)),l.forEach(p=>{p.checked=!0}),c()}),n.addEventListener("click",()=>{this.selectedIds.clear(),l.forEach(p=>{p.checked=!1}),c()});let d=t.createDiv({cls:"wl-modal-btn-row wl-csv-btn-row"}),u=d.createEl("button",{cls:"wl-btn",text:"Cancel"}),h=d.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Export CSV"});u.addEventListener("click",()=>this.close()),h.addEventListener("click",()=>{let p=e.filter(S=>this.selectedIds.has(S.id));if(p.length===0){new Tt.Notice("No titles selected.");return}let m=on(p),v=new Blob([m],{type:"text/csv;charset=utf-8;"}),f=URL.createObjectURL(v),y=activeDocument.createElement("a"),w=new Date,b=`${w.getFullYear()}-${String(w.getMonth()+1).padStart(2,"0")}-${String(w.getDate()).padStart(2,"0")}`;y.href=f,y.download=`watchlog-export-${b}.csv`,y.click(),URL.revokeObjectURL(f),new Tt.Notice(`Exported ${p.length} titles.`),this.close()})}renderImport(t){t.createEl("h2",{cls:"wl-modal-title",text:"Import from CSV"}),this.stepUpload=t.createDiv({cls:"wl-csv-step"});let e=this.stepUpload.createDiv({cls:"wl-csv-drop-zone"});e.createDiv({cls:"wl-csv-drop-label",text:"Select a CSV file to import"});let s=e.createEl("input",{attr:{type:"file",accept:".csv"},cls:"wl-csv-file-input"});this.stepMapping=t.createDiv({cls:"wl-csv-step"}),this.stepMapping.hide(),this.stepValueMap=t.createDiv({cls:"wl-csv-step"}),this.stepValueMap.hide(),this.stepPreview=t.createDiv({cls:"wl-csv-step"}),this.stepPreview.hide();let a=t.createDiv({cls:"wl-modal-btn-row wl-csv-btn-row"});this.progressWrap=a.createDiv({cls:"wl-csv-progress-wrap"}),this.progressWrap.hide(),this.progressWrap.createSpan({cls:"wl-csv-bg-note",text:"You can close this window \u2014 import will continue in the background."});let n=this.progressWrap.createDiv({cls:"wl-csv-progress-track"});this.progressBarFill=n.createDiv({cls:"wl-csv-progress-fill"}),this.progressText=this.progressWrap.createSpan({cls:"wl-csv-progress-text",text:"0 / 0"}),this.cancelBtn=a.createEl("button",{cls:"wl-btn",text:"Cancel"}),this.importBtn=a.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Import selected"}),this.importBtn.disabled=!0,this.importBtn.hide(),this.cancelBtn.addEventListener("click",()=>{this.isImporting?(this.importCancelled=!0,this.cancelBtn&&(this.cancelBtn.disabled=!0,this.cancelBtn.textContent="Cancelling\u2026")):this.close()}),this.importBtn.addEventListener("click",()=>void this.doImport()),s.addEventListener("change",()=>{var l;let r=(l=s.files)==null?void 0:l[0];if(!r)return;let o=new FileReader;o.onload=c=>{var u,h;let d=(u=c.target)==null?void 0:u.result;this.csvRows=ln(d),this.csvHeaders=((h=this.csvRows[0])!=null?h:[]).map(p=>p.trim()),this.columnMapping=cn(this.csvHeaders),this.showMappingStep()},o.readAsText(r)})}showMappingStep(){!this.stepUpload||!this.stepMapping||(this.stepUpload.hide(),this.stepMapping.show(),this.renderMappingStep(this.stepMapping))}renderMappingStep(t){var r;t.empty(),t.createDiv({cls:"wl-csv-step-title",text:"Map your columns"}),t.createDiv({cls:"wl-csv-step-desc",text:'Match each WatchLog field to a column from your CSV. Select "Skip" to leave a field empty.'}),t.createDiv({cls:"wl-csv-info-note",text:"Rows with empty fields will be skipped automatically. If you see missing titles, check that your CSV has no empty rows at the top."});let e="",s=t.createDiv({cls:"wl-csv-map-grid"}),a={};for(let o of Hi){let l=s.createDiv({cls:"wl-csv-map-row"});l.createSpan({cls:"wl-csv-map-label",text:o.label});let c=l.createEl("select",{cls:"wl-select wl-csv-map-select"});a[o.key]=c,c.createEl("option",{value:e,text:"\u2014 skip \u2014"});for(let d of this.csvHeaders)c.createEl("option",{value:d,text:d});c.value=(r=this.columnMapping[o.key])!=null?r:e}t.createEl("button",{cls:"wl-btn wl-btn-primary wl-csv-preview-btn",text:"Next \u2192"}).addEventListener("click",()=>{var v,f,y,w,b,S,k;for(let E of Hi)this.columnMapping[E.key]=(f=(v=a[E.key])==null?void 0:v.value)!=null?f:"";this.importRows=dn(this.csvRows,this.columnMapping,this.dataManager).map(E=>({...E,selected:!E.isDuplicate}));let o=new Set(this.plugin.settings.statuses.map(E=>E.name)),l=new Set(this.plugin.settings.types.map(E=>E.name)),c=[],d=[],u=[],h=new Set,p=new Set,m=new Set;for(let E of this.importRows){let D=(y=E.entry.status)==null?void 0:y.trim();D&&!o.has(D)&&!h.has(D)&&(c.push(D),h.add(D));let C=(w=E.entry.type)==null?void 0:w.trim();C&&!l.has(C)&&!p.has(C)&&(d.push(C),p.add(C));let x=this.columnMapping.rating;if(x){let M=((b=this.csvRows[0])!=null?b:[]).map(L=>L.trim()).indexOf(x);if(M>=0){let L=this.importRows.indexOf(E),A=((k=((S=this.csvRows[L+1])!=null?S:[])[M])!=null?k:"").trim();A&&isNaN(parseFloat(A))&&!m.has(A)&&(u.push(A),m.add(A))}}}c.length>0||d.length>0||u.length>0?this.showValueMapStep(c,d,u):this.showPreviewStep()})}showValueMapStep(t,e,s=[]){!this.stepMapping||!this.stepValueMap||(this.stepMapping.hide(),this.stepValueMap.show(),this.renderValueMapStep(this.stepValueMap,t,e,s))}renderValueMapStep(t,e,s,a=[]){t.empty(),t.createDiv({cls:"wl-csv-step-title",text:"Map unknown values"}),t.createDiv({cls:"wl-csv-step-desc",text:"Some values in your CSV were not recognized. Map each to an existing value, or choose how to handle it."});let n=this.plugin.settings.statuses.map(p=>p.name),r=this.plugin.settings.types.map(p=>p.name),o={},l={},c={};if(e.length>0){t.createDiv({cls:"wl-csv-valmap-section-title",text:"Status"});for(let p of e){let m=t.createDiv({cls:"wl-csv-valmap-row"});m.createSpan({cls:"wl-csv-valmap-orig",text:`"${p}"`}),m.createSpan({cls:"wl-csv-valmap-arrow",text:"\u2192"});let v=m.createEl("select",{cls:"wl-select wl-csv-valmap-select"});o[p]=v,v.createEl("option",{value:"",text:"\u2014 leave blank \u2014"});for(let w of n)v.createEl("option",{value:w,text:w});let f=p.toLowerCase(),y=n.find(w=>w.toLowerCase()===f);y&&(v.value=y)}}if(s.length>0){t.createDiv({cls:"wl-csv-valmap-section-title",text:"Type"});for(let p of s){let m=t.createDiv({cls:"wl-csv-valmap-row"});m.createSpan({cls:"wl-csv-valmap-orig",text:`"${p}"`}),m.createSpan({cls:"wl-csv-valmap-arrow",text:"\u2192"});let v=m.createEl("select",{cls:"wl-select wl-csv-valmap-select"});l[p]=v,v.createEl("option",{value:"",text:"\u2014 leave blank \u2014"});for(let w of r)v.createEl("option",{value:w,text:w});v.createEl("option",{value:qe,text:"+ create new type"});let f=p.toLowerCase(),y=r.find(w=>w.toLowerCase()===f);y?v.value=y:v.value=qe}}if(a.length>0){t.createDiv({cls:"wl-csv-valmap-section-title",text:"Rating"});for(let p of a){let m=t.createDiv({cls:"wl-csv-valmap-row"});m.createSpan({cls:"wl-csv-valmap-orig",text:`"${p}"`}),m.createSpan({cls:"wl-csv-valmap-arrow",text:"\u2192"});let v=m.createEl("select",{cls:"wl-select wl-csv-valmap-select"});c[p]=v,v.createEl("option",{value:"",text:"\u2014 leave blank \u2014"});for(let f=1;f<=5;f++)v.createEl("option",{value:String(f),text:`${f}/5`})}}let d=t.createDiv({cls:"wl-csv-valmap-btn-row"}),u=d.createEl("button",{cls:"wl-btn",text:"\u2190 back"}),h=d.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Preview \u2192"});u.addEventListener("click",()=>{!this.stepValueMap||!this.stepMapping||(this.stepValueMap.hide(),this.stepMapping.show())}),h.addEventListener("click",()=>{var p,m,v,f,y,w;this.statusValueMap={};for(let b of e)this.statusValueMap[b]=(m=(p=o[b])==null?void 0:p.value)!=null?m:"";this.typeValueMap={};for(let b of s)this.typeValueMap[b]=(f=(v=l[b])==null?void 0:v.value)!=null?f:"";this.ratingValueMap={};for(let b of a)this.ratingValueMap[b]=(w=(y=c[b])==null?void 0:y.value)!=null?w:"";this.applyValueMapsToRows(),this.showPreviewStep()})}applyValueMapsToRows(){var t,e,s,a,n,r,o;for(let l of this.importRows){let c=(e=(t=l.entry.status)==null?void 0:t.trim())!=null?e:"";if(c&&Object.prototype.hasOwnProperty.call(this.statusValueMap,c)){let h=(s=this.statusValueMap[c])!=null?s:"";l.entry.status=h||void 0}let d=(n=(a=l.entry.type)==null?void 0:a.trim())!=null?n:"";if(d&&Object.prototype.hasOwnProperty.call(this.typeValueMap,d)){let h=(r=this.typeValueMap[d])!=null?r:"";h===qe?l.entry.type=d:l.entry.type=h||void 0}let u=Object.keys(this.ratingValueMap).find(h=>{var w,b,S;let p=this.columnMapping.rating;if(!p)return!1;let v=((w=this.csvRows[0])!=null?w:[]).map(k=>k.trim()).indexOf(p);if(v<0)return!1;let f=this.importRows.indexOf(l);return((S=((b=this.csvRows[f+1])!=null?b:[])[v])!=null?S:"").trim()===h});if(u!==void 0){let h=(o=this.ratingValueMap[u])!=null?o:"";l.entry.rating=h?parseInt(h):0}l.isDuplicate=!!this.dataManager.getTitles().find(h=>{var p;return h.title.toLowerCase()===((p=l.entry.title)!=null?p:"").toLowerCase()})}}showPreviewStep(){!this.stepValueMap||!this.stepMapping||!this.stepPreview||!this.importBtn||(this.stepValueMap.hide(),this.stepMapping.hide(),this.stepPreview.show(),this.importBtn.show(),this.importBtn.disabled=this.importRows.filter(t=>t.selected).length===0,this.renderPreviewStep(this.stepPreview))}renderPreviewStep(t){var u;t.empty();let e=this.importRows.filter(h=>h.isDuplicate).length;e>0&&t.createDiv({cls:"wl-csv-dupe-warning",text:`${e} duplicate${e!==1?"s":""} found (highlighted). These are deselected by default.`});let s=t.createDiv({cls:"wl-csv-ctrl-row"}),a=s.createEl("button",{cls:"wl-btn",text:"\u2190 back"}),n=s.createEl("button",{cls:"wl-btn",text:"Select all"}),r=s.createEl("button",{cls:"wl-btn",text:"Select none"}),o=s.createSpan({cls:"wl-csv-count",text:""});a.addEventListener("click",()=>{if(!this.stepPreview||!this.stepValueMap||!this.stepMapping||!this.importBtn)return;this.stepPreview.hide(),this.importBtn.hide(),this.importBtn.disabled=!0,Object.keys(this.statusValueMap).length>0||Object.keys(this.typeValueMap).length>0||Object.keys(this.ratingValueMap).length>0?this.stepValueMap.show():this.stepMapping.show()});let l=t.createDiv({cls:"wl-csv-list"}),c=[],d=()=>{let h=this.importRows.filter(p=>p.selected).length;o.textContent=`${h} of ${this.importRows.length} selected`,this.importBtn&&(this.importBtn.disabled=h===0)};for(let h=0;h{this.importRows[y].selected=v.checked,d()})}n.addEventListener("click",()=>{this.importRows.forEach(h=>{h.selected=!0}),c.forEach(h=>{h.checked=!0}),d()}),r.addEventListener("click",()=>{this.importRows.forEach(h=>{h.selected=!1}),c.forEach(h=>{h.checked=!1}),d()}),d()}async doImport(){var c,d,u,h,p,m,v,f,y,w,b,S;let t=this.importRows.filter(k=>{var E;return k.selected&&((E=k.entry.title)==null?void 0:E.trim())});if(t.length===0){new Tt.Notice("No titles selected to import.");return}this.isImporting=!0,this.importCancelled=!1,this.importBtn&&(this.importBtn.disabled=!0),this.cancelBtn&&(this.cancelBtn.textContent="Cancel import"),this.progressWrap&&this.progressWrap.show(),this.progressText&&(this.progressText.textContent=`0 / ${t.length}`),this.progressBarFill&&(this.progressBarFill.style.width="0%");let e=()=>{this.importCancelled=!0};this.plugin.importProgress={current:0,total:t.length,cancel:e};let s=(c=this.plugin.settings.colorTheme)!=null?c:"default",a=new Set(this.plugin.settings.types.map(k=>k.name.toLowerCase())),n=new Set;for(let k of t){let E=(d=k.entry.type)==null?void 0:d.trim();E&&!a.has(E.toLowerCase())&&n.add(E)}for(let[k,E]of Object.entries(this.typeValueMap))E===qe&&!a.has(k.toLowerCase())&&n.add(k);if(n.size>0){for(let k of n)this.plugin.settings.types.push({name:k,color:un(s)});await this.plugin.saveSettings()}let r=10,o=0;try{for(let k=0;k0&&(L.watchedEpisodes=Array.from({length:L.totalEpisodes},(q,A)=>A+1)),D.push(L)}if(D.length===0)break;await this.dataManager.addTitleBatch(D),o+=D.length,this.plugin.importProgress={current:o,total:t.length,cancel:e};let C=Math.round(o/t.length*100);this.progressBarFill&&(this.progressBarFill.style.width=`${C}%`),this.progressText&&(this.progressText.textContent=`${o} / ${t.length}`)}}finally{this.isImporting=!1,this.plugin.importProgress=null,this.dataManager.notifyChange()}let l=n.size>0?` (${n.size} new type${n.size!==1?"s":""} created)`:"";this.importCancelled?(this.progressText&&(this.progressText.textContent=`Cancelled \u2014 ${o} / ${t.length} imported`),this.cancelBtn&&(this.cancelBtn.disabled=!1,this.cancelBtn.textContent="Close"),new Tt.Notice(`Import cancelled. ${o} title${o!==1?"s":""} imported.`)):(this.progressText&&(this.progressText.textContent=`Done \u2014 ${o} imported`),this.cancelBtn&&(this.cancelBtn.disabled=!1,this.cancelBtn.textContent="Close"),new Tt.Notice(`Imported ${o} title${o!==1?"s":""}${l}.`),this.close())}};var Bs=require("obsidian"),ue=class extends Bs.Modal{constructor(t,e,s){super(t);this.mode=e;this.onChoice=s}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("wl-draft-choice-modal"),this.titleEl.setText(this.mode==="export"?"Export to CSV":"Import from CSV"),t.createDiv({cls:"wl-draft-choice-subtitle",text:this.mode==="export"?"Which library do you want to export?":"Which library do you want to import into?"});let e=t.createDiv({cls:"wl-draft-choice-grid"}),s=(a,n)=>{let r=e.createEl("button",{cls:"wl-draft-choice-btn"});r.createDiv({cls:"wl-draft-choice-label",text:a}),r.addEventListener("click",()=>{this.close(),this.onChoice(n)})};s("Books","book"),s("Manga","manga")}onClose(){this.contentEl.empty()}};var Ct=require("obsidian");function hn(g){let i=String(g!=null?g:"");return i.includes(",")||i.includes('"')||i.includes(` -`)?`"${i.replace(/"/g,'""')}"`:i}function pn(g){let i=[],t=[],e="",s=!1,a=g.replace(/\r\n?/g,` +`?(t.push(e),e="",i.push(t),t=[]):e+=r}for((e.length>0||t.length>0)&&(t.push(e),i.push(t));i.length>0&&i[i.length-1].every(n=>n==="");)i.pop();return i}var da={jan:1,feb:2,mar:3,apr:4,may:5,jun:6,jul:7,aug:8,sep:9,oct:10,nov:11,dec:12};function ps(g){let i=g.trim();if(!i)return null;try{if(/^\d{4}-\d{2}-\d{2}$/.test(i))return i;let t=i.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);if(t){let r=parseInt(t[1]),o=parseInt(t[2]),l=parseInt(t[3]),c,d;return r>12?(c=r,d=o):o>12?(d=r,c=o):(c=r,d=o),d<1||d>12||c<1||c>31?null:`${l}-${String(d).padStart(2,"0")}-${String(c).padStart(2,"0")}`}let e=i.match(/^(\d{1,2})\s+([A-Za-z]{3,})\s+(\d{4})$/);if(e){let r=da[e[2].toLowerCase().slice(0,3)],o=parseInt(e[1]),l=parseInt(e[3]);if(r)return`${l}-${String(r).padStart(2,"0")}-${String(o).padStart(2,"0")}`}let s=i.match(/^([A-Za-z]{3,})\s+(\d{1,2}),?\s+(\d{4})$/);if(s){let r=da[s[1].toLowerCase().slice(0,3)],o=parseInt(s[2]),l=parseInt(s[3]);if(r)return`${l}-${String(r).padStart(2,"0")}-${String(o).padStart(2,"0")}`}let a=i.match(/^(\d{1,2})[.-](\d{1,2})[.-](\d{4})$/);if(a){let r=parseInt(a[1]),o=parseInt(a[2]),l=parseInt(a[3]);if(o>=1&&o<=12&&r>=1&&r<=31)return`${l}-${String(o).padStart(2,"0")}-${String(r).padStart(2,"0")}`}let n=new Date(i);if(!isNaN(n.getTime())){let r=n.getDate(),o=n.getMonth()+1;return`${n.getFullYear()}-${String(o).padStart(2,"0")}-${String(r).padStart(2,"0")}`}return null}catch(t){return null}}var gs=[{key:"title",label:"Name",autoDetect:["title","name"]},{key:"type",label:"Type",autoDetect:["type"]},{key:"status",label:"Status",autoDetect:["status"]},{key:"priority",label:"Priority",autoDetect:["priority"]},{key:"rating",label:"Rating",autoDetect:["rating","score"]},{key:"totalEpisodes",label:"Episodes",autoDetect:["episodes","totalepisodes","total episodes","episode count","ep count"]},{key:"episodeDuration",label:"Duration (min)",autoDetect:["duration","episodeduration","episode duration","minutes","runtime"]},{key:"dateStarted",label:"Date Started",autoDetect:["started","datestarted","date started","date_started","start date"]},{key:"dateFinished",label:"Date Finished",autoDetect:["finished","datefinished","date finished","date_finished","end date","finish date","completed date"]},{key:"releaseDate",label:"Release Date",autoDetect:["releasedate","release date","release_date","air date","airdate"]},{key:"externalLink",label:"Link",autoDetect:["link","externallink","external link","external_link","url"]},{key:"notes",label:"Notes",autoDetect:["notes","note","comment","comments"]}];function Gn(g){let i={};for(let t of gs){let e=g.find(s=>t.autoDetect.includes(s.toLowerCase()));i[t.key]=e!=null?e:""}return i}function Kn(g,i,t){var a;if(g.length<2)return[];let e=((a=g[0])!=null?a:[]).map(n=>n.trim()),s=t.getTitles();return g.slice(1).filter(n=>n.some(r=>r.trim())).map(n=>{var S;let r=T=>{var C;let M=i[T];if(!M)return"";let x=e.indexOf(M);return x>=0?((C=n[x])!=null?C:"").trim():""},o={},l=r("title");l&&(o.title=l);let c=r("type");c&&(o.type=c);let d=r("status");d&&(o.status=d);let u=r("priority");u&&(o.priority=u);let h=r("rating");if(h){let T=parseFloat(h)||0;o.rating=Math.max(0,Math.min(5,T))}let p=r("totalEpisodes");p&&(o.totalEpisodes=parseInt(p)||0);let m=r("episodeDuration");m&&(o.episodeDuration=parseInt(m)||0);let f=r("dateStarted");if(f){let T=ps(f);T&&(o.dateStarted=T)}let y=r("dateFinished");if(y){let T=ps(y);T&&(o.dateFinished=T)}let v=r("releaseDate");if(v){let T=ps(v);T&&(o.releaseDate=T)}let w=r("externalLink");w&&(o.externalLink=w);let b=r("notes");if(b&&(o.notes=b),!((S=o.title)!=null&&S.trim())&&!o.type&&!o.status&&!o.rating&&!o.totalEpisodes&&!o.episodeDuration&&!o.dateStarted&&!o.dateFinished&&!o.releaseDate&&!o.externalLink&&!o.notes)return null;let D=!!s.find(T=>{var M;return T.title.toLowerCase()===((M=o.title)!=null?M:"").toLowerCase()});return{entry:o,isDuplicate:D}}).filter(n=>n!==null)}var gi="__create__",ua={default:["#6366F1","#8B5CF6","#EC4899","#14B8A6","#F59E0B","#10B981","#3B82F6","#EF4444"],nightfall:["#7B2CBF","#9D4EDD","#C77DFF","#5A189A","#E040FB","#B388FF","#CE93D8","#9C27B0"],bluez:["#2C7DA0","#468FAF","#61A5C2","#1B6A8A","#0077B6","#00B4D8","#48CAE4","#90E0EF"]};function zn(g){var t,e;let i=(t=ua[g])!=null?t:ua.default;return(e=i[Math.floor(Math.random()*i.length)])!=null?e:"#888780"}var ke=class extends $t.Modal{constructor(t,e,s,a){super(t);this.selectedIds=new Set;this.csvRows=[];this.csvHeaders=[];this.columnMapping={};this.importRows=[];this.statusValueMap={};this.typeValueMap={};this.ratingValueMap={};this.stepUpload=null;this.stepMapping=null;this.stepValueMap=null;this.stepPreview=null;this.importBtn=null;this.cancelBtn=null;this.isImporting=!1;this.importCancelled=!1;this.progressWrap=null;this.progressBarFill=null;this.progressText=null;this.plugin=e,this.dataManager=s,this.mode=a}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("wl-csv-modal"),this.mode==="export"?this.renderExport(t):this.renderImport(t)}onClose(){this.contentEl.empty()}renderExport(t){t.createEl("h2",{cls:"wl-modal-title",text:"Export to CSV"});let e=this.dataManager.getTitles();e.forEach(p=>this.selectedIds.add(p.id));let s=t.createDiv({cls:"wl-csv-ctrl-row"}),a=s.createEl("button",{cls:"wl-btn",text:"Select all"}),n=s.createEl("button",{cls:"wl-btn",text:"Select none"}),r=s.createSpan({cls:"wl-csv-count",text:`${e.length} selected`}),o=t.createDiv({cls:"wl-csv-list"}),l=[],c=()=>{r.textContent=`${this.selectedIds.size} selected`};for(let p of e){let m=o.createDiv({cls:"wl-csv-row"}),f=m.createEl("input",{attr:{type:"checkbox"}});f.checked=!0,l.push(f),m.createSpan({cls:"wl-csv-row-title",text:p.title}),m.createSpan({cls:"wl-csv-row-meta",text:`${p.type} \xB7 ${p.status}`}),f.addEventListener("change",()=>{f.checked?this.selectedIds.add(p.id):this.selectedIds.delete(p.id),c()})}a.addEventListener("click",()=>{e.forEach(p=>this.selectedIds.add(p.id)),l.forEach(p=>{p.checked=!0}),c()}),n.addEventListener("click",()=>{this.selectedIds.clear(),l.forEach(p=>{p.checked=!1}),c()});let d=t.createDiv({cls:"wl-modal-btn-row wl-csv-btn-row"}),u=d.createEl("button",{cls:"wl-btn",text:"Cancel"}),h=d.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Export CSV"});u.addEventListener("click",()=>this.close()),h.addEventListener("click",()=>{let p=e.filter(E=>this.selectedIds.has(E.id));if(p.length===0){new $t.Notice("No titles selected.");return}let m=Un(p),f=new Blob([m],{type:"text/csv;charset=utf-8;"}),y=URL.createObjectURL(f),v=activeDocument.createElement("a"),w=new Date,b=`${w.getFullYear()}-${String(w.getMonth()+1).padStart(2,"0")}-${String(w.getDate()).padStart(2,"0")}`;v.href=y,v.download=`watchlog-export-${b}.csv`,v.click(),URL.revokeObjectURL(y),new $t.Notice(`Exported ${p.length} titles.`),this.close()})}renderImport(t){t.createEl("h2",{cls:"wl-modal-title",text:"Import from CSV"}),this.stepUpload=t.createDiv({cls:"wl-csv-step"});let e=this.stepUpload.createDiv({cls:"wl-csv-drop-zone"});e.createDiv({cls:"wl-csv-drop-label",text:"Select a CSV file to import"});let s=e.createEl("input",{attr:{type:"file",accept:".csv"},cls:"wl-csv-file-input"});this.stepMapping=t.createDiv({cls:"wl-csv-step"}),this.stepMapping.hide(),this.stepValueMap=t.createDiv({cls:"wl-csv-step"}),this.stepValueMap.hide(),this.stepPreview=t.createDiv({cls:"wl-csv-step"}),this.stepPreview.hide();let a=t.createDiv({cls:"wl-modal-btn-row wl-csv-btn-row"});this.progressWrap=a.createDiv({cls:"wl-csv-progress-wrap"}),this.progressWrap.hide(),this.progressWrap.createSpan({cls:"wl-csv-bg-note",text:"You can close this window \u2014 import will continue in the background."});let n=this.progressWrap.createDiv({cls:"wl-csv-progress-track"});this.progressBarFill=n.createDiv({cls:"wl-csv-progress-fill"}),this.progressText=this.progressWrap.createSpan({cls:"wl-csv-progress-text",text:"0 / 0"}),this.cancelBtn=a.createEl("button",{cls:"wl-btn",text:"Cancel"}),this.importBtn=a.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Import selected"}),this.importBtn.disabled=!0,this.importBtn.hide(),this.cancelBtn.addEventListener("click",()=>{this.isImporting?(this.importCancelled=!0,this.cancelBtn&&(this.cancelBtn.disabled=!0,this.cancelBtn.textContent="Cancelling\u2026")):this.close()}),this.importBtn.addEventListener("click",()=>void this.doImport()),s.addEventListener("change",()=>{var l;let r=(l=s.files)==null?void 0:l[0];if(!r)return;let o=new FileReader;o.onload=c=>{var u,h;let d=(u=c.target)==null?void 0:u.result;this.csvRows=Vn(d),this.csvHeaders=((h=this.csvRows[0])!=null?h:[]).map(p=>p.trim()),this.columnMapping=Gn(this.csvHeaders),this.showMappingStep()},o.readAsText(r)})}showMappingStep(){!this.stepUpload||!this.stepMapping||(this.stepUpload.hide(),this.stepMapping.show(),this.renderMappingStep(this.stepMapping))}renderMappingStep(t){var r;t.empty(),t.createDiv({cls:"wl-csv-step-title",text:"Map your columns"}),t.createDiv({cls:"wl-csv-step-desc",text:'Match each WatchLog field to a column from your CSV. Select "Skip" to leave a field empty.'}),t.createDiv({cls:"wl-csv-info-note",text:"Rows with empty fields will be skipped automatically. If you see missing titles, check that your CSV has no empty rows at the top."});let e="",s=t.createDiv({cls:"wl-csv-map-grid"}),a={};for(let o of gs){let l=s.createDiv({cls:"wl-csv-map-row"});l.createSpan({cls:"wl-csv-map-label",text:o.label});let c=l.createEl("select",{cls:"wl-select wl-csv-map-select"});a[o.key]=c,c.createEl("option",{value:e,text:"\u2014 skip \u2014"});for(let d of this.csvHeaders)c.createEl("option",{value:d,text:d});c.value=(r=this.columnMapping[o.key])!=null?r:e}t.createEl("button",{cls:"wl-btn wl-btn-primary wl-csv-preview-btn",text:"Next \u2192"}).addEventListener("click",()=>{var f,y,v,w,b,E,D;for(let S of gs)this.columnMapping[S.key]=(y=(f=a[S.key])==null?void 0:f.value)!=null?y:"";this.importRows=Kn(this.csvRows,this.columnMapping,this.dataManager).map(S=>({...S,selected:!S.isDuplicate}));let o=new Set(this.plugin.settings.statuses.map(S=>S.name)),l=new Set(this.plugin.settings.types.map(S=>S.name)),c=[],d=[],u=[],h=new Set,p=new Set,m=new Set;for(let S of this.importRows){let T=(v=S.entry.status)==null?void 0:v.trim();T&&!o.has(T)&&!h.has(T)&&(c.push(T),h.add(T));let M=(w=S.entry.type)==null?void 0:w.trim();M&&!l.has(M)&&!p.has(M)&&(d.push(M),p.add(M));let x=this.columnMapping.rating;if(x){let L=((b=this.csvRows[0])!=null?b:[]).map(I=>I.trim()).indexOf(x);if(L>=0){let I=this.importRows.indexOf(S),k=((D=((E=this.csvRows[I+1])!=null?E:[])[L])!=null?D:"").trim();k&&isNaN(parseFloat(k))&&!m.has(k)&&(u.push(k),m.add(k))}}}c.length>0||d.length>0||u.length>0?this.showValueMapStep(c,d,u):this.showPreviewStep()})}showValueMapStep(t,e,s=[]){!this.stepMapping||!this.stepValueMap||(this.stepMapping.hide(),this.stepValueMap.show(),this.renderValueMapStep(this.stepValueMap,t,e,s))}renderValueMapStep(t,e,s,a=[]){t.empty(),t.createDiv({cls:"wl-csv-step-title",text:"Map unknown values"}),t.createDiv({cls:"wl-csv-step-desc",text:"Some values in your CSV were not recognized. Map each to an existing value, or choose how to handle it."});let n=this.plugin.settings.statuses.map(p=>p.name),r=this.plugin.settings.types.map(p=>p.name),o={},l={},c={};if(e.length>0){t.createDiv({cls:"wl-csv-valmap-section-title",text:"Status"});for(let p of e){let m=t.createDiv({cls:"wl-csv-valmap-row"});m.createSpan({cls:"wl-csv-valmap-orig",text:`"${p}"`}),m.createSpan({cls:"wl-csv-valmap-arrow",text:"\u2192"});let f=m.createEl("select",{cls:"wl-select wl-csv-valmap-select"});o[p]=f,f.createEl("option",{value:"",text:"\u2014 leave blank \u2014"});for(let w of n)f.createEl("option",{value:w,text:w});let y=p.toLowerCase(),v=n.find(w=>w.toLowerCase()===y);v&&(f.value=v)}}if(s.length>0){t.createDiv({cls:"wl-csv-valmap-section-title",text:"Type"});for(let p of s){let m=t.createDiv({cls:"wl-csv-valmap-row"});m.createSpan({cls:"wl-csv-valmap-orig",text:`"${p}"`}),m.createSpan({cls:"wl-csv-valmap-arrow",text:"\u2192"});let f=m.createEl("select",{cls:"wl-select wl-csv-valmap-select"});l[p]=f,f.createEl("option",{value:"",text:"\u2014 leave blank \u2014"});for(let w of r)f.createEl("option",{value:w,text:w});f.createEl("option",{value:gi,text:"+ create new type"});let y=p.toLowerCase(),v=r.find(w=>w.toLowerCase()===y);v?f.value=v:f.value=gi}}if(a.length>0){t.createDiv({cls:"wl-csv-valmap-section-title",text:"Rating"});for(let p of a){let m=t.createDiv({cls:"wl-csv-valmap-row"});m.createSpan({cls:"wl-csv-valmap-orig",text:`"${p}"`}),m.createSpan({cls:"wl-csv-valmap-arrow",text:"\u2192"});let f=m.createEl("select",{cls:"wl-select wl-csv-valmap-select"});c[p]=f,f.createEl("option",{value:"",text:"\u2014 leave blank \u2014"});for(let y=1;y<=5;y++)f.createEl("option",{value:String(y),text:`${y}/5`})}}let d=t.createDiv({cls:"wl-csv-valmap-btn-row"}),u=d.createEl("button",{cls:"wl-btn",text:"\u2190 back"}),h=d.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Preview \u2192"});u.addEventListener("click",()=>{!this.stepValueMap||!this.stepMapping||(this.stepValueMap.hide(),this.stepMapping.show())}),h.addEventListener("click",()=>{var p,m,f,y,v,w;this.statusValueMap={};for(let b of e)this.statusValueMap[b]=(m=(p=o[b])==null?void 0:p.value)!=null?m:"";this.typeValueMap={};for(let b of s)this.typeValueMap[b]=(y=(f=l[b])==null?void 0:f.value)!=null?y:"";this.ratingValueMap={};for(let b of a)this.ratingValueMap[b]=(w=(v=c[b])==null?void 0:v.value)!=null?w:"";this.applyValueMapsToRows(),this.showPreviewStep()})}applyValueMapsToRows(){var t,e,s,a,n,r,o;for(let l of this.importRows){let c=(e=(t=l.entry.status)==null?void 0:t.trim())!=null?e:"";if(c&&Object.prototype.hasOwnProperty.call(this.statusValueMap,c)){let h=(s=this.statusValueMap[c])!=null?s:"";l.entry.status=h||void 0}let d=(n=(a=l.entry.type)==null?void 0:a.trim())!=null?n:"";if(d&&Object.prototype.hasOwnProperty.call(this.typeValueMap,d)){let h=(r=this.typeValueMap[d])!=null?r:"";h===gi?l.entry.type=d:l.entry.type=h||void 0}let u=Object.keys(this.ratingValueMap).find(h=>{var w,b,E;let p=this.columnMapping.rating;if(!p)return!1;let f=((w=this.csvRows[0])!=null?w:[]).map(D=>D.trim()).indexOf(p);if(f<0)return!1;let y=this.importRows.indexOf(l);return((E=((b=this.csvRows[y+1])!=null?b:[])[f])!=null?E:"").trim()===h});if(u!==void 0){let h=(o=this.ratingValueMap[u])!=null?o:"";l.entry.rating=h?parseInt(h):0}l.isDuplicate=!!this.dataManager.getTitles().find(h=>{var p;return h.title.toLowerCase()===((p=l.entry.title)!=null?p:"").toLowerCase()})}}showPreviewStep(){!this.stepValueMap||!this.stepMapping||!this.stepPreview||!this.importBtn||(this.stepValueMap.hide(),this.stepMapping.hide(),this.stepPreview.show(),this.importBtn.show(),this.importBtn.disabled=this.importRows.filter(t=>t.selected).length===0,this.renderPreviewStep(this.stepPreview))}renderPreviewStep(t){var u;t.empty();let e=this.importRows.filter(h=>h.isDuplicate).length;e>0&&t.createDiv({cls:"wl-csv-dupe-warning",text:`${e} duplicate${e!==1?"s":""} found (highlighted). These are deselected by default.`});let s=t.createDiv({cls:"wl-csv-ctrl-row"}),a=s.createEl("button",{cls:"wl-btn",text:"\u2190 back"}),n=s.createEl("button",{cls:"wl-btn",text:"Select all"}),r=s.createEl("button",{cls:"wl-btn",text:"Select none"}),o=s.createSpan({cls:"wl-csv-count",text:""});a.addEventListener("click",()=>{if(!this.stepPreview||!this.stepValueMap||!this.stepMapping||!this.importBtn)return;this.stepPreview.hide(),this.importBtn.hide(),this.importBtn.disabled=!0,Object.keys(this.statusValueMap).length>0||Object.keys(this.typeValueMap).length>0||Object.keys(this.ratingValueMap).length>0?this.stepValueMap.show():this.stepMapping.show()});let l=t.createDiv({cls:"wl-csv-list"}),c=[],d=()=>{let h=this.importRows.filter(p=>p.selected).length;o.textContent=`${h} of ${this.importRows.length} selected`,this.importBtn&&(this.importBtn.disabled=h===0)};for(let h=0;h{this.importRows[v].selected=f.checked,d()})}n.addEventListener("click",()=>{this.importRows.forEach(h=>{h.selected=!0}),c.forEach(h=>{h.checked=!0}),d()}),r.addEventListener("click",()=>{this.importRows.forEach(h=>{h.selected=!1}),c.forEach(h=>{h.checked=!1}),d()}),d()}async doImport(){var c,d,u,h,p,m,f,y,v,w,b,E;let t=this.importRows.filter(D=>{var S;return D.selected&&((S=D.entry.title)==null?void 0:S.trim())});if(t.length===0){new $t.Notice("No titles selected to import.");return}this.isImporting=!0,this.importCancelled=!1,this.importBtn&&(this.importBtn.disabled=!0),this.cancelBtn&&(this.cancelBtn.textContent="Cancel import"),this.progressWrap&&this.progressWrap.show(),this.progressText&&(this.progressText.textContent=`0 / ${t.length}`),this.progressBarFill&&(this.progressBarFill.style.width="0%");let e=()=>{this.importCancelled=!0};this.plugin.importProgress={current:0,total:t.length,cancel:e};let s=(c=this.plugin.settings.colorTheme)!=null?c:"default",a=new Set(this.plugin.settings.types.map(D=>D.name.toLowerCase())),n=new Set;for(let D of t){let S=(d=D.entry.type)==null?void 0:d.trim();S&&!a.has(S.toLowerCase())&&n.add(S)}for(let[D,S]of Object.entries(this.typeValueMap))S===gi&&!a.has(D.toLowerCase())&&n.add(D);if(n.size>0){for(let D of n)this.plugin.settings.types.push({name:D,color:zn(s)});await this.plugin.saveSettings()}let r=10,o=0;try{for(let D=0;D0&&(I.watchedEpisodes=Array.from({length:I.totalEpisodes},(H,k)=>k+1)),T.push(I)}if(T.length===0)break;await this.dataManager.addTitleBatch(T),o+=T.length,this.plugin.importProgress={current:o,total:t.length,cancel:e};let M=Math.round(o/t.length*100);this.progressBarFill&&(this.progressBarFill.style.width=`${M}%`),this.progressText&&(this.progressText.textContent=`${o} / ${t.length}`)}}finally{this.isImporting=!1,this.plugin.importProgress=null,this.dataManager.notifyChange()}let l=n.size>0?` (${n.size} new type${n.size!==1?"s":""} created)`:"";this.importCancelled?(this.progressText&&(this.progressText.textContent=`Cancelled \u2014 ${o} / ${t.length} imported`),this.cancelBtn&&(this.cancelBtn.disabled=!1,this.cancelBtn.textContent="Close"),new $t.Notice(`Import cancelled. ${o} title${o!==1?"s":""} imported.`)):(this.progressText&&(this.progressText.textContent=`Done \u2014 ${o} imported`),this.cancelBtn&&(this.cancelBtn.disabled=!1,this.cancelBtn.textContent="Close"),new $t.Notice(`Imported ${o} title${o!==1?"s":""}${l}.`),this.close())}};var ha=require("obsidian"),Me=class extends ha.Modal{constructor(t,e,s){super(t);this.mode=e;this.onChoice=s}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("wl-draft-choice-modal"),this.titleEl.setText(this.mode==="export"?"Export to CSV":"Import from CSV"),t.createDiv({cls:"wl-draft-choice-subtitle",text:this.mode==="export"?"Which library do you want to export?":"Which library do you want to import into?"});let e=t.createDiv({cls:"wl-draft-choice-grid"}),s=(a,n)=>{let r=e.createEl("button",{cls:"wl-draft-choice-btn"});r.createDiv({cls:"wl-draft-choice-label",text:a}),r.addEventListener("click",()=>{this.close(),this.onChoice(n)})};s("Books","book"),s("Manga","manga")}onClose(){this.contentEl.empty()}};var Wt=require("obsidian");function jn(g){let i=String(g!=null?g:"");return i.includes(",")||i.includes('"')||i.includes(` +`)?`"${i.replace(/"/g,'""')}"`:i}function qn(g){let i=[],t=[],e="",s=!1,a=g.replace(/\r\n?/g,` `);for(let n=0;n0||t.length>0)&&(t.push(e),i.push(t));i.length>0&&i[i.length-1].every(n=>n==="");)i.pop();return i}var Ps={jan:1,feb:2,mar:3,apr:4,may:5,jun:6,jul:7,aug:8,sep:9,oct:10,nov:11,dec:12};function gn(g){let i=g.trim();if(!i)return null;try{if(/^\d{4}-\d{2}-\d{2}$/.test(i))return i;let t=i.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);if(t){let r=parseInt(t[1]),o=parseInt(t[2]),l=parseInt(t[3]),c,d;return r>12?(c=r,d=o):o>12?(d=r,c=o):(c=r,d=o),d<1||d>12||c<1||c>31?null:`${l}-${String(d).padStart(2,"0")}-${String(c).padStart(2,"0")}`}let e=i.match(/^(\d{1,2})\s+([A-Za-z]{3,})\s+(\d{4})$/);if(e){let r=Ps[e[2].toLowerCase().slice(0,3)],o=parseInt(e[1]),l=parseInt(e[3]);if(r)return`${l}-${String(r).padStart(2,"0")}-${String(o).padStart(2,"0")}`}let s=i.match(/^([A-Za-z]{3,})\s+(\d{1,2}),?\s+(\d{4})$/);if(s){let r=Ps[s[1].toLowerCase().slice(0,3)],o=parseInt(s[2]),l=parseInt(s[3]);if(r)return`${l}-${String(r).padStart(2,"0")}-${String(o).padStart(2,"0")}`}let a=i.match(/^(\d{1,2})[.-](\d{1,2})[.-](\d{4})$/);if(a){let r=parseInt(a[1]),o=parseInt(a[2]),l=parseInt(a[3]);if(o>=1&&o<=12&&r>=1&&r<=31)return`${l}-${String(o).padStart(2,"0")}-${String(r).padStart(2,"0")}`}let n=new Date(i);if(!isNaN(n.getTime())){let r=n.getDate(),o=n.getMonth()+1;return`${n.getFullYear()}-${String(o).padStart(2,"0")}-${String(r).padStart(2,"0")}`}return null}catch(t){return null}}var mn=["title","author","status","rating","pagesRead","totalPages","chaptersRead","totalChapters","dateStarted","dateFinished","releaseDate","dateAdded","externalLink","googleBooksId"],vn=["title","author","status","rating","chaptersRead","totalChapters","volumesRead","totalVolumes","dateStarted","dateFinished","releaseDate","dateAdded","externalLink","malId"],Fs=[{key:"title",label:"Title",coercion:"string",autoDetect:["title","name"]},{key:"author",label:"Author",coercion:"string",autoDetect:["author","writer","by"]},{key:"status",label:"Status",coercion:"string",autoDetect:["status"]},{key:"rating",label:"Rating",coercion:"rating",autoDetect:["rating","score"]}],$s=[{key:"dateStarted",label:"Date Started",coercion:"date",autoDetect:["started","datestarted","date started","date_started","start date"]},{key:"dateFinished",label:"Date Finished",coercion:"date",autoDetect:["finished","datefinished","date finished","date_finished","end date","finish date","completed date"]},{key:"releaseDate",label:"Release Date",coercion:"date",autoDetect:["releasedate","release date","release_date","published","publish date"]},{key:"externalLink",label:"Link",coercion:"string",autoDetect:["link","externallink","external link","external_link","url"]}],fn=[...Fs,{key:"pagesRead",label:"Pages Read",coercion:"int",autoDetect:["pagesread","pages read","read pages","page"]},{key:"totalPages",label:"Total Pages",coercion:"int",autoDetect:["totalpages","total pages","pages","page count"]},{key:"chaptersRead",label:"Chapters Read",coercion:"int",autoDetect:["chaptersread","chapters read","read chapters"]},{key:"totalChapters",label:"Total Chapters",coercion:"int",autoDetect:["totalchapters","total chapters","chapters","chapter count"]},...$s,{key:"googleBooksId",label:"Google Books ID",coercion:"string",autoDetect:["googlebooksid","google books id","gbid","volumeid"]}],wn=[...Fs,{key:"chaptersRead",label:"Chapters Read",coercion:"int",autoDetect:["chaptersread","chapters read","read chapters"]},{key:"totalChapters",label:"Total Chapters",coercion:"int",autoDetect:["totalchapters","total chapters","chapters","chapter count"]},{key:"volumesRead",label:"Volumes Read",coercion:"int",autoDetect:["volumesread","volumes read","read volumes"]},{key:"totalVolumes",label:"Total Volumes",coercion:"int",autoDetect:["totalvolumes","total volumes","volumes","volume count"]},...$s,{key:"malId",label:"MAL ID",coercion:"string",autoDetect:["malid","mal id","myanimelist id","mal"]}];function yn(g){return g==="book"?{exportColumns:mn,importFields:fn}:{exportColumns:vn,importFields:wn}}function bn(g,i){let t={};for(let e of g){let s=i.find(a=>e.autoDetect.includes(a.toLowerCase()));t[e.key]=s!=null?s:""}return t}var he=class extends Ct.Modal{constructor(t,e,s,a){super(t);this.selectedIds=new Set;this.csvRows=[];this.csvHeaders=[];this.columnMapping={};this.importRows=[];this.statusValueMap={};this.ratingValueMap={};this.stepUpload=null;this.stepMapping=null;this.stepValueMap=null;this.stepPreview=null;this.importBtn=null;this.cancelBtn=null;this.isImporting=!1;this.importCancelled=!1;this.progressWrap=null;this.progressBarFill=null;this.progressText=null;this.plugin=e,this.kind=s,this.mode=a,this.schema=yn(s)}get kindLabel(){return this.kind==="book"?"Books":"Manga"}get itemNoun(){return this.kind==="book"?"book":"manga"}getItems(){return this.kind==="book"?this.plugin.readingDataManager.getBooks():this.plugin.readingDataManager.getMangaList()}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("wl-csv-modal"),this.mode==="export"?this.renderExport(t):this.renderImport(t)}onClose(){this.contentEl.empty()}itemsToCsv(t){let e=this.schema.exportColumns,s=e.join(","),a=t.map(n=>e.map(r=>hn(n[r])).join(","));return[s,...a].join(` -`)}renderExport(t){t.createEl("h2",{cls:"wl-modal-title",text:`Export ${this.kindLabel} to CSV`});let e=this.getItems();e.forEach(p=>this.selectedIds.add(p.id));let s=t.createDiv({cls:"wl-csv-ctrl-row"}),a=s.createEl("button",{cls:"wl-btn",text:"Select all"}),n=s.createEl("button",{cls:"wl-btn",text:"Select none"}),r=s.createSpan({cls:"wl-csv-count",text:`${e.length} selected`}),o=t.createDiv({cls:"wl-csv-list"}),l=[],c=()=>{r.textContent=`${this.selectedIds.size} selected`};for(let p of e){let m=o.createDiv({cls:"wl-csv-row"}),v=m.createEl("input",{attr:{type:"checkbox"}});v.checked=!0,l.push(v),m.createSpan({cls:"wl-csv-row-title",text:p.title});let f=[p.author,p.status].filter(Boolean).join(" \xB7 ");f&&m.createSpan({cls:"wl-csv-row-meta",text:f}),v.addEventListener("change",()=>{v.checked?this.selectedIds.add(p.id):this.selectedIds.delete(p.id),c()})}a.addEventListener("click",()=>{e.forEach(p=>this.selectedIds.add(p.id)),l.forEach(p=>{p.checked=!0}),c()}),n.addEventListener("click",()=>{this.selectedIds.clear(),l.forEach(p=>{p.checked=!1}),c()});let d=t.createDiv({cls:"wl-modal-btn-row wl-csv-btn-row"}),u=d.createEl("button",{cls:"wl-btn",text:"Cancel"}),h=d.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Export CSV"});u.addEventListener("click",()=>this.close()),h.addEventListener("click",()=>{let p=e.filter(S=>this.selectedIds.has(S.id));if(p.length===0){new Ct.Notice(`No ${this.itemNoun} selected.`);return}let m=this.itemsToCsv(p),v=new Blob([m],{type:"text/csv;charset=utf-8;"}),f=URL.createObjectURL(v),y=activeDocument.createElement("a"),w=new Date,b=`${w.getFullYear()}-${String(w.getMonth()+1).padStart(2,"0")}-${String(w.getDate()).padStart(2,"0")}`;y.href=f,y.download=`watchlog-${this.itemNoun==="book"?"books":"manga"}-export-${b}.csv`,y.click(),URL.revokeObjectURL(f),new Ct.Notice(`Exported ${p.length} ${this.kindLabel.toLowerCase()}.`),this.close()})}renderImport(t){t.createEl("h2",{cls:"wl-modal-title",text:`Import ${this.kindLabel} from CSV`}),this.stepUpload=t.createDiv({cls:"wl-csv-step"});let e=this.stepUpload.createDiv({cls:"wl-csv-drop-zone"});e.createDiv({cls:"wl-csv-drop-label",text:"Select a CSV file to import"});let s=e.createEl("input",{attr:{type:"file",accept:".csv"},cls:"wl-csv-file-input"});this.stepMapping=t.createDiv({cls:"wl-csv-step"}),this.stepMapping.hide(),this.stepValueMap=t.createDiv({cls:"wl-csv-step"}),this.stepValueMap.hide(),this.stepPreview=t.createDiv({cls:"wl-csv-step"}),this.stepPreview.hide();let a=t.createDiv({cls:"wl-modal-btn-row wl-csv-btn-row"});this.progressWrap=a.createDiv({cls:"wl-csv-progress-wrap"}),this.progressWrap.hide(),this.progressWrap.createSpan({cls:"wl-csv-bg-note",text:"You can close this window \u2014 import will continue in the background."});let n=this.progressWrap.createDiv({cls:"wl-csv-progress-track"});this.progressBarFill=n.createDiv({cls:"wl-csv-progress-fill"}),this.progressText=this.progressWrap.createSpan({cls:"wl-csv-progress-text",text:"0 / 0"}),this.cancelBtn=a.createEl("button",{cls:"wl-btn",text:"Cancel"}),this.importBtn=a.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Import selected"}),this.importBtn.disabled=!0,this.importBtn.hide(),this.cancelBtn.addEventListener("click",()=>{this.isImporting?(this.importCancelled=!0,this.cancelBtn&&(this.cancelBtn.disabled=!0,this.cancelBtn.textContent="Cancelling\u2026")):this.close()}),this.importBtn.addEventListener("click",()=>void this.doImport()),s.addEventListener("change",()=>{var l;let r=(l=s.files)==null?void 0:l[0];if(!r)return;let o=new FileReader;o.onload=c=>{var u,h;let d=(u=c.target)==null?void 0:u.result;this.csvRows=pn(d),this.csvHeaders=((h=this.csvRows[0])!=null?h:[]).map(p=>p.trim()),this.columnMapping=bn(this.schema.importFields,this.csvHeaders),this.showMappingStep()},o.readAsText(r)})}showMappingStep(){!this.stepUpload||!this.stepMapping||(this.stepUpload.hide(),this.stepMapping.show(),this.renderMappingStep(this.stepMapping))}renderMappingStep(t){var r;t.empty(),t.createDiv({cls:"wl-csv-step-title",text:"Map your columns"}),t.createDiv({cls:"wl-csv-step-desc",text:`Match each ${this.itemNoun==="book"?"Book":"Manga"} field to a column from your CSV. Select "\u2014 skip \u2014" to leave a field empty.`}),t.createDiv({cls:"wl-csv-info-note",text:"Rows with empty fields will be skipped automatically. If you see missing entries, check that your CSV has no empty rows at the top."});let e="",s=t.createDiv({cls:"wl-csv-map-grid"}),a={};for(let o of this.schema.importFields){let l=s.createDiv({cls:"wl-csv-map-row"});l.createSpan({cls:"wl-csv-map-label",text:o.label});let c=l.createEl("select",{cls:"wl-select wl-csv-map-select"});a[o.key]=c,c.createEl("option",{value:e,text:"\u2014 skip \u2014"});for(let d of this.csvHeaders)c.createEl("option",{value:d,text:d});c.value=(r=this.columnMapping[o.key])!=null?r:e}t.createEl("button",{cls:"wl-btn wl-btn-primary wl-csv-preview-btn",text:"Next \u2192"}).addEventListener("click",()=>{var v,f,y,w,b,S;for(let k of this.schema.importFields)this.columnMapping[k.key]=(f=(v=a[k.key])==null?void 0:v.value)!=null?f:"";this.importRows=this.applyMapping().map(k=>({...k,selected:!k.isDuplicate}));let o=new Set(wt),l=[],c=[],d=new Set,u=new Set,h=((y=this.csvRows[0])!=null?y:[]).map(k=>k.trim()),p=this.columnMapping.rating,m=p?h.indexOf(p):-1;for(let k of this.importRows){let E=(w=k.entry.status)==null?void 0:w.trim();if(E&&!o.has(E)&&!d.has(E)&&(l.push(E),d.add(E)),m>=0){let D=this.importRows.indexOf(k),x=((S=((b=this.csvRows[D+1])!=null?b:[])[m])!=null?S:"").trim();x&&isNaN(parseFloat(x))&&!u.has(x)&&(c.push(x),u.add(x))}}l.length>0||c.length>0?this.showValueMapStep(l,c):this.showPreviewStep()})}applyMapping(){var s;if(this.csvRows.length<2)return[];let t=((s=this.csvRows[0])!=null?s:[]).map(a=>a.trim()),e=this.getItems();return this.csvRows.slice(1).filter(a=>a.some(n=>n.trim())).map(a=>{let n=l=>{var u;let c=this.columnMapping[l];if(!c)return"";let d=t.indexOf(c);return d>=0?((u=a[d])!=null?u:"").trim():""},r={};for(let l of this.schema.importFields){let c=n(l.key);if(c)switch(l.coercion){case"string":r[l.key]=c;break;case"int":r[l.key]=parseInt(c)||0;break;case"rating":{let d=parseFloat(c)||0;r.rating=Math.max(0,Math.min(5,d));break}case"date":{let d=gn(c);d&&(r[l.key]=d);break}}}if(!r.title||!r.title.trim())return null;let o=!!e.find(l=>{var c;return l.title.toLowerCase()===((c=r.title)!=null?c:"").toLowerCase()});return{entry:r,isDuplicate:o}}).filter(a=>a!==null)}showValueMapStep(t,e){!this.stepMapping||!this.stepValueMap||(this.stepMapping.hide(),this.stepValueMap.show(),this.renderValueMapStep(this.stepValueMap,t,e))}renderValueMapStep(t,e,s){t.empty(),t.createDiv({cls:"wl-csv-step-title",text:"Map unknown values"}),t.createDiv({cls:"wl-csv-step-desc",text:"Some values in your CSV were not recognized. Map each to an existing value, or leave it blank."});let a={},n={};if(e.length>0){t.createDiv({cls:"wl-csv-valmap-section-title",text:"Status"});for(let c of e){let d=t.createDiv({cls:"wl-csv-valmap-row"});d.createSpan({cls:"wl-csv-valmap-orig",text:`"${c}"`}),d.createSpan({cls:"wl-csv-valmap-arrow",text:"\u2192"});let u=d.createEl("select",{cls:"wl-select wl-csv-valmap-select"});a[c]=u,u.createEl("option",{value:"",text:"\u2014 leave blank \u2014"});for(let m of lt)u.createEl("option",{value:m,text:m});let h=c.toLowerCase(),p=lt.find(m=>m.toLowerCase()===h);p&&(u.value=p)}}if(s.length>0){t.createDiv({cls:"wl-csv-valmap-section-title",text:"Rating"});for(let c of s){let d=t.createDiv({cls:"wl-csv-valmap-row"});d.createSpan({cls:"wl-csv-valmap-orig",text:`"${c}"`}),d.createSpan({cls:"wl-csv-valmap-arrow",text:"\u2192"});let u=d.createEl("select",{cls:"wl-select wl-csv-valmap-select"});n[c]=u,u.createEl("option",{value:"",text:"\u2014 leave blank \u2014"});for(let h=1;h<=5;h++)u.createEl("option",{value:String(h),text:`${h}/5`})}}let r=t.createDiv({cls:"wl-csv-valmap-btn-row"}),o=r.createEl("button",{cls:"wl-btn",text:"\u2190 back"}),l=r.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Preview \u2192"});o.addEventListener("click",()=>{!this.stepValueMap||!this.stepMapping||(this.stepValueMap.hide(),this.stepMapping.show())}),l.addEventListener("click",()=>{var c,d,u,h;this.statusValueMap={};for(let p of e)this.statusValueMap[p]=(d=(c=a[p])==null?void 0:c.value)!=null?d:"";this.ratingValueMap={};for(let p of s)this.ratingValueMap[p]=(h=(u=n[p])==null?void 0:u.value)!=null?h:"";this.applyValueMapsToRows(),this.showPreviewStep()})}applyValueMapsToRows(){var a,n,r,o,l,c,d;let t=((a=this.csvRows[0])!=null?a:[]).map(u=>u.trim()),e=this.columnMapping.rating,s=e?t.indexOf(e):-1;for(let u of this.importRows){let h=(r=(n=u.entry.status)==null?void 0:n.trim())!=null?r:"";if(h&&Object.prototype.hasOwnProperty.call(this.statusValueMap,h)){let p=(o=this.statusValueMap[h])!=null?o:"";u.entry.status=p||void 0}if(s>=0){let p=this.importRows.indexOf(u),v=((c=((l=this.csvRows[p+1])!=null?l:[])[s])!=null?c:"").trim();if(v&&Object.prototype.hasOwnProperty.call(this.ratingValueMap,v)){let f=(d=this.ratingValueMap[v])!=null?d:"";u.entry.rating=f?parseInt(f):0}}}}showPreviewStep(){!this.stepValueMap||!this.stepMapping||!this.stepPreview||!this.importBtn||(this.stepValueMap.hide(),this.stepMapping.hide(),this.stepPreview.show(),this.importBtn.show(),this.importBtn.disabled=this.importRows.filter(t=>t.selected).length===0,this.renderPreviewStep(this.stepPreview))}renderPreviewStep(t){var u;t.empty();let e=this.importRows.filter(h=>h.isDuplicate).length;e>0&&t.createDiv({cls:"wl-csv-dupe-warning",text:`${e} duplicate${e!==1?"s":""} found (highlighted). These are deselected by default.`});let s=t.createDiv({cls:"wl-csv-ctrl-row"}),a=s.createEl("button",{cls:"wl-btn",text:"\u2190 back"}),n=s.createEl("button",{cls:"wl-btn",text:"Select all"}),r=s.createEl("button",{cls:"wl-btn",text:"Select none"}),o=s.createSpan({cls:"wl-csv-count",text:""});a.addEventListener("click",()=>{if(!this.stepPreview||!this.stepValueMap||!this.stepMapping||!this.importBtn)return;this.stepPreview.hide(),this.importBtn.hide(),this.importBtn.disabled=!0,Object.keys(this.statusValueMap).length>0||Object.keys(this.ratingValueMap).length>0?this.stepValueMap.show():this.stepMapping.show()});let l=t.createDiv({cls:"wl-csv-list"}),c=[],d=()=>{let h=this.importRows.filter(p=>p.selected).length;o.textContent=`${h} of ${this.importRows.length} selected`,this.importBtn&&(this.importBtn.disabled=h===0)};for(let h=0;h{this.importRows[y].selected=v.checked,d()})}n.addEventListener("click",()=>{this.importRows.forEach(h=>{h.selected=!0}),c.forEach(h=>{h.checked=!0}),d()}),r.addEventListener("click",()=>{this.importRows.forEach(h=>{h.selected=!1}),c.forEach(h=>{h.checked=!1}),d()}),d()}buildBook(t,e){var n,r,o,l,c,d,u,h,p,m,v;let s=t.title.trim(),a=new Date().toISOString();return{id:this.plugin.readingDataManager.generateBookId(s),title:s,author:(n=t.author)!=null?n:"",status:t.status||e,rating:(r=t.rating)!=null?r:0,pagesRead:(o=t.pagesRead)!=null?o:0,totalPages:(l=t.totalPages)!=null?l:0,chaptersRead:(c=t.chaptersRead)!=null?c:0,totalChapters:(d=t.totalChapters)!=null?d:0,coverUrl:"",googleBooksId:(u=t.googleBooksId)!=null?u:"",externalLink:(h=t.externalLink)!=null?h:"",vaultPage:"",dateStarted:(p=t.dateStarted)!=null?p:null,dateFinished:(m=t.dateFinished)!=null?m:null,releaseDate:(v=t.releaseDate)!=null?v:null,dateAdded:a,dateModified:a,customFields:{}}}buildManga(t,e){var n,r,o,l,c,d,u,h,p,m,v;let s=t.title.trim(),a=new Date().toISOString();return{id:this.plugin.readingDataManager.generateMangaId(s),title:s,author:(n=t.author)!=null?n:"",status:t.status||e,rating:(r=t.rating)!=null?r:0,chaptersRead:(o=t.chaptersRead)!=null?o:0,totalChapters:(l=t.totalChapters)!=null?l:0,volumesRead:(c=t.volumesRead)!=null?c:0,totalVolumes:(d=t.totalVolumes)!=null?d:0,coverUrl:"",malId:(u=t.malId)!=null?u:"",externalLink:(h=t.externalLink)!=null?h:"",vaultPage:"",dateStarted:(p=t.dateStarted)!=null?p:null,dateFinished:(m=t.dateFinished)!=null?m:null,releaseDate:(v=t.releaseDate)!=null?v:null,dateAdded:a,dateModified:a,customFields:{}}}async doImport(){var r;let t=this.importRows.filter(o=>{var l;return o.selected&&((l=o.entry.title)==null?void 0:l.trim())});if(t.length===0){new Ct.Notice(`No ${this.itemNoun} selected to import.`);return}this.isImporting=!0,this.importCancelled=!1,this.importBtn&&(this.importBtn.disabled=!0),this.cancelBtn&&(this.cancelBtn.textContent="Cancel import"),this.progressWrap&&this.progressWrap.show(),this.progressText&&(this.progressText.textContent=`0 / ${t.length}`),this.progressBarFill&&(this.progressBarFill.style.width="0%");let e=this.plugin.readingDataManager,s=(r=e.getSettings().defaultStatus)!=null?r:"Plan to Read",a=10,n=0;try{for(let o=0;o{this.textSaveTimer=null,this.plugin.saveSettings()},500)}display(){let{containerEl:t}=this;t.empty(),t.addClass("wl-settings");let e=t.createDiv({cls:"wl-settings-nav"}),s=[{key:"general",label:"General"},{key:"api",label:"API"},{key:"customize",label:"Customize"},{key:"watchlist",label:"Watchlist"},{key:"drafts",label:"Drafts"},{key:"custom-lists",label:"Custom Lists"},{key:"reading",label:"Reading"},{key:"widgets",label:"Widgets"},{key:"quick-info",label:"Quick Info"}],a=new Map;for(let r of s){let o=e.createEl("button",{cls:`wl-settings-nav-btn${this.activeSection===r.key?" is-active":""}`,text:r.label});a.set(r.key,o),o.addEventListener("click",()=>{this.activeSection=r.key,a.forEach((l,c)=>{c===r.key?l.addClass("is-active"):l.removeClass("is-active")}),n.empty(),this.renderSection(n)})}let n=t.createDiv({cls:"wl-settings-body"});this.renderSection(n)}renderSection(t){switch(t.empty(),this.activeSection){case"general":this.renderGeneral(t);break;case"api":this.renderApi(t);break;case"customize":this.renderCustomize(t);break;case"watchlist":this.renderWatchlist(t);break;case"drafts":this.renderDrafts(t);break;case"custom-lists":this.renderCustomLists(t);break;case"reading":this.renderReading(t);break;case"widgets":this.renderWidgets(t);break;case"quick-info":this.renderQuickInfo(t);break}}renderGeneral(t){new R.Setting(t).setName("Dashboard card style").setDesc("Choose between ring charts or rectangular stat cards on the dashboard.").addDropdown(o=>{var l;return o.addOptions({circles:"Circles",rectangles:"Rectangles"}).setValue((l=this.plugin.settings.dashboardCardStyle)!=null?l:"circles").onChange(async c=>{this.plugin.settings.dashboardCardStyle=c,await this.plugin.saveSettings(),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed"))})}),new R.Setting(t).setName("Set finish date automatically").setDesc("Record today's date as the finish date when a watch title or reading entry is completed.").addToggle(o=>o.setValue(this.plugin.settings.setFinishDateAutomatically).onChange(async l=>{this.plugin.settings.setFinishDateAutomatically=l,await this.plugin.saveSettings()})),new R.Setting(t).setName("Re-fetch all posters").setDesc("Clears all cached poster and reading cover URLs. Watch posters reload lazily when you scroll the Cards view; reading covers can be re-fetched from each card's \u22EE menu.").addButton(o=>o.setButtonText("Re-fetch posters").onClick(()=>{let l=this.plugin.dataManager.getTitles(),c=this.plugin.readingDataManager.getBooks().length+this.plugin.readingDataManager.getMangaList().length;new N(this.app,`This will clear cached images for all ${l.length} watch titles and ${c} reading entries. Items without API access will show placeholder cards. Continue?`,()=>{this.refetchAllPosters()}).open()})),new R.Setting(t).setName("Show hint banners").setDesc("Show informational hint banners in Upcoming, Custom Lists, and Drafts tabs.").addToggle(o=>o.setValue(this.plugin.settings.showHintBanners).onChange(async l=>{this.plugin.settings.showHintBanners=l,await this.plugin.saveSettings(),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed"))})),new R.Setting(t).setName("Show Upcoming count in status bar").setDesc('Show a "N due" counter in the status bar when Upcoming entries are due. Click it to open the Upcoming tab. (Desktop only.)').addToggle(o=>o.setValue(this.plugin.settings.showUpcomingStatusBar).onChange(async l=>{this.plugin.settings.showUpcomingStatusBar=l,await this.plugin.saveSettings(),this.plugin.updateStatusBar()})),t.createDiv({cls:"wl-settings-section-title",text:"Backup & Restore"}),new R.Setting(t).setName("Export backup").setDesc("Export all watchlog data \u2014 watchlist, reading (books & manga) and activity log \u2014 into a single timestamped .JSON file.").addButton(o=>o.setButtonText("Export backup").onClick(()=>void this.exportBackup())),new R.Setting(t).setName("Restore from backup").setDesc("Restore from a .JSON backup file. This replaces your current watchlist, reading and activity-log data with the contents of the backup. Older watch-only backups restore the watchlist only and leave reading and activity log untouched.").addButton(o=>o.setButtonText("Restore from backup").onClick(()=>this.openRestoreDialog()));let e={wrap:null,fill:null,text:null};new R.Setting(t).setName("Regenerate note files").setDesc("Creates missing .md files for titles that don't have one. Existing files are not modified.").addButton(o=>o.setButtonText("Regenerate").onClick(()=>{let{wrap:l,fill:c,text:d}=e;l&&c&&d&&this.runRegenerate(l,c,d)}));let s=t.createDiv({cls:"wl-regen-progress-wrap"});s.hide(),s.createSpan({cls:"wl-csv-bg-note",text:"You can close settings \u2014 regeneration continues in the background."});let n=s.createDiv({cls:"wl-csv-progress-track"}).createDiv({cls:"wl-csv-progress-fill"}),r=s.createSpan({cls:"wl-csv-progress-text",text:"0 / 0"});e.wrap=s,e.fill=n,e.text=r}async exportBackup(){var d;let t=new Date,s=`watchlog-backup-${`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`}.json`,a=Object.assign({},(d=this.plugin.dataManager.getData())!=null?d:{});delete a.reading,delete a.history,delete a.migratedReadingHistory;let n={version:2,exportedAt:t.toISOString(),watch:a,reading:this.plugin.readingDataManager.getData(),history:this.plugin.historyManager.exportEntries()},r=JSON.stringify(n,null,2);if(R.Platform.isMobile){await this.exportBackupToVault(s,r);return}let o=new Blob([r],{type:"application/json"}),l=URL.createObjectURL(o),c=activeDocument.createElement("a");c.href=l,c.download=s,activeDocument.body.appendChild(c),c.click(),activeDocument.body.removeChild(c),URL.revokeObjectURL(l),new R.Notice(`Backup exported as ${s}`)}async exportBackupToVault(t,e){let s=this.app.vault.adapter,a=(0,R.normalizePath)("WatchLog/backups");if(!await s.exists(a))try{await s.mkdir(a)}catch(c){}let n=t.lastIndexOf("."),r=n===-1?t:t.slice(0,n),o=n===-1?"":t.slice(n),l=(0,R.normalizePath)(`${a}/${t}`);if(await s.exists(l)){let c=2;for(;await s.exists((0,R.normalizePath)(`${a}/${r}-${c}${o}`));)c++;l=(0,R.normalizePath)(`${a}/${r}-${c}${o}`)}await s.write(l,e),new R.Notice(`Backup saved to ${l}`)}openRestoreDialog(){let t=activeDocument.createElement("input");t.type="file",t.accept=".json",t.hide(),activeDocument.body.appendChild(t);let e=!1,s=()=>{if(t.parentElement)try{activeDocument.body.removeChild(t)}catch(n){}},a=()=>{window.setTimeout(()=>{e||s(),window.removeEventListener("focus",a)},200)};window.addEventListener("focus",a),t.addEventListener("change",()=>{var o;e=!0;let n=(o=t.files)==null?void 0:o[0];if(!n){s();return}let r=new FileReader;r.onload=l=>{var h;s();let c=(h=l.target)==null?void 0:h.result,d;try{d=JSON.parse(c)}catch(p){new R.Notice("Invalid backup file \u2014 could not parse JSON.");return}if(typeof d!="object"||d===null){new R.Notice("Invalid backup file \u2014 not an object.");return}let u=d;if(u.version===2){let p=u.watch,m=u.reading,v=u.history;if(!this.isValidWatchData(p)){new R.Notice("Invalid backup file \u2014 watch data missing required fields (titles, groups, settings).");return}if(!this.isValidReadingData(m)){new R.Notice("Invalid backup file \u2014 reading data missing required fields (books, manga).");return}if(!Array.isArray(v)){new R.Notice("Invalid backup file \u2014 activity log is not a list.");return}new N(this.app,"This will replace ALL current watchlog data \u2014 watchlist, reading (books & manga) and activity log. Continue?",()=>{(async()=>{let f=Object.assign({},p,{migratedReadingHistory:!0});await this.plugin.saveData(f),await this.plugin.loadSettings(),await this.plugin.dataManager.load(),await this.plugin.readingDataManager.restore(m),await this.plugin.historyManager.restore(v),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed")),new R.Notice("Backup restored successfully.")})()}).open();return}if(!this.isValidWatchData(d)){new R.Notice("Invalid backup file \u2014 missing required fields (titles, groups, settings).");return}new N(this.app,"This is a legacy (watchlist-only) backup. It will replace your current watchlist. Reading and activity-log data are left untouched. Continue?",()=>{(async()=>{let p=Object.assign({},d,{reading:this.plugin.readingDataManager.getData(),history:this.plugin.historyManager.exportEntries(),migratedReadingHistory:!0});await this.plugin.saveData(p),await this.plugin.loadSettings(),await this.plugin.dataManager.load(),await this.plugin.historyManager.load(),await this.plugin.readingDataManager.load(),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed")),new R.Notice("Legacy backup restored \u2014 watchlist only; reading and activity log left untouched.")})()}).open()},r.readAsText(n)}),t.click()}isValidWatchData(t){if(typeof t!="object"||t===null)return!1;let e=t;return Array.isArray(e.titles)&&Array.isArray(e.groups)&&typeof e.settings=="object"&&e.settings!==null}isValidReadingData(t){if(typeof t!="object"||t===null)return!1;let e=t;return Array.isArray(e.books)&&Array.isArray(e.manga)&&typeof e.settings=="object"&&e.settings!==null}async refetchAllPosters(){let t=this.plugin.dataManager.getTitles();for(let s of t)s.posterUrl="";await this.plugin.dataManager.save();let e=this.plugin.readingDataManager;for(let s of e.getBooks())s.coverUrl="";for(let s of e.getMangaList())s.coverUrl="";await e.saveAndNotify(),new R.Notice("Cached posters and covers cleared. Watch posters reload as you browse; refresh reading covers from each card's \u22EE menu.")}async runRegenerate(t,e,s){let a=this.plugin.dataManager.getTitles(),n=this.plugin.readingDataManager,r=n.getBooks(),o=n.getMangaList(),l=a.length+r.length+o.length;if(t.show(),l===0){s.textContent="Done \u2014 no missing files found";return}e.style.width="0%",s.textContent=`0 / ${l}`;let c=0,d=0,u=0,h=p=>{p?c++:d++,u++;let m=Math.round(u/l*100);e.style.width=`${m}%`,s.textContent=`${u} / ${l}`};for(let p of a)h(await this.plugin.dataManager.createMarkdownFileIfMissing(p));for(let p of r)h(await n.createReadingNoteIfMissing("book",p));for(let p of o)h(await n.createReadingNoteIfMissing("manga",p));c===0?s.textContent="Done \u2014 no missing files found":s.textContent=`Done \u2014 ${c} file${c!==1?"s":""} created, ${d} already existed`}apiCallout(t,e,s){let a=t.createDiv({cls:`wl-api-callout wl-api-callout--${s}`});return a.createDiv({cls:"wl-api-callout-title",text:e}),a.createDiv({cls:"wl-api-callout-body"})}renderApi(t){let e=this.apiCallout(t,"Movies & TV Shows","movies");new R.Setting(e).setName("Active API").setDesc("Which API to use for movies and tv shows.").addDropdown(u=>{var h;return u.addOptions({OMDb:"OMDb",TMDB:"TMDB"}).setValue((h=this.plugin.settings.activeApi)!=null?h:"OMDb").onChange(async p=>{this.plugin.settings.activeApi=p,await this.plugin.saveSettings()})});let s=e.createDiv({cls:"wl-settings-info"});s.createSpan({text:"Get a free OMDb API key at "}),s.createEl("a",{text:"omdbapi.com/apikey.aspx",href:"https://www.omdbapi.com/apikey.aspx",attr:{target:"_blank",rel:"noopener noreferrer"}}),s.createSpan({text:"."});let a;new R.Setting(e).setName("Omdb API key").addText(u=>(u.setPlaceholder("Paste your omdb key here").setValue(this.plugin.settings.omdbApiKey).onChange(h=>{this.plugin.settings.omdbApiKey=h,this.plugin.apiService.setOmdbKey(h),this.debouncedSaveSettings()}),u.inputEl.type="password",u)).addButton(u=>u.setButtonText("Test").onClick(async()=>{let h=await this.plugin.apiService.checkOmdbConnection();a.textContent=h?"\u2713 Connected":"\u2717 Failed \u2014 check your key",a.className=h?"wl-status-ok":"wl-status-error"})),a=e.createDiv({cls:"wl-status-indicator",text:this.plugin.settings.omdbApiKey?"(not tested)":"Not set"});let n=e.createDiv({cls:"wl-settings-info"});n.createSpan({text:"Get a free TMDB read access token at "}),n.createEl("a",{text:"themoviedb.org/settings/api",href:"https://www.themoviedb.org/settings/api",attr:{target:"_blank",rel:"noopener noreferrer"}}),n.createSpan({text:"."});let r;new R.Setting(e).setName("Tmdb API read access token").addText(u=>{var h;return u.setPlaceholder("Paste your tmdb key here").setValue((h=this.plugin.settings.tmdbApiKey)!=null?h:"").onChange(p=>{this.plugin.settings.tmdbApiKey=p,this.plugin.apiService.setTmdbKey(p),this.debouncedSaveSettings()}),u.inputEl.type="password",u}).addButton(u=>u.setButtonText("Test").onClick(async()=>{let h=await this.plugin.apiService.checkTmdbConnection();r.textContent=h?"\u2713 Connected":"\u2717 Failed \u2014 check your key",r.className=h?"wl-status-ok":"wl-status-error"})),r=e.createDiv({cls:"wl-status-indicator",text:this.plugin.settings.tmdbApiKey?"(not tested)":"Not set"});let o=this.apiCallout(t,"Anime","anime");new R.Setting(o).setName("Anime API source").setDesc("Which API to use for new anime titles.").addDropdown(u=>{var h;return u.addOptions({jikan:"Jikan (MyAnimeList)",anilist:"AniList"}).setValue((h=this.plugin.settings.animeApiSource)!=null?h:"jikan").onChange(async p=>{this.plugin.settings.animeApiSource=p,await this.plugin.saveSettings()})}),o.createDiv({cls:"wl-settings-info",text:"Jikan uses MyAnimeList's database (larger catalog, no API key needed). AniList has its own database with more precise airing schedules and a GraphQL API. This setting only affects new titles \u2014 existing titles keep their original API source."});let l=this.apiCallout(t,"Books","books"),c;new R.Setting(l).setName("Google Books API key").addText(u=>{var h;return u.setPlaceholder("Paste your Google Books key here").setValue((h=this.plugin.settings.googleBooksApiKey)!=null?h:"").onChange(p=>{this.plugin.settings.googleBooksApiKey=p,this.plugin.apiService.setGoogleBooksKey(p),this.debouncedSaveSettings()}),u.inputEl.type="password",u}).addButton(u=>u.setButtonText("Test").onClick(async()=>{c.textContent="Testing...",c.className="wl-status-indicator";try{let h=await this.plugin.apiService.checkGoogleBooksConnection();c.textContent=h?"\u2713 Connected":"\u2717 Failed",c.className=h?"wl-status-ok":"wl-status-error"}catch(h){c.textContent=`\u2717 ${Et(h)}`,c.className="wl-status-error"}})),c=l.createDiv({cls:"wl-status-indicator",text:this.plugin.settings.googleBooksApiKey?"(not tested)":"Not set"});let d=l.createDiv({cls:"wl-settings-info"});d.createSpan({text:"Get a free key in the Google Cloud Console: create a project, enable the Books API, then create an API key under "}),d.createEl("a",{text:"APIs & Services \u2192 Credentials",href:"https://console.cloud.google.com/apis/credentials",attr:{target:"_blank",rel:"noopener noreferrer"}}),d.createSpan({text:"."}),this.renderTypeApiMapping(t)}renderTypeApiMapping(t){var l,c,d;let e=t.createDiv({cls:"wl-settings-card"});e.createDiv({cls:"wl-settings-card-title",text:"API routing by type in Watchlist"}),e.createDiv({cls:"wl-settings-card-desc",text:"Choose which API group to use for each title type. Anime, Movie, and TV Show are locked to their default APIs."});let s=e.createDiv({cls:"wl-type-api-list"}),a=(l=this.plugin.settings.types)!=null?l:[],n=(c=this.plugin.settings.typeApiMapping)!=null?c:{},r=new Set(a.map(u=>u.name)),o=!1;for(let u of Object.keys(n))(!r.has(u)||u==="Anime"||u==="Movie"||u==="TV Show"||u==="TvShow")&&(delete n[u],o=!0);o&&this.plugin.saveSettings();for(let u of a){let h=s.createDiv({cls:"wl-type-api-row"});if(h.createSpan({cls:"wl-type-api-name",text:u.name}),u.name==="Anime")h.createSpan({cls:"wl-type-api-locked",text:"Jikan / AniList (locked)"});else if(u.name==="Movie"||u.name==="TV Show"||u.name==="TvShow")h.createSpan({cls:"wl-type-api-locked",text:"OMDb / TMDB (locked)"});else{let p=h.createEl("select",{cls:"wl-select wl-type-api-select"}),m=(d=n[u.name])!=null?d:"",v=[{value:"",label:"\u2014 Not set \u2014"},{value:"anime",label:"Anime API (Jikan / AniList)"},{value:"movie",label:"Movie / TV API (OMDb / TMDB)"}];for(let f of v){let y=p.createEl("option",{text:f.label,value:f.value});m===f.value&&(y.selected=!0)}p.addEventListener("change",()=>{let f=p.value;this.plugin.settings.typeApiMapping||(this.plugin.settings.typeApiMapping={}),f===""?delete this.plugin.settings.typeApiMapping[u.name]:this.plugin.settings.typeApiMapping[u.name]=f,this.plugin.saveSettings()})}}}renderCustomize(t){this.renderThemePicker(t);let e=[{key:"types",label:"Type"},{key:"statuses",label:"Status"},{key:"priorities",label:"Priority"}];for(let s of e)this.renderTagSection(t,s.label,s.key);this.renderSeasonColors(t),this.renderReadingColors(t)}renderReadingColors(t){let e=t.createDiv({cls:"wl-tag-section"});e.createDiv({cls:"wl-settings-section-title",text:"Reading"});let s=[{label:"Manga",kind:"manga"},{label:"Book",kind:"book"}],a=e.createDiv({cls:"wl-tags-list"});for(let{label:n,kind:r}of s){let o=a.createDiv({cls:"wl-tag-pill"}),l=o.createDiv({cls:"wl-tag-dot-wrap"}),c=l.createSpan({cls:"wl-tag-dot"});c.style.backgroundColor=this.plugin.settings.readingTypeColors[r];let d=l.createEl("input",{cls:"wl-tag-color-picker",attr:{type:"color",value:this.plugin.settings.readingTypeColors[r]}});c.addEventListener("click",()=>d.click()),d.addEventListener("change",()=>{(async()=>(this.plugin.settings.readingTypeColors[r]=d.value,c.style.backgroundColor=d.value,await this.plugin.saveSettings()))()}),o.createSpan({cls:"wl-tag-name",text:n})}}renderThemePicker(t){var o;let e=t.createDiv({cls:"wl-tag-section"});e.createDiv({cls:"wl-settings-section-title",text:"Theme"});let s=[{key:"default",label:"Default",colors:["#1D9E75","#378ADD","#BA7517","#7F77DD","#E24B4A"]},{key:"nightfall",label:"Nightfall",colors:["#10002B","#3C096C","#7B2CBF","#C77DFF","#E0AAFF"]},{key:"bluez",label:"Bluez",colors:["#012A4A","#01497C","#2C7DA0","#61A5C2","#A9D6E5"]}],a=(o=this.plugin.settings.colorTheme)!=null?o:"default",n=e.createDiv({cls:"wl-theme-cards"}),r=[];for(let l of s){let c=n.createDiv({cls:`wl-theme-card${a===l.key?" is-selected":""}`});r.push(c),c.createDiv({cls:"wl-theme-card-name",text:l.label});let d=c.createDiv({cls:"wl-theme-strip"});for(let u of l.colors){let h=d.createDiv({cls:"wl-theme-swatch"});h.style.backgroundColor=u}c.addEventListener("click",()=>{(async()=>{this.plugin.settings.colorTheme=l.key,await this.plugin.saveSettings();for(let h of r)h.removeClass("is-selected");c.addClass("is-selected"),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed"));let u=this.plugin.app.workspace.getLeavesOfType("watchlog-view");for(let h of u)h.view instanceof kt&&h.view.refreshUI()})()})}}renderSeasonColors(t){let e=t.createDiv({cls:"wl-tag-section"});e.createDiv({cls:"wl-settings-section-title",text:"Season colors"}),e.createDiv({cls:"wl-settings-info",text:"Colors cycle through seasons in order (Season 1 = color 1, etc.)."});let s=e.createDiv({cls:"wl-season-colors-list"}),a=()=>{s.empty(),this.plugin.settings.seasonPalette.forEach((l,c)=>{let d=s.createDiv({cls:"wl-season-color-pill"}),u=d.createEl("input",{cls:"wl-color-input",attr:{type:"color",value:l}});u.addEventListener("change",()=>{(async()=>(this.plugin.settings.seasonPalette[c]=u.value,await this.plugin.saveSettings()))()}),d.createSpan({cls:"wl-season-color-label",text:`Season ${c+1}`}),d.createSpan({cls:"wl-tag-del",text:"\xD7"}).addEventListener("click",()=>{(async()=>(this.plugin.settings.seasonPalette.splice(c,1),await this.plugin.saveSettings(),a()))()})})};a();let n=e.createDiv({cls:"wl-tag-add-row"}),r=n.createEl("input",{cls:"wl-color-input",attr:{type:"color",value:"#888780"}});n.createEl("button",{cls:"wl-btn wl-btn-success",text:"+ add color"}).addEventListener("click",()=>{(async()=>(this.plugin.settings.seasonPalette.push(r.value),await this.plugin.saveSettings(),r.value="#888780",a()))()})}renderTagSection(t,e,s){let a=s==="statuses",n=s==="types",r=t.createDiv({cls:"wl-tag-section"});r.createDiv({cls:"wl-settings-section-title",text:e}),a&&r.createDiv({cls:"wl-settings-info",text:"Status names are locked. Only the color can be changed."}),n&&r.createDiv({cls:"wl-settings-info",text:"Built-in types are locked. Custom types can be added and removed."});let o=r.createDiv({cls:"wl-tags-list"}),l=()=>{o.empty();for(let c of this.plugin.settings[s])this.renderTagPill(o,c,s,l)};if(l(),!a){let c=r.createDiv({cls:"wl-tag-add-row"}),d=c.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Name"}}),u=c.createEl("input",{cls:"wl-color-input",attr:{type:"color",value:"#888780"}});c.createEl("button",{cls:"wl-btn wl-btn-success",text:"+ add"}).addEventListener("click",()=>{(async()=>{let p=d.value.trim();p&&(this.plugin.settings[s].push({name:p,color:u.value}),await this.plugin.saveSettings(),d.value="",u.value="#888780",l())})()})}}renderTagPill(t,e,s,a){let n=t.createDiv({cls:"wl-tag-pill"}),r=n.createDiv({cls:"wl-tag-dot-wrap"}),o=r.createSpan({cls:"wl-tag-dot"});o.style.backgroundColor=e.color;let l=r.createEl("input",{cls:"wl-tag-color-picker",attr:{type:"color",value:e.color}});o.addEventListener("click",()=>l.click()),l.addEventListener("change",()=>{(async()=>(e.color=l.value,o.style.backgroundColor=l.value,await this.plugin.saveSettings()))()}),n.createSpan({cls:"wl-tag-name",text:e.name});let c=s==="types"&&Ye.LOCKED_TYPES.includes(e.name);s!=="statuses"&&!c&&n.createSpan({cls:"wl-tag-del",text:"\xD7"}).addEventListener("click",()=>{(async()=>(this.plugin.settings[s]=this.plugin.settings[s].filter(u=>u.name!==e.name),await this.plugin.saveSettings(),a(),new R.Notice(`Removed "${e.name}".`)))()})}renderWatchlist(t){new R.Setting(t).setName("Default watchlist view").setDesc("Which sub-tab opens by default when entering the Watchlist.").addDropdown(a=>{var n;return a.addOptions({list:"List",cards:"Cards"}).setValue((n=this.plugin.settings.defaultWatchlistView)!=null?n:"cards").onChange(async r=>{this.plugin.settings.defaultWatchlistView=r,await this.plugin.saveSettings()})}),new R.Setting(t).setName("Episode numbering").setDesc("Absolute: episodes numbered 1\u2192n across all seasons. Per season: each season restarts from 1 (display only, data is unchanged).").addDropdown(a=>{var n;return a.addOptions({absolute:"Absolute","per-season":"Per season"}).setValue((n=this.plugin.settings.episodeNumbering)!=null?n:"absolute").onChange(async r=>{this.plugin.settings.episodeNumbering=r,await this.plugin.saveSettings(),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed"))})}),new R.Setting(t).setName("Auto-complete on last episode").setDesc("Mark status as completed when all episodes are watched.").addToggle(a=>a.setValue(this.plugin.settings.autoCompleteOnLastEpisode).onChange(async n=>{this.plugin.settings.autoCompleteOnLastEpisode=n,await this.plugin.saveSettings()})),new R.Setting(t).setName("Colored type badges").setDesc("Show type and status badges with their configured colors. Disable for a plain text style.").addToggle(a=>a.setValue(this.plugin.settings.coloredTypeBadges).onChange(async n=>{this.plugin.settings.coloredTypeBadges=n,await this.plugin.saveSettings()})),t.createDiv({cls:"wl-settings-section-title",text:"Import / Export CSV"}),new R.Setting(t).setName("Export to CSV").setDesc("Export selected titles as a CSV file.").addButton(a=>a.setButtonText("Export CSV").onClick(()=>{new de(this.app,this.plugin,this.plugin.dataManager,"export").open()})),new R.Setting(t).setName("Import from CSV").setDesc("Import titles from a CSV file. Duplicates are highlighted before import.").addButton(a=>a.setButtonText("Import CSV").onClick(()=>{new de(this.app,this.plugin,this.plugin.dataManager,"import").open()})),t.createDiv({cls:"wl-settings-section-title",text:"Folders"}),new R.Setting(t).setName("Root folder name").setDesc("Vault folder where watchlog Markdown files are stored.").addText(a=>a.setValue(this.plugin.settings.rootFolder).onChange(async n=>{this.plugin.settings.rootFolder=n,await this.plugin.saveSettings()})),new R.Setting(t).setName("Auto-create folders").setDesc("Automatically create type subfolders on plugin load.").addToggle(a=>a.setValue(this.plugin.settings.autoCreateFolders).onChange(async n=>{this.plugin.settings.autoCreateFolders=n,await this.plugin.saveSettings()})),t.createDiv({cls:"wl-settings-section-title",text:"Type subfolders"});let e=t.createDiv({cls:"wl-folder-list"});(()=>{e.empty();for(let a of this.plugin.settings.types){let n=e.createDiv({cls:"wl-folder-row"});n.createSpan({cls:"wl-folder-type",text:a.name}),n.createSpan({cls:"wl-folder-path",text:`${this.plugin.settings.rootFolder}/${a.name}`})}})(),new R.Setting(t).setName("Create folders now").setDesc("Manually trigger folder creation for all current types.").addButton(a=>a.setButtonText("Create").onClick(async()=>{await this.plugin.dataManager.ensureFolders(),new R.Notice("Folders created.")}))}renderDrafts(t){t.createDiv({cls:"wl-settings-section-title",text:"Drafts"}),new R.Setting(t).setName("Vault tag to monitor").setDesc("Lines containing this tag followed by a title will appear in the drafts tab.").addText(e=>{var s;return e.setPlaceholder("#watchlog").setValue((s=this.plugin.settings.draftsVaultTag)!=null?s:"#watchlog").onChange(async a=>{this.plugin.settings.draftsVaultTag=a.trim()||"#watchlog",await this.plugin.saveSettings()})}),new R.Setting(t).setName("After adding a title").setDesc("What happens to a draft entry once you hit add and confirm.").addDropdown(e=>{var s;return e.addOptions({keep:"Keep as Added",remove:"Remove"}).setValue((s=this.plugin.settings.draftsAfterAdding)!=null?s:"keep").onChange(async a=>{this.plugin.settings.draftsAfterAdding=a,await this.plugin.saveSettings()})})}renderCustomLists(t){t.createDiv({cls:"wl-settings-section-title",text:"Custom Lists"}),new R.Setting(t).setName("Custom lists folder path").setDesc("Vault folder where custom list files are stored.").addText(e=>{var s;return e.setValue((s=this.plugin.settings.customListsFolder)!=null?s:"WatchLog/CustomLists").onChange(async a=>{this.plugin.settings.customListsFolder=a,await this.plugin.saveSettings()})}),new R.Setting(t).setName("Default columns").setDesc("Columns pre-populated when creating a new list. The name column is always included.").addButton(e=>{var a;let s=((a=this.plugin.settings.defaultCustomColumns)!=null?a:[]).length;e.setButtonText(`Edit (${s} column${s!==1?"s":""})`),e.onClick(()=>{new Pe(this.app,this.plugin).open()})}),new R.Setting(t).setName("Create folder now").setDesc("Manually create the custom lists folder in the vault.").addButton(e=>e.setButtonText("Create").onClick(async()=>{await new Ot(this.app,this.plugin).ensureFolder(),new R.Notice("Custom lists folder created.")}))}renderReading(t){let e=this.plugin.readingDataManager,s=e.getSettings();t.createDiv({cls:"wl-settings-section-title",text:"Reading"}),new R.Setting(t).setName("Reading folder path").setDesc("Vault folder where reading note files are generated. Changing this will not move existing files.").addText(a=>a.setPlaceholder("WatchLog/Reading").setValue(s.defaultFolder).onChange(n=>{let r=n.trim()||"WatchLog/Reading";e.updateSettings({defaultFolder:r})})),new R.Setting(t).setName("Default status for new entries").setDesc("Status pre-selected in the Add book / Add manga modal.").addDropdown(a=>{let n={};for(let r of lt)n[r]=r;a.addOptions(n).setValue(s.defaultStatus).onChange(r=>{e.updateSettings({defaultStatus:r})})}),new R.Setting(t).setName("Default sub-tab").setDesc("Which sub-tab opens by default when you switch to the Reading tab.").addDropdown(a=>{var n;a.addOptions({books:"Books",manga:"Manga"}).setValue((n=s.defaultSubTab)!=null?n:"books").onChange(r=>{e.updateSettings({defaultSubTab:r})})}),t.createDiv({cls:"wl-settings-section-title",text:"Import / Export CSV"}),new R.Setting(t).setName("Export to CSV").setDesc("Export your Books or Manga library as a CSV file.").addButton(a=>a.setButtonText("Export CSV").onClick(()=>{new ue(this.app,"export",n=>{new he(this.app,this.plugin,n,"export").open()}).open()})),new R.Setting(t).setName("Import from CSV").setDesc("Import Books or Manga from a CSV file, with column mapping and duplicate detection.").addButton(a=>a.setButtonText("Import CSV").onClick(()=>{new ue(this.app,"import",n=>{new he(this.app,this.plugin,n,"import").open()}).open()}))}renderQuickInfo(t){t.createDiv({cls:"wl-settings-section-title",text:"Quick Info"});let e=[{title:"\u{1F4CA} Dashboard",items:[{heading:"Please note",body:"Statuses To be released or Dropped (time left) are not included in any calculations, only Watching, Completed and Dropped (time watched)."},{heading:"Time Watched",body:"Calculated as: episodes watched \xD7 episode duration, summed across all titles with status Watching and Completed."},{heading:"Time Remaining",body:"Calculated as: episodes remaining \xD7 episode duration, summed across all titles with status Watching and Plan to Watch."},{heading:"Dropped",body:"Calculated as: episodes watched \xD7 episode duration, summed across all titles with status Dropped."}]},{title:"\u{1F4CB} Watchlist",items:[{heading:"Why Groups exist",body:"Groups let you combine related titles under one entry; for example, a movie and its sequel, a TV show and its anime adaptation, or an anime series and its movie. They appear as a single collapsible row in your Watchlist."},{heading:"Group Rating",body:"A group's rating is automatically calculated as the average of all individual title ratings within it."},{heading:"Pin to Top",body:"Pinning a title moves it to the top of your Watchlist regardless of sorting. Pinned titles also appear in the Now Watching widget, so you can quickly see what you're currently watching inside your notes or Homepage."},{heading:"How to add a new season",body:'Open the title and click Edit at the bottom. In the Edit modal, scroll down to the Seasons field and add a new line in the format "Season Name: N" (e.g. "Season 3: 10" or "Season name: 10").'}]},{title:"\u{1F50D} API & Search",items:[{heading:"Which API is used for what",body:`WatchLog uses a different API per content type: +`?(t.push(e),e="",i.push(t),t=[]):e+=r}for((e.length>0||t.length>0)&&(t.push(e),i.push(t));i.length>0&&i[i.length-1].every(n=>n==="");)i.pop();return i}var pa={jan:1,feb:2,mar:3,apr:4,may:5,jun:6,jul:7,aug:8,sep:9,oct:10,nov:11,dec:12};function Qn(g){let i=g.trim();if(!i)return null;try{if(/^\d{4}-\d{2}-\d{2}$/.test(i))return i;let t=i.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);if(t){let r=parseInt(t[1]),o=parseInt(t[2]),l=parseInt(t[3]),c,d;return r>12?(c=r,d=o):o>12?(d=r,c=o):(c=r,d=o),d<1||d>12||c<1||c>31?null:`${l}-${String(d).padStart(2,"0")}-${String(c).padStart(2,"0")}`}let e=i.match(/^(\d{1,2})\s+([A-Za-z]{3,})\s+(\d{4})$/);if(e){let r=pa[e[2].toLowerCase().slice(0,3)],o=parseInt(e[1]),l=parseInt(e[3]);if(r)return`${l}-${String(r).padStart(2,"0")}-${String(o).padStart(2,"0")}`}let s=i.match(/^([A-Za-z]{3,})\s+(\d{1,2}),?\s+(\d{4})$/);if(s){let r=pa[s[1].toLowerCase().slice(0,3)],o=parseInt(s[2]),l=parseInt(s[3]);if(r)return`${l}-${String(r).padStart(2,"0")}-${String(o).padStart(2,"0")}`}let a=i.match(/^(\d{1,2})[.-](\d{1,2})[.-](\d{4})$/);if(a){let r=parseInt(a[1]),o=parseInt(a[2]),l=parseInt(a[3]);if(o>=1&&o<=12&&r>=1&&r<=31)return`${l}-${String(o).padStart(2,"0")}-${String(r).padStart(2,"0")}`}let n=new Date(i);if(!isNaN(n.getTime())){let r=n.getDate(),o=n.getMonth()+1;return`${n.getFullYear()}-${String(o).padStart(2,"0")}-${String(r).padStart(2,"0")}`}return null}catch(t){return null}}var Yn=["title","author","status","rating","pagesRead","totalPages","chaptersRead","totalChapters","dateStarted","dateFinished","releaseDate","dateAdded","externalLink","googleBooksId"],Jn=["title","author","status","rating","chaptersRead","totalChapters","volumesRead","totalVolumes","dateStarted","dateFinished","releaseDate","dateAdded","externalLink","malId"],ga=[{key:"title",label:"Title",coercion:"string",autoDetect:["title","name"]},{key:"author",label:"Author",coercion:"string",autoDetect:["author","writer","by"]},{key:"status",label:"Status",coercion:"string",autoDetect:["status"]},{key:"rating",label:"Rating",coercion:"rating",autoDetect:["rating","score"]}],ma=[{key:"dateStarted",label:"Date Started",coercion:"date",autoDetect:["started","datestarted","date started","date_started","start date"]},{key:"dateFinished",label:"Date Finished",coercion:"date",autoDetect:["finished","datefinished","date finished","date_finished","end date","finish date","completed date"]},{key:"releaseDate",label:"Release Date",coercion:"date",autoDetect:["releasedate","release date","release_date","published","publish date"]},{key:"externalLink",label:"Link",coercion:"string",autoDetect:["link","externallink","external link","external_link","url"]}],Xn=[...ga,{key:"pagesRead",label:"Pages Read",coercion:"int",autoDetect:["pagesread","pages read","read pages","page"]},{key:"totalPages",label:"Total Pages",coercion:"int",autoDetect:["totalpages","total pages","pages","page count"]},{key:"chaptersRead",label:"Chapters Read",coercion:"int",autoDetect:["chaptersread","chapters read","read chapters"]},{key:"totalChapters",label:"Total Chapters",coercion:"int",autoDetect:["totalchapters","total chapters","chapters","chapter count"]},...ma,{key:"googleBooksId",label:"Google Books ID",coercion:"string",autoDetect:["googlebooksid","google books id","gbid","volumeid"]}],Zn=[...ga,{key:"chaptersRead",label:"Chapters Read",coercion:"int",autoDetect:["chaptersread","chapters read","read chapters"]},{key:"totalChapters",label:"Total Chapters",coercion:"int",autoDetect:["totalchapters","total chapters","chapters","chapter count"]},{key:"volumesRead",label:"Volumes Read",coercion:"int",autoDetect:["volumesread","volumes read","read volumes"]},{key:"totalVolumes",label:"Total Volumes",coercion:"int",autoDetect:["totalvolumes","total volumes","volumes","volume count"]},...ma,{key:"malId",label:"MAL ID",coercion:"string",autoDetect:["malid","mal id","myanimelist id","mal"]}];function tr(g){return g==="book"?{exportColumns:Yn,importFields:Xn}:{exportColumns:Jn,importFields:Zn}}function er(g,i){let t={};for(let e of g){let s=i.find(a=>e.autoDetect.includes(a.toLowerCase()));t[e.key]=s!=null?s:""}return t}var xe=class extends Wt.Modal{constructor(t,e,s,a){super(t);this.selectedIds=new Set;this.csvRows=[];this.csvHeaders=[];this.columnMapping={};this.importRows=[];this.statusValueMap={};this.ratingValueMap={};this.stepUpload=null;this.stepMapping=null;this.stepValueMap=null;this.stepPreview=null;this.importBtn=null;this.cancelBtn=null;this.isImporting=!1;this.importCancelled=!1;this.progressWrap=null;this.progressBarFill=null;this.progressText=null;this.plugin=e,this.kind=s,this.mode=a,this.schema=tr(s)}get kindLabel(){return this.kind==="book"?"Books":"Manga"}get itemNoun(){return this.kind==="book"?"book":"manga"}getItems(){return this.kind==="book"?this.plugin.readingDataManager.getBooks():this.plugin.readingDataManager.getMangaList()}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("wl-csv-modal"),this.mode==="export"?this.renderExport(t):this.renderImport(t)}onClose(){this.contentEl.empty()}itemsToCsv(t){let e=this.schema.exportColumns,s=e.join(","),a=t.map(n=>e.map(r=>jn(n[r])).join(","));return[s,...a].join(` +`)}renderExport(t){t.createEl("h2",{cls:"wl-modal-title",text:`Export ${this.kindLabel} to CSV`});let e=this.getItems();e.forEach(p=>this.selectedIds.add(p.id));let s=t.createDiv({cls:"wl-csv-ctrl-row"}),a=s.createEl("button",{cls:"wl-btn",text:"Select all"}),n=s.createEl("button",{cls:"wl-btn",text:"Select none"}),r=s.createSpan({cls:"wl-csv-count",text:`${e.length} selected`}),o=t.createDiv({cls:"wl-csv-list"}),l=[],c=()=>{r.textContent=`${this.selectedIds.size} selected`};for(let p of e){let m=o.createDiv({cls:"wl-csv-row"}),f=m.createEl("input",{attr:{type:"checkbox"}});f.checked=!0,l.push(f),m.createSpan({cls:"wl-csv-row-title",text:p.title});let y=[p.author,p.status].filter(Boolean).join(" \xB7 ");y&&m.createSpan({cls:"wl-csv-row-meta",text:y}),f.addEventListener("change",()=>{f.checked?this.selectedIds.add(p.id):this.selectedIds.delete(p.id),c()})}a.addEventListener("click",()=>{e.forEach(p=>this.selectedIds.add(p.id)),l.forEach(p=>{p.checked=!0}),c()}),n.addEventListener("click",()=>{this.selectedIds.clear(),l.forEach(p=>{p.checked=!1}),c()});let d=t.createDiv({cls:"wl-modal-btn-row wl-csv-btn-row"}),u=d.createEl("button",{cls:"wl-btn",text:"Cancel"}),h=d.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Export CSV"});u.addEventListener("click",()=>this.close()),h.addEventListener("click",()=>{let p=e.filter(E=>this.selectedIds.has(E.id));if(p.length===0){new Wt.Notice(`No ${this.itemNoun} selected.`);return}let m=this.itemsToCsv(p),f=new Blob([m],{type:"text/csv;charset=utf-8;"}),y=URL.createObjectURL(f),v=activeDocument.createElement("a"),w=new Date,b=`${w.getFullYear()}-${String(w.getMonth()+1).padStart(2,"0")}-${String(w.getDate()).padStart(2,"0")}`;v.href=y,v.download=`watchlog-${this.itemNoun==="book"?"books":"manga"}-export-${b}.csv`,v.click(),URL.revokeObjectURL(y),new Wt.Notice(`Exported ${p.length} ${this.kindLabel.toLowerCase()}.`),this.close()})}renderImport(t){t.createEl("h2",{cls:"wl-modal-title",text:`Import ${this.kindLabel} from CSV`}),this.stepUpload=t.createDiv({cls:"wl-csv-step"});let e=this.stepUpload.createDiv({cls:"wl-csv-drop-zone"});e.createDiv({cls:"wl-csv-drop-label",text:"Select a CSV file to import"});let s=e.createEl("input",{attr:{type:"file",accept:".csv"},cls:"wl-csv-file-input"});this.stepMapping=t.createDiv({cls:"wl-csv-step"}),this.stepMapping.hide(),this.stepValueMap=t.createDiv({cls:"wl-csv-step"}),this.stepValueMap.hide(),this.stepPreview=t.createDiv({cls:"wl-csv-step"}),this.stepPreview.hide();let a=t.createDiv({cls:"wl-modal-btn-row wl-csv-btn-row"});this.progressWrap=a.createDiv({cls:"wl-csv-progress-wrap"}),this.progressWrap.hide(),this.progressWrap.createSpan({cls:"wl-csv-bg-note",text:"You can close this window \u2014 import will continue in the background."});let n=this.progressWrap.createDiv({cls:"wl-csv-progress-track"});this.progressBarFill=n.createDiv({cls:"wl-csv-progress-fill"}),this.progressText=this.progressWrap.createSpan({cls:"wl-csv-progress-text",text:"0 / 0"}),this.cancelBtn=a.createEl("button",{cls:"wl-btn",text:"Cancel"}),this.importBtn=a.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Import selected"}),this.importBtn.disabled=!0,this.importBtn.hide(),this.cancelBtn.addEventListener("click",()=>{this.isImporting?(this.importCancelled=!0,this.cancelBtn&&(this.cancelBtn.disabled=!0,this.cancelBtn.textContent="Cancelling\u2026")):this.close()}),this.importBtn.addEventListener("click",()=>void this.doImport()),s.addEventListener("change",()=>{var l;let r=(l=s.files)==null?void 0:l[0];if(!r)return;let o=new FileReader;o.onload=c=>{var u,h;let d=(u=c.target)==null?void 0:u.result;this.csvRows=qn(d),this.csvHeaders=((h=this.csvRows[0])!=null?h:[]).map(p=>p.trim()),this.columnMapping=er(this.schema.importFields,this.csvHeaders),this.showMappingStep()},o.readAsText(r)})}showMappingStep(){!this.stepUpload||!this.stepMapping||(this.stepUpload.hide(),this.stepMapping.show(),this.renderMappingStep(this.stepMapping))}renderMappingStep(t){var r;t.empty(),t.createDiv({cls:"wl-csv-step-title",text:"Map your columns"}),t.createDiv({cls:"wl-csv-step-desc",text:`Match each ${this.itemNoun==="book"?"Book":"Manga"} field to a column from your CSV. Select "\u2014 skip \u2014" to leave a field empty.`}),t.createDiv({cls:"wl-csv-info-note",text:"Rows with empty fields will be skipped automatically. If you see missing entries, check that your CSV has no empty rows at the top."});let e="",s=t.createDiv({cls:"wl-csv-map-grid"}),a={};for(let o of this.schema.importFields){let l=s.createDiv({cls:"wl-csv-map-row"});l.createSpan({cls:"wl-csv-map-label",text:o.label});let c=l.createEl("select",{cls:"wl-select wl-csv-map-select"});a[o.key]=c,c.createEl("option",{value:e,text:"\u2014 skip \u2014"});for(let d of this.csvHeaders)c.createEl("option",{value:d,text:d});c.value=(r=this.columnMapping[o.key])!=null?r:e}t.createEl("button",{cls:"wl-btn wl-btn-primary wl-csv-preview-btn",text:"Next \u2192"}).addEventListener("click",()=>{var f,y,v,w,b,E;for(let D of this.schema.importFields)this.columnMapping[D.key]=(y=(f=a[D.key])==null?void 0:f.value)!=null?y:"";this.importRows=this.applyMapping().map(D=>({...D,selected:!D.isDuplicate}));let o=new Set(Mt),l=[],c=[],d=new Set,u=new Set,h=((v=this.csvRows[0])!=null?v:[]).map(D=>D.trim()),p=this.columnMapping.rating,m=p?h.indexOf(p):-1;for(let D of this.importRows){let S=(w=D.entry.status)==null?void 0:w.trim();if(S&&!o.has(S)&&!d.has(S)&&(l.push(S),d.add(S)),m>=0){let T=this.importRows.indexOf(D),x=((E=((b=this.csvRows[T+1])!=null?b:[])[m])!=null?E:"").trim();x&&isNaN(parseFloat(x))&&!u.has(x)&&(c.push(x),u.add(x))}}l.length>0||c.length>0?this.showValueMapStep(l,c):this.showPreviewStep()})}applyMapping(){var s;if(this.csvRows.length<2)return[];let t=((s=this.csvRows[0])!=null?s:[]).map(a=>a.trim()),e=this.getItems();return this.csvRows.slice(1).filter(a=>a.some(n=>n.trim())).map(a=>{let n=l=>{var u;let c=this.columnMapping[l];if(!c)return"";let d=t.indexOf(c);return d>=0?((u=a[d])!=null?u:"").trim():""},r={};for(let l of this.schema.importFields){let c=n(l.key);if(c)switch(l.coercion){case"string":r[l.key]=c;break;case"int":r[l.key]=parseInt(c)||0;break;case"rating":{let d=parseFloat(c)||0;r.rating=Math.max(0,Math.min(5,d));break}case"date":{let d=Qn(c);d&&(r[l.key]=d);break}}}if(!r.title||!r.title.trim())return null;let o=!!e.find(l=>{var c;return l.title.toLowerCase()===((c=r.title)!=null?c:"").toLowerCase()});return{entry:r,isDuplicate:o}}).filter(a=>a!==null)}showValueMapStep(t,e){!this.stepMapping||!this.stepValueMap||(this.stepMapping.hide(),this.stepValueMap.show(),this.renderValueMapStep(this.stepValueMap,t,e))}renderValueMapStep(t,e,s){t.empty(),t.createDiv({cls:"wl-csv-step-title",text:"Map unknown values"}),t.createDiv({cls:"wl-csv-step-desc",text:"Some values in your CSV were not recognized. Map each to an existing value, or leave it blank."});let a={},n={};if(e.length>0){t.createDiv({cls:"wl-csv-valmap-section-title",text:"Status"});for(let c of e){let d=t.createDiv({cls:"wl-csv-valmap-row"});d.createSpan({cls:"wl-csv-valmap-orig",text:`"${c}"`}),d.createSpan({cls:"wl-csv-valmap-arrow",text:"\u2192"});let u=d.createEl("select",{cls:"wl-select wl-csv-valmap-select"});a[c]=u,u.createEl("option",{value:"",text:"\u2014 leave blank \u2014"});for(let m of ct)u.createEl("option",{value:m,text:m});let h=c.toLowerCase(),p=ct.find(m=>m.toLowerCase()===h);p&&(u.value=p)}}if(s.length>0){t.createDiv({cls:"wl-csv-valmap-section-title",text:"Rating"});for(let c of s){let d=t.createDiv({cls:"wl-csv-valmap-row"});d.createSpan({cls:"wl-csv-valmap-orig",text:`"${c}"`}),d.createSpan({cls:"wl-csv-valmap-arrow",text:"\u2192"});let u=d.createEl("select",{cls:"wl-select wl-csv-valmap-select"});n[c]=u,u.createEl("option",{value:"",text:"\u2014 leave blank \u2014"});for(let h=1;h<=5;h++)u.createEl("option",{value:String(h),text:`${h}/5`})}}let r=t.createDiv({cls:"wl-csv-valmap-btn-row"}),o=r.createEl("button",{cls:"wl-btn",text:"\u2190 back"}),l=r.createEl("button",{cls:"wl-btn wl-btn-primary",text:"Preview \u2192"});o.addEventListener("click",()=>{!this.stepValueMap||!this.stepMapping||(this.stepValueMap.hide(),this.stepMapping.show())}),l.addEventListener("click",()=>{var c,d,u,h;this.statusValueMap={};for(let p of e)this.statusValueMap[p]=(d=(c=a[p])==null?void 0:c.value)!=null?d:"";this.ratingValueMap={};for(let p of s)this.ratingValueMap[p]=(h=(u=n[p])==null?void 0:u.value)!=null?h:"";this.applyValueMapsToRows(),this.showPreviewStep()})}applyValueMapsToRows(){var a,n,r,o,l,c,d;let t=((a=this.csvRows[0])!=null?a:[]).map(u=>u.trim()),e=this.columnMapping.rating,s=e?t.indexOf(e):-1;for(let u of this.importRows){let h=(r=(n=u.entry.status)==null?void 0:n.trim())!=null?r:"";if(h&&Object.prototype.hasOwnProperty.call(this.statusValueMap,h)){let p=(o=this.statusValueMap[h])!=null?o:"";u.entry.status=p||void 0}if(s>=0){let p=this.importRows.indexOf(u),f=((c=((l=this.csvRows[p+1])!=null?l:[])[s])!=null?c:"").trim();if(f&&Object.prototype.hasOwnProperty.call(this.ratingValueMap,f)){let y=(d=this.ratingValueMap[f])!=null?d:"";u.entry.rating=y?parseInt(y):0}}}}showPreviewStep(){!this.stepValueMap||!this.stepMapping||!this.stepPreview||!this.importBtn||(this.stepValueMap.hide(),this.stepMapping.hide(),this.stepPreview.show(),this.importBtn.show(),this.importBtn.disabled=this.importRows.filter(t=>t.selected).length===0,this.renderPreviewStep(this.stepPreview))}renderPreviewStep(t){var u;t.empty();let e=this.importRows.filter(h=>h.isDuplicate).length;e>0&&t.createDiv({cls:"wl-csv-dupe-warning",text:`${e} duplicate${e!==1?"s":""} found (highlighted). These are deselected by default.`});let s=t.createDiv({cls:"wl-csv-ctrl-row"}),a=s.createEl("button",{cls:"wl-btn",text:"\u2190 back"}),n=s.createEl("button",{cls:"wl-btn",text:"Select all"}),r=s.createEl("button",{cls:"wl-btn",text:"Select none"}),o=s.createSpan({cls:"wl-csv-count",text:""});a.addEventListener("click",()=>{if(!this.stepPreview||!this.stepValueMap||!this.stepMapping||!this.importBtn)return;this.stepPreview.hide(),this.importBtn.hide(),this.importBtn.disabled=!0,Object.keys(this.statusValueMap).length>0||Object.keys(this.ratingValueMap).length>0?this.stepValueMap.show():this.stepMapping.show()});let l=t.createDiv({cls:"wl-csv-list"}),c=[],d=()=>{let h=this.importRows.filter(p=>p.selected).length;o.textContent=`${h} of ${this.importRows.length} selected`,this.importBtn&&(this.importBtn.disabled=h===0)};for(let h=0;h{this.importRows[v].selected=f.checked,d()})}n.addEventListener("click",()=>{this.importRows.forEach(h=>{h.selected=!0}),c.forEach(h=>{h.checked=!0}),d()}),r.addEventListener("click",()=>{this.importRows.forEach(h=>{h.selected=!1}),c.forEach(h=>{h.checked=!1}),d()}),d()}buildBook(t,e){var n,r,o,l,c,d,u,h,p,m,f;let s=t.title.trim(),a=new Date().toISOString();return{id:this.plugin.readingDataManager.generateBookId(s),title:s,author:(n=t.author)!=null?n:"",status:t.status||e,rating:(r=t.rating)!=null?r:0,pagesRead:(o=t.pagesRead)!=null?o:0,totalPages:(l=t.totalPages)!=null?l:0,chaptersRead:(c=t.chaptersRead)!=null?c:0,totalChapters:(d=t.totalChapters)!=null?d:0,coverUrl:"",googleBooksId:(u=t.googleBooksId)!=null?u:"",externalLink:(h=t.externalLink)!=null?h:"",vaultPage:"",dateStarted:(p=t.dateStarted)!=null?p:null,dateFinished:(m=t.dateFinished)!=null?m:null,releaseDate:(f=t.releaseDate)!=null?f:null,dateAdded:a,dateModified:a,customFields:{}}}buildManga(t,e){var n,r,o,l,c,d,u,h,p,m,f;let s=t.title.trim(),a=new Date().toISOString();return{id:this.plugin.readingDataManager.generateMangaId(s),title:s,author:(n=t.author)!=null?n:"",status:t.status||e,rating:(r=t.rating)!=null?r:0,chaptersRead:(o=t.chaptersRead)!=null?o:0,totalChapters:(l=t.totalChapters)!=null?l:0,volumesRead:(c=t.volumesRead)!=null?c:0,totalVolumes:(d=t.totalVolumes)!=null?d:0,coverUrl:"",malId:(u=t.malId)!=null?u:"",externalLink:(h=t.externalLink)!=null?h:"",vaultPage:"",dateStarted:(p=t.dateStarted)!=null?p:null,dateFinished:(m=t.dateFinished)!=null?m:null,releaseDate:(f=t.releaseDate)!=null?f:null,dateAdded:a,dateModified:a,customFields:{}}}async doImport(){var r;let t=this.importRows.filter(o=>{var l;return o.selected&&((l=o.entry.title)==null?void 0:l.trim())});if(t.length===0){new Wt.Notice(`No ${this.itemNoun} selected to import.`);return}this.isImporting=!0,this.importCancelled=!1,this.importBtn&&(this.importBtn.disabled=!0),this.cancelBtn&&(this.cancelBtn.textContent="Cancel import"),this.progressWrap&&this.progressWrap.show(),this.progressText&&(this.progressText.textContent=`0 / ${t.length}`),this.progressBarFill&&(this.progressBarFill.style.width="0%");let e=this.plugin.readingDataManager,s=(r=e.getSettings().defaultStatus)!=null?r:"Plan to Read",a=10,n=0;try{for(let o=0;o{this.textSaveTimer=null,this.plugin.saveSettings()},500)}display(){let{containerEl:t}=this;t.empty(),t.addClass("wl-settings");let e=t.createDiv({cls:"wl-settings-nav"}),s=[{key:"general",label:"General"},{key:"api",label:"API"},{key:"customize",label:"Customize"},{key:"watchlist",label:"Watchlist"},{key:"drafts",label:"Drafts"},{key:"custom-lists",label:"Custom Lists"},{key:"reading",label:"Reading"},{key:"widgets",label:"Widgets"},{key:"quick-info",label:"Quick Info"}],a=new Map;for(let r of s){let o=e.createEl("button",{cls:`wl-settings-nav-btn${this.activeSection===r.key?" is-active":""}`,text:r.label});a.set(r.key,o),o.addEventListener("click",()=>{this.activeSection=r.key,a.forEach((l,c)=>{c===r.key?l.addClass("is-active"):l.removeClass("is-active")}),n.empty(),this.renderSection(n)})}let n=t.createDiv({cls:"wl-settings-body"});this.renderSection(n)}renderSection(t){switch(t.empty(),this.activeSection){case"general":this.renderGeneral(t);break;case"api":this.renderApi(t);break;case"customize":this.renderCustomize(t);break;case"watchlist":this.renderWatchlist(t);break;case"drafts":this.renderDrafts(t);break;case"custom-lists":this.renderCustomLists(t);break;case"reading":this.renderReading(t);break;case"widgets":this.renderWidgets(t);break;case"quick-info":this.renderQuickInfo(t);break}}renderGeneral(t){new A.Setting(t).setName("Dashboard card style").setDesc("Choose between ring charts or rectangular stat cards on the dashboard.").addDropdown(o=>{var l;return o.addOptions({circles:"Circles",rectangles:"Rectangles"}).setValue((l=this.plugin.settings.dashboardCardStyle)!=null?l:"circles").onChange(async c=>{this.plugin.settings.dashboardCardStyle=c,await this.plugin.saveSettings(),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed"))})}),new A.Setting(t).setName("Set finish date automatically").setDesc("Record today's date as the finish date when a watch title or reading entry is completed.").addToggle(o=>o.setValue(this.plugin.settings.setFinishDateAutomatically).onChange(async l=>{this.plugin.settings.setFinishDateAutomatically=l,await this.plugin.saveSettings()})),new A.Setting(t).setName("Re-fetch all posters").setDesc("Clears all cached poster and reading cover URLs. Watch posters reload lazily when you scroll the Cards view; reading covers can be re-fetched from each card's \u22EE menu.").addButton(o=>o.setButtonText("Re-fetch posters").onClick(()=>{let l=this.plugin.dataManager.getTitles(),c=this.plugin.readingDataManager.getBooks().length+this.plugin.readingDataManager.getMangaList().length;new _(this.app,`This will clear cached images for all ${l.length} watch titles and ${c} reading entries. Items without API access will show placeholder cards. Continue?`,()=>{this.refetchAllPosters()}).open()})),new A.Setting(t).setName("Rewrite all note frontmatter").setDesc("Rewrites the YAML frontmatter on every existing Watchlist and Reading note, applying newer frontmatter fields to older notes. Body content (## Notes / ## Quotes) is preserved. Notes without a file on disk are skipped \u2014 use Regenerate to create them.").addButton(o=>o.setButtonText("Rewrite frontmatter").onClick(()=>{let l=this.plugin.dataManager.getTitles(),c=this.plugin.readingDataManager.getBooks().length+this.plugin.readingDataManager.getMangaList().length;new _(this.app,`This will rewrite the YAML frontmatter on all existing notes for ${l.length} watch titles and ${c} reading entries. Body content is preserved; notes without a file on disk are skipped. Continue?`,()=>{this.rewriteAllFrontmatter()}).open()})),new A.Setting(t).setName("Show hint banners").setDesc("Show informational hint banners in Upcoming, Custom Lists, and Drafts tabs.").addToggle(o=>o.setValue(this.plugin.settings.showHintBanners).onChange(async l=>{this.plugin.settings.showHintBanners=l,await this.plugin.saveSettings(),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed"))})),new A.Setting(t).setName("Show Upcoming count in status bar").setDesc('Show a "N due" counter in the status bar when Upcoming entries are due. Click it to open the Upcoming tab. (Desktop only.)').addToggle(o=>o.setValue(this.plugin.settings.showUpcomingStatusBar).onChange(async l=>{this.plugin.settings.showUpcomingStatusBar=l,await this.plugin.saveSettings(),this.plugin.updateStatusBar()})),t.createDiv({cls:"wl-settings-section-title",text:"Backup & Restore"}),new A.Setting(t).setName("Export backup").setDesc("Export all watchlog data \u2014 watchlist, reading (books & manga) and activity log \u2014 into a single timestamped .JSON file.").addButton(o=>o.setButtonText("Export backup").onClick(()=>void this.exportBackup())),new A.Setting(t).setName("Restore from backup").setDesc("Restore from a .JSON backup file. This replaces your current watchlist, reading and activity-log data with the contents of the backup. Older watch-only backups restore the watchlist only and leave reading and activity log untouched.").addButton(o=>o.setButtonText("Restore from backup").onClick(()=>this.openRestoreDialog()));let e={wrap:null,fill:null,text:null};new A.Setting(t).setName("Regenerate note files").setDesc("Creates missing .md files for titles that don't have one. Existing files are not modified.").addButton(o=>o.setButtonText("Regenerate").onClick(()=>{let{wrap:l,fill:c,text:d}=e;l&&c&&d&&this.runRegenerate(l,c,d)}));let s=t.createDiv({cls:"wl-regen-progress-wrap"});s.hide(),s.createSpan({cls:"wl-csv-bg-note",text:"You can close settings \u2014 regeneration continues in the background."});let n=s.createDiv({cls:"wl-csv-progress-track"}).createDiv({cls:"wl-csv-progress-fill"}),r=s.createSpan({cls:"wl-csv-progress-text",text:"0 / 0"});e.wrap=s,e.fill=n,e.text=r}async exportBackup(){var d;let t=new Date,s=`watchlog-backup-${`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`}.json`,a=Object.assign({},(d=this.plugin.dataManager.getData())!=null?d:{});delete a.reading,delete a.history,delete a.migratedReadingHistory;let n={version:2,exportedAt:t.toISOString(),watch:a,reading:this.plugin.readingDataManager.getData(),history:this.plugin.historyManager.exportEntries()},r=JSON.stringify(n,null,2);if(A.Platform.isMobile){await this.exportBackupToVault(s,r);return}let o=new Blob([r],{type:"application/json"}),l=URL.createObjectURL(o),c=activeDocument.createElement("a");c.href=l,c.download=s,activeDocument.body.appendChild(c),c.click(),activeDocument.body.removeChild(c),URL.revokeObjectURL(l),new A.Notice(`Backup exported as ${s}`)}async exportBackupToVault(t,e){let s=this.app.vault.adapter,a=(0,A.normalizePath)("WatchLog/backups");if(!await s.exists(a))try{await s.mkdir(a)}catch(c){}let n=t.lastIndexOf("."),r=n===-1?t:t.slice(0,n),o=n===-1?"":t.slice(n),l=(0,A.normalizePath)(`${a}/${t}`);if(await s.exists(l)){let c=2;for(;await s.exists((0,A.normalizePath)(`${a}/${r}-${c}${o}`));)c++;l=(0,A.normalizePath)(`${a}/${r}-${c}${o}`)}await s.write(l,e),new A.Notice(`Backup saved to ${l}`)}openRestoreDialog(){let t=activeDocument.createElement("input");t.type="file",t.accept=".json",t.hide(),activeDocument.body.appendChild(t);let e=!1,s=()=>{if(t.parentElement)try{activeDocument.body.removeChild(t)}catch(n){}},a=()=>{window.setTimeout(()=>{e||s(),window.removeEventListener("focus",a)},200)};window.addEventListener("focus",a),t.addEventListener("change",()=>{var o;e=!0;let n=(o=t.files)==null?void 0:o[0];if(!n){s();return}let r=new FileReader;r.onload=l=>{var h;s();let c=(h=l.target)==null?void 0:h.result,d;try{d=JSON.parse(c)}catch(p){new A.Notice("Invalid backup file \u2014 could not parse JSON.");return}if(typeof d!="object"||d===null){new A.Notice("Invalid backup file \u2014 not an object.");return}let u=d;if(u.version===2){let p=u.watch,m=u.reading,f=u.history;if(!this.isValidWatchData(p)){new A.Notice("Invalid backup file \u2014 watch data missing required fields (titles, groups, settings).");return}if(!this.isValidReadingData(m)){new A.Notice("Invalid backup file \u2014 reading data missing required fields (books, manga).");return}if(!Array.isArray(f)){new A.Notice("Invalid backup file \u2014 activity log is not a list.");return}new _(this.app,"This will replace ALL current watchlog data \u2014 watchlist, reading (books & manga) and activity log. Continue?",()=>{(async()=>{let y=Object.assign({},p,{migratedReadingHistory:!0});await this.plugin.saveData(y),await this.plugin.loadSettings(),await this.plugin.dataManager.load(),await this.plugin.readingDataManager.restore(m),await this.plugin.historyManager.restore(f),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed")),new A.Notice("Backup restored successfully.")})()}).open();return}if(!this.isValidWatchData(d)){new A.Notice("Invalid backup file \u2014 missing required fields (titles, groups, settings).");return}new _(this.app,"This is a legacy (watchlist-only) backup. It will replace your current watchlist. Reading and activity-log data are left untouched. Continue?",()=>{(async()=>{let p=Object.assign({},d,{reading:this.plugin.readingDataManager.getData(),history:this.plugin.historyManager.exportEntries(),migratedReadingHistory:!0});await this.plugin.saveData(p),await this.plugin.loadSettings(),await this.plugin.dataManager.load(),await this.plugin.historyManager.load(),await this.plugin.readingDataManager.load(),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed")),new A.Notice("Legacy backup restored \u2014 watchlist only; reading and activity log left untouched.")})()}).open()},r.readAsText(n)}),t.click()}isValidWatchData(t){if(typeof t!="object"||t===null)return!1;let e=t;return Array.isArray(e.titles)&&Array.isArray(e.groups)&&typeof e.settings=="object"&&e.settings!==null}isValidReadingData(t){if(typeof t!="object"||t===null)return!1;let e=t;return Array.isArray(e.books)&&Array.isArray(e.manga)&&typeof e.settings=="object"&&e.settings!==null}async refetchAllPosters(){let t=this.plugin.dataManager.getTitles();for(let s of t)s.posterUrl="";await this.plugin.dataManager.save();let e=this.plugin.readingDataManager;for(let s of e.getBooks())s.coverUrl="";for(let s of e.getMangaList())s.coverUrl="";await e.saveAndNotify(),new A.Notice("Cached posters and covers cleared. Watch posters reload as you browse; refresh reading covers from each card's \u22EE menu.")}async rewriteAllFrontmatter(){let t=this.plugin.dataManager,e=this.plugin.readingDataManager,s=t.getTitles(),a=e.getBooks(),n=e.getMangaList(),r=s.length+a.length+n.length;if(r===0){new A.Notice("No notes to rewrite.");return}let o=[...s.map(b=>()=>t.rewriteFrontmatterIfExists(b)),...a.map(b=>()=>e.rewriteFrontmatterIfExists("book",b)),...n.map(b=>()=>e.rewriteFrontmatterIfExists("manga",b))],l=!1,c=()=>{l=!0};this.plugin.importProgress={current:0,total:r,cancel:c},t.notifyChange();let d=new A.Notice("",0),u=d.messageEl.createSpan({text:`Rewriting frontmatter\u2026 0 / ${r}`}),h=d.messageEl.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Cancel"});h.setCssProps({"margin-left":"8px"}),h.addEventListener("click",c);let p=10,m=0,f=0,y=0;try{for(let b=0;bwindow.setTimeout(E,0)))}finally{this.plugin.importProgress=null,t.notifyChange(),d.hide()}let v=f>0?`, ${f} skipped (no file)`:"",w=l?"Cancelled \u2014 ":"Done \u2014 ";new A.Notice(`${w}${m} note${m!==1?"s":""} rewritten${v}.`)}async runRegenerate(t,e,s){let a=this.plugin.dataManager.getTitles(),n=this.plugin.readingDataManager,r=n.getBooks(),o=n.getMangaList(),l=a.length+r.length+o.length;if(t.show(),l===0){s.textContent="Done \u2014 no missing files found";return}e.style.width="0%",s.textContent=`0 / ${l}`;let c=0,d=0,u=0,h=p=>{p?c++:d++,u++;let m=Math.round(u/l*100);e.style.width=`${m}%`,s.textContent=`${u} / ${l}`};for(let p of a)h(await this.plugin.dataManager.createMarkdownFileIfMissing(p));for(let p of r)h(await n.createReadingNoteIfMissing("book",p));for(let p of o)h(await n.createReadingNoteIfMissing("manga",p));c===0?s.textContent="Done \u2014 no missing files found":s.textContent=`Done \u2014 ${c} file${c!==1?"s":""} created, ${d} already existed`}apiCallout(t,e,s){let a=t.createDiv({cls:`wl-api-callout wl-api-callout--${s}`});return a.createDiv({cls:"wl-api-callout-title",text:e}),a.createDiv({cls:"wl-api-callout-body"})}renderApi(t){let e=this.apiCallout(t,"Movies & TV Shows","movies");new A.Setting(e).setName("Active API").setDesc("Which API to use for movies and tv shows.").addDropdown(u=>{var h;return u.addOptions({OMDb:"OMDb",TMDB:"TMDB"}).setValue((h=this.plugin.settings.activeApi)!=null?h:"OMDb").onChange(async p=>{this.plugin.settings.activeApi=p,await this.plugin.saveSettings()})});let s=e.createDiv({cls:"wl-settings-info"});s.createSpan({text:"Get a free OMDb API key at "}),s.createEl("a",{text:"omdbapi.com/apikey.aspx",href:"https://www.omdbapi.com/apikey.aspx",attr:{target:"_blank",rel:"noopener noreferrer"}}),s.createSpan({text:"."});let a;new A.Setting(e).setName("Omdb API key").addText(u=>(u.setPlaceholder("Paste your omdb key here").setValue(this.plugin.settings.omdbApiKey).onChange(h=>{this.plugin.settings.omdbApiKey=h,this.plugin.apiService.setOmdbKey(h),this.debouncedSaveSettings()}),u.inputEl.type="password",u)).addButton(u=>u.setButtonText("Test").onClick(async()=>{let h=await this.plugin.apiService.checkOmdbConnection();a.textContent=h?"\u2713 Connected":"\u2717 Failed \u2014 check your key",a.className=h?"wl-status-ok":"wl-status-error"})),a=e.createDiv({cls:"wl-status-indicator",text:this.plugin.settings.omdbApiKey?"(not tested)":"Not set"});let n=e.createDiv({cls:"wl-settings-info"});n.createSpan({text:"Get a free TMDB read access token at "}),n.createEl("a",{text:"themoviedb.org/settings/api",href:"https://www.themoviedb.org/settings/api",attr:{target:"_blank",rel:"noopener noreferrer"}}),n.createSpan({text:"."});let r;new A.Setting(e).setName("Tmdb API read access token").addText(u=>{var h;return u.setPlaceholder("Paste your tmdb key here").setValue((h=this.plugin.settings.tmdbApiKey)!=null?h:"").onChange(p=>{this.plugin.settings.tmdbApiKey=p,this.plugin.apiService.setTmdbKey(p),this.debouncedSaveSettings()}),u.inputEl.type="password",u}).addButton(u=>u.setButtonText("Test").onClick(async()=>{let h=await this.plugin.apiService.checkTmdbConnection();r.textContent=h?"\u2713 Connected":"\u2717 Failed \u2014 check your key",r.className=h?"wl-status-ok":"wl-status-error"})),r=e.createDiv({cls:"wl-status-indicator",text:this.plugin.settings.tmdbApiKey?"(not tested)":"Not set"});let o=this.apiCallout(t,"Anime","anime");new A.Setting(o).setName("Anime API source").setDesc("Which API to use for new anime titles.").addDropdown(u=>{var h;return u.addOptions({jikan:"Jikan (MyAnimeList)",anilist:"AniList"}).setValue((h=this.plugin.settings.animeApiSource)!=null?h:"jikan").onChange(async p=>{this.plugin.settings.animeApiSource=p,await this.plugin.saveSettings()})}),o.createDiv({cls:"wl-settings-info",text:"Jikan uses MyAnimeList's database (larger catalog, no API key needed). AniList has its own database with more precise airing schedules and a GraphQL API. This setting only affects new titles \u2014 existing titles keep their original API source."});let l=this.apiCallout(t,"Books","books"),c;new A.Setting(l).setName("Google Books API key").addText(u=>{var h;return u.setPlaceholder("Paste your Google Books key here").setValue((h=this.plugin.settings.googleBooksApiKey)!=null?h:"").onChange(p=>{this.plugin.settings.googleBooksApiKey=p,this.plugin.apiService.setGoogleBooksKey(p),this.debouncedSaveSettings()}),u.inputEl.type="password",u}).addButton(u=>u.setButtonText("Test").onClick(async()=>{c.textContent="Testing...",c.className="wl-status-indicator";try{let h=await this.plugin.apiService.checkGoogleBooksConnection();c.textContent=h?"\u2713 Connected":"\u2717 Failed",c.className=h?"wl-status-ok":"wl-status-error"}catch(h){c.textContent=`\u2717 ${It(h)}`,c.className="wl-status-error"}})),c=l.createDiv({cls:"wl-status-indicator",text:this.plugin.settings.googleBooksApiKey?"(not tested)":"Not set"});let d=l.createDiv({cls:"wl-settings-info"});d.createSpan({text:"Get a free key in the Google Cloud Console: create a project, enable the Books API, then create an API key under "}),d.createEl("a",{text:"APIs & Services \u2192 Credentials",href:"https://console.cloud.google.com/apis/credentials",attr:{target:"_blank",rel:"noopener noreferrer"}}),d.createSpan({text:"."}),this.renderTypeApiMapping(t)}renderTypeApiMapping(t){var l,c,d;let e=t.createDiv({cls:"wl-settings-card"});e.createDiv({cls:"wl-settings-card-title",text:"API routing by type in Watchlist"}),e.createDiv({cls:"wl-settings-card-desc",text:"Choose which API group to use for each title type. Anime, Movie, and TV Show are locked to their default APIs."});let s=e.createDiv({cls:"wl-type-api-list"}),a=(l=this.plugin.settings.types)!=null?l:[],n=(c=this.plugin.settings.typeApiMapping)!=null?c:{},r=new Set(a.map(u=>u.name)),o=!1;for(let u of Object.keys(n))(!r.has(u)||u==="Anime"||u==="Movie"||u==="TV Show"||u==="TvShow")&&(delete n[u],o=!0);o&&this.plugin.saveSettings();for(let u of a){let h=s.createDiv({cls:"wl-type-api-row"});if(h.createSpan({cls:"wl-type-api-name",text:u.name}),u.name==="Anime")h.createSpan({cls:"wl-type-api-locked",text:"Jikan / AniList (locked)"});else if(u.name==="Movie"||u.name==="TV Show"||u.name==="TvShow")h.createSpan({cls:"wl-type-api-locked",text:"OMDb / TMDB (locked)"});else{let p=h.createEl("select",{cls:"wl-select wl-type-api-select"}),m=(d=n[u.name])!=null?d:"",f=[{value:"",label:"\u2014 Not set \u2014"},{value:"anime",label:"Anime API (Jikan / AniList)"},{value:"movie",label:"Movie / TV API (OMDb / TMDB)"}];for(let y of f){let v=p.createEl("option",{text:y.label,value:y.value});m===y.value&&(v.selected=!0)}p.addEventListener("change",()=>{let y=p.value;this.plugin.settings.typeApiMapping||(this.plugin.settings.typeApiMapping={}),y===""?delete this.plugin.settings.typeApiMapping[u.name]:this.plugin.settings.typeApiMapping[u.name]=y,this.plugin.saveSettings()})}}}renderCustomize(t){this.renderThemePicker(t);let e=[{key:"types",label:"Type"},{key:"statuses",label:"Status"},{key:"priorities",label:"Priority"}];for(let s of e)this.renderTagSection(t,s.label,s.key);this.renderSeasonColors(t),this.renderReadingColors(t)}renderReadingColors(t){let e=t.createDiv({cls:"wl-tag-section"});e.createDiv({cls:"wl-settings-section-title",text:"Reading"});let s=[{label:"Manga",kind:"manga"},{label:"Book",kind:"book"}],a=e.createDiv({cls:"wl-tags-list"});for(let{label:n,kind:r}of s){let o=a.createDiv({cls:"wl-tag-pill"}),l=o.createDiv({cls:"wl-tag-dot-wrap"}),c=l.createSpan({cls:"wl-tag-dot"});c.style.backgroundColor=this.plugin.settings.readingTypeColors[r];let d=l.createEl("input",{cls:"wl-tag-color-picker",attr:{type:"color",value:this.plugin.settings.readingTypeColors[r]}});c.addEventListener("click",()=>d.click()),d.addEventListener("change",()=>{(async()=>(this.plugin.settings.readingTypeColors[r]=d.value,c.style.backgroundColor=d.value,await this.plugin.saveSettings()))()}),o.createSpan({cls:"wl-tag-name",text:n})}}renderThemePicker(t){var o;let e=t.createDiv({cls:"wl-tag-section"});e.createDiv({cls:"wl-settings-section-title",text:"Theme"});let s=[{key:"default",label:"Default",colors:["#1D9E75","#378ADD","#BA7517","#7F77DD","#E24B4A"]},{key:"nightfall",label:"Nightfall",colors:["#10002B","#3C096C","#7B2CBF","#C77DFF","#E0AAFF"]},{key:"bluez",label:"Bluez",colors:["#012A4A","#01497C","#2C7DA0","#61A5C2","#A9D6E5"]}],a=(o=this.plugin.settings.colorTheme)!=null?o:"default",n=e.createDiv({cls:"wl-theme-cards"}),r=[];for(let l of s){let c=n.createDiv({cls:`wl-theme-card${a===l.key?" is-selected":""}`});r.push(c),c.createDiv({cls:"wl-theme-card-name",text:l.label});let d=c.createDiv({cls:"wl-theme-strip"});for(let u of l.colors){let h=d.createDiv({cls:"wl-theme-swatch"});h.style.backgroundColor=u}c.addEventListener("click",()=>{(async()=>{this.plugin.settings.colorTheme=l.key,await this.plugin.saveSettings();for(let h of r)h.removeClass("is-selected");c.addClass("is-selected"),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed"));let u=this.plugin.app.workspace.getLeavesOfType("watchlog-view");for(let h of u)h.view instanceof Ft&&h.view.refreshUI()})()})}}renderSeasonColors(t){let e=t.createDiv({cls:"wl-tag-section"});e.createDiv({cls:"wl-settings-section-title",text:"Season colors"}),e.createDiv({cls:"wl-settings-info",text:"Colors cycle through seasons in order (Season 1 = color 1, etc.)."});let s=e.createDiv({cls:"wl-season-colors-list"}),a=()=>{s.empty(),this.plugin.settings.seasonPalette.forEach((l,c)=>{let d=s.createDiv({cls:"wl-season-color-pill"}),u=d.createEl("input",{cls:"wl-color-input",attr:{type:"color",value:l}});u.addEventListener("change",()=>{(async()=>(this.plugin.settings.seasonPalette[c]=u.value,await this.plugin.saveSettings()))()}),d.createSpan({cls:"wl-season-color-label",text:`Season ${c+1}`}),d.createSpan({cls:"wl-tag-del",text:"\xD7"}).addEventListener("click",()=>{(async()=>(this.plugin.settings.seasonPalette.splice(c,1),await this.plugin.saveSettings(),a()))()})})};a();let n=e.createDiv({cls:"wl-tag-add-row"}),r=n.createEl("input",{cls:"wl-color-input",attr:{type:"color",value:"#888780"}});n.createEl("button",{cls:"wl-btn wl-btn-success",text:"+ add color"}).addEventListener("click",()=>{(async()=>(this.plugin.settings.seasonPalette.push(r.value),await this.plugin.saveSettings(),r.value="#888780",a()))()})}renderTagSection(t,e,s){let a=s==="statuses",n=s==="types",r=t.createDiv({cls:"wl-tag-section"});r.createDiv({cls:"wl-settings-section-title",text:e}),a&&r.createDiv({cls:"wl-settings-info",text:"Status names are locked. Only the color can be changed."}),n&&r.createDiv({cls:"wl-settings-info",text:"Built-in types are locked. Custom types can be added and removed."});let o=r.createDiv({cls:"wl-tags-list"}),l=()=>{o.empty();for(let c of this.plugin.settings[s])this.renderTagPill(o,c,s,l)};if(l(),!a){let c=r.createDiv({cls:"wl-tag-add-row"}),d=c.createEl("input",{cls:"wl-modal-input",attr:{type:"text",placeholder:"Name"}}),u=c.createEl("input",{cls:"wl-color-input",attr:{type:"color",value:"#888780"}});c.createEl("button",{cls:"wl-btn wl-btn-success",text:"+ add"}).addEventListener("click",()=>{(async()=>{let p=d.value.trim();p&&(this.plugin.settings[s].push({name:p,color:u.value}),await this.plugin.saveSettings(),d.value="",u.value="#888780",l())})()})}}renderTagPill(t,e,s,a){let n=t.createDiv({cls:"wl-tag-pill"}),r=n.createDiv({cls:"wl-tag-dot-wrap"}),o=r.createSpan({cls:"wl-tag-dot"});o.style.backgroundColor=e.color;let l=r.createEl("input",{cls:"wl-tag-color-picker",attr:{type:"color",value:e.color}});o.addEventListener("click",()=>l.click()),l.addEventListener("change",()=>{(async()=>(e.color=l.value,o.style.backgroundColor=l.value,await this.plugin.saveSettings()))()}),n.createSpan({cls:"wl-tag-name",text:e.name});let c=s==="types"&&fi.LOCKED_TYPES.includes(e.name);s!=="statuses"&&!c&&n.createSpan({cls:"wl-tag-del",text:"\xD7"}).addEventListener("click",()=>{(async()=>(this.plugin.settings[s]=this.plugin.settings[s].filter(u=>u.name!==e.name),await this.plugin.saveSettings(),a(),new A.Notice(`Removed "${e.name}".`)))()})}renderWatchlist(t){new A.Setting(t).setName("Default watchlist view").setDesc("Which sub-tab opens by default when entering the Watchlist.").addDropdown(a=>{var n;return a.addOptions({list:"List",cards:"Cards"}).setValue((n=this.plugin.settings.defaultWatchlistView)!=null?n:"cards").onChange(async r=>{this.plugin.settings.defaultWatchlistView=r,await this.plugin.saveSettings()})}),new A.Setting(t).setName("Episode numbering").setDesc("Absolute: episodes numbered 1\u2192n across all seasons. Per season: each season restarts from 1 (display only, data is unchanged).").addDropdown(a=>{var n;return a.addOptions({absolute:"Absolute","per-season":"Per season"}).setValue((n=this.plugin.settings.episodeNumbering)!=null?n:"absolute").onChange(async r=>{this.plugin.settings.episodeNumbering=r,await this.plugin.saveSettings(),activeDocument.dispatchEvent(new CustomEvent("watchlog-data-changed"))})}),new A.Setting(t).setName("Default type for new titles").setDesc('Type preselected when adding a title. "Last type used" follows whatever you added last.').addDropdown(a=>{var n;a.addOption(xt,"* Last type used");for(let r of this.plugin.settings.types)a.addOption(r.name,r.name);a.setValue((n=this.plugin.settings.defaultAddType)!=null?n:xt).onChange(async r=>{this.plugin.settings.defaultAddType=r,await this.plugin.saveSettings()})}),new A.Setting(t).setName("Auto-complete on last episode").setDesc("Mark status as completed when all episodes are watched.").addToggle(a=>a.setValue(this.plugin.settings.autoCompleteOnLastEpisode).onChange(async n=>{this.plugin.settings.autoCompleteOnLastEpisode=n,await this.plugin.saveSettings()})),new A.Setting(t).setName("Colored type badges").setDesc("Show type and status badges with their configured colors. Disable for a plain text style.").addToggle(a=>a.setValue(this.plugin.settings.coloredTypeBadges).onChange(async n=>{this.plugin.settings.coloredTypeBadges=n,await this.plugin.saveSettings()})),t.createDiv({cls:"wl-settings-section-title",text:"Import / Export CSV"}),new A.Setting(t).setName("Export to CSV").setDesc("Export selected titles as a CSV file.").addButton(a=>a.setButtonText("Export CSV").onClick(()=>{new ke(this.app,this.plugin,this.plugin.dataManager,"export").open()})),new A.Setting(t).setName("Import from CSV").setDesc("Import titles from a CSV file. Duplicates are highlighted before import.").addButton(a=>a.setButtonText("Import CSV").onClick(()=>{new ke(this.app,this.plugin,this.plugin.dataManager,"import").open()})),t.createDiv({cls:"wl-settings-section-title",text:"Folders"}),new A.Setting(t).setName("Root folder name").setDesc("Vault folder where watchlog Markdown files are stored.").addText(a=>a.setValue(this.plugin.settings.rootFolder).onChange(async n=>{this.plugin.settings.rootFolder=n,await this.plugin.saveSettings()})),new A.Setting(t).setName("Auto-create folders").setDesc("Automatically create type subfolders on plugin load.").addToggle(a=>a.setValue(this.plugin.settings.autoCreateFolders).onChange(async n=>{this.plugin.settings.autoCreateFolders=n,await this.plugin.saveSettings()})),t.createDiv({cls:"wl-settings-section-title",text:"Type subfolders"});let e=t.createDiv({cls:"wl-folder-list"});(()=>{e.empty();for(let a of this.plugin.settings.types){let n=e.createDiv({cls:"wl-folder-row"});n.createSpan({cls:"wl-folder-type",text:a.name}),n.createSpan({cls:"wl-folder-path",text:`${this.plugin.settings.rootFolder}/${a.name}`})}})(),new A.Setting(t).setName("Create folders now").setDesc("Manually trigger folder creation for all current types.").addButton(a=>a.setButtonText("Create").onClick(async()=>{await this.plugin.dataManager.ensureFolders(),new A.Notice("Folders created.")}))}renderDrafts(t){t.createDiv({cls:"wl-settings-section-title",text:"Drafts"}),new A.Setting(t).setName("Vault tag to monitor").setDesc("Lines containing this tag followed by a title will appear in the drafts tab.").addText(e=>{var s;return e.setPlaceholder("#watchlog").setValue((s=this.plugin.settings.draftsVaultTag)!=null?s:"#watchlog").onChange(async a=>{this.plugin.settings.draftsVaultTag=a.trim()||"#watchlog",await this.plugin.saveSettings()})}),new A.Setting(t).setName("After adding a title").setDesc("What happens to a draft entry once you hit add and confirm.").addDropdown(e=>{var s;return e.addOptions({keep:"Keep as Added",remove:"Remove"}).setValue((s=this.plugin.settings.draftsAfterAdding)!=null?s:"keep").onChange(async a=>{this.plugin.settings.draftsAfterAdding=a,await this.plugin.saveSettings()})})}renderCustomLists(t){t.createDiv({cls:"wl-settings-section-title",text:"Custom Lists"}),new A.Setting(t).setName("Custom lists folder path").setDesc("Vault folder where custom list files are stored.").addText(e=>{var s;return e.setValue((s=this.plugin.settings.customListsFolder)!=null?s:"WatchLog/CustomLists").onChange(async a=>{this.plugin.settings.customListsFolder=a,await this.plugin.saveSettings()})}),new A.Setting(t).setName("Default columns").setDesc("Columns pre-populated when creating a new list. The name column is always included.").addButton(e=>{var a;let s=((a=this.plugin.settings.defaultCustomColumns)!=null?a:[]).length;e.setButtonText(`Edit (${s} column${s!==1?"s":""})`),e.onClick(()=>{new ri(this.app,this.plugin).open()})}),new A.Setting(t).setName("Create folder now").setDesc("Manually create the custom lists folder in the vault.").addButton(e=>e.setButtonText("Create").onClick(async()=>{await new te(this.app,this.plugin).ensureFolder(),new A.Notice("Custom lists folder created.")}))}renderReading(t){let e=this.plugin.readingDataManager,s=e.getSettings();t.createDiv({cls:"wl-settings-section-title",text:"Reading"}),new A.Setting(t).setName("Reading folder path").setDesc("Vault folder where reading note files are generated. Changing this will not move existing files.").addText(a=>a.setPlaceholder("WatchLog/Reading").setValue(s.defaultFolder).onChange(n=>{let r=n.trim()||"WatchLog/Reading";e.updateSettings({defaultFolder:r})})),new A.Setting(t).setName("Default status for new entries").setDesc("Status pre-selected in the Add book / Add manga modal.").addDropdown(a=>{let n={};for(let r of ct)n[r]=r;a.addOptions(n).setValue(s.defaultStatus).onChange(r=>{e.updateSettings({defaultStatus:r})})}),new A.Setting(t).setName("Default sub-tab").setDesc("Which sub-tab opens by default when you switch to the Reading tab.").addDropdown(a=>{var n;a.addOptions({books:"Books",manga:"Manga"}).setValue((n=s.defaultSubTab)!=null?n:"books").onChange(r=>{e.updateSettings({defaultSubTab:r})})}),t.createDiv({cls:"wl-settings-section-title",text:"Import / Export CSV"}),new A.Setting(t).setName("Export to CSV").setDesc("Export your Books or Manga library as a CSV file.").addButton(a=>a.setButtonText("Export CSV").onClick(()=>{new Me(this.app,"export",n=>{new xe(this.app,this.plugin,n,"export").open()}).open()})),new A.Setting(t).setName("Import from CSV").setDesc("Import Books or Manga from a CSV file, with column mapping and duplicate detection.").addButton(a=>a.setButtonText("Import CSV").onClick(()=>{new Me(this.app,"import",n=>{new xe(this.app,this.plugin,n,"import").open()}).open()}))}renderQuickInfo(t){t.createDiv({cls:"wl-settings-section-title",text:"Quick Info"});let e=[{title:"\u{1F4CA} Dashboard",items:[{heading:"Please note",body:"Statuses To be released or Dropped (time left) are not included in any calculations, only Watching, Completed and Dropped (time watched)."},{heading:"Time Watched",body:"Calculated as: episodes watched \xD7 episode duration, summed across all titles with status Watching and Completed."},{heading:"Time Remaining",body:"Calculated as: episodes remaining \xD7 episode duration, summed across all titles with status Watching and Plan to Watch."},{heading:"Dropped",body:"Calculated as: episodes watched \xD7 episode duration, summed across all titles with status Dropped."}]},{title:"\u{1F4CB} Watchlist",items:[{heading:"Why Groups exist",body:"Groups let you combine related titles under one entry; for example, a movie and its sequel, a TV show and its anime adaptation, or an anime series and its movie. They appear as a single collapsible row in your Watchlist."},{heading:"Group Rating",body:"A group's rating is automatically calculated as the average of all individual title ratings within it."},{heading:"Pin to Top",body:"Pinning a title moves it to the top of your Watchlist regardless of sorting. Pinned titles also appear in the Now Watching widget, so you can quickly see what you're currently watching inside your notes or Homepage."},{heading:"How to add a new season",body:'Open the title and click Edit at the bottom. In the Edit modal, scroll down to the Seasons field and add a new line in the format "Season Name: N" (e.g. "Season 3: 10" or "Season name: 10").'}]},{title:"\u{1F50D} API & Search",items:[{heading:"Which API is used for what",body:`WatchLog uses a different API per content type: \u2022 Anime \u2014 Jikan (MyAnimeList data) or AniList, whichever you set under Settings \u2192 API \u2192 Anime. No key is needed for either. \u2022 Movies & TV Shows \u2014 OMDb or TMDB, whichever is set as active under Settings \u2192 API. Both need a free key/token. \u2022 Books (Reading) \u2014 Google Books. A free API key is required; add it under Settings \u2192 API \u2192 Books. @@ -121,10 +127,10 @@ ${t} The anime API choice only affects new titles \u2014 existing titles keep the source they were added with. -Make sure the correct type is selected before searching. If Anime is selected and you search for a movie or TV show (or vice versa), it most likely won't be found, because each type queries its own API. APIs are a convenience, not a requirement \u2014 you can always add a title manually. The "Add from URL" button also relies on an API.`}]},{title:"\u{1F4DA} Reading",items:[{heading:"Books vs Manga",body:"Reading has two independent sub-tabs: Books and Manga. Each keeps its own entries, custom columns, filters, sort order, and saved filter. Set which one opens by default under Settings \u2192 Reading."},{heading:"Statuses",body:'Reading entries use five statuses: Reading, Completed, Plan to Read, To be released, and Dropped. "To be released" is set automatically when an entry has a release date in the future and cannot be chosen manually \u2014 once that date passes, the entry reverts to Plan to Read. Future-dated entries also appear in the shared Upcoming tab.'},{heading:"Progress tracking",body:'Books track pages read out of total pages. Manga track chapters read out of total chapters, plus volumes read out of total volumes. The card progress bar fills based on pages (books) or chapters (manga); entries with no total show "No progress" instead of a percentage.'},{heading:"Notes & favorite quotes",body:"Each entry generates a Markdown note file (under your Reading folder) with frontmatter plus Notes and Quotes sections. Favorite quotes you add from an entry's detail view are saved into that note as quote callouts, so they live alongside your own notes."},{heading:"Covers",body:`Covers are fetched automatically as cards scroll into view \u2014 Google Books for books, Jikan for manga. If a cover is missing or wrong, use "Refresh cover" from a card's \u22EE menu. (Refreshing a book cover needs the Google Books API key.)`},{heading:"Custom columns",body:"Use the \u2699 button in the Reading toolbar to add custom columns (text, number, or select). Columns are per sub-tab, and you can filter and sort by them just like the built-in fields."}]},{title:"\u{1F4C5} Upcoming",items:[{heading:"How Upcoming works",body:"Any title with a release date set in the future is automatically marked as To be released and appears in this tab. This status cannot be set manually; it is determined solely by the release date you enter. If a title has already started airing but only some episodes are out (e.g. an ongoing series), it will not appear here automatically; you'll need to manually add it through the Add button in the Upcoming tab."}]}];for(let s of e){let a=t.createDiv({cls:"wl-qi-section"}),n=a.createDiv({cls:"wl-qi-section-header"}),r=n.createSpan({cls:"wl-qi-chevron",text:"\u25B6"});n.createSpan({cls:"wl-qi-section-label",text:s.title});let o=a.createDiv({cls:"wl-qi-section-body wl-qi-section-body-hidden"});for(let l of s.items){let c=o.createDiv({cls:"wl-qi-banner"});c.createDiv({cls:"wl-qi-banner-heading",text:l.heading}),c.createDiv({cls:"wl-qi-banner-body",text:l.body})}n.addEventListener("click",()=>{let l=!o.hasClass("wl-qi-section-body-hidden");l?o.addClass("wl-qi-section-body-hidden"):o.removeClass("wl-qi-section-body-hidden"),r.textContent=l?"\u25B6":"\u25BC"})}}renderWidgets(t){t.createDiv({cls:"wl-settings-info",text:'Insert widgets into notes using the "WatchLog: Insert widget" command. Configure the keyboard shortcut in Obsidian Settings \u2192 Hotkeys.'});let e=[{name:"wl-todo",desc:'Track a specific title inline \u2014 shows type, status, progress, and a "next episode" checkbox.',syntax:"```wl-todo\nTitle Name\nmini\n```"},{name:"wl-todo (full)",desc:"Track a specific title inline (full card).",syntax:"```wl-todo\nTitle Name\n```"},{name:"wl-stat: completed",desc:"Completed titles count \u2014 compact inline stat card.",syntax:"```wl-stat\ncompleted\n```"},{name:"wl-stat: time",desc:"Time watched & remaining combined (mini).",syntax:"```wl-stat\ntime\n```"},{name:"wl-upcoming: next",desc:"Next upcoming title with name, type badge, release date, and countdown.",syntax:"```wl-upcoming\nnext\n```"},{name:"wl-nowwatching",desc:"Currently pinned title with name, type badge, and progress bar.",syntax:"```wl-nowwatching\n```"},{name:"wl-stat: time completed full",desc:"Full-width triple card: Time Watched \xB7 Time Remaining \xB7 Completed.",syntax:"```wl-stat\ntime completed full\n```"},{name:"wl-now-next",desc:"Full-width double card: Now Watching \xB7 Up Next.",syntax:"```wl-now-next\n```"}];for(let s of e){let a=t.createDiv({cls:"wl-widget-info-section"});a.createDiv({cls:"wl-widget-info-name",text:s.name}),a.createDiv({cls:"wl-widget-info-desc",text:s.desc});let n=a.createDiv({cls:"wl-widget-info-code-row"});n.createEl("code",{cls:"wl-widget-info-code",text:s.syntax});let r=n.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Copy"});r.addEventListener("click",()=>{navigator.clipboard.writeText(s.syntax).then(()=>{r.textContent="Copied!",window.setTimeout(()=>{r.textContent="Copy"},1500)})})}}};Ye.LOCKED_TYPES=["Anime","Movie","TV Show"];var Qe=Ye;var Ws=require("obsidian"),pe=class extends Ws.FuzzySuggestModal{constructor(i,t,e){super(i),this.titles=t,this.onSelect=e,this.setPlaceholder("Search for a title to insert...")}getItems(){return this.titles}getItemText(i){return`${i.title} (${i.type})`}onChooseItem(i){this.onSelect(i)}};var Je=class{constructor(i,t){this.widgetRegistry=new Map;this.widgetMiniRegistry=new Map;this.widgetRerender=new Map;this.plugin=i,this.dataManager=t,this.plugin.registerMarkdownCodeBlockProcessor("watchlog",(e,s,a)=>this.process(e,s,a)),this.plugin.registerMarkdownCodeBlockProcessor("wl-todo",(e,s,a)=>this.processWlTodo(e,s)),this.plugin.registerMarkdownCodeBlockProcessor("wl-stat",(e,s,a)=>this.processWlStat(e,s)),this.plugin.registerMarkdownCodeBlockProcessor("wl-upcoming",(e,s,a)=>this.processWlUpcoming(e,s)),this.plugin.registerMarkdownCodeBlockProcessor("wl-nowwatching",(e,s,a)=>this.processWlNowWatching(e,s)),this.plugin.registerMarkdownCodeBlockProcessor("wl-now-next",(e,s,a)=>this.processWlNowNext(e,s)),this.dataChangedListener=()=>this.onDataChanged(),activeDocument.addEventListener("watchlog-data-changed",this.dataChangedListener),i.register(()=>{activeDocument.removeEventListener("watchlog-data-changed",this.dataChangedListener)})}onDataChanged(){var e;let i=[];for(let[s,a]of this.widgetRegistry){if(!s.isConnected){i.push(s);continue}let n=this.dataManager.getTitle(a);if(!n){i.push(s);continue}((e=this.widgetMiniRegistry.get(s))!=null?e:!1)?this.renderWidgetMinimal(s,n):this.renderWidget(s,n)}for(let s of i)this.widgetRegistry.delete(s),this.widgetMiniRegistry.delete(s);let t=[];for(let[s,a]of this.widgetRerender){if(!s.isConnected){t.push(s);continue}try{a()}catch(n){console.warn("[WL] widget rerender failed:",n)}}for(let s of t)this.widgetRerender.delete(s)}cleanup(){this.widgetRegistry.clear(),this.widgetMiniRegistry.clear(),this.widgetRerender.clear()}process(i,t,e){var r;let s=i.match(/id:\s*(.+)/),a=(r=s==null?void 0:s[1])==null?void 0:r.trim();if(!a){t.createDiv({cls:"wl-widget-error",text:"WatchLog: missing id field."});return}let n=this.dataManager.getTitle(a);if(!n){t.createDiv({cls:"wl-widget-error",text:`WatchLog: title "${a}" not found.`});return}this.widgetRegistry.set(t,a),this.renderWidget(t,n)}renderWidget(i,t){this.renderWidgetFull(i,t)}renderWidgetFull(i,t){var m;i.empty(),i.addClass("wl-widget");let e=i.createDiv({cls:"wl-widget-main-row"}),s=e.createEl("input",{cls:"wl-widget-cb",attr:{type:"checkbox"}});s.title="Personal task marker (does not affect watchlog data)",s.addEventListener("change",()=>{let v=e.querySelector(".wl-widget-title");v&&(v.style.textDecoration=s.checked?"line-through":"",v.style.opacity=s.checked?"0.5":"")}),e.createSpan({cls:"wl-widget-title",text:t.title}),this.sep(e);let a=this.getTagDef(t.type,this.plugin.settings.types),n=this.plugin.settings.coloredTypeBadges,r=e.createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});n&&a&&(r.style.backgroundColor=H(t.type,a.color,this.plugin.settings.colorTheme)),this.sep(e);let o=this.getTagDef(t.status,this.plugin.settings.statuses),l=e.createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.status});n&&o&&(l.style.backgroundColor=H(t.status,o.color,this.plugin.settings.colorTheme)),this.sep(e);let c=this.dataManager.getProgress(t),d=e.createDiv({cls:"wl-widget-bar-wrap"});d.createDiv({cls:"wl-progress-bar"}).style.width=`${c}%`,this.sep(e),e.createSpan({cls:"wl-widget-percent",text:`${c}%`}),this.sep(e);let u=(m=t.dateStarted)!=null?m:t.dateAdded,h=t.dateStarted?`since ${this.formatShortDate(u)}`:`added ${this.formatShortDate(u)}`;if(e.createSpan({cls:"wl-widget-date",text:h}),t.type==="Movie"){let v=i.createDiv({cls:"wl-widget-next-row"}),f=t.watchedEpisodes.includes(1),y=v.createEl("input",{cls:"wl-widget-next-cb",attr:{type:"checkbox"}});y.checked=f,y.title="Mark movie as watched",y.addEventListener("change",()=>{this.dataManager.markEpisodeWatched(t.id,1,y.checked).then(()=>{let w=this.dataManager.getTitle(t.id);w&&this.renderWidget(i,w)})}),v.createSpan({cls:"wl-widget-next-label",text:f?"Watched":"Mark as watched"})}else{let v=this.dataManager.getNextUnwatchedEpisode(t),f=i.createDiv({cls:"wl-widget-next-row"});if(v!==null){let y=f.createEl("input",{cls:"wl-widget-next-cb",attr:{type:"checkbox"}});y.checked=!1,y.title=`Mark Episode ${v} as watched`,y.addEventListener("change",()=>{this.dataManager.markEpisodeWatched(t.id,v,!0).then(()=>{let w=this.dataManager.getTitle(t.id);w&&this.renderWidget(i,w)})}),f.createSpan({cls:"wl-widget-next-label",text:`Next up: Ep ${v}`})}else f.createSpan({cls:"wl-widget-next-label",text:"\u2713 All episodes watched"})}}renderWidgetMinimal(i,t){i.empty(),i.addClass("wl-widget-minimal");let e=i.createDiv({cls:"wl-widget-minimal-row"}),s=e.createEl("input",{cls:"wl-widget-cb",attr:{type:"checkbox"}});s.title="Personal task marker (does not affect watchlog data)",s.addEventListener("change",()=>{let u=e.querySelector(".wl-widget-title");u&&(u.style.textDecoration=s.checked?"line-through":"",u.style.opacity=s.checked?"0.5":"")}),e.createSpan({cls:"wl-widget-title",text:t.title}),this.sep(e);let a=this.getTagDef(t.type,this.plugin.settings.types),n=this.plugin.settings.coloredTypeBadges,r=e.createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});n&&a&&(r.style.backgroundColor=H(t.type,a.color,this.plugin.settings.colorTheme)),this.sep(e);let o=this.getTagDef(t.status,this.plugin.settings.statuses),l=e.createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.status});n&&o&&(l.style.backgroundColor=H(t.status,o.color,this.plugin.settings.colorTheme)),this.sep(e);let c=this.dataManager.getProgress(t);if(e.createSpan({cls:"wl-widget-percent",text:`${c}%`}),this.sep(e),t.type==="Movie"){let u=t.watchedEpisodes.includes(1),h=e.createEl("input",{cls:"wl-widget-next-cb",attr:{type:"checkbox"}});h.checked=u,h.title="Mark movie as watched",h.addEventListener("change",()=>{this.dataManager.markEpisodeWatched(t.id,1,h.checked).then(()=>{let p=this.dataManager.getTitle(t.id);p&&this.renderWidgetMinimal(i,p)})})}else{let u=this.dataManager.getNextUnwatchedEpisode(t),h=e.createEl("input",{cls:"wl-widget-next-cb",attr:{type:"checkbox"}});u!==null?(h.checked=!1,h.title=`Mark Episode ${u} as watched`,h.addEventListener("change",()=>{this.dataManager.markEpisodeWatched(t.id,u,!0).then(()=>{let p=this.dataManager.getTitle(t.id);p&&this.renderWidgetMinimal(i,p)})})):(h.checked=!0,h.disabled=!0,h.title="All episodes watched")}}sep(i){i.createSpan({cls:"wl-widget-sep",text:"\xB7"})}getTagDef(i,t){return t.find(e=>e.name===i)}formatShortDate(i){try{let t=new Date(i);return`${String(t.getDate()).padStart(2,"0")}/${String(t.getMonth()+1).padStart(2,"0")}/${String(t.getFullYear()).slice(2)}`}catch(t){return i}}processWlTodo(i,t){var r;let e=i.trim().split(` -`).map(o=>o.trim()).filter(Boolean),s=e.includes("mini"),a=(r=e.find(o=>o!=="mini"))!=null?r:"";if(!a){t.createDiv({cls:"wl-widget-error",text:"wl-todo: missing title name."});return}let n=this.dataManager.getTitles().find(o=>o.title.toLowerCase()===a.toLowerCase());if(!n){t.createDiv({cls:"wl-widget-error",text:`wl-todo: "${a}" not found.`});return}this.widgetRegistry.set(t,n.id),this.widgetMiniRegistry.set(t,s),s?this.renderWidgetMinimal(t,n):this.renderWidget(t,n)}processWlStat(i,t){this.widgetRerender.set(t,()=>this.renderWlStat(i,t)),this.renderWlStat(i,t)}renderWlStat(i,t){let e=i.trim().toLowerCase();if(t.empty(),t.addClass("wl-wstat"),e==="watched"){let s=this.dataManager.getTotalTimeWatched();this.renderStatCard(t,"\u{1F550}",z(s),"watched")}else if(e==="completed"){let s=this.dataManager.getCompletedCount();this.renderStatCard(t,"\u2705",`${s} titles`,"completed")}else if(e==="remaining"){let s=this.dataManager.getTotalTimeRemaining();this.renderStatCard(t,"\u23F3",z(s),"remaining")}else if(e==="time"){let s=this.dataManager.getTotalTimeWatched(),a=this.dataManager.getTotalTimeRemaining();this.renderTimeCardMini(t,s,a)}else if(e==="time full"){let s=this.dataManager.getTotalTimeWatched(),a=this.dataManager.getTotalTimeRemaining();this.renderTimeCardFull(t,s,a)}else if(e==="completed full"){let s=this.dataManager.getCompletedCount();this.renderCompletedCardFull(t,s)}else if(e==="time completed full"){let s=this.dataManager.getTotalTimeWatched(),a=this.dataManager.getTotalTimeRemaining(),n=this.dataManager.getCompletedCount();this.renderTripleStatCard(t,s,a,n)}else t.createDiv({cls:"wl-widget-error",text:`wl-stat: unknown stat "${e}". Use watched, completed, remaining, time, time full, completed full, or time completed full.`})}renderStatCard(i,t,e,s){i.empty();let a=i.createDiv({cls:"wl-stat-card"});a.createSpan({cls:"wl-stat-icon",text:t}),a.createSpan({cls:"wl-stat-value",text:e}),a.createSpan({cls:"wl-stat-label",text:s})}renderTimeCardMini(i,t,e){i.empty();let s=i.createDiv({cls:"wl-stat-card wl-stat-card-time"});s.createSpan({cls:"wl-stat-icon",text:"\u{1F550}"}),s.createSpan({cls:"wl-stat-value",text:z(t)}),s.createSpan({cls:"wl-stat-label",text:"watched"}),s.createSpan({cls:"wl-stat-sep",text:"\xB7"}),s.createSpan({cls:"wl-stat-icon",text:"\u23F3"}),s.createSpan({cls:"wl-stat-value",text:z(e)}),s.createSpan({cls:"wl-stat-label",text:"left"})}renderTimeCardFull(i,t,e){i.empty();let s=i.createDiv({cls:"wl-full-card wl-full-card-time"});s.createDiv({cls:"wl-full-card-header",text:"Time"});let a=s.createDiv({cls:"wl-full-card-time-cols"}),n=(r,o)=>{let l=a.createDiv({cls:"wl-full-card-time-col"});l.createDiv({cls:"wl-full-card-value",text:z(r)}),l.createDiv({cls:"wl-full-card-days",text:this.formatTimeDays(r)}),l.createDiv({cls:"wl-full-card-sub",text:o})};n(t,"watched"),n(e,"remaining")}formatTimeDays(i){let t=Math.floor(i/1440),e=Math.floor(i%1440/60);return t===0?e>0?`${e}h`:"0h":`${t} days ${e}h`}renderCompletedCardFull(i,t){i.empty();let e=i.createDiv({cls:"wl-full-card"});e.createDiv({cls:"wl-full-card-header",text:"Completed"}),e.createDiv({cls:"wl-full-card-value",text:String(t)}),e.createDiv({cls:"wl-full-card-sub",text:"titles completed"})}renderTripleStatCard(i,t,e,s){i.empty(),i.addClass("wl-wstat-triple");let n=i.createDiv({cls:"wl-full-card wl-full-card-triple"}).createDiv({cls:"wl-triple-cols"}),r=(l,c)=>{let d=n.createDiv({cls:"wl-triple-col"});d.createDiv({cls:"wl-full-card-value",text:z(l)}),d.createDiv({cls:"wl-full-card-days",text:this.formatTimeDays(l)}),d.createDiv({cls:"wl-full-card-sub",text:c})};r(t,"watched"),n.createDiv({cls:"wl-vert-sep"}),r(e,"remaining"),n.createDiv({cls:"wl-vert-sep"});let o=n.createDiv({cls:"wl-triple-col"});o.createDiv({cls:"wl-full-card-value",text:String(s)}),o.createDiv({cls:"wl-full-card-sub",text:"completed"})}processWlUpcoming(i,t){this.widgetRerender.set(t,()=>this.renderWlUpcoming(i,t)),this.renderWlUpcoming(i,t)}renderWlUpcoming(i,t){t.empty();let e=i.trim().toLowerCase(),s=e==="next full";if(e!=="next"&&e!=="next full"){t.createDiv({cls:"wl-widget-error",text:'wl-upcoming: only "next" or "next full" is supported.'});return}let a=this.dataManager.getAirtimeEntries(),n=this.dataManager.getTitles(),r=new Map(n.map(y=>[y.id,y])),o=Date.now(),l=null,c=1/0;for(let y of a){let w=r.get(y.titleId);if(!w||y.schedule.recurrence!=="once"||!y.schedule.releaseDate)continue;let b=new Date(y.schedule.releaseDate+"T12:00:00").getTime();if(b>=o&&b=30?` (${Math.round(m/30)} month${Math.round(m/30)!==1?"s":""})`:"",f=m===0?"today":m===1?"tomorrow":`in ${m} days${v}`;d.createSpan({cls:"wl-upcoming-countdown",text:f})}renderUpcomingFull(i,t){i.empty();let e=i.createDiv({cls:"wl-full-card"});if(e.createDiv({cls:"wl-full-card-header",text:"Up Next"}),!t){e.createDiv({cls:"wl-full-card-sub",text:"No upcoming titles."});return}e.createDiv({cls:"wl-full-card-title",text:t.titleName});let s=e.createDiv({cls:"wl-full-card-meta"}),a=this.getTagDef(t.type,this.plugin.settings.types),n=this.plugin.settings.coloredTypeBadges,r=s.createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});n&&a&&(r.style.backgroundColor=H(t.type,a.color,this.plugin.settings.colorTheme));let o=t.daysUntil,l=o===0?"today":o===1?"tomorrow":`in ${o} day${o!==1?"s":""}`;s.createSpan({text:l}),s.createSpan({cls:"wl-full-card-sub",text:t.releaseDate})}processWlNowWatching(i,t){this.widgetRerender.set(t,()=>this.renderWlNowWatching(i,t)),this.renderWlNowWatching(i,t)}renderWlNowWatching(i,t){t.empty();let e=i.trim().toLowerCase()==="full";t.addClass("wl-wnowwatching");let s=this.dataManager.getTitles().find(m=>m.pinned),a=this.dataManager.getPinnedGroupId(),n=a?this.dataManager.getGroups().find(m=>m.id===a):null;if(e){this.renderNowWatchingFull(t,s!=null?s:null,n!=null?n:null);return}if(!s&&!n){t.createDiv({cls:"wl-nowwatching-card wl-nowwatching-empty",text:"Pin a title to set it as now watching."});return}let r=t.createDiv({cls:"wl-nowwatching-card"});if(n){r.createSpan({cls:"wl-nowwatching-title",text:n.name});let m=this.dataManager.getTitles(),v=new Map(m.map(k=>[k.id,k])),f=n.titleIds.map(k=>v.get(k)).filter(k=>k!==void 0),y=f.reduce((k,E)=>k+E.watchedEpisodes.length,0),w=f.reduce((k,E)=>k+this.dataManager.getEffectiveTotal(E),0),b=w>0?Math.min(100,Math.round(y/w*100)):0;r.createSpan({cls:"wl-nowwatching-ep",text:`${f.length} title${f.length!==1?"s":""}`});let S=r.createDiv({cls:"wl-nowwatching-bar-wrap"});S.createDiv({cls:"wl-nowwatching-bar"}).style.width=`${b}%`,r.createSpan({cls:"wl-nowwatching-pct",text:`${b}%`});return}let o=s;r.createSpan({cls:"wl-nowwatching-title",text:o.title});let l=this.getTagDef(o.type,this.plugin.settings.types),c=this.plugin.settings.coloredTypeBadges,d=r.createSpan({cls:c?"wl-badge wl-badge-sm":"wl-badge-plain",text:o.type});if(c&&l&&(d.style.backgroundColor=H(o.type,l.color,this.plugin.settings.colorTheme)),o.type!=="Movie"){let m=this.dataManager.getNextUnwatchedEpisode(o);r.createSpan({cls:"wl-nowwatching-ep",text:m!==null?`Ep ${m}`:"\u2713 Completed"})}let u=this.dataManager.getProgress(o),p=r.createDiv({cls:"wl-nowwatching-bar-wrap"}).createDiv({cls:"wl-nowwatching-bar"});p.style.width=`${u}%`,r.createSpan({cls:"wl-nowwatching-pct",text:`${u}%`})}renderNowWatchingFull(i,t,e){i.empty();let s=i.createDiv({cls:"wl-full-card wl-full-card-nw"});if(s.createDiv({cls:"wl-full-card-header",text:"NOW WATCHING"}),!t&&!e){s.createDiv({cls:"wl-full-card-sub",text:"Pin a title to set it as now watching."});return}if(e){s.createDiv({cls:"wl-full-card-title",text:e.name});let u=this.dataManager.getTitles(),h=new Map(u.map(b=>[b.id,b])),p=e.titleIds.map(b=>h.get(b)).filter(b=>b!==void 0),m=p.reduce((b,S)=>b+S.watchedEpisodes.length,0),v=p.reduce((b,S)=>b+this.dataManager.getEffectiveTotal(S),0),f=v>0?Math.min(100,Math.round(m/v*100)):0,y=s.createDiv({cls:"wl-nw-bottom-row"});y.createSpan({cls:"wl-full-card-sub",text:`${p.length} title${p.length!==1?"s":""}`});let w=y.createDiv({cls:"wl-nw-bar-col"});w.createDiv({cls:"wl-nw-pct",text:`${f}%`}),w.createDiv({cls:"wl-full-card-bar-wrap"}).createDiv({cls:"wl-full-card-bar"}).style.width=`${f}%`;return}let a=t;s.createDiv({cls:"wl-full-card-title",text:a.title});let n=this.dataManager.getProgress(a),r=s.createDiv({cls:"wl-nw-bottom-row"}),o=this.getTagDef(a.type,this.plugin.settings.types),l=this.plugin.settings.coloredTypeBadges,c=r.createSpan({cls:l?"wl-badge wl-badge-sm":"wl-badge-plain",text:a.type});l&&o&&(c.style.backgroundColor=H(a.type,o.color,this.plugin.settings.colorTheme));let d=r.createDiv({cls:"wl-nw-bar-col"});d.createDiv({cls:"wl-nw-pct",text:`${n}%`}),d.createDiv({cls:"wl-full-card-bar-wrap"}).createDiv({cls:"wl-full-card-bar"}).style.width=`${n}%`}processWlNowNext(i,t){this.widgetRerender.set(t,()=>this.renderWlNowNext(i,t)),this.renderWlNowNext(i,t)}renderWlNowNext(i,t){t.empty(),t.addClass("wl-wnownext");let e=this.dataManager.getTitles().find(u=>u.pinned),s=this.dataManager.getPinnedGroupId(),a=s?this.dataManager.getGroups().find(u=>u.id===s):null,n=this.dataManager.getAirtimeEntries(),r=this.dataManager.getTitles(),o=new Map(r.map(u=>[u.id,u])),l=Date.now(),c=null,d=1/0;for(let u of n){let h=o.get(u.titleId);if(!h||u.schedule.recurrence!=="once"||!u.schedule.releaseDate)continue;let p=new Date(u.schedule.releaseDate+"T12:00:00").getTime();if(p>=l&&p[m.id,m])),d=e.titleIds.map(m=>c.get(m)).filter(m=>m!==void 0),u=d.reduce((m,v)=>m+v.watchedEpisodes.length,0),h=d.reduce((m,v)=>m+this.dataManager.getEffectiveTotal(v),0),p=h>0?Math.min(100,Math.round(u/h*100)):0;r.createDiv({cls:"wl-full-card-sub",text:`${d.length} title${d.length!==1?"s":""} \xB7 ${p}%`})}else{let l=t;r.createDiv({cls:"wl-full-card-title",text:l.title});let c=this.dataManager.getProgress(l);r.createDiv({cls:"wl-full-card-sub",text:`${c}%`})}n.createDiv({cls:"wl-vert-sep"});let o=n.createDiv({cls:"wl-double-col"});if(o.createDiv({cls:"wl-full-card-header",text:"UPCOMING NEXT"}),!s)o.createDiv({cls:"wl-full-card-sub",text:"No upcoming."});else{o.createDiv({cls:"wl-full-card-title",text:s.titleName});let l=s.daysUntil,c=l===0?"today":l===1?"tomorrow":`in ${l}d`;o.createDiv({cls:"wl-full-card-sub",text:`${s.releaseDate} \xB7 ${c}`})}}};var Xe=class extends X.Plugin{constructor(){super(...arguments);this.settings=dt;this.dataManager=new qt(this);this.readingDataManager=new Qt(this);this.apiService=new Jt("","");this.historyManager=new jt(this);this.importProgress=null;this.notifiedEntries=new Set;this.statusBarEl=null}async onload(){await this.loadSettings(),this.dataManager=new qt(this),await this.dataManager.load(),await this.migrateReadingHistory(),this.dataManager.startWatchingExternalChanges(),this.apiService=new Jt(this.settings.omdbApiKey,this.settings.tmdbApiKey,this.settings.googleBooksApiKey),this.readingDataManager=new Qt(this),this.historyManager=new jt(this),this.dataManager.setHistoryManager(this.historyManager),this.readingDataManager.setHistoryManager(this.historyManager),await this.historyManager.load(),await this.readingDataManager.load(),this.posterService=new fe(this.dataManager,()=>this.settings),await this.dataManager.ensureFolders(),this.startAirtimeScheduler(),this.registerView(ce,e=>new kt(e,this,this.dataManager)),this.widgetRenderer=new Je(this,this.dataManager),this.addRibbonIcon("tv","Watchlog",()=>{this.activateView()}),this.addCommand({id:"open-panel",name:"Open panel",callback:()=>void this.activateView()}),this.addCommand({id:"add-title",name:"Add title",callback:()=>{new ht(this.app,this,this.dataManager,()=>{this.activateView()}).open()}}),this.addCommand({id:"insert-widget",name:"Insert widget",editorCallback:(e,s)=>{this.openWidgetPalette(e)}}),this.addCommand({id:"search-title",name:"Search title",callback:()=>{let e=this.dataManager.getTitles();new pe(this.app,e,s=>{this.activateView().then(()=>{new X.Notice(`"${s.title}" \u2014 ${s.type} \xB7 ${s.status}`)})}).open()}}),this.addSettingTab(new Qe(this.app,this)),this.setupStatusBar();let t=()=>this.updateStatusBar();activeDocument.addEventListener("watchlog-data-changed",t),this.register(()=>activeDocument.removeEventListener("watchlog-data-changed",t))}onunload(){var t,e,s;this.dataManager.flushPendingSaveSync(),this.dataManager.flushPosterSaveSync(),this.dataManager.flushQueuedSaveSync(),(t=this.readingDataManager)==null||t.flushCoverSave(),(e=this.posterService)==null||e.destroy(),(s=this.widgetRenderer)==null||s.cleanup()}startAirtimeScheduler(){this.checkAirtimeNotifications(),this.registerInterval(window.setInterval(()=>{this.checkAirtimeNotifications()},6e4))}markAirtimeHandled(t){this.notifiedEntries.add(t)}checkAirtimeNotifications(){var n,r,o,l;let t=new Date,e=`${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`,s=`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`,a=this.dataManager.getAirtimeEntries();for(let c of a){if(!c.schedule.releaseTime||c.schedule.releaseTime!==e||!this.isScheduledForToday(c.schedule))continue;let d=`${c.id}-${s}`;if(this.notifiedEntries.has(d))continue;this.notifiedEntries.add(d);let u,h;if(c.source==="reading"){let m=((n=c.readingKind)!=null?n:"book")==="book"?this.readingDataManager.getBook(c.titleId):this.readingDataManager.getManga(c.titleId);if(!m)continue;u=m.title,h=(o=(r=c.totalEpisodes)!=null?r:m.totalChapters)!=null?o:0}else{let p=this.dataManager.getTitle(c.titleId);if(!p)continue;u=p.title,h=(l=c.totalEpisodes)!=null?l:p.totalEpisodes}if(new X.Notice(u,8e3),h>1&&c.currentEpisode!==void 0){let p=c.currentEpisode+1;p<=h&&(c.currentEpisode=p,this.dataManager.updateAirtimeEntry(c))}}this.updateStatusBar()}setupStatusBar(){X.Platform.isMobile||(this.statusBarEl=this.addStatusBarItem(),this.statusBarEl.addClass("wl-statusbar-upcoming"),this.statusBarEl.setAttribute("aria-label","WatchLog \u2014 Upcoming due"),this.statusBarEl.addEventListener("click",()=>void this.activateView("upcoming")),this.updateStatusBar())}updateStatusBar(){let t=this.statusBarEl;if(!t)return;if(!this.settings.showUpcomingStatusBar){t.hide();return}let e=vt.getAiredDueCount(this.dataManager,this.readingDataManager)+vt.getMaybeDueCount(this.dataManager);if(e<=0){t.hide();return}t.empty(),t.show();let s=t.createSpan({cls:"wl-statusbar-icon"});(0,X.setIcon)(s,"tv"),t.createSpan({cls:"wl-statusbar-text",text:`${e} due`})}isScheduledForToday(t){var a;let e=new Date,s=new Date(e.getFullYear(),e.getMonth(),e.getDate());if(t.recurrence==="daily")return!0;if(t.recurrence==="weekly")return t.dayOfWeek===e.getDay();if(t.recurrence==="monthly")return e.getDate()===((a=t.dayOfMonth)!=null?a:-1);if(t.recurrence==="once"&&t.releaseDate){let n=new Date(t.releaseDate+"T00:00:00");return new Date(n.getFullYear(),n.getMonth(),n.getDate()).getTime()===s.getTime()}return!1}async loadSettings(){var s,a,n,r,o,l,c;let t=await this.loadData();this.settings=Object.assign({},dt,(s=t==null?void 0:t.settings)!=null?s:{}),(a=t==null?void 0:t.settings)!=null&&a.listFilters&&(this.settings.listFilters=Object.assign({},dt.listFilters,t.settings.listFilters)),this.settings.animeApiSource===void 0&&(this.settings.animeApiSource="jikan"),this.settings.typeApiMapping===void 0&&(this.settings.typeApiMapping={}),this.settings.readingTypeColors?(this.settings.readingTypeColors.manga||(this.settings.readingTypeColors.manga="#D4537E"),this.settings.readingTypeColors.book||(this.settings.readingTypeColors.book="#D85A30")):this.settings.readingTypeColors={manga:"#D4537E",book:"#D85A30"},this.settings.defaultWatchlistView!=="list"&&this.settings.defaultWatchlistView!=="cards"&&(this.settings.defaultWatchlistView="cards"),this.settings.showUpcomingStatusBar===void 0&&(this.settings.showUpcomingStatusBar=!0),(n=this.settings.types)!=null&&n.length||(this.settings.types=dt.types),(r=this.settings.statuses)!=null&&r.length||(this.settings.statuses=dt.statuses),(o=this.settings.reviews)!=null&&o.length||(this.settings.reviews=dt.reviews),(l=this.settings.priorities)!=null&&l.length||(this.settings.priorities=dt.priorities),(c=this.settings.seasonPalette)!=null&&c.length||(this.settings.seasonPalette=dt.seasonPalette);let e=this.settings.statuses.find(d=>d.name==="Plan to watch");if(e&&e.color==="#888780"&&(e.color="#00A9A5"),!this.settings.statuses.find(d=>d.name==="To be released")){let d=this.settings.statuses.findIndex(h=>h.name==="Completed"),u=d>=0?d+1:this.settings.statuses.length;this.settings.statuses.splice(u,0,{name:"To be released",color:"#E8873A"})}}async saveSettings(){await this.dataManager.saveSettings(this.settings)}async migrateReadingHistory(){var d,u,h,p,m,v,f,y,w,b,S,k;let t=this.dataManager.getData();if(t.migratedReadingHistory===!0)return;let e=this.app.vault.adapter,s=`${this.app.vault.configDir}/plugins/watchlog`,a=(0,X.normalizePath)(`${s}/reading.json`),n=(0,X.normalizePath)(`${s}/history.json`),r=!1,o=null;try{if(await e.exists(a)){let E=await e.read(a);o=JSON.parse(E),r=!0}else r=!0}catch(E){r=!1,console.warn("[WL] reading.json read/parse failed \u2014 migration will retry next load:",E)}let l=!1,c=null;try{if(await e.exists(n)){let E=await e.read(n),D=JSON.parse(E);c=Array.isArray(D.entries)?D.entries:[],l=!0}else l=!0}catch(E){l=!1,console.warn("[WL] history.json read/parse failed \u2014 migration will retry next load:",E)}if(r&&o){let E=((u=(d=o.books)==null?void 0:d.length)!=null?u:0)>0||((p=(h=o.manga)==null?void 0:h.length)!=null?p:0)>0||((v=(m=o.bookColumns)==null?void 0:m.length)!=null?v:0)>0||((y=(f=o.mangaColumns)==null?void 0:f.length)!=null?y:0)>0,D=!!t.reading&&(((b=(w=t.reading.books)==null?void 0:w.length)!=null?b:0)>0||((k=(S=t.reading.manga)==null?void 0:S.length)!=null?k:0)>0);(E||!D)&&(t.reading=o)}if(l&&c){let E=Array.isArray(t.history)&&t.history.length>0;(c.length>0||!E)&&(t.history=c)}r&&l&&(t.migratedReadingHistory=!0),await this.dataManager.persist()}openWidgetPalette(t){let e=[{name:"wl-todo \u2014 Track a title (full)",id:"wl-todo"},{name:"wl-todo mini \u2014 Track a title (compact)",id:"wl-todo:mini"},{name:"wl-stat: watched \u2014 Time watched (mini)",id:"wl-stat:watched"},{name:"wl-stat: completed \u2014 Completed titles (mini)",id:"wl-stat:completed"},{name:"wl-stat: remaining \u2014 Time remaining (mini)",id:"wl-stat:remaining"},{name:"wl-stat: time \u2014 Watched + remaining (mini)",id:"wl-stat:time"},{name:"wl-upcoming: next \u2014 Next upcoming (mini)",id:"wl-upcoming:next"},{name:"wl-stat: time completed full \u2014 Time \xB7 Remaining \xB7 Completed card",id:"wl-stat:time completed full"},{name:"wl-now-next \u2014 Now Watching + Up Next card",id:"wl-now-next"}];new Ni(this.app,e,s=>{if(s.id==="wl-todo"||s.id==="wl-todo:mini"){let a=this.dataManager.getTitles();if(a.length===0){new X.Notice("No titles in your watchlog library yet.");return}let n=s.id==="wl-todo:mini";new pe(this.app,a,r=>{n?t.replaceSelection(`\`\`\`wl-todo +Make sure the correct type is selected before searching. If Anime is selected and you search for a movie or TV show (or vice versa), it most likely won't be found, because each type queries its own API. APIs are a convenience, not a requirement \u2014 you can always add a title manually. The "Add from URL" button also relies on an API.`}]},{title:"\u{1F4DA} Reading",items:[{heading:"Books vs Manga",body:"Reading has two independent sub-tabs: Books and Manga. Each keeps its own entries, custom columns, filters, sort order, and saved filter. Set which one opens by default under Settings \u2192 Reading."},{heading:"Statuses",body:'Reading entries use five statuses: Reading, Completed, Plan to Read, To be released, and Dropped. "To be released" is set automatically when an entry has a release date in the future and cannot be chosen manually \u2014 once that date passes, the entry reverts to Plan to Read. Future-dated entries also appear in the shared Upcoming tab.'},{heading:"Progress tracking",body:'Books track pages read out of total pages. Manga track chapters read out of total chapters, plus volumes read out of total volumes. The card progress bar fills based on pages (books) or chapters (manga); entries with no total show "No progress" instead of a percentage.'},{heading:"Notes & favorite quotes",body:"Each entry generates a Markdown note file (under your Reading folder) with frontmatter plus Notes and Quotes sections. Favorite quotes you add from an entry's detail view are saved into that note as quote callouts, so they live alongside your own notes."},{heading:"Covers",body:`Covers are fetched automatically as cards scroll into view \u2014 Google Books for books, Jikan for manga. If a cover is missing or wrong, use "Refresh cover" from a card's \u22EE menu. (Refreshing a book cover needs the Google Books API key.)`},{heading:"Custom columns",body:"Use the \u2699 button in the Reading toolbar to add custom columns (text, number, or select). Columns are per sub-tab, and you can filter and sort by them just like the built-in fields."}]},{title:"\u{1F4C5} Upcoming",items:[{heading:"How Upcoming works",body:"Any title with a release date set in the future is automatically marked as To be released and appears in this tab. This status cannot be set manually; it is determined solely by the release date you enter. If a title has already started airing but only some episodes are out (e.g. an ongoing series), it will not appear here automatically; you'll need to manually add it through the Add button in the Upcoming tab."}]}];for(let s of e){let a=t.createDiv({cls:"wl-qi-section"}),n=a.createDiv({cls:"wl-qi-section-header"}),r=n.createSpan({cls:"wl-qi-chevron",text:"\u25B6"});n.createSpan({cls:"wl-qi-section-label",text:s.title});let o=a.createDiv({cls:"wl-qi-section-body wl-qi-section-body-hidden"});for(let l of s.items){let c=o.createDiv({cls:"wl-qi-banner"});c.createDiv({cls:"wl-qi-banner-heading",text:l.heading}),c.createDiv({cls:"wl-qi-banner-body",text:l.body})}n.addEventListener("click",()=>{let l=!o.hasClass("wl-qi-section-body-hidden");l?o.addClass("wl-qi-section-body-hidden"):o.removeClass("wl-qi-section-body-hidden"),r.textContent=l?"\u25B6":"\u25BC"})}}renderWidgets(t){t.createDiv({cls:"wl-settings-info",text:'Insert widgets into notes using the "WatchLog: Insert widget" command. Configure the keyboard shortcut in Obsidian Settings \u2192 Hotkeys.'});let e=[{name:"wl-todo",desc:'Track a specific title inline \u2014 shows type, status, progress, and a "next episode" checkbox.',syntax:"```wl-todo\nTitle Name\nmini\n```"},{name:"wl-todo (full)",desc:"Track a specific title inline (full card).",syntax:"```wl-todo\nTitle Name\n```"},{name:"wl-stat: completed",desc:"Completed titles count \u2014 compact inline stat card.",syntax:"```wl-stat\ncompleted\n```"},{name:"wl-stat: time",desc:"Time watched & remaining combined (mini).",syntax:"```wl-stat\ntime\n```"},{name:"wl-upcoming: next",desc:"Next upcoming title with name, type badge, release date, and countdown.",syntax:"```wl-upcoming\nnext\n```"},{name:"wl-nowwatching",desc:"Currently pinned title with name, type badge, and progress bar.",syntax:"```wl-nowwatching\n```"},{name:"wl-stat: time completed full",desc:"Full-width triple card: Time Watched \xB7 Time Remaining \xB7 Completed.",syntax:"```wl-stat\ntime completed full\n```"},{name:"wl-now-next",desc:"Full-width double card: Now Watching \xB7 Up Next.",syntax:"```wl-now-next\n```"}];for(let s of e){let a=t.createDiv({cls:"wl-widget-info-section"});a.createDiv({cls:"wl-widget-info-name",text:s.name}),a.createDiv({cls:"wl-widget-info-desc",text:s.desc});let n=a.createDiv({cls:"wl-widget-info-code-row"});n.createEl("code",{cls:"wl-widget-info-code",text:s.syntax});let r=n.createEl("button",{cls:"wl-btn wl-btn-sm",text:"Copy"});r.addEventListener("click",()=>{navigator.clipboard.writeText(s.syntax).then(()=>{r.textContent="Copied!",window.setTimeout(()=>{r.textContent="Copy"},1500)})})}}};fi.LOCKED_TYPES=["Anime","Movie","TV Show"];var mi=fi;var fa=require("obsidian"),Le=class extends fa.FuzzySuggestModal{constructor(i,t,e){super(i),this.titles=t,this.onSelect=e,this.setPlaceholder("Search for a title to insert...")}getItems(){return this.titles}getItemText(i){return`${i.title} (${i.type})`}onChooseItem(i){this.onSelect(i)}};var vi=class{constructor(i,t){this.widgetRegistry=new Map;this.widgetMiniRegistry=new Map;this.widgetRerender=new Map;this.plugin=i,this.dataManager=t,this.plugin.registerMarkdownCodeBlockProcessor("watchlog",(e,s,a)=>this.process(e,s,a)),this.plugin.registerMarkdownCodeBlockProcessor("wl-todo",(e,s,a)=>this.processWlTodo(e,s)),this.plugin.registerMarkdownCodeBlockProcessor("wl-stat",(e,s,a)=>this.processWlStat(e,s)),this.plugin.registerMarkdownCodeBlockProcessor("wl-upcoming",(e,s,a)=>this.processWlUpcoming(e,s)),this.plugin.registerMarkdownCodeBlockProcessor("wl-nowwatching",(e,s,a)=>this.processWlNowWatching(e,s)),this.plugin.registerMarkdownCodeBlockProcessor("wl-now-next",(e,s,a)=>this.processWlNowNext(e,s)),this.dataChangedListener=()=>this.onDataChanged(),activeDocument.addEventListener("watchlog-data-changed",this.dataChangedListener),i.register(()=>{activeDocument.removeEventListener("watchlog-data-changed",this.dataChangedListener)})}onDataChanged(){var e;let i=[];for(let[s,a]of this.widgetRegistry){if(!s.isConnected){i.push(s);continue}let n=this.dataManager.getTitle(a);if(!n){i.push(s);continue}((e=this.widgetMiniRegistry.get(s))!=null?e:!1)?this.renderWidgetMinimal(s,n):this.renderWidget(s,n)}for(let s of i)this.widgetRegistry.delete(s),this.widgetMiniRegistry.delete(s);let t=[];for(let[s,a]of this.widgetRerender){if(!s.isConnected){t.push(s);continue}try{a()}catch(n){console.warn("[WL] widget rerender failed:",n)}}for(let s of t)this.widgetRerender.delete(s)}cleanup(){this.widgetRegistry.clear(),this.widgetMiniRegistry.clear(),this.widgetRerender.clear()}process(i,t,e){var r;let s=i.match(/id:\s*(.+)/),a=(r=s==null?void 0:s[1])==null?void 0:r.trim();if(!a){t.createDiv({cls:"wl-widget-error",text:"WatchLog: missing id field."});return}let n=this.dataManager.getTitle(a);if(!n){t.createDiv({cls:"wl-widget-error",text:`WatchLog: title "${a}" not found.`});return}this.widgetRegistry.set(t,a),this.renderWidget(t,n)}renderWidget(i,t){this.renderWidgetFull(i,t)}renderWidgetFull(i,t){var m;i.empty(),i.addClass("wl-widget");let e=i.createDiv({cls:"wl-widget-main-row"}),s=e.createEl("input",{cls:"wl-widget-cb",attr:{type:"checkbox"}});s.title="Personal task marker (does not affect watchlog data)",s.addEventListener("change",()=>{let f=e.querySelector(".wl-widget-title");f&&(f.style.textDecoration=s.checked?"line-through":"",f.style.opacity=s.checked?"0.5":"")}),e.createSpan({cls:"wl-widget-title",text:t.title}),this.sep(e);let a=this.getTagDef(t.type,this.plugin.settings.types),n=this.plugin.settings.coloredTypeBadges,r=e.createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});n&&a&&(r.style.backgroundColor=N(t.type,a.color,this.plugin.settings.colorTheme)),this.sep(e);let o=this.getTagDef(t.status,this.plugin.settings.statuses),l=e.createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.status});n&&o&&(l.style.backgroundColor=N(t.status,o.color,this.plugin.settings.colorTheme)),this.sep(e);let c=this.dataManager.getProgress(t),d=e.createDiv({cls:"wl-widget-bar-wrap"});d.createDiv({cls:"wl-progress-bar"}).style.width=`${c}%`,this.sep(e),e.createSpan({cls:"wl-widget-percent",text:`${c}%`}),this.sep(e);let u=(m=t.dateStarted)!=null?m:t.dateAdded,h=t.dateStarted?`since ${this.formatShortDate(u)}`:`added ${this.formatShortDate(u)}`;if(e.createSpan({cls:"wl-widget-date",text:h}),t.type==="Movie"){let f=i.createDiv({cls:"wl-widget-next-row"}),y=t.watchedEpisodes.includes(1),v=f.createEl("input",{cls:"wl-widget-next-cb",attr:{type:"checkbox"}});v.checked=y,v.title="Mark movie as watched",v.addEventListener("change",()=>{this.dataManager.markEpisodeWatched(t.id,1,v.checked).then(()=>{let w=this.dataManager.getTitle(t.id);w&&this.renderWidget(i,w)})}),f.createSpan({cls:"wl-widget-next-label",text:y?"Watched":"Mark as watched"})}else{let f=this.dataManager.getNextUnwatchedEpisode(t),y=i.createDiv({cls:"wl-widget-next-row"});if(f!==null){let v=y.createEl("input",{cls:"wl-widget-next-cb",attr:{type:"checkbox"}});v.checked=!1,v.title=`Mark Episode ${f} as watched`,v.addEventListener("change",()=>{this.dataManager.markEpisodeWatched(t.id,f,!0).then(()=>{let w=this.dataManager.getTitle(t.id);w&&this.renderWidget(i,w)})}),y.createSpan({cls:"wl-widget-next-label",text:`Next up: Ep ${f}`})}else y.createSpan({cls:"wl-widget-next-label",text:"\u2713 All episodes watched"})}}renderWidgetMinimal(i,t){i.empty(),i.addClass("wl-widget-minimal");let e=i.createDiv({cls:"wl-widget-minimal-row"}),s=e.createEl("input",{cls:"wl-widget-cb",attr:{type:"checkbox"}});s.title="Personal task marker (does not affect watchlog data)",s.addEventListener("change",()=>{let u=e.querySelector(".wl-widget-title");u&&(u.style.textDecoration=s.checked?"line-through":"",u.style.opacity=s.checked?"0.5":"")}),e.createSpan({cls:"wl-widget-title",text:t.title}),this.sep(e);let a=this.getTagDef(t.type,this.plugin.settings.types),n=this.plugin.settings.coloredTypeBadges,r=e.createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});n&&a&&(r.style.backgroundColor=N(t.type,a.color,this.plugin.settings.colorTheme)),this.sep(e);let o=this.getTagDef(t.status,this.plugin.settings.statuses),l=e.createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.status});n&&o&&(l.style.backgroundColor=N(t.status,o.color,this.plugin.settings.colorTheme)),this.sep(e);let c=this.dataManager.getProgress(t);if(e.createSpan({cls:"wl-widget-percent",text:`${c}%`}),this.sep(e),t.type==="Movie"){let u=t.watchedEpisodes.includes(1),h=e.createEl("input",{cls:"wl-widget-next-cb",attr:{type:"checkbox"}});h.checked=u,h.title="Mark movie as watched",h.addEventListener("change",()=>{this.dataManager.markEpisodeWatched(t.id,1,h.checked).then(()=>{let p=this.dataManager.getTitle(t.id);p&&this.renderWidgetMinimal(i,p)})})}else{let u=this.dataManager.getNextUnwatchedEpisode(t),h=e.createEl("input",{cls:"wl-widget-next-cb",attr:{type:"checkbox"}});u!==null?(h.checked=!1,h.title=`Mark Episode ${u} as watched`,h.addEventListener("change",()=>{this.dataManager.markEpisodeWatched(t.id,u,!0).then(()=>{let p=this.dataManager.getTitle(t.id);p&&this.renderWidgetMinimal(i,p)})})):(h.checked=!0,h.disabled=!0,h.title="All episodes watched")}}sep(i){i.createSpan({cls:"wl-widget-sep",text:"\xB7"})}getTagDef(i,t){return t.find(e=>e.name===i)}formatShortDate(i){try{let t=new Date(i);return`${String(t.getDate()).padStart(2,"0")}/${String(t.getMonth()+1).padStart(2,"0")}/${String(t.getFullYear()).slice(2)}`}catch(t){return i}}processWlTodo(i,t){var r;let e=i.trim().split(` +`).map(o=>o.trim()).filter(Boolean),s=e.includes("mini"),a=(r=e.find(o=>o!=="mini"))!=null?r:"";if(!a){t.createDiv({cls:"wl-widget-error",text:"wl-todo: missing title name."});return}let n=this.dataManager.getTitles().find(o=>o.title.toLowerCase()===a.toLowerCase());if(!n){t.createDiv({cls:"wl-widget-error",text:`wl-todo: "${a}" not found.`});return}this.widgetRegistry.set(t,n.id),this.widgetMiniRegistry.set(t,s),s?this.renderWidgetMinimal(t,n):this.renderWidget(t,n)}processWlStat(i,t){this.widgetRerender.set(t,()=>this.renderWlStat(i,t)),this.renderWlStat(i,t)}renderWlStat(i,t){let e=i.trim().toLowerCase();if(t.empty(),t.addClass("wl-wstat"),e==="watched"){let s=this.dataManager.getTotalTimeWatched();this.renderStatCard(t,"\u{1F550}",j(s),"watched")}else if(e==="completed"){let s=this.dataManager.getCompletedCount();this.renderStatCard(t,"\u2705",`${s} titles`,"completed")}else if(e==="remaining"){let s=this.dataManager.getTotalTimeRemaining();this.renderStatCard(t,"\u23F3",j(s),"remaining")}else if(e==="time"){let s=this.dataManager.getTotalTimeWatched(),a=this.dataManager.getTotalTimeRemaining();this.renderTimeCardMini(t,s,a)}else if(e==="time full"){let s=this.dataManager.getTotalTimeWatched(),a=this.dataManager.getTotalTimeRemaining();this.renderTimeCardFull(t,s,a)}else if(e==="completed full"){let s=this.dataManager.getCompletedCount();this.renderCompletedCardFull(t,s)}else if(e==="time completed full"){let s=this.dataManager.getTotalTimeWatched(),a=this.dataManager.getTotalTimeRemaining(),n=this.dataManager.getCompletedCount();this.renderTripleStatCard(t,s,a,n)}else t.createDiv({cls:"wl-widget-error",text:`wl-stat: unknown stat "${e}". Use watched, completed, remaining, time, time full, completed full, or time completed full.`})}renderStatCard(i,t,e,s){i.empty();let a=i.createDiv({cls:"wl-stat-card"});a.createSpan({cls:"wl-stat-icon",text:t}),a.createSpan({cls:"wl-stat-value",text:e}),a.createSpan({cls:"wl-stat-label",text:s})}renderTimeCardMini(i,t,e){i.empty();let s=i.createDiv({cls:"wl-stat-card wl-stat-card-time"});s.createSpan({cls:"wl-stat-icon",text:"\u{1F550}"}),s.createSpan({cls:"wl-stat-value",text:j(t)}),s.createSpan({cls:"wl-stat-label",text:"watched"}),s.createSpan({cls:"wl-stat-sep",text:"\xB7"}),s.createSpan({cls:"wl-stat-icon",text:"\u23F3"}),s.createSpan({cls:"wl-stat-value",text:j(e)}),s.createSpan({cls:"wl-stat-label",text:"left"})}renderTimeCardFull(i,t,e){i.empty();let s=i.createDiv({cls:"wl-full-card wl-full-card-time"});s.createDiv({cls:"wl-full-card-header",text:"Time"});let a=s.createDiv({cls:"wl-full-card-time-cols"}),n=(r,o)=>{let l=a.createDiv({cls:"wl-full-card-time-col"});l.createDiv({cls:"wl-full-card-value",text:j(r)}),l.createDiv({cls:"wl-full-card-days",text:this.formatTimeDays(r)}),l.createDiv({cls:"wl-full-card-sub",text:o})};n(t,"watched"),n(e,"remaining")}formatTimeDays(i){let t=Math.floor(i/1440),e=Math.floor(i%1440/60);return t===0?e>0?`${e}h`:"0h":`${t} days ${e}h`}renderCompletedCardFull(i,t){i.empty();let e=i.createDiv({cls:"wl-full-card"});e.createDiv({cls:"wl-full-card-header",text:"Completed"}),e.createDiv({cls:"wl-full-card-value",text:String(t)}),e.createDiv({cls:"wl-full-card-sub",text:"titles completed"})}renderTripleStatCard(i,t,e,s){i.empty(),i.addClass("wl-wstat-triple");let n=i.createDiv({cls:"wl-full-card wl-full-card-triple"}).createDiv({cls:"wl-triple-cols"}),r=(l,c)=>{let d=n.createDiv({cls:"wl-triple-col"});d.createDiv({cls:"wl-full-card-value",text:j(l)}),d.createDiv({cls:"wl-full-card-days",text:this.formatTimeDays(l)}),d.createDiv({cls:"wl-full-card-sub",text:c})};r(t,"watched"),n.createDiv({cls:"wl-vert-sep"}),r(e,"remaining"),n.createDiv({cls:"wl-vert-sep"});let o=n.createDiv({cls:"wl-triple-col"});o.createDiv({cls:"wl-full-card-value",text:String(s)}),o.createDiv({cls:"wl-full-card-sub",text:"completed"})}processWlUpcoming(i,t){this.widgetRerender.set(t,()=>this.renderWlUpcoming(i,t)),this.renderWlUpcoming(i,t)}renderWlUpcoming(i,t){t.empty();let e=i.trim().toLowerCase(),s=e==="next full";if(e!=="next"&&e!=="next full"){t.createDiv({cls:"wl-widget-error",text:'wl-upcoming: only "next" or "next full" is supported.'});return}let a=this.dataManager.getAirtimeEntries(),n=this.dataManager.getTitles(),r=new Map(n.map(v=>[v.id,v])),o=Date.now(),l=null,c=1/0;for(let v of a){let w=r.get(v.titleId);if(!w||v.schedule.recurrence!=="once"||!v.schedule.releaseDate)continue;let b=new Date(v.schedule.releaseDate+"T12:00:00").getTime();if(b>=o&&b=30?` (${Math.round(m/30)} month${Math.round(m/30)!==1?"s":""})`:"",y=m===0?"today":m===1?"tomorrow":`in ${m} days${f}`;d.createSpan({cls:"wl-upcoming-countdown",text:y})}renderUpcomingFull(i,t){i.empty();let e=i.createDiv({cls:"wl-full-card"});if(e.createDiv({cls:"wl-full-card-header",text:"Up Next"}),!t){e.createDiv({cls:"wl-full-card-sub",text:"No upcoming titles."});return}e.createDiv({cls:"wl-full-card-title",text:t.titleName});let s=e.createDiv({cls:"wl-full-card-meta"}),a=this.getTagDef(t.type,this.plugin.settings.types),n=this.plugin.settings.coloredTypeBadges,r=s.createSpan({cls:n?"wl-badge wl-badge-sm":"wl-badge-plain",text:t.type});n&&a&&(r.style.backgroundColor=N(t.type,a.color,this.plugin.settings.colorTheme));let o=t.daysUntil,l=o===0?"today":o===1?"tomorrow":`in ${o} day${o!==1?"s":""}`;s.createSpan({text:l}),s.createSpan({cls:"wl-full-card-sub",text:t.releaseDate})}processWlNowWatching(i,t){this.widgetRerender.set(t,()=>this.renderWlNowWatching(i,t)),this.renderWlNowWatching(i,t)}renderWlNowWatching(i,t){t.empty();let e=i.trim().toLowerCase()==="full";t.addClass("wl-wnowwatching");let s=this.dataManager.getTitles().find(m=>m.pinned),a=this.dataManager.getPinnedGroupId(),n=a?this.dataManager.getGroups().find(m=>m.id===a):null;if(e){this.renderNowWatchingFull(t,s!=null?s:null,n!=null?n:null);return}if(!s&&!n){t.createDiv({cls:"wl-nowwatching-card wl-nowwatching-empty",text:"Pin a title to set it as now watching."});return}let r=t.createDiv({cls:"wl-nowwatching-card"});if(n){r.createSpan({cls:"wl-nowwatching-title",text:n.name});let m=this.dataManager.getTitles(),f=new Map(m.map(D=>[D.id,D])),y=n.titleIds.map(D=>f.get(D)).filter(D=>D!==void 0),v=y.reduce((D,S)=>D+S.watchedEpisodes.length,0),w=y.reduce((D,S)=>D+this.dataManager.getEffectiveTotal(S),0),b=w>0?Math.min(100,Math.round(v/w*100)):0;r.createSpan({cls:"wl-nowwatching-ep",text:`${y.length} title${y.length!==1?"s":""}`});let E=r.createDiv({cls:"wl-nowwatching-bar-wrap"});E.createDiv({cls:"wl-nowwatching-bar"}).style.width=`${b}%`,r.createSpan({cls:"wl-nowwatching-pct",text:`${b}%`});return}let o=s;r.createSpan({cls:"wl-nowwatching-title",text:o.title});let l=this.getTagDef(o.type,this.plugin.settings.types),c=this.plugin.settings.coloredTypeBadges,d=r.createSpan({cls:c?"wl-badge wl-badge-sm":"wl-badge-plain",text:o.type});if(c&&l&&(d.style.backgroundColor=N(o.type,l.color,this.plugin.settings.colorTheme)),o.type!=="Movie"){let m=this.dataManager.getNextUnwatchedEpisode(o);r.createSpan({cls:"wl-nowwatching-ep",text:m!==null?`Ep ${m}`:"\u2713 Completed"})}let u=this.dataManager.getProgress(o),p=r.createDiv({cls:"wl-nowwatching-bar-wrap"}).createDiv({cls:"wl-nowwatching-bar"});p.style.width=`${u}%`,r.createSpan({cls:"wl-nowwatching-pct",text:`${u}%`})}renderNowWatchingFull(i,t,e){i.empty();let s=i.createDiv({cls:"wl-full-card wl-full-card-nw"});if(s.createDiv({cls:"wl-full-card-header",text:"NOW WATCHING"}),!t&&!e){s.createDiv({cls:"wl-full-card-sub",text:"Pin a title to set it as now watching."});return}if(e){s.createDiv({cls:"wl-full-card-title",text:e.name});let u=this.dataManager.getTitles(),h=new Map(u.map(b=>[b.id,b])),p=e.titleIds.map(b=>h.get(b)).filter(b=>b!==void 0),m=p.reduce((b,E)=>b+E.watchedEpisodes.length,0),f=p.reduce((b,E)=>b+this.dataManager.getEffectiveTotal(E),0),y=f>0?Math.min(100,Math.round(m/f*100)):0,v=s.createDiv({cls:"wl-nw-bottom-row"});v.createSpan({cls:"wl-full-card-sub",text:`${p.length} title${p.length!==1?"s":""}`});let w=v.createDiv({cls:"wl-nw-bar-col"});w.createDiv({cls:"wl-nw-pct",text:`${y}%`}),w.createDiv({cls:"wl-full-card-bar-wrap"}).createDiv({cls:"wl-full-card-bar"}).style.width=`${y}%`;return}let a=t;s.createDiv({cls:"wl-full-card-title",text:a.title});let n=this.dataManager.getProgress(a),r=s.createDiv({cls:"wl-nw-bottom-row"}),o=this.getTagDef(a.type,this.plugin.settings.types),l=this.plugin.settings.coloredTypeBadges,c=r.createSpan({cls:l?"wl-badge wl-badge-sm":"wl-badge-plain",text:a.type});l&&o&&(c.style.backgroundColor=N(a.type,o.color,this.plugin.settings.colorTheme));let d=r.createDiv({cls:"wl-nw-bar-col"});d.createDiv({cls:"wl-nw-pct",text:`${n}%`}),d.createDiv({cls:"wl-full-card-bar-wrap"}).createDiv({cls:"wl-full-card-bar"}).style.width=`${n}%`}processWlNowNext(i,t){this.widgetRerender.set(t,()=>this.renderWlNowNext(i,t)),this.renderWlNowNext(i,t)}renderWlNowNext(i,t){t.empty(),t.addClass("wl-wnownext");let e=this.dataManager.getTitles().find(u=>u.pinned),s=this.dataManager.getPinnedGroupId(),a=s?this.dataManager.getGroups().find(u=>u.id===s):null,n=this.dataManager.getAirtimeEntries(),r=this.dataManager.getTitles(),o=new Map(r.map(u=>[u.id,u])),l=Date.now(),c=null,d=1/0;for(let u of n){let h=o.get(u.titleId);if(!h||u.schedule.recurrence!=="once"||!u.schedule.releaseDate)continue;let p=new Date(u.schedule.releaseDate+"T12:00:00").getTime();if(p>=l&&p[m.id,m])),d=e.titleIds.map(m=>c.get(m)).filter(m=>m!==void 0),u=d.reduce((m,f)=>m+f.watchedEpisodes.length,0),h=d.reduce((m,f)=>m+this.dataManager.getEffectiveTotal(f),0),p=h>0?Math.min(100,Math.round(u/h*100)):0;r.createDiv({cls:"wl-full-card-sub",text:`${d.length} title${d.length!==1?"s":""} \xB7 ${p}%`})}else{let l=t;r.createDiv({cls:"wl-full-card-title",text:l.title});let c=this.dataManager.getProgress(l);r.createDiv({cls:"wl-full-card-sub",text:`${c}%`})}n.createDiv({cls:"wl-vert-sep"});let o=n.createDiv({cls:"wl-double-col"});if(o.createDiv({cls:"wl-full-card-header",text:"UPCOMING NEXT"}),!s)o.createDiv({cls:"wl-full-card-sub",text:"No upcoming."});else{o.createDiv({cls:"wl-full-card-title",text:s.titleName});let l=s.daysUntil,c=l===0?"today":l===1?"tomorrow":`in ${l}d`;o.createDiv({cls:"wl-full-card-sub",text:`${s.releaseDate} \xB7 ${c}`})}}};var wi=class extends Z.Plugin{constructor(){super(...arguments);this.settings=ht;this.dataManager=new de(this);this.readingDataManager=new ue(this);this.apiService=new he("","");this.historyManager=new ce(this);this.importProgress=null;this.notifiedEntries=new Set;this.statusBarEl=null}async onload(){await this.loadSettings(),this.dataManager=new de(this),await this.dataManager.load(),await this.migrateReadingHistory(),this.dataManager.startWatchingExternalChanges(),this.apiService=new he(this.settings.omdbApiKey,this.settings.tmdbApiKey,this.settings.googleBooksApiKey),this.readingDataManager=new ue(this),this.historyManager=new ce(this),this.dataManager.setHistoryManager(this.historyManager),this.readingDataManager.setHistoryManager(this.historyManager),await this.historyManager.load(),await this.readingDataManager.load(),this.posterService=new We(this.dataManager,()=>this.settings),await this.dataManager.ensureFolders(),this.startAirtimeScheduler(),this.registerView(Ce,e=>new Ft(e,this,this.dataManager)),this.widgetRenderer=new vi(this,this.dataManager),this.addRibbonIcon("tv","Watchlog",()=>{this.activateView()}),this.addCommand({id:"open-panel",name:"Open panel",callback:()=>void this.activateView()}),this.addCommand({id:"add-title",name:"Add title",callback:()=>{new ft(this.app,this,this.dataManager,()=>{this.activateView()}).open()}}),this.addCommand({id:"insert-widget",name:"Insert widget",editorCallback:(e,s)=>{this.openWidgetPalette(e)}}),this.addCommand({id:"search-title",name:"Search title",callback:()=>{let e=this.dataManager.getTitles();new Le(this.app,e,s=>{this.activateView().then(()=>{new Z.Notice(`"${s.title}" \u2014 ${s.type} \xB7 ${s.status}`)})}).open()}}),this.addSettingTab(new mi(this.app,this)),this.setupStatusBar();let t=()=>this.updateStatusBar();activeDocument.addEventListener("watchlog-data-changed",t),this.register(()=>activeDocument.removeEventListener("watchlog-data-changed",t))}onunload(){var t,e,s;this.dataManager.flushPendingSaveSync(),this.dataManager.flushPosterSaveSync(),this.dataManager.flushQueuedSaveSync(),(t=this.readingDataManager)==null||t.flushCoverSave(),(e=this.posterService)==null||e.destroy(),(s=this.widgetRenderer)==null||s.cleanup()}startAirtimeScheduler(){this.checkAirtimeNotifications(),this.registerInterval(window.setInterval(()=>{this.checkAirtimeNotifications()},6e4))}markAirtimeHandled(t){this.notifiedEntries.add(t)}checkAirtimeNotifications(){var n,r,o,l;let t=new Date,e=`${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`,s=`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`,a=this.dataManager.getAirtimeEntries();for(let c of a){if(!c.schedule.releaseTime||c.schedule.releaseTime!==e||!this.isScheduledForToday(c.schedule))continue;let d=`${c.id}-${s}`;if(this.notifiedEntries.has(d))continue;this.notifiedEntries.add(d);let u,h;if(c.source==="reading"){let m=((n=c.readingKind)!=null?n:"book")==="book"?this.readingDataManager.getBook(c.titleId):this.readingDataManager.getManga(c.titleId);if(!m)continue;u=m.title,h=(o=(r=c.totalEpisodes)!=null?r:m.totalChapters)!=null?o:0}else{let p=this.dataManager.getTitle(c.titleId);if(!p)continue;u=p.title,h=(l=c.totalEpisodes)!=null?l:p.totalEpisodes}if(new Z.Notice(u,8e3),h>1&&c.currentEpisode!==void 0){let p=c.currentEpisode+1;p<=h&&(c.currentEpisode=p,this.dataManager.updateAirtimeEntry(c))}}this.updateStatusBar()}setupStatusBar(){Z.Platform.isMobile||(this.statusBarEl=this.addStatusBarItem(),this.statusBarEl.addClass("wl-statusbar-upcoming"),this.statusBarEl.setAttribute("aria-label","WatchLog \u2014 Upcoming due"),this.statusBarEl.addEventListener("click",()=>void this.activateView("upcoming")),this.updateStatusBar())}updateStatusBar(){let t=this.statusBarEl;if(!t)return;if(!this.settings.showUpcomingStatusBar){t.hide();return}let e=Dt.getAiredDueCount(this.dataManager,this.readingDataManager)+Dt.getMaybeDueCount(this.dataManager);if(e<=0){t.hide();return}t.empty(),t.show();let s=t.createSpan({cls:"wl-statusbar-icon"});(0,Z.setIcon)(s,"tv"),t.createSpan({cls:"wl-statusbar-text",text:`${e} due`})}isScheduledForToday(t){var a;let e=new Date,s=new Date(e.getFullYear(),e.getMonth(),e.getDate());if(t.recurrence==="daily")return!0;if(t.recurrence==="weekly")return t.dayOfWeek===e.getDay();if(t.recurrence==="monthly")return e.getDate()===((a=t.dayOfMonth)!=null?a:-1);if(t.recurrence==="once"&&t.releaseDate){let n=new Date(t.releaseDate+"T00:00:00");return new Date(n.getFullYear(),n.getMonth(),n.getDate()).getTime()===s.getTime()}return!1}async loadSettings(){var s,a,n,r,o,l,c;let t=await this.loadData();this.settings=Object.assign({},ht,(s=t==null?void 0:t.settings)!=null?s:{}),(a=t==null?void 0:t.settings)!=null&&a.listFilters&&(this.settings.listFilters=Object.assign({},ht.listFilters,t.settings.listFilters)),this.settings.animeApiSource===void 0&&(this.settings.animeApiSource="jikan"),this.settings.typeApiMapping===void 0&&(this.settings.typeApiMapping={}),this.settings.readingTypeColors?(this.settings.readingTypeColors.manga||(this.settings.readingTypeColors.manga="#D4537E"),this.settings.readingTypeColors.book||(this.settings.readingTypeColors.book="#D85A30")):this.settings.readingTypeColors={manga:"#D4537E",book:"#D85A30"},this.settings.defaultWatchlistView!=="list"&&this.settings.defaultWatchlistView!=="cards"&&(this.settings.defaultWatchlistView="cards"),this.settings.showUpcomingStatusBar===void 0&&(this.settings.showUpcomingStatusBar=!0),this.settings.defaultAddType===void 0&&(this.settings.defaultAddType=xt),this.settings.lastAddedType===void 0&&(this.settings.lastAddedType=""),(n=this.settings.types)!=null&&n.length||(this.settings.types=ht.types),(r=this.settings.statuses)!=null&&r.length||(this.settings.statuses=ht.statuses),(o=this.settings.reviews)!=null&&o.length||(this.settings.reviews=ht.reviews),(l=this.settings.priorities)!=null&&l.length||(this.settings.priorities=ht.priorities),(c=this.settings.seasonPalette)!=null&&c.length||(this.settings.seasonPalette=ht.seasonPalette);let e=this.settings.statuses.find(d=>d.name==="Plan to watch");if(e&&e.color==="#888780"&&(e.color="#00A9A5"),!this.settings.statuses.find(d=>d.name==="To be released")){let d=this.settings.statuses.findIndex(h=>h.name==="Completed"),u=d>=0?d+1:this.settings.statuses.length;this.settings.statuses.splice(u,0,{name:"To be released",color:"#E8873A"})}}async saveSettings(){await this.dataManager.saveSettings(this.settings)}resolveDefaultAddType(){var n,r,o,l;let t=(n=this.settings.types)!=null?n:[],e=(o=(r=t[0])==null?void 0:r.name)!=null?o:"",s=c=>!!c&&t.some(d=>d.name===c),a=(l=this.settings.defaultAddType)!=null?l:xt;return a===xt?s(this.settings.lastAddedType)?this.settings.lastAddedType:e:s(a)?a:e}async migrateReadingHistory(){var d,u,h,p,m,f,y,v,w,b,E,D;let t=this.dataManager.getData();if(t.migratedReadingHistory===!0)return;let e=this.app.vault.adapter,s=`${this.app.vault.configDir}/plugins/watchlog`,a=(0,Z.normalizePath)(`${s}/reading.json`),n=(0,Z.normalizePath)(`${s}/history.json`),r=!1,o=null;try{if(await e.exists(a)){let S=await e.read(a);o=JSON.parse(S),r=!0}else r=!0}catch(S){r=!1,console.warn("[WL] reading.json read/parse failed \u2014 migration will retry next load:",S)}let l=!1,c=null;try{if(await e.exists(n)){let S=await e.read(n),T=JSON.parse(S);c=Array.isArray(T.entries)?T.entries:[],l=!0}else l=!0}catch(S){l=!1,console.warn("[WL] history.json read/parse failed \u2014 migration will retry next load:",S)}if(r&&o){let S=((u=(d=o.books)==null?void 0:d.length)!=null?u:0)>0||((p=(h=o.manga)==null?void 0:h.length)!=null?p:0)>0||((f=(m=o.bookColumns)==null?void 0:m.length)!=null?f:0)>0||((v=(y=o.mangaColumns)==null?void 0:y.length)!=null?v:0)>0,T=!!t.reading&&(((b=(w=t.reading.books)==null?void 0:w.length)!=null?b:0)>0||((D=(E=t.reading.manga)==null?void 0:E.length)!=null?D:0)>0);(S||!T)&&(t.reading=o)}if(l&&c){let S=Array.isArray(t.history)&&t.history.length>0;(c.length>0||!S)&&(t.history=c)}r&&l&&(t.migratedReadingHistory=!0),await this.dataManager.persist()}openWidgetPalette(t){let e=[{name:"wl-todo \u2014 Track a title (full)",id:"wl-todo"},{name:"wl-todo mini \u2014 Track a title (compact)",id:"wl-todo:mini"},{name:"wl-stat: watched \u2014 Time watched (mini)",id:"wl-stat:watched"},{name:"wl-stat: completed \u2014 Completed titles (mini)",id:"wl-stat:completed"},{name:"wl-stat: remaining \u2014 Time remaining (mini)",id:"wl-stat:remaining"},{name:"wl-stat: time \u2014 Watched + remaining (mini)",id:"wl-stat:time"},{name:"wl-upcoming: next \u2014 Next upcoming (mini)",id:"wl-upcoming:next"},{name:"wl-stat: time completed full \u2014 Time \xB7 Remaining \xB7 Completed card",id:"wl-stat:time completed full"},{name:"wl-now-next \u2014 Now Watching + Up Next card",id:"wl-now-next"}];new ms(this.app,e,s=>{if(s.id==="wl-todo"||s.id==="wl-todo:mini"){let a=this.dataManager.getTitles();if(a.length===0){new Z.Notice("No titles in your watchlog library yet.");return}let n=s.id==="wl-todo:mini";new Le(this.app,a,r=>{n?t.replaceSelection(`\`\`\`wl-todo ${r.title} mini \`\`\``):t.replaceSelection(`\`\`\`wl-todo ${r.title} -\`\`\``)}).open()}else s.id==="wl-stat:watched"?t.replaceSelection("```wl-stat\nwatched\n```"):s.id==="wl-stat:completed"?t.replaceSelection("```wl-stat\ncompleted\n```"):s.id==="wl-stat:remaining"?t.replaceSelection("```wl-stat\nremaining\n```"):s.id==="wl-stat:time"?t.replaceSelection("```wl-stat\ntime\n```"):s.id==="wl-upcoming:next"?t.replaceSelection("```wl-upcoming\nnext\n```"):s.id==="wl-stat:time completed full"?t.replaceSelection("```wl-stat\ntime completed full\n```"):s.id==="wl-now-next"&&t.replaceSelection("```wl-now-next\n```")}).open()}async activateView(t){let{workspace:e}=this.app,s=e.getLeavesOfType(ce);if(s.length>0){let n=s[0];e.revealLeaf(n),t&&n.view instanceof kt&&n.view.setActiveTab(t);return}let a=e.getLeaf("tab");await a.setViewState({type:ce,active:!0}),e.revealLeaf(a),t&&a.view instanceof kt&&a.view.setActiveTab(t)}},Ni=class extends X.FuzzySuggestModal{constructor(i,t,e){super(i),this.items=t,this.onSelect=e,this.setPlaceholder("Select a widget to insert...")}getItems(){return this.items}getItemText(i){return i.name}onChooseItem(i){this.onSelect(i)}}; +\`\`\``)}).open()}else s.id==="wl-stat:watched"?t.replaceSelection("```wl-stat\nwatched\n```"):s.id==="wl-stat:completed"?t.replaceSelection("```wl-stat\ncompleted\n```"):s.id==="wl-stat:remaining"?t.replaceSelection("```wl-stat\nremaining\n```"):s.id==="wl-stat:time"?t.replaceSelection("```wl-stat\ntime\n```"):s.id==="wl-upcoming:next"?t.replaceSelection("```wl-upcoming\nnext\n```"):s.id==="wl-stat:time completed full"?t.replaceSelection("```wl-stat\ntime completed full\n```"):s.id==="wl-now-next"&&t.replaceSelection("```wl-now-next\n```")}).open()}async activateView(t){let{workspace:e}=this.app,s=e.getLeavesOfType(Ce);if(s.length>0){let n=s[0];e.revealLeaf(n),t&&n.view instanceof Ft&&n.view.setActiveTab(t);return}let a=e.getLeaf("tab");await a.setViewState({type:Ce,active:!0}),e.revealLeaf(a),t&&a.view instanceof Ft&&a.view.setActiveTab(t)}},ms=class extends Z.FuzzySuggestModal{constructor(i,t,e){super(i),this.items=t,this.onSelect=e,this.setPlaceholder("Select a widget to insert...")}getItems(){return this.items}getItemText(i){return i.name}onChooseItem(i){this.onSelect(i)}}; diff --git a/manifest.json b/manifest.json index a26b70b..54c2c96 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "watchlog", "name": "WatchLog", - "version": "2.1.0", + "version": "2.2.0", "minAppVersion": "1.7.2", "description": "Track your anime, movies, books, manga and TV shows; with episode tracking, progress stats, upcoming release alerts, and embeddable widgets.", "author": "BogdanS", diff --git a/package.json b/package.json index 5c34294..330b468 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "watchlog-plugin", - "version": "2.1.0", + "version": "2.2.0", "description": "Track your anime, movies, books, manga and TV shows; with episode tracking, progress stats, upcoming release alerts, and embeddable widgets.", "main": "main.js", "type": "module", diff --git a/src/AddFromUrlModal.ts b/src/AddFromUrlModal.ts index 63badb9..35cdfe0 100644 --- a/src/AddFromUrlModal.ts +++ b/src/AddFromUrlModal.ts @@ -87,6 +87,9 @@ export class AddFromUrlModal extends Modal { releaseDate: result.releaseDate, link: result.url, seasons: result.seasons, + trailerUrl: result.trailerUrl ?? '', + director: result.director, + cast: result.cast, }).open(); } finally { if (this.addBtn) { diff --git a/src/AddReadingModal.ts b/src/AddReadingModal.ts index 75137fb..b0e7d46 100644 --- a/src/AddReadingModal.ts +++ b/src/AddReadingModal.ts @@ -3,6 +3,7 @@ import type WatchLogPlugin from './main'; import type { ReadingDataManager } from './ReadingDataManager'; import type { BookSearchResult, MangaSearchResult } from './ApiService'; import { googleBooksErrorMessage } from './ApiService'; +import { renderSearchThumbnail } from './SearchThumbnail'; import { Book, Manga, @@ -333,9 +334,11 @@ export class AddReadingModal extends Modal { } for (const r of results) { const item = this.lookupResultsEl.createDiv({ cls: 'wl-reading-lookup-item' }); - this.renderLookupItemTitle(item, r.title, r.url); + renderSearchThumbnail(item, r.coverUrl, r.title, '📖'); + const text = item.createDiv({ cls: 'wl-reading-lookup-item-text' }); + this.renderLookupItemTitle(text, r.title, r.url); const meta = [r.author || 'Unknown author', r.year ? String(r.year) : ''].filter(Boolean).join(' · '); - item.createDiv({ cls: 'wl-reading-lookup-item-meta', text: meta }); + text.createDiv({ cls: 'wl-reading-lookup-item-meta', text: meta }); item.addEventListener('click', () => this.applyBookResult(r)); } } @@ -363,9 +366,11 @@ export class AddReadingModal extends Modal { } for (const r of results) { const item = this.lookupResultsEl.createDiv({ cls: 'wl-reading-lookup-item' }); - this.renderLookupItemTitle(item, r.title, r.url); + renderSearchThumbnail(item, r.coverUrl, r.title, '📓'); + const text = item.createDiv({ cls: 'wl-reading-lookup-item-text' }); + this.renderLookupItemTitle(text, r.title, r.url); const meta = [r.author || 'Unknown author', r.year ? String(r.year) : ''].filter(Boolean).join(' · '); - item.createDiv({ cls: 'wl-reading-lookup-item-meta', text: meta }); + text.createDiv({ cls: 'wl-reading-lookup-item-meta', text: meta }); item.addEventListener('click', () => this.applyMangaResult(r)); } } diff --git a/src/AddTitleModal.ts b/src/AddTitleModal.ts index 556fdb3..2aeae7f 100644 --- a/src/AddTitleModal.ts +++ b/src/AddTitleModal.ts @@ -9,6 +9,7 @@ import type { Season, } from './types'; import { formatDateDisplay, parseDateInput, parseReleaseDateInput, getApiGroupForType } from './types'; +import { renderSearchThumbnail } from './SearchThumbnail'; type SearchResult = AnimeSearchResult | MediaSearchResult; @@ -42,6 +43,11 @@ export class AddTitleModal extends Modal { private fieldDateStarted = ''; private fieldMalId: number | null = null; private fieldAnilistId: number | null = null; + // Trailer resolved at selection ('' unfetched, 'none' source w/o trailer, or URL). + private fieldTrailerUrl = ''; + // Credits resolved at selection ([] unfetched, ['none'] unavailable, or names). + private fieldDirector: string[] = []; + private fieldCast: string[] = []; private skipDuplicateCheck = false; private duplicateWarningEl: HTMLElement | null = null; @@ -68,12 +74,18 @@ export class AddTitleModal extends Modal { releaseDate: string; link: string; seasons: Season[]; + trailerUrl?: string; + director?: string[]; + cast?: string[]; }, ) { super(app); this.plugin = plugin; this.dataManager = dataManager; this.onAdded = onAdded; + // Preselect the resolved default type; a prefill type (e.g. from a URL + // detection) takes precedence and overrides it below. + this.selectedType = this.plugin.resolveDefaultAddType() || this.selectedType; if (prefill) { this.selectedType = prefill.type; if (prefill.title) { @@ -88,6 +100,9 @@ export class AddTitleModal extends Modal { this.fieldReleaseDate = prefill.releaseDate; this.fieldLink = prefill.link; this.fieldSeasons = prefill.seasons; + if (prefill.trailerUrl !== undefined) this.fieldTrailerUrl = prefill.trailerUrl; + if (prefill.director !== undefined) this.fieldDirector = prefill.director; + if (prefill.cast !== undefined) this.fieldCast = prefill.cast; } } @@ -210,12 +225,14 @@ export class AddTitleModal extends Modal { if (this.searchResults.length === 0) return; this.searchResults.forEach((result, idx) => { - const item = this.resultsEl!.createDiv({ cls: 'wl-result-item' }); + const item = this.resultsEl!.createDiv({ cls: 'wl-result-item wl-has-thumb' }); + renderSearchThumbnail(item, result.posterUrl, result.title, '🎬'); + const text = item.createDiv({ cls: 'wl-result-text' }); const epText = isAnimeResult(result) ? `${result.episodes} eps` : result.episodes > 0 ? `${result.episodes} eps` : result.mediaType; - item.createDiv({ cls: 'wl-result-title', text: result.title }); - item.createDiv({ cls: 'wl-result-meta', text: `${epText} · ${result.releaseDate}` }); + text.createDiv({ cls: 'wl-result-title', text: result.title }); + text.createDiv({ cls: 'wl-result-meta', text: `${epText} · ${result.releaseDate}` }); item.dataset['idx'] = String(idx); item.addEventListener('click', () => void this.selectResult(result, item)); }); @@ -245,6 +262,9 @@ export class AddTitleModal extends Modal { this.fieldReleaseDate = full.releaseDate; this.fieldLink = full.url; this.fieldSeasons = full.seasons; + this.fieldTrailerUrl = full.trailerUrl ?? ''; + this.fieldDirector = full.director ?? []; + this.fieldCast = full.cast ?? []; } } else if (!isAnimeResult(result) && result.mediaType === 'movie') { const full = activeApi === 'TMDB' @@ -258,6 +278,9 @@ export class AddTitleModal extends Modal { this.fieldReleaseDate = full.releaseDate; this.fieldLink = full.url; this.fieldSeasons = full.seasons; + this.fieldTrailerUrl = full.trailerUrl ?? ''; + this.fieldDirector = full.director ?? []; + this.fieldCast = full.cast ?? []; } } else { const anime = result as AnimeSearchResult; @@ -267,6 +290,10 @@ export class AddTitleModal extends Modal { this.fieldReleaseDate = anime.releaseDate; this.fieldLink = anime.url; this.fieldSeasons = anime.seasons; + this.fieldTrailerUrl = anime.trailerUrl ?? ''; + // Anime sources don't carry credits — clear any stale movie/TV selection. + this.fieldDirector = []; + this.fieldCast = []; if (anime.anilistId && anime.anilistId > 0) { this.fieldAnilistId = anime.anilistId; this.fieldMalId = null; @@ -282,6 +309,10 @@ export class AddTitleModal extends Modal { this.fieldReleaseDate = result.releaseDate; this.fieldLink = result.url; this.fieldSeasons = result.seasons; + // Anime search results already carry a trailer; movie/TV list rows do not. + this.fieldTrailerUrl = result.trailerUrl ?? ''; + this.fieldDirector = !isAnimeResult(result) ? (result.director ?? []) : []; + this.fieldCast = !isAnimeResult(result) ? (result.cast ?? []) : []; } this.renderForm(); @@ -297,6 +328,17 @@ export class AddTitleModal extends Modal { return row; }; + // A paired-row cell: [label][fixed-width input]. The left cell keeps the + // standard label width so its input aligns with the full-width fields; the + // right cell anchors to the row's right edge (see wl-modal-pair-cell-right). + const makeCell = (row: HTMLElement, label: string, right = false): HTMLElement => { + const cell = row.createDiv({ + cls: right ? 'wl-modal-pair-cell wl-modal-pair-cell-right' : 'wl-modal-pair-cell', + }); + cell.createSpan({ cls: 'wl-modal-label', text: label }); + return cell; + }; + // Title const titleRow = makeRow('Title'); const titleInput = titleRow.createEl('input', { @@ -306,19 +348,19 @@ export class AddTitleModal extends Modal { titleInput.value = this.fieldTitle; titleInput.addEventListener('input', () => { this.fieldTitle = titleInput.value; }); - // Episodes - const epsRow = makeRow('Episodes'); - const epsInput = epsRow.createEl('input', { - cls: 'wl-modal-input wl-modal-input-sm', + // Episodes + Ep. duration paired 50/50 on one row to reclaim vertical space. + const epsDurRow = this.formEl.createDiv({ cls: 'wl-modal-row wl-modal-row-pair' }); + const epsCell = makeCell(epsDurRow, 'Episodes'); + const epsInput = epsCell.createEl('input', { + cls: 'wl-modal-input', attr: { type: 'number', min: '0', placeholder: '0' }, }); epsInput.value = String(this.fieldEpisodes); epsInput.addEventListener('input', () => { this.fieldEpisodes = parseInt(epsInput.value) || 0; }); - // Duration - const durRow = makeRow('Ep. duration (min)'); - const durInput = durRow.createEl('input', { - cls: 'wl-modal-input wl-modal-input-sm', + const durCell = makeCell(epsDurRow, 'Ep. duration (min)', true); + const durInput = durCell.createEl('input', { + cls: 'wl-modal-input', attr: { type: 'number', min: '0', placeholder: '24' }, }); durInput.value = String(this.fieldDuration); @@ -361,18 +403,19 @@ export class AddTitleModal extends Modal { linkInput.value = this.fieldLink; linkInput.addEventListener('input', () => { this.fieldLink = linkInput.value; }); - // Status (exclude "To be released" — it is auto-assigned based on releaseDate) - const statusRow = makeRow('Status'); - const statusSelect = statusRow.createEl('select', { cls: 'wl-select' }); + // Status + Priority paired 50/50 on one row to reclaim vertical space. + // (Status excludes "To be released" — it is auto-assigned based on releaseDate.) + const statusPriRow = this.formEl.createDiv({ cls: 'wl-modal-row wl-modal-row-pair' }); + const statusCell = makeCell(statusPriRow, 'Status'); + const statusSelect = statusCell.createEl('select', { cls: 'wl-select' }); for (const s of this.plugin.settings.statuses.filter((s) => s.name !== 'To be released')) { const opt = statusSelect.createEl('option', { text: s.name, value: s.name }); if (s.name === this.fieldStatus) opt.selected = true; } statusSelect.addEventListener('change', () => { this.fieldStatus = statusSelect.value; }); - // Priority - const priRow = makeRow('Priority'); - const priSelect = priRow.createEl('select', { cls: 'wl-select' }); + const priCell = makeCell(statusPriRow, 'Priority', true); + const priSelect = priCell.createEl('select', { cls: 'wl-select' }); for (const p of this.plugin.settings.priorities) { const opt = priSelect.createEl('option', { text: p.name, value: p.name }); if (p.name === this.fieldPriority) opt.selected = true; @@ -511,6 +554,12 @@ export class AddTitleModal extends Modal { externalLink: this.fieldLink, seasons: this.fieldSeasons, watchedEpisodes: [], + posterUrl: '', + trailerUrl: this.fieldTrailerUrl, + manualTrailerUrl: '', + // Empty stays absent (= unfetched) so the detail modal's lazy backfill runs. + ...(this.fieldDirector.length > 0 ? { director: this.fieldDirector } : {}), + ...(this.fieldCast.length > 0 ? { cast: this.fieldCast } : {}), ...(this.fieldMalId !== null ? { malId: this.fieldMalId } : {}), ...(this.fieldAnilistId !== null ? { anilistId: this.fieldAnilistId } : {}), }; @@ -525,6 +574,10 @@ export class AddTitleModal extends Modal { await this.dataManager.addTitle(entry); + // Remember the type that was actually used so "Last type used" can follow it. + this.plugin.settings.lastAddedType = entry.type; + void this.plugin.saveSettings(); + // Fire-and-forget community rating fetch (no await — non-blocking) void (async () => { const animeSource = this.plugin.settings.animeApiSource ?? 'jikan'; diff --git a/src/ApiService.ts b/src/ApiService.ts index 6924142..81d90bd 100644 --- a/src/ApiService.ts +++ b/src/ApiService.ts @@ -12,11 +12,14 @@ import type { TmdbTvDetail, TmdbExternalIds, TmdbFindResult, + TmdbVideo, + TmdbCreditsResult, Season, AniListMedia, AniListSearchResponse, AniListMediaResponse, } from './types'; +import { normalizeCreditsForStore } from './types'; const JIKAN_BASE = 'https://api.jikan.moe/v4'; const OMDB_BASE = 'https://www.omdbapi.com'; @@ -27,6 +30,48 @@ const GOOGLE_BOOKS_BASE = 'https://www.googleapis.com/books/v1'; const JIKAN_RATE_LIMIT_MS = 400; const API_TIMEOUT_MS = 8000; +/** Canonical YouTube watch URL from a raw video id. */ +function youtubeWatchUrl(id: string): string { + return `https://www.youtube.com/watch?v=${id}`; +} + +/** + * Extracts a YouTube video id from any of the shapes providers hand back — + * `watch?v=ID`, `youtu.be/ID`, or `/embed/ID` (Jikan frequently ships only the + * embed URL while leaving youtube_id / url null). Empty string when none match. + */ +function extractYoutubeId(url: string | null | undefined): string { + if (!url) return ''; + const m = url.match(/(?:[?&]v=|\/embed\/|youtu\.be\/)([A-Za-z0-9_-]{6,})/); + return m?.[1] ?? ''; +} + +/** + * Splits an OMDb comma-separated name string ("Director" / "Actors") into a + * normalized stored list: trimmed names capped at MAX_CAST, or ['none'] when + * the field is absent / 'N/A' — so both APIs yield the same shape. + */ +function omdbNamesToCredits(s: string | undefined): string[] { + if (!s || s === 'N/A') return normalizeCreditsForStore([]); + return normalizeCreditsForStore(s.split(',')); +} + +/** + * Maps a TMDB `credits` payload to the stored { director, cast } shape: + * directors from crew entries with the Director job, cast from the (already + * billing-ordered) cast list — both normalized and capped like OMDb's. + */ +function tmdbCreditsToStored(credits: TmdbCreditsResult | undefined): { director: string[]; cast: string[] } { + const director = (credits?.crew ?? []) + .filter((c) => c.job === 'Director' && c.name) + .map((c) => c.name!); + const cast = (credits?.cast ?? []).map((c) => c.name ?? ''); + return { + director: normalizeCreditsForStore(director), + cast: normalizeCreditsForStore(cast), + }; +} + export interface BookSearchResult { title: string; author: string; @@ -266,6 +311,10 @@ export class ApiService { averageScore: media.averageScore ?? undefined, genres: media.genres ?? undefined, posterUrl: media.coverImage?.large ?? media.coverImage?.medium ?? undefined, + trailerUrl: + media.trailer?.site === 'youtube' && media.trailer.id + ? youtubeWatchUrl(media.trailer.id) + : 'none', }; } @@ -287,6 +336,7 @@ export class ApiService { coverImage { large medium } description genres + trailer { id site } } } } @@ -315,6 +365,7 @@ export class ApiService { averageScore popularity coverImage { large } + trailer { id site } nextAiringEpisode { airingAt episode @@ -346,6 +397,16 @@ export class ApiService { } } + /** Resolves a Jikan `trailer` object to a YouTube URL, or 'none' when absent. */ + private jikanTrailerUrl(trailer: JikanAnime['trailer']): string { + if (!trailer) return 'none'; + const id = + (trailer.youtube_id ?? '') || + extractYoutubeId(trailer.url) || + extractYoutubeId(trailer.embed_url); + return id ? youtubeWatchUrl(id) : 'none'; + } + private mapJikanAnime(anime: JikanAnime): AnimeSearchResult { const durationStr = anime.duration ?? '24 min per ep'; const durationMatch = durationStr.match(/(\d+)\s*min/); @@ -361,6 +422,8 @@ export class ApiService { releaseDate: anime.aired?.from ? (anime.aired.from.split('T')[0] ?? '') : '', url: anime.url, seasons, + posterUrl: anime.images?.jpg?.small_image_url ?? anime.images?.jpg?.image_url ?? undefined, + trailerUrl: this.jikanTrailerUrl(anime.trailer), }; } @@ -403,6 +466,9 @@ export class ApiService { releaseDate: this.parseOmdbDate(data.Released ?? data.Year), url: `https://www.imdb.com/title/${data.imdbID}`, seasons: [{ name: 'Movie', episodes: 1, offset: 0 }], + trailerUrl: 'none', // OMDb does not provide trailers. + director: omdbNamesToCredits(data.Director), + cast: omdbNamesToCredits(data.Actors), }; } catch { return null; @@ -437,6 +503,9 @@ export class ApiService { releaseDate: this.parseOmdbDate(data.Released ?? data.Year), url: `https://www.imdb.com/title/${data.imdbID}`, seasons, + trailerUrl: 'none', // OMDb does not provide trailers. + director: omdbNamesToCredits(data.Director), + cast: omdbNamesToCredits(data.Actors), }; } catch { return null; @@ -479,6 +548,17 @@ export class ApiService { } } + /** Detail lookup for a single anime's trailer (Jikan /anime/{mal_id}). Returns a URL or 'none'. */ + async getJikanTrailerByMalId(malId: number): Promise { + try { + const url = `${JIKAN_BASE}/anime/${malId}`; + const data = (await this.throttleJikan(() => this.fetchWithTimeout(url))) as { data?: JikanAnime }; + return this.jikanTrailerUrl(data.data?.trailer); + } catch { + return 'none'; + } + } + /** * Converts OMDb "DD Mon YYYY" dates (e.g. "08 Feb 2026") to YYYY-MM-DD. * Returns the input unchanged if it doesn't match that pattern (e.g. year-only "2026"). @@ -527,17 +607,34 @@ export class ApiService { releaseDate: item.release_date ?? item.first_air_date ?? '', url: '', seasons: [], + posterUrl: item.poster_path ? `https://image.tmdb.org/t/p/w92${item.poster_path}` : undefined, })); } catch { return []; } } + /** + * Picks the best trailer from a TMDB `videos.results` list: an official YouTube + * Trailer first, then any YouTube Trailer, then any YouTube Teaser. Returns a + * YouTube watch URL, or 'none' when nothing suitable exists. + */ + private pickTmdbTrailer(videos: TmdbVideo[] | undefined): string { + const yt = (videos ?? []).filter((v) => v.site === 'YouTube' && v.key); + const pick = + yt.find((v) => v.type === 'Trailer' && v.official === true) ?? + yt.find((v) => v.type === 'Trailer') ?? + yt.find((v) => v.type === 'Teaser'); + return pick ? youtubeWatchUrl(pick.key) : 'none'; + } + async getTmdbMovieDetails(tmdbId: string): Promise { if (!this.tmdbApiKey) return null; try { + // append_to_response=videos,credits folds the trailer + director/cast + // lookups into the detail call (no extra round-trips). const [detailData, extData] = await Promise.all([ - this.fetchWithTimeout(`${TMDB_BASE}/movie/${tmdbId}`, this.tmdbHeaders()), + this.fetchWithTimeout(`${TMDB_BASE}/movie/${tmdbId}?append_to_response=videos,credits`, this.tmdbHeaders()), this.fetchWithTimeout(`${TMDB_BASE}/movie/${tmdbId}/external_ids`, this.tmdbHeaders()), ]); const detail = detailData as TmdbMovieDetail; @@ -552,6 +649,8 @@ export class ApiService { releaseDate: detail.release_date ?? '', url: imdbId ? `https://www.imdb.com/title/${imdbId}` : '', seasons: [{ name: 'Movie', episodes: 1, offset: 0 }], + trailerUrl: this.pickTmdbTrailer(detail.videos?.results), + ...tmdbCreditsToStored(detail.credits), }; } catch { return null; @@ -562,7 +661,7 @@ export class ApiService { if (!this.tmdbApiKey) return null; try { const [detailData, extData] = await Promise.all([ - this.fetchWithTimeout(`${TMDB_BASE}/tv/${tmdbId}`, this.tmdbHeaders()), + this.fetchWithTimeout(`${TMDB_BASE}/tv/${tmdbId}?append_to_response=videos,credits`, this.tmdbHeaders()), this.fetchWithTimeout(`${TMDB_BASE}/tv/${tmdbId}/external_ids`, this.tmdbHeaders()), ]); const detail = detailData as TmdbTvDetail; @@ -587,6 +686,8 @@ export class ApiService { releaseDate: detail.first_air_date ?? '', url: imdbId ? `https://www.imdb.com/title/${imdbId}` : '', seasons, + trailerUrl: this.pickTmdbTrailer(detail.videos?.results), + ...tmdbCreditsToStored(detail.credits), }; } catch { return null; @@ -754,6 +855,111 @@ export class ApiService { return null; } + /** + * Re-fetches the trailer for an existing title from its source, reusing the same + * paths as add-time: AniList/Jikan for anime (honouring `animeApiSource`, falling + * back to the other ID), TMDB-by-IMDb for movies/TV. OMDb (and anything else) + * yields 'none'. Returns a YouTube watch URL or the sentinel 'none'. + */ + async fetchTrailer( + title: WatchLogTitle, + animeApiSource: 'jikan' | 'anilist' = 'jikan', + apiGroup: 'anime' | 'movie' | '' = '', + ): Promise { + const resolvedGroup: 'anime' | 'movie' | '' = + apiGroup || (title.type === 'Anime' ? 'anime' : title.type === 'Movie' || title.type === 'TV Show' || title.type === 'TvShow' ? 'movie' : ''); + + if (resolvedGroup === 'anime') { + const hasMal = (title.malId ?? 0) > 0; + const hasAniList = (title.anilistId ?? 0) > 0; + const tryAniList = async (): Promise => { + if (!hasAniList) return 'none'; + const media = await this.getAniListById(title.anilistId!); + return media?.trailer?.site === 'youtube' && media.trailer.id + ? youtubeWatchUrl(media.trailer.id) + : 'none'; + }; + const tryJikan = async (): Promise => { + if (!hasMal) return 'none'; + return this.getJikanTrailerByMalId(title.malId!); + }; + const order = animeApiSource === 'anilist' ? [tryAniList, tryJikan] : [tryJikan, tryAniList]; + for (const attempt of order) { + const url = await attempt(); + if (url && url !== 'none') return url; + } + return 'none'; + } + + if (resolvedGroup === 'movie') { + const imdbId = this.extractImdbId(title.externalLink ?? ''); + // Only TMDB carries trailers; OMDb never does. + if (imdbId && this.tmdbApiKey) { + const full = await this.getTmdbByImdbId(imdbId); + if (full?.trailerUrl && full.trailerUrl !== 'none') return full.trailerUrl; + } + return 'none'; + } + + return 'none'; + } + + /** + * One-time director/cast backfill for an existing title, keyed off the IMDb id + * in its stored externalLink. Prefers the active API, falls back to the other + * one when it has a key. Returns normalized stored lists (names or ['none']), + * or null when there is no usable id / no keyed API / the requests failed — + * the caller marks the fields 'none' in that case so it never re-attempts. + */ + async fetchCredits( + title: WatchLogTitle, + activeApi: 'OMDb' | 'TMDB' = 'OMDb', + ): Promise<{ director: string[]; cast: string[] } | null> { + const imdbId = this.extractImdbId(title.externalLink ?? ''); + if (!imdbId) return null; + + // OMDb: Director/Actors ride in the plain detail response — one cheap call + // (deliberately NOT getOmdbTvDetails, which fans out per-season requests). + const tryOmdb = async (): Promise<{ director: string[]; cast: string[] } | null> => { + if (!this.omdbApiKey) return null; + try { + const url = `${OMDB_BASE}/?i=${encodeURIComponent(imdbId)}&apikey=${encodeURIComponent(this.omdbApiKey)}`; + const data = (await this.fetchWithTimeout(url)) as OmdbDetailResponse; + if (data.Response === 'False' || !data.imdbID) return null; + return { + director: omdbNamesToCredits(data.Director), + cast: omdbNamesToCredits(data.Actors), + }; + } catch { + return null; + } + }; + + // TMDB: resolve the IMDb id via /find, then hit the lean /credits endpoint. + const tryTmdb = async (): Promise<{ director: string[]; cast: string[] } | null> => { + if (!this.tmdbApiKey) return null; + try { + const findUrl = `${TMDB_BASE}/find/${encodeURIComponent(imdbId)}?external_source=imdb_id`; + const found = (await this.fetchWithTimeout(findUrl, this.tmdbHeaders())) as TmdbFindResult; + const movieId = found.movie_results?.[0]?.id; + const tvId = found.tv_results?.[0]?.id; + const path = movieId !== undefined ? `movie/${movieId}` : tvId !== undefined ? `tv/${tvId}` : null; + if (!path) return null; + const credits = (await this.fetchWithTimeout(`${TMDB_BASE}/${path}/credits`, this.tmdbHeaders())) as TmdbCreditsResult; + return tmdbCreditsToStored(credits); + } catch { + return null; + } + }; + + const order = activeApi === 'TMDB' ? [tryTmdb, tryOmdb] : [tryOmdb, tryTmdb]; + for (const attempt of order) { + const result = await attempt(); + if (result) return result; + } + return null; + } + // ─── Google Books (Books) ───────────────────────────────────────────────────── /** diff --git a/src/ColorPicker.ts b/src/ColorPicker.ts new file mode 100644 index 0000000..bc5f633 --- /dev/null +++ b/src/ColorPicker.ts @@ -0,0 +1,169 @@ +import { FIELD_COLORS, DEFAULT_FIELD_COLOR } from './types'; + +// ───────────────────────────────────────────────────────────────────────────── +// ColorPicker — shared swatch-picker UI + fill/border colour derivation. +// +// The Reading subsystem historically stored a colour as the "600 stop" hex and +// looked up a paired "50 stop" light tint from a hardcoded table. That only +// worked for the 8 presets. These helpers derive the fill/border variants from +// ANY hex (so custom colours render correctly) while keeping the exact preset +// tints for the 8 built-ins — behaviour for presets is unchanged. +// ───────────────────────────────────────────────────────────────────────────── + +/** Normalize hex input to lowercase `#rrggbb`, expanding `#rgb`. Returns the + * default field colour for anything unparseable. */ +function normalizeHex(input: string): string { + const hex = (input ?? '').trim().toLowerCase(); + const short = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/.exec(hex); + if (short) return `#${short[1]}${short[1]}${short[2]}${short[2]}${short[3]}${short[3]}`; + if (/^#[0-9a-f]{6}$/.test(hex)) return hex; + return DEFAULT_FIELD_COLOR.toLowerCase(); +} + +function hexToRgb(hex: string): { r: number; g: number; b: number } { + const n = normalizeHex(hex); + return { + r: parseInt(n.slice(1, 3), 16), + g: parseInt(n.slice(3, 5), 16), + b: parseInt(n.slice(5, 7), 16), + }; +} + +function toHexComponent(v: number): string { + return Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, '0'); +} + +/** Mix a colour toward white. `amount` is the fraction of the colour kept. */ +function mixWithWhite(hex: string, amount: number): string { + const { r, g, b } = hexToRgb(hex); + const mix = (c: number): number => 255 * (1 - amount) + c * amount; + return `#${toHexComponent(mix(r))}${toHexComponent(mix(g))}${toHexComponent(mix(b))}`; +} + +/** + * Light fill tint for a given colour. For the 8 presets this returns the exact + * authored `color50` so existing fields render identically; for any other hex + * it derives a light tint programmatically. + */ +export function deriveFillColor(color: string): string { + const norm = normalizeHex(color); + for (const { color600, color50 } of FIELD_COLORS) { + if (normalizeHex(color600) === norm) return color50; + } + return mixWithWhite(norm, 0.12); +} + +/** + * Border / strong-accent colour for a given colour. This is the colour itself + * (the historical "600 stop"), normalized so it works for arbitrary hex input. + */ +export function deriveBorderColor(color: string): string { + return normalizeHex(color); +} + +export interface ColorPickerOptions { + /** Element the palette is positioned beneath. */ + anchor: HTMLElement; + /** Element the palette is appended to (positioned `fixed`, so any container works). */ + container: HTMLElement; + /** Currently selected colour. */ + current: string; + /** When true, offer a full-spectrum custom-colour swatch in addition to the 8 presets. */ + allowCustom: boolean; + /** Called with the chosen colour (a `#rrggbb` hex), or `null` when the user + * picks the clear/"no colour" swatch (consumer should revert to its unset state). */ + onPick: (color: string | null) => void; +} + +/** + * Opens the shared colour-swatch picker — the 8 presets plus, when enabled, a + * custom full-spectrum swatch (native colour input / hex). Matches the visual + * style of the original Reading swatch palette. + */ +export function openColorPicker(opts: ColorPickerOptions): void { + const { anchor, container, current, allowCustom, onPick } = opts; + + // Remove any palette already open in this container. + container.querySelectorAll('.wl-reading-col-palette').forEach((el) => el.remove()); + + const rect = anchor.getBoundingClientRect(); + const palette = container.createDiv({ cls: 'wl-reading-col-palette' }); + palette.style.top = `${rect.bottom + 4}px`; + palette.style.left = `${rect.left}px`; + // Capture the owning document once so add/remove can't desync across popout windows. + const doc = container.ownerDocument; + const normCurrent = normalizeHex(current); + + const close = (e: MouseEvent): void => { + if (!palette.contains(e.target as Node) && e.target !== anchor) { + palette.remove(); + doc.removeEventListener('mousedown', close, true); + } + }; + const dismiss = (): void => { + palette.remove(); + doc.removeEventListener('mousedown', close, true); + }; + + let matchedPreset = false; + for (const { color600, color50 } of FIELD_COLORS) { + const swatch = palette.createEl('button', { cls: 'wl-reading-col-palette-swatch' }); + swatch.style.backgroundColor = color50; + swatch.style.borderColor = color600; + if (normalizeHex(color600) === normCurrent) { + swatch.addClass('is-active'); + matchedPreset = true; + } + swatch.title = color600; + swatch.addEventListener('click', (e) => { + e.stopPropagation(); + dismiss(); + onPick(color600); + }); + } + + if (allowCustom) { + const customSwatch = palette.createEl('button', { + cls: 'wl-reading-col-palette-swatch wl-color-custom-swatch', + }); + customSwatch.title = 'Custom color…'; + if (matchedPreset) { + // Current colour is a preset: present the custom swatch as a rainbow invite. + customSwatch.addClass('wl-color-custom-rainbow'); + } else { + // Current colour is custom: show it, marked active. + customSwatch.addClass('is-active'); + customSwatch.style.backgroundColor = deriveFillColor(normCurrent); + customSwatch.style.borderColor = deriveBorderColor(normCurrent); + } + + const colorInput = customSwatch.createEl('input', { + cls: 'wl-color-custom-input', + attr: { type: 'color' }, + }); + colorInput.value = normCurrent; + customSwatch.addEventListener('click', (e) => { + e.stopPropagation(); + colorInput.click(); + }); + colorInput.addEventListener('change', (e) => { + e.stopPropagation(); + const picked = normalizeHex(colorInput.value); + dismiss(); + onPick(picked); + }); + } + + // Clear / "no colour" swatch — reverts the consumer to its default appearance. + const clearSwatch = palette.createEl('button', { + cls: 'wl-reading-col-palette-swatch wl-color-clear-swatch', + }); + clearSwatch.title = 'No color (reset to default)'; + clearSwatch.addEventListener('click', (e) => { + e.stopPropagation(); + dismiss(); + onPick(null); + }); + + window.setTimeout(() => doc.addEventListener('mousedown', close, true), 0); +} diff --git a/src/CustomListsTab.ts b/src/CustomListsTab.ts index cf4b90e..80eeb80 100644 --- a/src/CustomListsTab.ts +++ b/src/CustomListsTab.ts @@ -1,8 +1,16 @@ -import { App, Component, MarkdownRenderer, Modal, Notice, TFile, normalizePath, Setting } from 'obsidian'; +import { App, Component, MarkdownRenderer, Modal, Notice, Platform, TFile, normalizePath, Setting } from 'obsidian'; import type WatchLogPlugin from './main'; import type { DataManager } from './DataManager'; import type { CustomListColumn, CustomListRow, CustomList } from './types'; +import { DEFAULT_FIELD_COLOR } from './types'; import { ConfirmModal } from './ConfirmModal'; +import { openColorPicker, deriveFillColor, deriveBorderColor } from './ColorPicker'; +import { openStatusDropdown } from './StatusDropdown'; + +/** Minimum width (px) a resizable column can be dragged to. */ +const MIN_COL_WIDTH = 60; +/** Fallback width (px) for a resizable column that has no explicit width in resizable mode. */ +const DEFAULT_COL_WIDTH = 140; // ───────────────────────────────────────────────────────────────────────────── // CustomListManager — vault I/O @@ -63,6 +71,17 @@ export class CustomListManager { } } + /** Reads each named list and returns a `name → tabColor` map for tab rendering. + * Lists without a colour (or that fail to load) are simply omitted. */ + async loadTabColors(names: string[]): Promise> { + const out = new Map(); + await Promise.all(names.map(async (name) => { + const list = await this.loadList(name); + if (list?.tabColor) out.set(name, list.tabColor); + })); + return out; + } + private parse(name: string, content: string): CustomList | null { const notesMatch = content.match(/## Notes\n([\s\S]*?)(?=\n## |\s*$)/); const notes = (notesMatch?.[1] ?? '').trim(); @@ -70,10 +89,14 @@ export class CustomListManager { const dataMatch = content.match(/## Data\n```json\n([\s\S]*?)\n```/); let columns: CustomListColumn[] = []; let rows: CustomListRow[] = []; + let tabColor: string | undefined; + let nameWidth: number | undefined; if (dataMatch?.[1]) { try { - const p = JSON.parse(dataMatch[1]) as { columns?: unknown; rows?: unknown }; + const p = JSON.parse(dataMatch[1]) as { columns?: unknown; rows?: unknown; tabColor?: unknown; nameWidth?: unknown }; + if (typeof p.tabColor === 'string') tabColor = p.tabColor; + if (typeof p.nameWidth === 'number') nameWidth = p.nameWidth; if (Array.isArray(p.columns)) { columns = (p.columns as unknown[]).filter((c): c is CustomListColumn => typeof c === 'object' && c !== null && @@ -93,7 +116,7 @@ export class CustomListManager { } } - return { name, columns, rows, notes }; + return { name, columns, rows, notes, tabColor, nameWidth }; } async saveList(list: CustomList): Promise { @@ -143,7 +166,11 @@ export class CustomListManager { } private serialize(list: CustomList): string { - const json = JSON.stringify({ columns: list.columns, rows: list.rows }, null, 2); + const json = JSON.stringify( + { columns: list.columns, rows: list.rows, tabColor: list.tabColor, nameWidth: list.nameWidth }, + null, + 2, + ); return `# ${list.name}\n\n## Notes\n${list.notes}\n\n## Data\n\`\`\`json\n${json}\n\`\`\`\n`; } @@ -179,6 +206,21 @@ export class CustomListManager { } } +/** Aligns a column's option-colour map with its (trimmed) options on save: + * drops colours for removed options and clears the map for non-select columns. */ +function normalizeOptionColors(col: CustomListColumn): void { + if (col.type !== 'select') { delete col.optionColors; return; } + if (!col.optionColors) return; + const opts = new Set(col.options ?? []); + const cleaned: Record = {}; + for (const [k, v] of Object.entries(col.optionColors)) { + const tk = k.trim(); + if (opts.has(tk)) cleaned[tk] = v; + } + if (Object.keys(cleaned).length) col.optionColors = cleaned; + else delete col.optionColors; +} + // ───────────────────────────────────────────────────────────────────────────── // Shared column list renderer (used by EditColumnsModal & DefaultColumnsModal) // ───────────────────────────────────────────────────────────────────────────── @@ -192,6 +234,7 @@ function renderColumnList( onDelete: (idx: number) => void, onTypeChange: () => void, onAdd?: () => void, + onOptionRename?: (colId: string, oldVal: string, newVal: string) => void, ): void { listEl.empty(); listEl.addClass('wl-editcol-card-grid'); @@ -253,7 +296,26 @@ function renderColumnList( if (col.type === t) opt.selected = true; } typeSelect.addEventListener('change', () => { - col.type = typeSelect.value as CustomListColumn['type']; + const newType = typeSelect.value as CustomListColumn['type']; + if (newType === 'select') { + // Rebuild the option list from the distinct non-empty values already + // present in this column's cells, in order of first appearance. This + // replaces any previously-stored options (so stale/orphaned options + // don't resurrect) and leaves the cell values themselves untouched — + // after the switch every populated cell holds a valid option. + const seen = new Set(); + const derived: string[] = []; + for (const row of existingRows) { + const raw = (row as Record)[col.id]; + if (typeof raw !== 'string' && typeof raw !== 'number') continue; + const val = String(raw).trim(); + if (!val || seen.has(val)) continue; + seen.add(val); + derived.push(val); + } + col.options = derived; + } + col.type = newType; onTypeChange(); }); @@ -317,20 +379,78 @@ function renderColumnList( optsArea.empty(); (col.options ?? []).forEach((opt, oi) => { const optRow = optsArea.createDiv({ cls: 'wl-editcol-card-opt-row' }); + + // Per-option colour dot — reuses the shared picker + derivation helpers. + const colorDot = optRow.createEl('button', { + cls: 'wl-reading-col-color-dot wl-editcol-opt-color-dot', + }); + colorDot.title = 'Option color'; + const syncDot = (): void => { + const c = col.optionColors?.[col.options?.[oi] ?? '']; + if (c) { + colorDot.removeClass('is-unset'); + colorDot.setCssProps({ 'background-color': deriveFillColor(c), 'border-color': deriveBorderColor(c) }); + } else { + colorDot.addClass('is-unset'); + colorDot.setCssProps({ 'background-color': '', 'border-color': '' }); + } + }; + syncDot(); + colorDot.addEventListener('click', (e) => { + e.stopPropagation(); + const key = col.options?.[oi] ?? ''; + if (!key) return; // can't colour a blank option + openColorPicker({ + anchor: colorDot, + container: listEl, + current: col.optionColors?.[key] ?? DEFAULT_FIELD_COLOR, + allowCustom: true, + onPick: (color) => { + if (color === null) { + if (col.optionColors) delete col.optionColors[key]; + } else { + if (!col.optionColors) col.optionColors = {}; + col.optionColors[key] = color; + } + syncDot(); + }, + }); + }); + const optInput = optRow.createEl('input', { cls: 'wl-modal-input wl-editcol-card-opt-input', attr: { type: 'text', value: opt, placeholder: 'Option' }, }); + let prevVal = opt; optInput.addEventListener('input', () => { if (!col.options) col.options = []; - col.options[oi] = optInput.value; + const nextVal = optInput.value; + if (nextVal !== prevVal) { + // Keep any assigned colour attached to the renamed value. + if (col.optionColors) { + const moved = col.optionColors[prevVal]; + if (moved !== undefined) { + if (nextVal) col.optionColors[nextVal] = moved; + delete col.optionColors[prevVal]; + } + } + // Record the rename so row cells can be migrated at save time. + onOptionRename?.(col.id, prevVal, nextVal); + } + col.options[oi] = nextVal; + prevVal = nextVal; }); const delOpt = optRow.createEl('button', { cls: 'wl-btn wl-btn-sm wl-editcol-card-opt-del', text: '×', attr: { title: 'Remove this option' }, }); - delOpt.addEventListener('click', () => { col.options?.splice(oi, 1); renderOpts(); }); + delOpt.addEventListener('click', () => { + const key = col.options?.[oi]; + col.options?.splice(oi, 1); + if (key && col.optionColors) delete col.optionColors[key]; + renderOpts(); + }); }); const addOpt = optsArea.createEl('button', { cls: 'wl-btn wl-btn-sm wl-editcol-card-opt-add', @@ -363,7 +483,11 @@ export class EditColumnsModal extends Modal { private manager: CustomListManager; private onSave: (columns: CustomListColumn[]) => Promise; private cols: CustomListColumn[]; + private tabColor: string | undefined; private listEl!: HTMLElement; + // colId → (original option value → latest value). Applied to row cells on Save + // only — never live, so a Cancel can't leak a rename into a later cell-edit save. + private optionRenames: Map> = new Map(); constructor( app: App, @@ -375,14 +499,19 @@ export class EditColumnsModal extends Modal { this.list = list; this.manager = manager; this.onSave = onSave; + this.tabColor = list.tabColor; this.cols = list.columns .filter(c => !c.locked) - .map(c => ({ ...c, options: c.options ? [...c.options] : undefined })); + .map(c => ({ + ...c, + options: c.options ? [...c.options] : undefined, + optionColors: c.optionColors ? { ...c.optionColors } : undefined, + })); } onOpen(): void { this.modalEl.addClass('wl-editcol-modal'); - this.titleEl.setText(`Edit Columns — ${this.list.name}`); + this.titleEl.setText(`Table settings — ${this.list.name}`); this.contentEl.addClass('wl-editcols-modal'); this.renderBody(); } @@ -391,6 +520,8 @@ export class EditColumnsModal extends Modal { this.contentEl.empty(); this.contentEl.addClass('wl-editcols-modal'); + this.renderTabColorRow(this.contentEl); + this.listEl = this.contentEl.createDiv({ cls: 'wl-editcols-list' }); this.renderCols(); @@ -401,6 +532,37 @@ export class EditColumnsModal extends Modal { saveBtn.addEventListener('click', () => void this.handleSave()); } + private renderTabColorRow(parent: HTMLElement): void { + const row = parent.createDiv({ cls: 'wl-editcols-tabcolor-row' }); + row.createSpan({ cls: 'wl-editcols-tabcolor-label', text: 'Tab color' }); + + const dot = row.createEl('button', { cls: 'wl-reading-col-color-dot wl-editcols-tabcolor-dot' }); + + const sync = (): void => { + if (this.tabColor) { + dot.removeClass('is-unset'); + dot.setCssProps({ 'background-color': this.tabColor }); + } else { + dot.addClass('is-unset'); + dot.setCssProps({ 'background-color': '' }); + } + }; + sync(); + + dot.title = 'Choose tab color'; + dot.addEventListener('click', (e) => { + e.stopPropagation(); + openColorPicker({ + anchor: dot, + container: this.contentEl, + current: this.tabColor ?? DEFAULT_FIELD_COLOR, + allowCustom: true, + // Clear swatch → null → revert to the default (uncoloured) tab name. + onPick: (color) => { this.tabColor = color ?? undefined; sync(); }, + }); + }); + } + private renderCols(): void { renderColumnList( this.listEl, @@ -424,9 +586,38 @@ export class EditColumnsModal extends Modal { }); this.renderBody(); }, + (colId, oldVal, newVal) => this.recordOptionRename(colId, oldVal, newVal), ); } + /** Accumulates a net (original → latest) rename per option, composing + * incremental keystrokes so "A"→"Ap"→"Apple" collapses to "A"→"Apple". */ + private recordOptionRename(colId: string, oldVal: string, newVal: string): void { + let m = this.optionRenames.get(colId); + if (!m) { m = new Map(); this.optionRenames.set(colId, m); } + // If some original already maps to oldVal, extend that chain; else start fresh. + let origKey: string | null = null; + for (const [orig, cur] of m) { if (cur === oldVal) { origKey = orig; break; } } + m.set(origKey ?? oldVal, newVal); + } + + /** Migrates row cells from each original option value to its final value. + * Only exact matches in the renamed column are touched; orphan values that + * were never an option, and options created fresh this session (orig ''), + * are left alone. */ + private applyOptionRenamesToRows(): void { + for (const [colId, m] of this.optionRenames) { + for (const [orig, final] of m) { + if (orig === '' || orig === final) continue; + for (const r of this.list.rows) { + if ((r as Record)[colId] === orig) { + (r as Record)[colId] = final; + } + } + } + } + } + private handleSave(): void { for (const col of this.cols) { if (!col.label.trim()) { new Notice('Column names cannot be empty.'); return; } @@ -438,7 +629,10 @@ export class EditColumnsModal extends Modal { for (const col of this.cols) { col.label = col.label.trim(); if (col.options) col.options = col.options.map(o => o.trim()).filter(o => o); + normalizeOptionColors(col); } + this.applyOptionRenamesToRows(); + this.list.tabColor = this.tabColor; void this.onSave(this.cols).then(() => this.close()); } } @@ -458,7 +652,11 @@ export class DefaultColumnsModal extends Modal { this.plugin = plugin; this.manager = new CustomListManager(app, plugin); this.cols = (plugin.settings.defaultCustomColumns ?? []) - .map(c => ({ ...c, options: c.options ? [...c.options] : undefined })); + .map(c => ({ + ...c, + options: c.options ? [...c.options] : undefined, + optionColors: c.optionColors ? { ...c.optionColors } : undefined, + })); } onOpen(): void { @@ -524,6 +722,7 @@ export class DefaultColumnsModal extends Modal { for (const col of this.cols) { col.label = col.label.trim(); if (col.options) col.options = col.options.map(o => o.trim()).filter(o => o); + normalizeOptionColors(col); } this.plugin.settings.defaultCustomColumns = this.cols; await this.plugin.saveSettings(); @@ -772,9 +971,11 @@ export class CustomListsTab { this.currentList = await this.manager.loadList(this.activeListName); } + const tabColors = await this.manager.loadTabColors(this.listNames); + if (gen !== this.renderGeneration) return; // stale render this.container.empty(); - this.buildSubTabs(); + this.buildSubTabs(tabColors); if (this.currentList) { this.buildListView(this.currentList); @@ -788,7 +989,7 @@ export class CustomListsTab { btn.addEventListener('click', () => this.promptCreateList()); } - private buildSubTabs(): void { + private buildSubTabs(tabColors: Map): void { const tabBar = this.container.createDiv({ cls: 'wl-cl-sub-tabs' }); let dragFromName: string | null = null; @@ -799,6 +1000,8 @@ export class CustomListsTab { tab.setAttribute('draggable', 'true'); const nameSpan = tab.createSpan({ cls: 'wl-cl-sub-tab-name', text: name }); + const tabColor = tabColors.get(name); + if (tabColor) nameSpan.style.color = tabColor; nameSpan.addEventListener('dblclick', (e) => { e.stopPropagation(); this.startRenameTab(tab, nameSpan, name); @@ -878,7 +1081,12 @@ export class CustomListsTab { private promptCreateList(): void { new ListNameModal(this.plugin.app, this.listNames, (trimmed) => { const defaultCols = (this.plugin.settings.defaultCustomColumns ?? []) - .map(c => ({ ...c, id: c.id, options: c.options ? [...c.options] : undefined })); + .map(c => ({ + ...c, + id: c.id, + options: c.options ? [...c.options] : undefined, + optionColors: c.optionColors ? { ...c.optionColors } : undefined, + })); const newList: CustomList = { name: trimmed, columns: defaultCols, rows: [], notes: '' }; @@ -944,10 +1152,14 @@ export class CustomListsTab { // Export toolbar.createEl('button', { cls: 'wl-btn wl-btn-sm', text: 'Export' }) - .addEventListener('click', () => void this.exportToClipboard(list)); + .addEventListener('click', () => this.exportToClipboard(list)); - // Edit Columns - toolbar.createEl('button', { cls: 'wl-btn wl-btn-sm', text: 'Edit columns' }) + // Import + toolbar.createEl('button', { cls: 'wl-btn wl-btn-sm', text: 'Import' }) + .addEventListener('click', () => this.openImport(list)); + + // Table settings + toolbar.createEl('button', { cls: 'wl-btn wl-btn-sm', text: 'Table settings' }) .addEventListener('click', () => { new EditColumnsModal( this.plugin.app, @@ -1040,23 +1252,45 @@ export class CustomListsTab { return panel; } - private async exportToClipboard(list: CustomList): Promise { + /** Gather the export table (headers + plain string cells) once, reused by every format. */ + private gatherExportData(list: CustomList): { headers: string[]; rows: string[][] } { const nonLockedCols = list.columns.filter(c => !c.locked); const allCols = [{ id: '#', label: '#' }, { id: 'name', label: 'Name' }, ...nonLockedCols]; - const header = '| ' + allCols.map(c => c.label).join(' | ') + ' |'; - const sep = '| ' + allCols.map(() => '---').join(' | ') + ' |'; - const rows = this.getFilteredSortedRows(list).map((row, i) => { - const cells = allCols.map(c => { - if (c.id === '#') return String(i + 1); - const val = (row as Record)[c.id]; - return val !== undefined && val !== null ? String(val) : ''; - }); - return '| ' + cells.join(' | ') + ' |'; - }); - try { - await navigator.clipboard.writeText([header, sep, ...rows].join('\n')); - new Notice('Copied to clipboard!'); - } catch { new Notice('Failed to copy to clipboard.'); } + const headers = allCols.map(c => c.label); + const rows = this.getFilteredSortedRows(list).map((row, i) => allCols.map(c => { + if (c.id === '#') return String(i + 1); + const val = (row as Record)[c.id]; + return val !== undefined && val !== null ? String(val) : ''; + })); + return { headers, rows }; + } + + private buildMarkdown(data: { headers: string[]; rows: string[][] }): string { + const header = '| ' + data.headers.join(' | ') + ' |'; + const sep = '| ' + data.headers.map(() => '---').join(' | ') + ' |'; + const rows = data.rows.map(cells => '| ' + cells.join(' | ') + ' |'); + return [header, sep, ...rows].join('\n'); + } + + private buildTsv(data: { headers: string[]; rows: string[][] }): string { + return [data.headers, ...data.rows].map(cells => cells.join('\t')).join('\n'); + } + + private exportToClipboard(list: CustomList): void { + new ExportFormatModal(this.plugin.app, (format) => { + const data = this.gatherExportData(list); + const text = format === 'tsv' ? this.buildTsv(data) : this.buildMarkdown(data); + navigator.clipboard.writeText(text) + .then(() => new Notice('Copied to clipboard!')) + .catch(() => new Notice('Failed to copy to clipboard.')); + }).open(); + } + + private openImport(list: CustomList): void { + new ImportListModal(this.plugin.app, list, this.manager, async () => { + await this.manager.saveList(list); + await this.render(); + }).open(); } private getFilteredSortedRows(list: CustomList): CustomListRow[] { @@ -1094,12 +1328,28 @@ export class CustomListsTab { // Header const thead = table.createDiv({ cls: 'wl-cl-thead' }); const hRow = thead.createDiv({ cls: 'wl-cl-tr wl-cl-tr-header' }); - hRow.createDiv({ cls: 'wl-cl-th wl-cl-th-tick' }); // tick column header + // Tick column header: two-state select-all toggle over the visible rows. + const tickTh = hRow.createDiv({ cls: 'wl-cl-th wl-cl-th-tick' }); + const allChecked = visibleRows.length > 0 && visibleRows.every(r => r.checked === true); + const selectAllBtn = tickTh.createDiv({ cls: `wl-cl-tick-btn${allChecked ? ' is-checked' : ''}` }); + selectAllBtn.title = allChecked ? 'Uncheck all visible rows' : 'Check all visible rows'; + selectAllBtn.textContent = allChecked ? '✓' : '○'; + selectAllBtn.addEventListener('click', () => { + // Only affect currently visible (filtered/searched) rows. + const visibleIds = new Set(visibleRows.map(r => r.id)); + const next = !allChecked; + for (const r of list.rows) if (visibleIds.has(r.id)) r.checked = next; + void this.manager.saveList(list).then(() => { container.empty(); this.buildTable(container, list, countEl); }); + }); hRow.createDiv({ cls: 'wl-cl-th wl-cl-th-num', text: '#' }); - hRow.createDiv({ cls: 'wl-cl-th', text: 'Name' }); + const nameTh = hRow.createDiv({ cls: 'wl-cl-th', text: 'Name' }); + nameTh.dataset.wlCol = '__name'; + this.addResizeHandle(nameTh, '__name', list, table); for (const col of nonLockedCols) { const th = hRow.createDiv({ cls: 'wl-cl-th' }); + th.dataset.wlCol = col.id; th.createSpan({ text: col.label }); + this.addResizeHandle(th, col.id, list, table); if (col.type === 'number' && col.autoTime) { const refreshBtn = th.createSpan({ cls: 'wl-cl-autotime-refresh', text: '↻' }); refreshBtn.title = 'Refresh remaining time values'; @@ -1139,10 +1389,12 @@ export class CustomListsTab { tr.createDiv({ cls: 'wl-cl-td wl-cl-td-num', text: String(displayIdx + 1) }); const nameCell = tr.createDiv({ cls: 'wl-cl-td wl-cl-td-name' }); + nameCell.dataset.wlCol = '__name'; this.renderNameCell(nameCell, row, list, countEl, nonLockedCols, container); for (const col of nonLockedCols) { const td = tr.createDiv({ cls: 'wl-cl-td' }); + td.dataset.wlCol = col.id; this.renderCustomCell(td, row, col, list); } @@ -1197,6 +1449,9 @@ export class CustomListsTab { }); }); + // Apply any persisted column widths (switches the table into resizable mode). + this.applyColumnWidths(table, list); + // Add row const addRowEl = container.createDiv({ cls: 'wl-cl-add-row' }); addRowEl.createEl('button', { cls: 'wl-btn wl-btn-sm wl-btn-success', text: '+ add row' }) @@ -1215,6 +1470,101 @@ export class CustomListsTab { }); } + // ── Column resize (Excel-style) ───────────────────────────────────────────── + + /** True when the Name column or any custom column has an explicit width set. */ + private isTableResizable(list: CustomList): boolean { + return list.nameWidth !== undefined || list.columns.some((c) => !c.locked && c.width !== undefined); + } + + private getColWidth(list: CustomList, key: string): number | undefined { + if (key === '__name') return list.nameWidth; + return list.columns.find((c) => c.id === key)?.width; + } + + private setColWidth(list: CustomList, key: string, width: number): void { + if (key === '__name') { list.nameWidth = width; return; } + const col = list.columns.find((c) => c.id === key); + if (col) col.width = width; + } + + /** + * Applies persisted widths to every resizable column. Once any width exists the + * table enters explicit-width mode (no flex redistribution, horizontal scroll); + * resizable columns without a stored width fall back to a default fixed width so + * they cannot compress to absorb a neighbour's resize. Lists never resized keep + * the original flex layout untouched. + */ + private applyColumnWidths(table: HTMLElement, list: CustomList): void { + if (!this.isTableResizable(list)) { + table.removeClass('wl-cl-table-resizable'); + return; + } + table.addClass('wl-cl-table-resizable'); + const apply = (key: string, width: number | undefined): void => { + const w = width ?? DEFAULT_COL_WIDTH; + table.querySelectorAll(`[data-wl-col="${key}"]`).forEach((el) => { + el.addClass('wl-cl-col-fixed'); + el.setCssProps({ '--wl-cl-cw': `${w}px` }); + }); + }; + apply('__name', list.nameWidth); + for (const col of list.columns) { + if (col.locked) continue; + apply(col.id, col.width); + } + } + + /** + * Pins every resizable column to its current rendered width. Called the first + * time a handle is grabbed so switching into explicit-width mode does not make + * the columns jump. + */ + private pinCurrentWidths(table: HTMLElement, list: CustomList): void { + const measure = (key: string): number => { + const el = table.querySelector(`.wl-cl-th[data-wl-col="${key}"]`); + return el ? Math.round(el.getBoundingClientRect().width) : DEFAULT_COL_WIDTH; + }; + if (list.nameWidth === undefined) list.nameWidth = measure('__name'); + for (const col of list.columns) { + if (col.locked || col.width !== undefined) continue; + col.width = measure(col.id); + } + } + + /** Adds a right-edge drag handle to a resizable header cell (desktop only). */ + private addResizeHandle(th: HTMLElement, key: string, list: CustomList, table: HTMLElement): void { + if (Platform.isMobile) return; + th.addClass('wl-cl-th-resizable'); + const handle = th.createDiv({ cls: 'wl-cl-col-resize' }); + handle.addEventListener('mousedown', (e) => { + e.preventDefault(); + e.stopPropagation(); + // Pin every column to its current width, then switch to explicit-width mode. + this.pinCurrentWidths(table, list); + this.applyColumnWidths(table, list); + const startX = e.clientX; + const startWidth = this.getColWidth(list, key) ?? DEFAULT_COL_WIDTH; + const onMove = (ev: MouseEvent): void => { + const newWidth = Math.max(MIN_COL_WIDTH, Math.round(startWidth + (ev.clientX - startX))); + this.setColWidth(list, key, newWidth); + table.querySelectorAll(`[data-wl-col="${key}"]`).forEach((el) => { + el.setCssProps({ '--wl-cl-cw': `${newWidth}px` }); + }); + }; + const onUp = (): void => { + activeDocument.removeEventListener('mousemove', onMove); + activeDocument.removeEventListener('mouseup', onUp); + activeDocument.body.removeClass('wl-cl-col-resizing'); + // Persist only on drag end. + void this.manager.saveList(list); + }; + activeDocument.addEventListener('mousemove', onMove); + activeDocument.addEventListener('mouseup', onUp); + activeDocument.body.addClass('wl-cl-col-resizing'); + }); + } + // ── Cell rendering ───────────────────────────────────────────────────────── private renderNameCell( @@ -1402,8 +1752,18 @@ export class CustomListsTab { if (col.type === 'select') { const strVal = String(val ?? ''); - if (strVal) cell.createSpan({ cls: 'wl-cl-select-badge', text: strVal }); - else cell.createSpan({ cls: 'wl-cl-cell-empty', text: '—' }); + if (strVal) { + const badge = cell.createSpan({ cls: 'wl-cl-select-badge', text: strVal }); + const optColor = col.optionColors?.[strVal]; + // No colour assigned → leave the badge exactly as the default CSS renders it. + if (optColor) { + badge.style.backgroundColor = deriveFillColor(optColor); + badge.style.borderColor = deriveBorderColor(optColor); + badge.style.color = deriveBorderColor(optColor); + } + } else { + cell.createSpan({ cls: 'wl-cl-cell-empty', text: '—' }); + } } else { const strVal = val !== undefined && val !== null && val !== '' ? String(val) : ''; if (strVal) { @@ -1415,7 +1775,44 @@ export class CustomListsTab { } } - cell.addEventListener('click', () => this.startCustomEdit(cell, row, col, list), { once: true }); + // Select cells open the shared dropdown directly on a single click (the + // native