@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.
- package/README.md +159 -0
- package/dist/adapter.iife.js +15328 -0
- package/dist/adapter.iife.js.map +7 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/netflix-api.d.ts +13 -0
- package/dist/netflix-api.d.ts.map +1 -0
- package/dist/netflix-api.js +59 -0
- package/dist/netflix-api.js.map +1 -0
- package/dist/tools/add-to-my-list.d.ts +7 -0
- package/dist/tools/add-to-my-list.d.ts.map +1 -0
- package/dist/tools/add-to-my-list.js +26 -0
- package/dist/tools/add-to-my-list.js.map +1 -0
- package/dist/tools/get-current-user.d.ts +15 -0
- package/dist/tools/get-current-user.d.ts.map +1 -0
- package/dist/tools/get-current-user.js +22 -0
- package/dist/tools/get-current-user.js.map +1 -0
- package/dist/tools/get-notifications.d.ts +12 -0
- package/dist/tools/get-notifications.d.ts.map +1 -0
- package/dist/tools/get-notifications.js +33 -0
- package/dist/tools/get-notifications.js.map +1 -0
- package/dist/tools/get-seasons.d.ts +23 -0
- package/dist/tools/get-seasons.d.ts.map +1 -0
- package/dist/tools/get-seasons.js +96 -0
- package/dist/tools/get-seasons.js.map +1 -0
- package/dist/tools/get-title-details.d.ts +27 -0
- package/dist/tools/get-title-details.d.ts.map +1 -0
- package/dist/tools/get-title-details.js +91 -0
- package/dist/tools/get-title-details.js.map +1 -0
- package/dist/tools/get-title.d.ts +22 -0
- package/dist/tools/get-title.d.ts.map +1 -0
- package/dist/tools/get-title.js +40 -0
- package/dist/tools/get-title.js.map +1 -0
- package/dist/tools/get-watch-history.d.ts +15 -0
- package/dist/tools/get-watch-history.d.ts.map +1 -0
- package/dist/tools/get-watch-history.js +57 -0
- package/dist/tools/get-watch-history.js.map +1 -0
- package/dist/tools/list-continue-watching.d.ts +22 -0
- package/dist/tools/list-continue-watching.d.ts.map +1 -0
- package/dist/tools/list-continue-watching.js +52 -0
- package/dist/tools/list-continue-watching.js.map +1 -0
- package/dist/tools/list-genre-titles.d.ts +23 -0
- package/dist/tools/list-genre-titles.d.ts.map +1 -0
- package/dist/tools/list-genre-titles.js +52 -0
- package/dist/tools/list-genre-titles.js.map +1 -0
- package/dist/tools/list-my-list.d.ts +22 -0
- package/dist/tools/list-my-list.d.ts.map +1 -0
- package/dist/tools/list-my-list.js +55 -0
- package/dist/tools/list-my-list.js.map +1 -0
- package/dist/tools/list-profiles.d.ts +11 -0
- package/dist/tools/list-profiles.d.ts.map +1 -0
- package/dist/tools/list-profiles.js +67 -0
- package/dist/tools/list-profiles.js.map +1 -0
- package/dist/tools/list-top-10.d.ts +27 -0
- package/dist/tools/list-top-10.d.ts.map +1 -0
- package/dist/tools/list-top-10.js +65 -0
- package/dist/tools/list-top-10.js.map +1 -0
- package/dist/tools/list-trending.d.ts +22 -0
- package/dist/tools/list-trending.d.ts.map +1 -0
- package/dist/tools/list-trending.js +51 -0
- package/dist/tools/list-trending.js.map +1 -0
- package/dist/tools/navigate-to-genre.d.ts +8 -0
- package/dist/tools/navigate-to-genre.d.ts.map +1 -0
- package/dist/tools/navigate-to-genre.js +23 -0
- package/dist/tools/navigate-to-genre.js.map +1 -0
- package/dist/tools/navigate-to-title.d.ts +8 -0
- package/dist/tools/navigate-to-title.d.ts.map +1 -0
- package/dist/tools/navigate-to-title.js +23 -0
- package/dist/tools/navigate-to-title.js.map +1 -0
- package/dist/tools/play-title.d.ts +8 -0
- package/dist/tools/play-title.d.ts.map +1 -0
- package/dist/tools/play-title.js +23 -0
- package/dist/tools/play-title.js.map +1 -0
- package/dist/tools/rate-title.d.ts +13 -0
- package/dist/tools/rate-title.d.ts.map +1 -0
- package/dist/tools/rate-title.js +36 -0
- package/dist/tools/rate-title.js.map +1 -0
- package/dist/tools/remove-from-my-list.d.ts +7 -0
- package/dist/tools/remove-from-my-list.d.ts.map +1 -0
- package/dist/tools/remove-from-my-list.js +26 -0
- package/dist/tools/remove-from-my-list.js.map +1 -0
- package/dist/tools/schemas.d.ts +185 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +163 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/tools/search-titles.d.ts +29 -0
- package/dist/tools/search-titles.d.ts.map +1 -0
- package/dist/tools/search-titles.js +75 -0
- package/dist/tools/search-titles.js.map +1 -0
- package/dist/tools.json +1648 -0
- package/package.json +54 -0
|
@@ -0,0 +1,51 @@
|
|
|
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 listTrending = defineTool({
|
|
7
|
+
name: 'list_trending',
|
|
8
|
+
displayName: 'List Trending',
|
|
9
|
+
description: 'Get currently trending titles on Netflix. Returns popular movies and shows that are trending in the user\'s region. This reads the "Trending Now" row from the Netflix homepage.',
|
|
10
|
+
summary: 'Get trending titles on Netflix',
|
|
11
|
+
icon: 'trending-up',
|
|
12
|
+
group: 'Browse',
|
|
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('Trending 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 = [['trendingNow', { from: 0, to: limit - 1 }, ['summary', 'title']]];
|
|
26
|
+
const result = (await pe.get.bind(pe)(...paths));
|
|
27
|
+
const data = result?.json ?? {};
|
|
28
|
+
const trendingData = data?.trendingNow;
|
|
29
|
+
if (!trendingData) {
|
|
30
|
+
return { titles: [] };
|
|
31
|
+
}
|
|
32
|
+
const titles = [];
|
|
33
|
+
for (const [key, entry] of Object.entries(trendingData)) {
|
|
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
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
return { titles };
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=list-trending.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-trending.js","sourceRoot":"","sources":["../../src/tools/list-trending.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,YAAY,GAAG,UAAU,CAAC;IACrC,IAAI,EAAE,eAAe;IACrB,WAAW,EAAE,eAAe;IAC5B,WAAW,EACT,kLAAkL;IACpL,OAAO,EAAE,gCAAgC;IACzC,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,QAAQ;IACf,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,iBAAiB,CAAC;KACzD,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,CAAC,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAElF,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,YAAY,GAAI,IAAgD,EAAE,WAAW,CAAC;QACpF,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,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,YAAY,CAAC,EAAE,CAAC;YACxD,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,SAAS;gBAAE,SAAS;YACpD,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;aAC/B,CAAC,CACf,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,CAAC;IACpB,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const navigateToGenre: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
|
|
3
|
+
genre_id: z.ZodNumber;
|
|
4
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
5
|
+
success: z.ZodBoolean;
|
|
6
|
+
url: z.ZodString;
|
|
7
|
+
}, z.core.$strip>>;
|
|
8
|
+
//# sourceMappingURL=navigate-to-genre.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigate-to-genre.d.ts","sourceRoot":"","sources":["../../src/tools/navigate-to-genre.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe;;;;;kBAoB1B,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export const navigateToGenre = defineTool({
|
|
4
|
+
name: 'navigate_to_genre',
|
|
5
|
+
displayName: 'Navigate to Genre',
|
|
6
|
+
description: 'Navigate the browser to a Netflix genre browse page. 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).',
|
|
7
|
+
summary: 'Open a genre page in the browser',
|
|
8
|
+
icon: 'compass',
|
|
9
|
+
group: 'Browse',
|
|
10
|
+
input: z.object({
|
|
11
|
+
genre_id: z.number().int().describe('Netflix genre ID (e.g., 1365 for Action, 6548 for Comedy)'),
|
|
12
|
+
}),
|
|
13
|
+
output: z.object({
|
|
14
|
+
success: z.boolean().describe('Whether navigation was initiated'),
|
|
15
|
+
url: z.string().describe('The URL navigated to'),
|
|
16
|
+
}),
|
|
17
|
+
handle: async (params) => {
|
|
18
|
+
const url = `https://www.netflix.com/browse/genre/${params.genre_id}`;
|
|
19
|
+
window.location.href = url;
|
|
20
|
+
return { success: true, url };
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=navigate-to-genre.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigate-to-genre.js","sourceRoot":"","sources":["../../src/tools/navigate-to-genre.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC;IACxC,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,mBAAmB;IAChC,WAAW,EACT,oUAAoU;IACtU,OAAO,EAAE,kCAAkC;IAC3C,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;KACjG,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QACjE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;KACjD,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,GAAG,GAAG,wCAAwC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtE,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAChC,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const navigateToTitle: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
|
|
3
|
+
video_id: z.ZodNumber;
|
|
4
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
5
|
+
success: z.ZodBoolean;
|
|
6
|
+
url: z.ZodString;
|
|
7
|
+
}, z.core.$strip>>;
|
|
8
|
+
//# sourceMappingURL=navigate-to-title.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigate-to-title.d.ts","sourceRoot":"","sources":["../../src/tools/navigate-to-title.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe;;;;;kBAoB1B,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export const navigateToTitle = defineTool({
|
|
4
|
+
name: 'navigate_to_title',
|
|
5
|
+
displayName: 'Navigate to Title',
|
|
6
|
+
description: 'Navigate the browser to a Netflix title page. This opens the detail view for a movie or TV show where the user can see more info or start playback. Use search_titles or get_title to find the video ID first.',
|
|
7
|
+
summary: 'Open a title page in the browser',
|
|
8
|
+
icon: 'external-link',
|
|
9
|
+
group: 'Browse',
|
|
10
|
+
input: z.object({
|
|
11
|
+
video_id: z.number().int().describe('Netflix video ID to navigate to'),
|
|
12
|
+
}),
|
|
13
|
+
output: z.object({
|
|
14
|
+
success: z.boolean().describe('Whether navigation was initiated'),
|
|
15
|
+
url: z.string().describe('The URL navigated to'),
|
|
16
|
+
}),
|
|
17
|
+
handle: async (params) => {
|
|
18
|
+
const url = `https://www.netflix.com/title/${params.video_id}`;
|
|
19
|
+
window.location.href = url;
|
|
20
|
+
return { success: true, url };
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=navigate-to-title.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigate-to-title.js","sourceRoot":"","sources":["../../src/tools/navigate-to-title.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC;IACxC,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,mBAAmB;IAChC,WAAW,EACT,gNAAgN;IAClN,OAAO,EAAE,kCAAkC;IAC3C,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;KACvE,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QACjE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;KACjD,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,GAAG,GAAG,iCAAiC,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC/D,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAChC,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const playTitle: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
|
|
3
|
+
video_id: z.ZodNumber;
|
|
4
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
5
|
+
success: z.ZodBoolean;
|
|
6
|
+
url: z.ZodString;
|
|
7
|
+
}, z.core.$strip>>;
|
|
8
|
+
//# sourceMappingURL=play-title.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"play-title.d.ts","sourceRoot":"","sources":["../../src/tools/play-title.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS;;;;;kBAoBpB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export const playTitle = defineTool({
|
|
4
|
+
name: 'play_title',
|
|
5
|
+
displayName: 'Play Title',
|
|
6
|
+
description: 'Start playing a Netflix movie or TV show in the browser. Navigates directly to the Netflix player for the given video ID. For TV shows, pass the specific episode video ID to play that episode.',
|
|
7
|
+
summary: 'Start playing a title',
|
|
8
|
+
icon: 'play',
|
|
9
|
+
group: 'Playback',
|
|
10
|
+
input: z.object({
|
|
11
|
+
video_id: z.number().int().describe('Netflix video ID to play (movie or episode)'),
|
|
12
|
+
}),
|
|
13
|
+
output: z.object({
|
|
14
|
+
success: z.boolean().describe('Whether playback navigation was initiated'),
|
|
15
|
+
url: z.string().describe('The player URL navigated to'),
|
|
16
|
+
}),
|
|
17
|
+
handle: async (params) => {
|
|
18
|
+
const url = `https://www.netflix.com/watch/${params.video_id}`;
|
|
19
|
+
window.location.href = url;
|
|
20
|
+
return { success: true, url };
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=play-title.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"play-title.js","sourceRoot":"","sources":["../../src/tools/play-title.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,SAAS,GAAG,UAAU,CAAC;IAClC,IAAI,EAAE,YAAY;IAClB,WAAW,EAAE,YAAY;IACzB,WAAW,EACT,kMAAkM;IACpM,OAAO,EAAE,uBAAuB;IAChC,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,UAAU;IACjB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;KACnF,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;QAC1E,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;KACxD,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,GAAG,GAAG,iCAAiC,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC/D,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAChC,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const rateTitle: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
|
|
3
|
+
video_id: z.ZodNumber;
|
|
4
|
+
rating: z.ZodEnum<{
|
|
5
|
+
THUMBS_UNRATED: "THUMBS_UNRATED";
|
|
6
|
+
THUMBS_UP: "THUMBS_UP";
|
|
7
|
+
THUMBS_WAY_UP: "THUMBS_WAY_UP";
|
|
8
|
+
THUMBS_DOWN: "THUMBS_DOWN";
|
|
9
|
+
}>;
|
|
10
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
11
|
+
success: z.ZodBoolean;
|
|
12
|
+
}, z.core.$strip>>;
|
|
13
|
+
//# sourceMappingURL=rate-title.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-title.d.ts","sourceRoot":"","sources":["../../src/tools/rate-title.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS;;;;;;;;;;kBAsCpB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ToolError, getPageGlobal } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export const rateTitle = defineTool({
|
|
5
|
+
name: 'rate_title',
|
|
6
|
+
displayName: 'Rate Title',
|
|
7
|
+
description: 'Rate a Netflix movie or TV show using the thumbs rating system. Netflix uses three rating levels: thumbs up, thumbs way up (love it), and thumbs down. Pass "THUMBS_UP", "THUMBS_WAY_UP", "THUMBS_DOWN", or "THUMBS_UNRATED" to clear a rating.',
|
|
8
|
+
summary: 'Rate a movie or show',
|
|
9
|
+
icon: 'thumbs-up',
|
|
10
|
+
group: 'Library',
|
|
11
|
+
input: z.object({
|
|
12
|
+
video_id: z.number().int().describe('Netflix video ID to rate'),
|
|
13
|
+
rating: z
|
|
14
|
+
.enum(['THUMBS_UP', 'THUMBS_WAY_UP', 'THUMBS_DOWN', 'THUMBS_UNRATED'])
|
|
15
|
+
.describe('Rating: THUMBS_UP, THUMBS_WAY_UP, THUMBS_DOWN, or THUMBS_UNRATED to clear'),
|
|
16
|
+
}),
|
|
17
|
+
output: z.object({
|
|
18
|
+
success: z.boolean().describe('Whether the operation succeeded'),
|
|
19
|
+
}),
|
|
20
|
+
handle: async (params) => {
|
|
21
|
+
const pe = getPageGlobal('netflix.appContext.state.pathEvaluator');
|
|
22
|
+
if (!pe?.call) {
|
|
23
|
+
throw ToolError.internal('Netflix pathEvaluator not available on page.');
|
|
24
|
+
}
|
|
25
|
+
const ratingMap = {
|
|
26
|
+
THUMBS_DOWN: 1,
|
|
27
|
+
THUMBS_UP: 2,
|
|
28
|
+
THUMBS_WAY_UP: 3,
|
|
29
|
+
THUMBS_UNRATED: 0,
|
|
30
|
+
};
|
|
31
|
+
const ratingValue = ratingMap[params.rating] ?? 0;
|
|
32
|
+
await pe.call.bind(pe)(['videos', params.video_id, 'rating', 'rate'], [ratingValue], []);
|
|
33
|
+
return { success: true };
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=rate-title.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-title.js","sourceRoot":"","sources":["../../src/tools/rate-title.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;AAExB,MAAM,CAAC,MAAM,SAAS,GAAG,UAAU,CAAC;IAClC,IAAI,EAAE,YAAY;IAClB,WAAW,EAAE,YAAY;IACzB,WAAW,EACT,iPAAiP;IACnP,OAAO,EAAE,sBAAsB;IAC/B,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;QAC/D,MAAM,EAAE,CAAC;aACN,IAAI,CAAC,CAAC,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;aACrE,QAAQ,CAAC,2EAA2E,CAAC;KACzF,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;KACjE,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,EAAE,GAAG,aAAa,CAAC,wCAAwC,CAEzD,CAAC;QAET,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;YACd,MAAM,SAAS,CAAC,QAAQ,CAAC,8CAA8C,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,SAAS,GAA2B;YACxC,WAAW,EAAE,CAAC;YACd,SAAS,EAAE,CAAC;YACZ,aAAa,EAAE,CAAC;YAChB,cAAc,EAAE,CAAC;SAClB,CAAC;QACF,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAElD,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC;QAEzF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const removeFromMyList: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
|
|
3
|
+
video_id: z.ZodNumber;
|
|
4
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
5
|
+
success: z.ZodBoolean;
|
|
6
|
+
}, z.core.$strip>>;
|
|
7
|
+
//# sourceMappingURL=remove-from-my-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-from-my-list.d.ts","sourceRoot":"","sources":["../../src/tools/remove-from-my-list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,gBAAgB;;;;kBA2B3B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ToolError, getPageGlobal } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export const removeFromMyList = defineTool({
|
|
5
|
+
name: 'remove_from_my_list',
|
|
6
|
+
displayName: 'Remove from My List',
|
|
7
|
+
description: 'Remove a movie or TV show from the current Netflix profile\'s "My List". Use list_my_list to see what is currently in the list.',
|
|
8
|
+
summary: 'Remove a title from My List',
|
|
9
|
+
icon: 'bookmark-minus',
|
|
10
|
+
group: 'Library',
|
|
11
|
+
input: z.object({
|
|
12
|
+
video_id: z.number().int().describe('Netflix video ID to remove'),
|
|
13
|
+
}),
|
|
14
|
+
output: z.object({
|
|
15
|
+
success: z.boolean().describe('Whether the operation succeeded'),
|
|
16
|
+
}),
|
|
17
|
+
handle: async (params) => {
|
|
18
|
+
const pe = getPageGlobal('netflix.appContext.state.pathEvaluator');
|
|
19
|
+
if (!pe?.call) {
|
|
20
|
+
throw ToolError.internal('Netflix pathEvaluator not available on page.');
|
|
21
|
+
}
|
|
22
|
+
await pe.call.bind(pe)(['lolomos', 'removeFromList'], [params.video_id], []);
|
|
23
|
+
return { success: true };
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=remove-from-my-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-from-my-list.js","sourceRoot":"","sources":["../../src/tools/remove-from-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;AAExB,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;IACzC,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EAAE,qBAAqB;IAClC,WAAW,EACT,iIAAiI;IACnI,OAAO,EAAE,6BAA6B;IACtC,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;KAClE,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;KACjE,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,EAAE,GAAG,aAAa,CAAC,wCAAwC,CAEzD,CAAC;QAET,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;YACd,MAAM,SAAS,CAAC,QAAQ,CAAC,8CAA8C,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,gBAAgB,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;QAE7E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const titleSchema: z.ZodObject<{
|
|
3
|
+
video_id: z.ZodNumber;
|
|
4
|
+
title: z.ZodString;
|
|
5
|
+
type: z.ZodString;
|
|
6
|
+
year: z.ZodNumber;
|
|
7
|
+
is_original: z.ZodBoolean;
|
|
8
|
+
maturity_rating: z.ZodString;
|
|
9
|
+
maturity_description: z.ZodString;
|
|
10
|
+
synopsis: z.ZodString;
|
|
11
|
+
genres: z.ZodString;
|
|
12
|
+
watch_status: z.ZodString;
|
|
13
|
+
is_in_my_list: z.ZodBoolean;
|
|
14
|
+
runtime_minutes: z.ZodNumber;
|
|
15
|
+
num_seasons: z.ZodString;
|
|
16
|
+
image_url: z.ZodString;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
export interface RawTitle {
|
|
19
|
+
videoId?: number;
|
|
20
|
+
title?: string;
|
|
21
|
+
__typename?: string;
|
|
22
|
+
latestYear?: number;
|
|
23
|
+
isOriginal?: boolean;
|
|
24
|
+
contentAdvisory?: {
|
|
25
|
+
certificationValue?: string;
|
|
26
|
+
maturityDescription?: string;
|
|
27
|
+
};
|
|
28
|
+
synopsis?: {
|
|
29
|
+
value?: string;
|
|
30
|
+
};
|
|
31
|
+
contextualSynopsis?: {
|
|
32
|
+
text?: string;
|
|
33
|
+
};
|
|
34
|
+
textEvidence?: Array<{
|
|
35
|
+
text?: string;
|
|
36
|
+
}>;
|
|
37
|
+
watchStatus?: string;
|
|
38
|
+
isInPlaylist?: boolean;
|
|
39
|
+
isInRemindMeList?: boolean;
|
|
40
|
+
runtimeSec?: number;
|
|
41
|
+
displayRuntimeSec?: number;
|
|
42
|
+
numSeasonsLabel?: string;
|
|
43
|
+
artwork?: {
|
|
44
|
+
url?: string;
|
|
45
|
+
};
|
|
46
|
+
artworkUrl?: string;
|
|
47
|
+
summary?: {
|
|
48
|
+
type?: string;
|
|
49
|
+
isOriginal?: boolean;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export declare const mapTitle: (t: RawTitle) => z.infer<typeof titleSchema>;
|
|
53
|
+
export declare const episodeSchema: z.ZodObject<{
|
|
54
|
+
video_id: z.ZodNumber;
|
|
55
|
+
title: z.ZodString;
|
|
56
|
+
episode_number: z.ZodNumber;
|
|
57
|
+
season_number: z.ZodNumber;
|
|
58
|
+
synopsis: z.ZodString;
|
|
59
|
+
runtime_minutes: z.ZodNumber;
|
|
60
|
+
watch_status: z.ZodString;
|
|
61
|
+
bookmark_position_seconds: z.ZodNumber;
|
|
62
|
+
image_url: z.ZodString;
|
|
63
|
+
}, z.core.$strip>;
|
|
64
|
+
export interface RawEpisode {
|
|
65
|
+
videoId?: number;
|
|
66
|
+
title?: string;
|
|
67
|
+
number?: number;
|
|
68
|
+
seasonNumber?: number;
|
|
69
|
+
synopsis?: {
|
|
70
|
+
value?: string;
|
|
71
|
+
};
|
|
72
|
+
contextualSynopsis?: {
|
|
73
|
+
text?: string;
|
|
74
|
+
};
|
|
75
|
+
runtimeSec?: number;
|
|
76
|
+
displayRuntimeSec?: number;
|
|
77
|
+
watchStatus?: string;
|
|
78
|
+
bookmark?: {
|
|
79
|
+
position?: number;
|
|
80
|
+
};
|
|
81
|
+
artwork?: {
|
|
82
|
+
url?: string;
|
|
83
|
+
};
|
|
84
|
+
artworkUrl?: string;
|
|
85
|
+
}
|
|
86
|
+
export declare const mapEpisode: (e: RawEpisode, seasonNum?: number) => z.infer<typeof episodeSchema>;
|
|
87
|
+
export declare const seasonSchema: z.ZodObject<{
|
|
88
|
+
video_id: z.ZodNumber;
|
|
89
|
+
season_number: z.ZodNumber;
|
|
90
|
+
title: z.ZodString;
|
|
91
|
+
episode_count: z.ZodNumber;
|
|
92
|
+
}, z.core.$strip>;
|
|
93
|
+
export interface RawSeason {
|
|
94
|
+
videoId?: number;
|
|
95
|
+
seasonNumber?: number;
|
|
96
|
+
title?: string;
|
|
97
|
+
episodes?: {
|
|
98
|
+
totalCount?: number;
|
|
99
|
+
};
|
|
100
|
+
episodeCount?: number;
|
|
101
|
+
}
|
|
102
|
+
export declare const mapSeason: (s: RawSeason) => z.infer<typeof seasonSchema>;
|
|
103
|
+
export declare const profileSchema: z.ZodObject<{
|
|
104
|
+
guid: z.ZodString;
|
|
105
|
+
name: z.ZodString;
|
|
106
|
+
is_kids: z.ZodBoolean;
|
|
107
|
+
avatar_url: z.ZodString;
|
|
108
|
+
is_active: z.ZodBoolean;
|
|
109
|
+
}, z.core.$strip>;
|
|
110
|
+
export interface RawProfile {
|
|
111
|
+
guid?: string;
|
|
112
|
+
profileName?: string;
|
|
113
|
+
firstName?: string;
|
|
114
|
+
isKids?: boolean;
|
|
115
|
+
avatar?: {
|
|
116
|
+
url?: string;
|
|
117
|
+
images?: Record<string, {
|
|
118
|
+
url?: string;
|
|
119
|
+
}>;
|
|
120
|
+
};
|
|
121
|
+
avatarUrl?: string;
|
|
122
|
+
isActive?: boolean;
|
|
123
|
+
isCurrent?: boolean;
|
|
124
|
+
}
|
|
125
|
+
export declare const mapProfile: (p: RawProfile) => z.infer<typeof profileSchema>;
|
|
126
|
+
export declare const userInfoSchema: z.ZodObject<{
|
|
127
|
+
guid: z.ZodString;
|
|
128
|
+
name: z.ZodString;
|
|
129
|
+
email: z.ZodString;
|
|
130
|
+
member_since: z.ZodString;
|
|
131
|
+
membership_status: z.ZodString;
|
|
132
|
+
country: z.ZodString;
|
|
133
|
+
num_profiles: z.ZodNumber;
|
|
134
|
+
maturity_level: z.ZodNumber;
|
|
135
|
+
can_playback: z.ZodBoolean;
|
|
136
|
+
}, z.core.$strip>;
|
|
137
|
+
export interface RawUserInfo {
|
|
138
|
+
guid?: string;
|
|
139
|
+
userGuid?: string;
|
|
140
|
+
name?: string;
|
|
141
|
+
accountOwnerName?: string;
|
|
142
|
+
email?: string;
|
|
143
|
+
memberSince?: string;
|
|
144
|
+
membershipStatus?: string;
|
|
145
|
+
currentCountry?: string;
|
|
146
|
+
numProfiles?: number;
|
|
147
|
+
maturity?: number;
|
|
148
|
+
pacsFeatures?: {
|
|
149
|
+
featureResponses?: Array<{
|
|
150
|
+
featureName?: string;
|
|
151
|
+
responseClassification?: string;
|
|
152
|
+
}>;
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
export declare const mapUserInfo: (u: RawUserInfo) => z.infer<typeof userInfoSchema>;
|
|
156
|
+
/** Map an Apollo cache entry to the RawTitle shape for mapTitle. */
|
|
157
|
+
export declare const apolloEntryToRawTitle: (entry: Record<string, unknown>) => RawTitle;
|
|
158
|
+
export declare const watchHistorySchema: z.ZodObject<{
|
|
159
|
+
video_id: z.ZodNumber;
|
|
160
|
+
title: z.ZodString;
|
|
161
|
+
type: z.ZodString;
|
|
162
|
+
watch_status: z.ZodString;
|
|
163
|
+
bookmark_position_seconds: z.ZodNumber;
|
|
164
|
+
runtime_seconds: z.ZodNumber;
|
|
165
|
+
last_watched: z.ZodString;
|
|
166
|
+
}, z.core.$strip>;
|
|
167
|
+
export interface RawWatchHistoryEntry {
|
|
168
|
+
videoId?: number;
|
|
169
|
+
title?: string;
|
|
170
|
+
type?: string;
|
|
171
|
+
__typename?: string;
|
|
172
|
+
watchStatus?: string;
|
|
173
|
+
bookmark?: {
|
|
174
|
+
position?: number;
|
|
175
|
+
};
|
|
176
|
+
bookmarkPosition?: number;
|
|
177
|
+
runtimeSec?: number;
|
|
178
|
+
runtime?: number;
|
|
179
|
+
dateStr?: string;
|
|
180
|
+
summary?: {
|
|
181
|
+
type?: string;
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
export declare const mapWatchHistoryEntry: (e: RawWatchHistoryEntry) => z.infer<typeof watchHistorySchema>;
|
|
185
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/tools/schemas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
// --- Title (Movie or Show) ---
|
|
3
|
+
export const titleSchema = z.object({
|
|
4
|
+
video_id: z.number().int().describe('Netflix video ID'),
|
|
5
|
+
title: z.string().describe('Title name'),
|
|
6
|
+
type: z.string().describe('Content type: movie, show, or supplemental'),
|
|
7
|
+
year: z.number().int().describe('Release year or latest year'),
|
|
8
|
+
is_original: z.boolean().describe('Whether this is a Netflix Original'),
|
|
9
|
+
maturity_rating: z.string().describe('Maturity rating (e.g., TV-MA, PG-13)'),
|
|
10
|
+
maturity_description: z.string().describe('Description of the maturity rating'),
|
|
11
|
+
synopsis: z.string().describe('Content synopsis or description'),
|
|
12
|
+
genres: z.string().describe('Comma-separated genre tags'),
|
|
13
|
+
watch_status: z.string().describe('Watch status: NOT_WATCHED, STARTED, or WATCHED'),
|
|
14
|
+
is_in_my_list: z.boolean().describe('Whether the title is in the user My List'),
|
|
15
|
+
runtime_minutes: z.number().describe('Runtime in minutes (for movies) or 0 for shows'),
|
|
16
|
+
num_seasons: z.string().describe('Number of seasons label (for shows) or empty'),
|
|
17
|
+
image_url: z.string().describe('Thumbnail image URL'),
|
|
18
|
+
});
|
|
19
|
+
export const mapTitle = (t) => ({
|
|
20
|
+
video_id: t.videoId ?? 0,
|
|
21
|
+
title: t.title ?? '',
|
|
22
|
+
type: t.__typename?.toLowerCase() ?? t.summary?.type ?? '',
|
|
23
|
+
year: t.latestYear ?? 0,
|
|
24
|
+
is_original: t.isOriginal ?? t.summary?.isOriginal ?? false,
|
|
25
|
+
maturity_rating: t.contentAdvisory?.certificationValue ?? '',
|
|
26
|
+
maturity_description: t.contentAdvisory?.maturityDescription ?? '',
|
|
27
|
+
synopsis: t.contextualSynopsis?.text ?? t.synopsis?.value ?? t.textEvidence?.[0]?.text ?? '',
|
|
28
|
+
genres: t.textEvidence?.[0]?.text ?? '',
|
|
29
|
+
watch_status: t.watchStatus ?? 'NOT_WATCHED',
|
|
30
|
+
is_in_my_list: t.isInPlaylist ?? t.isInRemindMeList ?? false,
|
|
31
|
+
runtime_minutes: Math.round((t.displayRuntimeSec ?? t.runtimeSec ?? 0) / 60),
|
|
32
|
+
num_seasons: t.numSeasonsLabel ?? '',
|
|
33
|
+
image_url: t.artwork?.url ?? t.artworkUrl ?? '',
|
|
34
|
+
});
|
|
35
|
+
// --- Episode ---
|
|
36
|
+
export const episodeSchema = z.object({
|
|
37
|
+
video_id: z.number().int().describe('Episode video ID'),
|
|
38
|
+
title: z.string().describe('Episode title'),
|
|
39
|
+
episode_number: z.number().int().describe('Episode number within the season'),
|
|
40
|
+
season_number: z.number().int().describe('Season number'),
|
|
41
|
+
synopsis: z.string().describe('Episode synopsis'),
|
|
42
|
+
runtime_minutes: z.number().describe('Runtime in minutes'),
|
|
43
|
+
watch_status: z.string().describe('Watch status: NOT_WATCHED, STARTED, or WATCHED'),
|
|
44
|
+
bookmark_position_seconds: z.number().describe('Bookmark position in seconds (0 if not started)'),
|
|
45
|
+
image_url: z.string().describe('Episode thumbnail URL'),
|
|
46
|
+
});
|
|
47
|
+
export const mapEpisode = (e, seasonNum) => ({
|
|
48
|
+
video_id: e.videoId ?? 0,
|
|
49
|
+
title: e.title ?? '',
|
|
50
|
+
episode_number: e.number ?? 0,
|
|
51
|
+
season_number: seasonNum ?? e.seasonNumber ?? 0,
|
|
52
|
+
synopsis: e.contextualSynopsis?.text ?? e.synopsis?.value ?? '',
|
|
53
|
+
runtime_minutes: Math.round((e.displayRuntimeSec ?? e.runtimeSec ?? 0) / 60),
|
|
54
|
+
watch_status: e.watchStatus ?? 'NOT_WATCHED',
|
|
55
|
+
bookmark_position_seconds: e.bookmark?.position ?? 0,
|
|
56
|
+
image_url: e.artwork?.url ?? e.artworkUrl ?? '',
|
|
57
|
+
});
|
|
58
|
+
// --- Season ---
|
|
59
|
+
export const seasonSchema = z.object({
|
|
60
|
+
video_id: z.number().int().describe('Season video ID'),
|
|
61
|
+
season_number: z.number().int().describe('Season number'),
|
|
62
|
+
title: z.string().describe('Season title (e.g., "Season 1")'),
|
|
63
|
+
episode_count: z.number().int().describe('Number of episodes in the season'),
|
|
64
|
+
});
|
|
65
|
+
export const mapSeason = (s) => ({
|
|
66
|
+
video_id: s.videoId ?? 0,
|
|
67
|
+
season_number: s.seasonNumber ?? 0,
|
|
68
|
+
title: s.title ?? '',
|
|
69
|
+
episode_count: s.episodes?.totalCount ?? s.episodeCount ?? 0,
|
|
70
|
+
});
|
|
71
|
+
// --- Profile ---
|
|
72
|
+
export const profileSchema = z.object({
|
|
73
|
+
guid: z.string().describe('Profile GUID'),
|
|
74
|
+
name: z.string().describe('Profile display name'),
|
|
75
|
+
is_kids: z.boolean().describe('Whether this is a kids profile'),
|
|
76
|
+
avatar_url: z.string().describe('Avatar image URL'),
|
|
77
|
+
is_active: z.boolean().describe('Whether this is the currently active profile'),
|
|
78
|
+
});
|
|
79
|
+
export const mapProfile = (p) => ({
|
|
80
|
+
guid: p.guid ?? '',
|
|
81
|
+
name: p.profileName ?? p.firstName ?? '',
|
|
82
|
+
is_kids: p.isKids ?? false,
|
|
83
|
+
avatar_url: p.avatar?.url ?? p.avatarUrl ?? '',
|
|
84
|
+
is_active: p.isActive ?? p.isCurrent ?? false,
|
|
85
|
+
});
|
|
86
|
+
// --- User Info ---
|
|
87
|
+
export const userInfoSchema = z.object({
|
|
88
|
+
guid: z.string().describe('User GUID'),
|
|
89
|
+
name: z.string().describe('Account owner name'),
|
|
90
|
+
email: z.string().describe('Account email (if available)'),
|
|
91
|
+
member_since: z.string().describe('Membership start date (e.g., "January 2025")'),
|
|
92
|
+
membership_status: z.string().describe('Membership status (e.g., CURRENT_MEMBER)'),
|
|
93
|
+
country: z.string().describe('Current country code'),
|
|
94
|
+
num_profiles: z.number().int().describe('Total number of profiles on the account'),
|
|
95
|
+
maturity_level: z.number().int().describe('Content maturity level for this profile'),
|
|
96
|
+
can_playback: z.boolean().describe('Whether playback is allowed'),
|
|
97
|
+
});
|
|
98
|
+
export const mapUserInfo = (u) => {
|
|
99
|
+
const canPlayback = u.pacsFeatures?.featureResponses?.find(f => f.featureName === 'CAN_PLAYBACK')?.responseClassification === 'ALLOWED';
|
|
100
|
+
return {
|
|
101
|
+
guid: u.guid ?? u.userGuid ?? '',
|
|
102
|
+
name: u.accountOwnerName ?? u.name ?? '',
|
|
103
|
+
email: u.email ?? '',
|
|
104
|
+
member_since: u.memberSince ?? '',
|
|
105
|
+
membership_status: u.membershipStatus ?? '',
|
|
106
|
+
country: u.currentCountry ?? '',
|
|
107
|
+
num_profiles: u.numProfiles ?? 0,
|
|
108
|
+
maturity_level: u.maturity ?? 0,
|
|
109
|
+
can_playback: canPlayback ?? false,
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
// --- Apollo Cache Helper ---
|
|
113
|
+
/** Map an Apollo cache entry to the RawTitle shape for mapTitle. */
|
|
114
|
+
export const apolloEntryToRawTitle = (entry) => {
|
|
115
|
+
let artworkUrl = '';
|
|
116
|
+
let genres = '';
|
|
117
|
+
for (const [k, v] of Object.entries(entry)) {
|
|
118
|
+
if (!artworkUrl && (k.startsWith('artwork(') || k.startsWith('artworkExtended('))) {
|
|
119
|
+
const art = v;
|
|
120
|
+
if (art?.url && typeof art.url === 'string')
|
|
121
|
+
artworkUrl = art.url;
|
|
122
|
+
}
|
|
123
|
+
if (!genres && k.startsWith('textEvidence(')) {
|
|
124
|
+
const tags = v;
|
|
125
|
+
if (tags?.[0]?.text)
|
|
126
|
+
genres = tags[0].text;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
videoId: entry.videoId,
|
|
131
|
+
title: entry.title,
|
|
132
|
+
__typename: entry.__typename,
|
|
133
|
+
latestYear: entry.latestYear,
|
|
134
|
+
watchStatus: entry.watchStatus,
|
|
135
|
+
isInPlaylist: entry.isInPlaylist,
|
|
136
|
+
isInRemindMeList: entry.isInRemindMeList,
|
|
137
|
+
runtimeSec: (entry.displayRuntimeSec ?? entry.runtimeSec),
|
|
138
|
+
numSeasonsLabel: entry.numSeasonsLabel,
|
|
139
|
+
contentAdvisory: entry.contentAdvisory,
|
|
140
|
+
artworkUrl,
|
|
141
|
+
textEvidence: genres ? [{ text: genres }] : undefined,
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
// --- Watch History Entry ---
|
|
145
|
+
export const watchHistorySchema = z.object({
|
|
146
|
+
video_id: z.number().int().describe('Netflix video ID'),
|
|
147
|
+
title: z.string().describe('Title name'),
|
|
148
|
+
type: z.string().describe('Content type: movie or show'),
|
|
149
|
+
watch_status: z.string().describe('Watch status: STARTED or WATCHED'),
|
|
150
|
+
bookmark_position_seconds: z.number().describe('Bookmark position in seconds'),
|
|
151
|
+
runtime_seconds: z.number().describe('Total runtime in seconds'),
|
|
152
|
+
last_watched: z.string().describe('ISO 8601 timestamp of last watch (if available)'),
|
|
153
|
+
});
|
|
154
|
+
export const mapWatchHistoryEntry = (e) => ({
|
|
155
|
+
video_id: e.videoId ?? 0,
|
|
156
|
+
title: e.title ?? '',
|
|
157
|
+
type: e.__typename?.toLowerCase() ?? e.summary?.type ?? e.type ?? '',
|
|
158
|
+
watch_status: e.watchStatus ?? 'STARTED',
|
|
159
|
+
bookmark_position_seconds: e.bookmark?.position ?? e.bookmarkPosition ?? 0,
|
|
160
|
+
runtime_seconds: e.runtimeSec ?? e.runtime ?? 0,
|
|
161
|
+
last_watched: e.dateStr ?? '',
|
|
162
|
+
});
|
|
163
|
+
//# sourceMappingURL=schemas.js.map
|