@opentabs-dev/opentabs-plugin-netflix 0.0.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +159 -0
  2. package/dist/adapter.iife.js +15328 -0
  3. package/dist/adapter.iife.js.map +7 -0
  4. package/dist/index.d.ts +14 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +56 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/netflix-api.d.ts +13 -0
  9. package/dist/netflix-api.d.ts.map +1 -0
  10. package/dist/netflix-api.js +59 -0
  11. package/dist/netflix-api.js.map +1 -0
  12. package/dist/tools/add-to-my-list.d.ts +7 -0
  13. package/dist/tools/add-to-my-list.d.ts.map +1 -0
  14. package/dist/tools/add-to-my-list.js +26 -0
  15. package/dist/tools/add-to-my-list.js.map +1 -0
  16. package/dist/tools/get-current-user.d.ts +15 -0
  17. package/dist/tools/get-current-user.d.ts.map +1 -0
  18. package/dist/tools/get-current-user.js +22 -0
  19. package/dist/tools/get-current-user.js.map +1 -0
  20. package/dist/tools/get-notifications.d.ts +12 -0
  21. package/dist/tools/get-notifications.d.ts.map +1 -0
  22. package/dist/tools/get-notifications.js +33 -0
  23. package/dist/tools/get-notifications.js.map +1 -0
  24. package/dist/tools/get-seasons.d.ts +23 -0
  25. package/dist/tools/get-seasons.d.ts.map +1 -0
  26. package/dist/tools/get-seasons.js +96 -0
  27. package/dist/tools/get-seasons.js.map +1 -0
  28. package/dist/tools/get-title-details.d.ts +27 -0
  29. package/dist/tools/get-title-details.d.ts.map +1 -0
  30. package/dist/tools/get-title-details.js +91 -0
  31. package/dist/tools/get-title-details.js.map +1 -0
  32. package/dist/tools/get-title.d.ts +22 -0
  33. package/dist/tools/get-title.d.ts.map +1 -0
  34. package/dist/tools/get-title.js +40 -0
  35. package/dist/tools/get-title.js.map +1 -0
  36. package/dist/tools/get-watch-history.d.ts +15 -0
  37. package/dist/tools/get-watch-history.d.ts.map +1 -0
  38. package/dist/tools/get-watch-history.js +57 -0
  39. package/dist/tools/get-watch-history.js.map +1 -0
  40. package/dist/tools/list-continue-watching.d.ts +22 -0
  41. package/dist/tools/list-continue-watching.d.ts.map +1 -0
  42. package/dist/tools/list-continue-watching.js +52 -0
  43. package/dist/tools/list-continue-watching.js.map +1 -0
  44. package/dist/tools/list-genre-titles.d.ts +23 -0
  45. package/dist/tools/list-genre-titles.d.ts.map +1 -0
  46. package/dist/tools/list-genre-titles.js +52 -0
  47. package/dist/tools/list-genre-titles.js.map +1 -0
  48. package/dist/tools/list-my-list.d.ts +22 -0
  49. package/dist/tools/list-my-list.d.ts.map +1 -0
  50. package/dist/tools/list-my-list.js +55 -0
  51. package/dist/tools/list-my-list.js.map +1 -0
  52. package/dist/tools/list-profiles.d.ts +11 -0
  53. package/dist/tools/list-profiles.d.ts.map +1 -0
  54. package/dist/tools/list-profiles.js +67 -0
  55. package/dist/tools/list-profiles.js.map +1 -0
  56. package/dist/tools/list-top-10.d.ts +27 -0
  57. package/dist/tools/list-top-10.d.ts.map +1 -0
  58. package/dist/tools/list-top-10.js +65 -0
  59. package/dist/tools/list-top-10.js.map +1 -0
  60. package/dist/tools/list-trending.d.ts +22 -0
  61. package/dist/tools/list-trending.d.ts.map +1 -0
  62. package/dist/tools/list-trending.js +51 -0
  63. package/dist/tools/list-trending.js.map +1 -0
  64. package/dist/tools/navigate-to-genre.d.ts +8 -0
  65. package/dist/tools/navigate-to-genre.d.ts.map +1 -0
  66. package/dist/tools/navigate-to-genre.js +23 -0
  67. package/dist/tools/navigate-to-genre.js.map +1 -0
  68. package/dist/tools/navigate-to-title.d.ts +8 -0
  69. package/dist/tools/navigate-to-title.d.ts.map +1 -0
  70. package/dist/tools/navigate-to-title.js +23 -0
  71. package/dist/tools/navigate-to-title.js.map +1 -0
  72. package/dist/tools/play-title.d.ts +8 -0
  73. package/dist/tools/play-title.d.ts.map +1 -0
  74. package/dist/tools/play-title.js +23 -0
  75. package/dist/tools/play-title.js.map +1 -0
  76. package/dist/tools/rate-title.d.ts +13 -0
  77. package/dist/tools/rate-title.d.ts.map +1 -0
  78. package/dist/tools/rate-title.js +36 -0
  79. package/dist/tools/rate-title.js.map +1 -0
  80. package/dist/tools/remove-from-my-list.d.ts +7 -0
  81. package/dist/tools/remove-from-my-list.d.ts.map +1 -0
  82. package/dist/tools/remove-from-my-list.js +26 -0
  83. package/dist/tools/remove-from-my-list.js.map +1 -0
  84. package/dist/tools/schemas.d.ts +185 -0
  85. package/dist/tools/schemas.d.ts.map +1 -0
  86. package/dist/tools/schemas.js +163 -0
  87. package/dist/tools/schemas.js.map +1 -0
  88. package/dist/tools/search-titles.d.ts +29 -0
  89. package/dist/tools/search-titles.d.ts.map +1 -0
  90. package/dist/tools/search-titles.js +75 -0
  91. package/dist/tools/search-titles.js.map +1 -0
  92. package/dist/tools.json +1648 -0
  93. package/package.json +54 -0
@@ -0,0 +1,40 @@
1
+ import { ToolError, getPageGlobal, defineTool } from '@opentabs-dev/plugin-sdk';
2
+ import { z } from 'zod';
3
+ import { readApolloTitle } from '../netflix-api.js';
4
+ import { apolloEntryToRawTitle, mapTitle, titleSchema } from './schemas.js';
5
+ export const getTitle = defineTool({
6
+ name: 'get_title',
7
+ displayName: 'Get Title',
8
+ description: 'Get detailed information about a Netflix movie or TV show by its video ID. Returns title metadata including synopsis, rating, watch status, and whether it is in My List. Use search_titles to find video IDs.',
9
+ summary: 'Get details for a movie or show',
10
+ icon: 'film',
11
+ group: 'Browse',
12
+ input: z.object({
13
+ video_id: z.number().int().describe('Netflix video ID'),
14
+ }),
15
+ output: z.object({ title: titleSchema }),
16
+ handle: async (params) => {
17
+ // Try the Apollo Client cache first
18
+ const cached = readApolloTitle(params.video_id);
19
+ if (cached) {
20
+ return { title: mapTitle(apolloEntryToRawTitle(cached)) };
21
+ }
22
+ // Fall back to pathEvaluator to load the data
23
+ const pe = getPageGlobal('netflix.appContext.state.pathEvaluator');
24
+ if (!pe?.get) {
25
+ throw ToolError.internal('Netflix pathEvaluator not available on page.');
26
+ }
27
+ await pe.get.bind(pe)([
28
+ 'videos',
29
+ params.video_id,
30
+ ['title', 'summary', 'queue', 'inRemindMeList', 'runtime', 'bookmarkPosition', 'current'],
31
+ ]);
32
+ // Re-check Apollo cache after pathEvaluator populates it
33
+ const afterFetch = readApolloTitle(params.video_id);
34
+ if (afterFetch) {
35
+ return { title: mapTitle(apolloEntryToRawTitle(afterFetch)) };
36
+ }
37
+ throw ToolError.notFound(`Title with video ID ${params.video_id} not found.`);
38
+ },
39
+ });
40
+ //# sourceMappingURL=get-title.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-title.js","sourceRoot":"","sources":["../../src/tools/get-title.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE5E,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAC;IACjC,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,WAAW;IACxB,WAAW,EACT,gNAAgN;IAClN,OAAO,EAAE,iCAAiC;IAC1C,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;KACxD,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IACxC,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,oCAAoC;QACpC,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChD,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QAC5D,CAAC;QAED,8CAA8C;QAC9C,MAAM,EAAE,GAAG,aAAa,CAAC,wCAAwC,CAEzD,CAAC;QAET,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC;YACb,MAAM,SAAS,CAAC,QAAQ,CAAC,8CAA8C,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpB,QAAQ;YACR,MAAM,CAAC,QAAQ;YACf,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,kBAAkB,EAAE,SAAS,CAAC;SAC1F,CAAC,CAAC;QAEH,yDAAyD;QACzD,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACpD,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;QAChE,CAAC;QAED,MAAM,SAAS,CAAC,QAAQ,CAAC,uBAAuB,MAAM,CAAC,QAAQ,aAAa,CAAC,CAAC;IAChF,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { z } from 'zod';
2
+ export declare const getWatchHistory: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ limit: z.ZodOptional<z.ZodNumber>;
4
+ }, z.core.$strip>, z.ZodObject<{
5
+ entries: z.ZodArray<z.ZodObject<{
6
+ video_id: z.ZodNumber;
7
+ title: z.ZodString;
8
+ type: z.ZodString;
9
+ watch_status: z.ZodString;
10
+ bookmark_position_seconds: z.ZodNumber;
11
+ runtime_seconds: z.ZodNumber;
12
+ last_watched: z.ZodString;
13
+ }, z.core.$strip>>;
14
+ }, z.core.$strip>>;
15
+ //# sourceMappingURL=get-watch-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-watch-history.d.ts","sourceRoot":"","sources":["../../src/tools/get-watch-history.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,eAAe;;;;;;;;;;;;kBA+D1B,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { ToolError, getPageGlobal } from '@opentabs-dev/plugin-sdk';
2
+ import { defineTool } from '@opentabs-dev/plugin-sdk';
3
+ import { z } from 'zod';
4
+ import { readApolloTitle } from '../netflix-api.js';
5
+ import { mapWatchHistoryEntry, watchHistorySchema } from './schemas.js';
6
+ export const getWatchHistory = defineTool({
7
+ name: 'get_watch_history',
8
+ displayName: 'Get Watch History',
9
+ description: 'Get the recent viewing history for the current Netflix profile. Returns titles the user has watched or started watching, with watch progress information.',
10
+ summary: 'Get recent viewing history',
11
+ icon: 'history',
12
+ group: 'Library',
13
+ input: z.object({
14
+ limit: z.number().int().min(1).max(50).optional().describe('Max results to return (default 20, max 50)'),
15
+ }),
16
+ output: z.object({
17
+ entries: z.array(watchHistorySchema).describe('Watch history entries'),
18
+ }),
19
+ handle: async (params) => {
20
+ const limit = params.limit ?? 20;
21
+ const pe = getPageGlobal('netflix.appContext.state.pathEvaluator');
22
+ if (!pe?.get) {
23
+ throw ToolError.internal('Netflix pathEvaluator not available on page.');
24
+ }
25
+ const paths = [
26
+ [
27
+ 'viewingActivity',
28
+ { from: 0, to: limit - 1 },
29
+ ['title', 'date', 'bookmark', 'runtime', 'series', 'seriesTitle', 'seasonDescriptor', 'episodeTitle'],
30
+ ],
31
+ ];
32
+ const result = (await pe.get.bind(pe)(...paths));
33
+ const data = result?.json ?? {};
34
+ const historyData = data?.viewingActivity;
35
+ if (!historyData) {
36
+ return { entries: [] };
37
+ }
38
+ const entries = [];
39
+ for (const [key, entry] of Object.entries(historyData)) {
40
+ if (key === 'length' || key === '$__path' || key === 'size')
41
+ continue;
42
+ const item = entry;
43
+ const videoId = item?.videoId;
44
+ // Try to enrich with cached data
45
+ const titleVal = videoId ? (readApolloTitle(videoId)?.title ?? null) : null;
46
+ entries.push(mapWatchHistoryEntry({
47
+ videoId: videoId ?? 0,
48
+ title: titleVal ?? item?.title ?? item?.seriesTitle ?? '',
49
+ dateStr: item?.date ?? '',
50
+ bookmark: item?.bookmark,
51
+ runtime: item?.runtime,
52
+ }));
53
+ }
54
+ return { entries };
55
+ },
56
+ });
57
+ //# sourceMappingURL=get-watch-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-watch-history.js","sourceRoot":"","sources":["../../src/tools/get-watch-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAExE,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC;IACxC,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,mBAAmB;IAChC,WAAW,EACT,2JAA2J;IAC7J,OAAO,EAAE,4BAA4B;IACrC,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;KACzG,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC;KACvE,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;QAEjC,MAAM,EAAE,GAAG,aAAa,CAAC,wCAAwC,CAEzD,CAAC;QAET,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC;YACb,MAAM,SAAS,CAAC,QAAQ,CAAC,8CAA8C,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,KAAK,GAAG;YACZ;gBACE,iBAAiB;gBACjB,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,GAAG,CAAC,EAAE;gBAC1B,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,kBAAkB,EAAE,cAAc,CAAC;aACtG;SACF,CAAC;QAEF,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAuC,CAAC;QACvF,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QAEhC,MAAM,WAAW,GAAI,IAAgD,EAAE,eAAe,CAAC;QACvF,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACzB,CAAC;QAED,MAAM,OAAO,GAA8C,EAAE,CAAC;QAC9D,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YACvD,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,MAAM;gBAAE,SAAS;YACtE,MAAM,IAAI,GAAG,KAAgC,CAAC;YAC9C,MAAM,OAAO,GAAG,IAAI,EAAE,OAA6B,CAAC;YAEpD,iCAAiC;YACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAE,eAAe,CAAC,OAAO,CAAC,EAAE,KAA4B,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAEpG,OAAO,CAAC,IAAI,CACV,oBAAoB,CAAC;gBACnB,OAAO,EAAE,OAAO,IAAI,CAAC;gBACrB,KAAK,EAAE,QAAQ,IAAK,IAAI,EAAE,KAA4B,IAAK,IAAI,EAAE,WAAkC,IAAI,EAAE;gBACzG,OAAO,EAAG,IAAI,EAAE,IAA2B,IAAI,EAAE;gBACjD,QAAQ,EAAE,IAAI,EAAE,QAA6C;gBAC7D,OAAO,EAAE,IAAI,EAAE,OAA6B;aAC7C,CAAC,CACH,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,CAAC;IACrB,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ export declare const listContinueWatching: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ limit: z.ZodOptional<z.ZodNumber>;
4
+ }, z.core.$strip>, z.ZodObject<{
5
+ titles: z.ZodArray<z.ZodObject<{
6
+ video_id: z.ZodNumber;
7
+ title: z.ZodString;
8
+ type: z.ZodString;
9
+ year: z.ZodNumber;
10
+ is_original: z.ZodBoolean;
11
+ maturity_rating: z.ZodString;
12
+ maturity_description: z.ZodString;
13
+ synopsis: z.ZodString;
14
+ genres: z.ZodString;
15
+ watch_status: z.ZodString;
16
+ is_in_my_list: z.ZodBoolean;
17
+ runtime_minutes: z.ZodNumber;
18
+ num_seasons: z.ZodString;
19
+ image_url: z.ZodString;
20
+ }, z.core.$strip>>;
21
+ }, z.core.$strip>>;
22
+ //# sourceMappingURL=list-continue-watching.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-continue-watching.d.ts","sourceRoot":"","sources":["../../src/tools/list-continue-watching.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;kBAwD/B,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { ToolError, getPageGlobal } from '@opentabs-dev/plugin-sdk';
2
+ import { defineTool } from '@opentabs-dev/plugin-sdk';
3
+ import { z } from 'zod';
4
+ import { readApolloTitle } from '../netflix-api.js';
5
+ import { mapTitle, titleSchema } from './schemas.js';
6
+ export const listContinueWatching = defineTool({
7
+ name: 'list_continue_watching',
8
+ displayName: 'List Continue Watching',
9
+ description: 'Get titles the user has started but not finished watching. Returns movies and shows with their bookmark positions. Useful for resuming playback or seeing what the user was recently watching.',
10
+ summary: 'Get in-progress titles',
11
+ icon: 'play-circle',
12
+ group: 'Library',
13
+ input: z.object({
14
+ limit: z.number().int().min(1).max(40).optional().describe('Max results to return (default 20, max 40)'),
15
+ }),
16
+ output: z.object({
17
+ titles: z.array(titleSchema).describe('Continue watching titles'),
18
+ }),
19
+ handle: async (params) => {
20
+ const limit = params.limit ?? 20;
21
+ const pe = getPageGlobal('netflix.appContext.state.pathEvaluator');
22
+ if (!pe?.get) {
23
+ throw ToolError.internal('Netflix pathEvaluator not available on page.');
24
+ }
25
+ const paths = [['continueWatching', { from: 0, to: limit - 1 }, ['summary', 'title']]];
26
+ const result = (await pe.get.bind(pe)(...paths));
27
+ const data = result?.json ?? {};
28
+ const cwData = data?.continueWatching;
29
+ if (!cwData) {
30
+ return { titles: [] };
31
+ }
32
+ const titles = [];
33
+ for (const [key, entry] of Object.entries(cwData)) {
34
+ if (key === 'length' || key === '$__path')
35
+ continue;
36
+ const videoEntry = entry;
37
+ const summaryVal = videoEntry?.summary;
38
+ const videoId = summaryVal?.id ?? 0;
39
+ if (!videoId)
40
+ continue;
41
+ const titleVal = readApolloTitle(videoId)?.title ?? '';
42
+ titles.push(mapTitle({
43
+ videoId,
44
+ title: titleVal || videoEntry?.title || '',
45
+ summary: summaryVal,
46
+ watchStatus: 'STARTED',
47
+ }));
48
+ }
49
+ return { titles };
50
+ },
51
+ });
52
+ //# sourceMappingURL=list-continue-watching.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-continue-watching.js","sourceRoot":"","sources":["../../src/tools/list-continue-watching.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { z } from 'zod';
2
+ export declare const listGenreTitles: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ genre_id: z.ZodNumber;
4
+ limit: z.ZodOptional<z.ZodNumber>;
5
+ }, z.core.$strip>, z.ZodObject<{
6
+ titles: z.ZodArray<z.ZodObject<{
7
+ video_id: z.ZodNumber;
8
+ title: z.ZodString;
9
+ type: z.ZodString;
10
+ year: z.ZodNumber;
11
+ is_original: z.ZodBoolean;
12
+ maturity_rating: z.ZodString;
13
+ maturity_description: z.ZodString;
14
+ synopsis: z.ZodString;
15
+ genres: z.ZodString;
16
+ watch_status: z.ZodString;
17
+ is_in_my_list: z.ZodBoolean;
18
+ runtime_minutes: z.ZodNumber;
19
+ num_seasons: z.ZodString;
20
+ image_url: z.ZodString;
21
+ }, z.core.$strip>>;
22
+ }, z.core.$strip>>;
23
+ //# sourceMappingURL=list-genre-titles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-genre-titles.d.ts","sourceRoot":"","sources":["../../src/tools/list-genre-titles.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;kBA2D1B,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { ToolError, getPageGlobal } from '@opentabs-dev/plugin-sdk';
2
+ import { defineTool } from '@opentabs-dev/plugin-sdk';
3
+ import { z } from 'zod';
4
+ import { readApolloTitle } from '../netflix-api.js';
5
+ import { mapTitle, titleSchema } from './schemas.js';
6
+ export const listGenreTitles = defineTool({
7
+ name: 'list_genre_titles',
8
+ displayName: 'List Genre Titles',
9
+ description: 'Browse Netflix titles by genre ID. Common genre IDs: 83 (TV Shows), 34399 (Movies), 1365 (Action), 5763 (Drama), 6548 (Comedy), 8933 (Thriller), 7424 (Anime), 2243108 (Korean TV), 26065 (Sci-Fi), 8711 (Horror), 10118 (Comic & Superhero), 13335 (Reality TV), 11559 (Stand-Up Comedy), 6839 (Documentaries). Navigate to netflix.com/browse/genre/<id> to discover more genre IDs.',
10
+ summary: 'Browse titles in a genre category',
11
+ icon: 'layout-grid',
12
+ group: 'Browse',
13
+ input: z.object({
14
+ genre_id: z.number().int().describe('Netflix genre ID (e.g., 1365 for Action, 6548 for Comedy)'),
15
+ limit: z.number().int().min(1).max(40).optional().describe('Max results to return (default 20, max 40)'),
16
+ }),
17
+ output: z.object({
18
+ titles: z.array(titleSchema).describe('Titles in the genre'),
19
+ }),
20
+ handle: async (params) => {
21
+ const limit = params.limit ?? 20;
22
+ const pe = getPageGlobal('netflix.appContext.state.pathEvaluator');
23
+ if (!pe?.get) {
24
+ throw ToolError.internal('Netflix pathEvaluator not available on page.');
25
+ }
26
+ const paths = [['genres', params.genre_id, 'su', { from: 0, to: limit - 1 }, ['summary', 'title']]];
27
+ const result = (await pe.get.bind(pe)(...paths));
28
+ const data = result?.json ?? {};
29
+ const genreData = data?.genres?.[String(params.genre_id)]?.su;
30
+ if (!genreData) {
31
+ return { titles: [] };
32
+ }
33
+ const titles = [];
34
+ for (const [key, entry] of Object.entries(genreData)) {
35
+ if (key === 'length' || key === '$__path')
36
+ continue;
37
+ const videoEntry = entry;
38
+ const summaryVal = videoEntry?.summary;
39
+ const videoId = summaryVal?.id ?? 0;
40
+ if (!videoId)
41
+ continue;
42
+ const titleVal = readApolloTitle(videoId)?.title ?? '';
43
+ titles.push(mapTitle({
44
+ videoId,
45
+ title: titleVal || videoEntry?.title || '',
46
+ summary: summaryVal,
47
+ }));
48
+ }
49
+ return { titles };
50
+ },
51
+ });
52
+ //# sourceMappingURL=list-genre-titles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-genre-titles.js","sourceRoot":"","sources":["../../src/tools/list-genre-titles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ export declare const listMyList: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ limit: z.ZodOptional<z.ZodNumber>;
4
+ }, z.core.$strip>, z.ZodObject<{
5
+ titles: z.ZodArray<z.ZodObject<{
6
+ video_id: z.ZodNumber;
7
+ title: z.ZodString;
8
+ type: z.ZodString;
9
+ year: z.ZodNumber;
10
+ is_original: z.ZodBoolean;
11
+ maturity_rating: z.ZodString;
12
+ maturity_description: z.ZodString;
13
+ synopsis: z.ZodString;
14
+ genres: z.ZodString;
15
+ watch_status: z.ZodString;
16
+ is_in_my_list: z.ZodBoolean;
17
+ runtime_minutes: z.ZodNumber;
18
+ num_seasons: z.ZodString;
19
+ image_url: z.ZodString;
20
+ }, z.core.$strip>>;
21
+ }, z.core.$strip>>;
22
+ //# sourceMappingURL=list-my-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-my-list.d.ts","sourceRoot":"","sources":["../../src/tools/list-my-list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;kBA2DrB,CAAC"}
@@ -0,0 +1,55 @@
1
+ import { ToolError, getPageGlobal } from '@opentabs-dev/plugin-sdk';
2
+ import { defineTool } from '@opentabs-dev/plugin-sdk';
3
+ import { z } from 'zod';
4
+ import { readApolloTitle } from '../netflix-api.js';
5
+ import { mapTitle, titleSchema } from './schemas.js';
6
+ export const listMyList = defineTool({
7
+ name: 'list_my_list',
8
+ displayName: 'List My List',
9
+ description: 'Get all titles in the current Netflix profile\'s "My List" (saved titles). Returns movies and shows the user has added to their list.',
10
+ summary: 'Get titles in My List',
11
+ icon: 'bookmark',
12
+ group: 'Library',
13
+ input: z.object({
14
+ limit: z.number().int().min(1).max(75).optional().describe('Max results to return (default 40, max 75)'),
15
+ }),
16
+ output: z.object({
17
+ titles: z.array(titleSchema).describe('Titles in My List'),
18
+ }),
19
+ handle: async (params) => {
20
+ const limit = params.limit ?? 40;
21
+ const pe = getPageGlobal('netflix.appContext.state.pathEvaluator');
22
+ if (!pe?.get) {
23
+ throw ToolError.internal('Netflix pathEvaluator not available on page.');
24
+ }
25
+ const paths = [
26
+ ['mylist', { from: 0, to: limit - 1 }, ['summary', 'title']],
27
+ ['mylist', 'length'],
28
+ ];
29
+ const result = (await pe.get.bind(pe)(...paths));
30
+ const data = result?.json ?? {};
31
+ const myListData = data?.mylist;
32
+ if (!myListData) {
33
+ return { titles: [] };
34
+ }
35
+ const titles = [];
36
+ for (const [key, entry] of Object.entries(myListData)) {
37
+ if (key === 'length' || key === '$__path' || key === 'size')
38
+ continue;
39
+ const videoEntry = entry;
40
+ const summaryVal = videoEntry?.summary;
41
+ const videoId = summaryVal?.id ?? 0;
42
+ if (!videoId)
43
+ continue;
44
+ const titleVal = readApolloTitle(videoId)?.title ?? '';
45
+ titles.push(mapTitle({
46
+ videoId,
47
+ title: titleVal || videoEntry?.title || '',
48
+ summary: summaryVal,
49
+ isInPlaylist: true,
50
+ }));
51
+ }
52
+ return { titles };
53
+ },
54
+ });
55
+ //# sourceMappingURL=list-my-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-my-list.js","sourceRoot":"","sources":["../../src/tools/list-my-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAiB,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAC;IACnC,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,cAAc;IAC3B,WAAW,EACT,uIAAuI;IACzI,OAAO,EAAE,uBAAuB;IAChC,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;KACzG,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;KAC3D,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;QAEjC,MAAM,EAAE,GAAG,aAAa,CAAC,wCAAwC,CAEzD,CAAC;QAET,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC;YACb,MAAM,SAAS,CAAC,QAAQ,CAAC,8CAA8C,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,KAAK,GAAG;YACZ,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC5D,CAAC,QAAQ,EAAE,QAAQ,CAAC;SACrB,CAAC;QAEF,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAuC,CAAC;QACvF,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QAEhC,MAAM,UAAU,GAAI,IAAgD,EAAE,MAAM,CAAC;QAC7E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACxB,CAAC;QAED,MAAM,MAAM,GAAkC,EAAE,CAAC;QACjD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YACtD,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,MAAM;gBAAE,SAAS;YACtE,MAAM,UAAU,GAAG,KAAgC,CAAC;YACpD,MAAM,UAAU,GAAG,UAAU,EAAE,OAA8C,CAAC;YAC9E,MAAM,OAAO,GAAI,UAAU,EAAE,EAAyB,IAAI,CAAC,CAAC;YAC5D,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,QAAQ,GAAI,eAAe,CAAC,OAAO,CAAC,EAAE,KAA4B,IAAI,EAAE,CAAC;YAC/E,MAAM,CAAC,IAAI,CACT,QAAQ,CAAC;gBACP,OAAO;gBACP,KAAK,EAAE,QAAQ,IAAK,UAAU,EAAE,KAA4B,IAAI,EAAE;gBAClE,OAAO,EAAE,UAAiC;gBAC1C,YAAY,EAAE,IAAI;aACP,CAAC,CACf,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,CAAC;IACpB,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod';
2
+ export declare const listProfiles: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
3
+ profiles: z.ZodArray<z.ZodObject<{
4
+ guid: z.ZodString;
5
+ name: z.ZodString;
6
+ is_kids: z.ZodBoolean;
7
+ avatar_url: z.ZodString;
8
+ is_active: z.ZodBoolean;
9
+ }, z.core.$strip>>;
10
+ }, z.core.$strip>>;
11
+ //# sourceMappingURL=list-profiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-profiles.d.ts","sourceRoot":"","sources":["../../src/tools/list-profiles.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,YAAY;;;;;;;;kBAqEvB,CAAC"}
@@ -0,0 +1,67 @@
1
+ import { getPageGlobal } from '@opentabs-dev/plugin-sdk';
2
+ import { defineTool } from '@opentabs-dev/plugin-sdk';
3
+ import { z } from 'zod';
4
+ import { getUserInfo } from '../netflix-api.js';
5
+ import { mapProfile, profileSchema } from './schemas.js';
6
+ export const listProfiles = defineTool({
7
+ name: 'list_profiles',
8
+ displayName: 'List Profiles',
9
+ description: 'List all profiles on the Netflix account. Returns each profile with its name, avatar, and whether it is the currently active profile.',
10
+ summary: 'List all Netflix profiles',
11
+ icon: 'users',
12
+ group: 'Account',
13
+ input: z.object({}),
14
+ output: z.object({
15
+ profiles: z.array(profileSchema).describe('Netflix profiles'),
16
+ }),
17
+ handle: async () => {
18
+ const profiles = [];
19
+ const userInfo = getUserInfo();
20
+ const currentGuid = (userInfo?.guid ?? userInfo?.userGuid);
21
+ // Read profiles from the Falcor cache inline (avoids circular reference issues)
22
+ const falcorCache = getPageGlobal('netflix.falcorCache');
23
+ const profilesList = falcorCache?.profilesList;
24
+ const profilesMap = falcorCache?.profiles;
25
+ if (profilesList && profilesMap) {
26
+ const summary = profilesList.summary;
27
+ const count = summary?.length ?? 10;
28
+ for (let i = 0; i < count; i++) {
29
+ const profileRef = profilesList[String(i)];
30
+ if (!profileRef)
31
+ continue;
32
+ // Falcor refs use { $type: 'ref', value: ['profiles', '<guid>'] }
33
+ const refValue = profileRef.value;
34
+ const guid = refValue?.[1];
35
+ if (!guid)
36
+ continue;
37
+ const profile = profilesMap[guid];
38
+ // Falcor wraps data in { $type: 'atom', value: { ... } } — unwrap the atom
39
+ const summaryAtom = profile?.summary;
40
+ const profileData = summaryAtom?.$type === 'atom' ? summaryAtom.value : summaryAtom;
41
+ const raw = {
42
+ guid,
43
+ profileName: profileData?.profileName ?? '',
44
+ firstName: profileData?.firstName ?? '',
45
+ isKids: profileData?.isKids ?? false,
46
+ avatarUrl: '',
47
+ isActive: guid === currentGuid,
48
+ };
49
+ profiles.push(mapProfile(raw));
50
+ }
51
+ }
52
+ else if (currentGuid && userInfo) {
53
+ // Fallback: return just the current profile from userInfo
54
+ const raw = {
55
+ guid: currentGuid,
56
+ profileName: userInfo.accountOwnerName ?? userInfo.name ?? '',
57
+ firstName: userInfo.accountOwnerName ?? userInfo.firstName ?? '',
58
+ isKids: false,
59
+ avatarUrl: '',
60
+ isActive: true,
61
+ };
62
+ profiles.push(mapProfile(raw));
63
+ }
64
+ return { profiles };
65
+ },
66
+ });
67
+ //# sourceMappingURL=list-profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-profiles.js","sourceRoot":"","sources":["../../src/tools/list-profiles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { z } from 'zod';
2
+ export declare const listTop10: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ type: z.ZodOptional<z.ZodEnum<{
4
+ tv: "tv";
5
+ all: "all";
6
+ movie: "movie";
7
+ }>>;
8
+ }, z.core.$strip>, z.ZodObject<{
9
+ titles: z.ZodArray<z.ZodObject<{
10
+ video_id: z.ZodNumber;
11
+ title: z.ZodString;
12
+ type: z.ZodString;
13
+ year: z.ZodNumber;
14
+ is_original: z.ZodBoolean;
15
+ maturity_rating: z.ZodString;
16
+ maturity_description: z.ZodString;
17
+ synopsis: z.ZodString;
18
+ genres: z.ZodString;
19
+ watch_status: z.ZodString;
20
+ is_in_my_list: z.ZodBoolean;
21
+ runtime_minutes: z.ZodNumber;
22
+ num_seasons: z.ZodString;
23
+ image_url: z.ZodString;
24
+ rank: z.ZodNumber;
25
+ }, z.core.$strip>>;
26
+ }, z.core.$strip>>;
27
+ //# sourceMappingURL=list-top-10.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-top-10.d.ts","sourceRoot":"","sources":["../../src/tools/list-top-10.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;kBAoEpB,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { ToolError, getPageGlobal } from '@opentabs-dev/plugin-sdk';
2
+ import { defineTool } from '@opentabs-dev/plugin-sdk';
3
+ import { z } from 'zod';
4
+ import { readApolloTitle } from '../netflix-api.js';
5
+ import { mapTitle, titleSchema } from './schemas.js';
6
+ export const listTop10 = defineTool({
7
+ name: 'list_top_10',
8
+ displayName: 'List Top 10',
9
+ description: 'Get the Netflix Top 10 list for the user\'s region. Returns the most-watched titles currently ranking on Netflix. Optionally filter by "tv" or "movie".',
10
+ summary: 'Get Netflix Top 10 titles',
11
+ icon: 'trophy',
12
+ group: 'Browse',
13
+ input: z.object({
14
+ type: z
15
+ .enum(['all', 'tv', 'movie'])
16
+ .optional()
17
+ .describe('Filter by content type: "all" (default), "tv", or "movie"'),
18
+ }),
19
+ output: z.object({
20
+ titles: z.array(titleSchema.extend({
21
+ rank: z.number().int().describe('Current rank (1-10)'),
22
+ })),
23
+ }),
24
+ handle: async (params) => {
25
+ const filterType = params.type ?? 'all';
26
+ const pe = getPageGlobal('netflix.appContext.state.pathEvaluator');
27
+ if (!pe?.get) {
28
+ throw ToolError.internal('Netflix pathEvaluator not available on page.');
29
+ }
30
+ const paths = [['topN', { from: 0, to: 9 }, ['summary', 'title']]];
31
+ const result = (await pe.get.bind(pe)(...paths));
32
+ const data = result?.json ?? {};
33
+ const topNData = data?.topN;
34
+ if (!topNData) {
35
+ return { titles: [] };
36
+ }
37
+ const titles = [];
38
+ let rank = 1;
39
+ for (const [key, entry] of Object.entries(topNData)) {
40
+ if (key === 'length' || key === '$__path')
41
+ continue;
42
+ const videoEntry = entry;
43
+ const summaryVal = videoEntry?.summary;
44
+ const videoId = summaryVal?.id ?? 0;
45
+ if (!videoId)
46
+ continue;
47
+ const videoType = summaryVal?.type ?? '';
48
+ if (filterType === 'tv' && videoType !== 'show')
49
+ continue;
50
+ if (filterType === 'movie' && videoType !== 'movie')
51
+ continue;
52
+ const titleVal = readApolloTitle(videoId)?.title ?? '';
53
+ titles.push({
54
+ ...mapTitle({
55
+ videoId,
56
+ title: titleVal || videoEntry?.title || '',
57
+ summary: summaryVal,
58
+ }),
59
+ rank: rank++,
60
+ });
61
+ }
62
+ return { titles };
63
+ },
64
+ });
65
+ //# sourceMappingURL=list-top-10.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-top-10.js","sourceRoot":"","sources":["../../src/tools/list-top-10.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ export declare const listTrending: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ limit: z.ZodOptional<z.ZodNumber>;
4
+ }, z.core.$strip>, z.ZodObject<{
5
+ titles: z.ZodArray<z.ZodObject<{
6
+ video_id: z.ZodNumber;
7
+ title: z.ZodString;
8
+ type: z.ZodString;
9
+ year: z.ZodNumber;
10
+ is_original: z.ZodBoolean;
11
+ maturity_rating: z.ZodString;
12
+ maturity_description: z.ZodString;
13
+ synopsis: z.ZodString;
14
+ genres: z.ZodString;
15
+ watch_status: z.ZodString;
16
+ is_in_my_list: z.ZodBoolean;
17
+ runtime_minutes: z.ZodNumber;
18
+ num_seasons: z.ZodString;
19
+ image_url: z.ZodString;
20
+ }, z.core.$strip>>;
21
+ }, z.core.$strip>>;
22
+ //# sourceMappingURL=list-trending.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-trending.d.ts","sourceRoot":"","sources":["../../src/tools/list-trending.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;kBAuDvB,CAAC"}