Skip to content

Commit 87d7e23

Browse files
committed
chore: v3
1 parent c7e8da3 commit 87d7e23

File tree

7 files changed

+92
-28
lines changed

7 files changed

+92
-28
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",
77
"scripts": {
8-
"build": "tsup",
8+
"build": "rm -rf ./dist && tsup",
99
"test": "vitest"
1010
},
1111
"devDependencies": {

src/client.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export interface ClientOptions {
55
kodikApiUrl?: string;
66
}
77

8-
const KODIK_API_URL = 'https://kodikapi.com';
8+
export const KODIK_API_URL = 'https://kodikapi.com';
99

1010
const endpointsArr: (keyof APIMethods)[] =
1111
['countries', 'genres', 'list', 'qualities', 'search', 'translations', 'years', 'qualitiesV2', 'translationsV2'];
@@ -21,7 +21,6 @@ export class ClientError extends Error {
2121

2222
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
2323
export class Client {
24-
// private agent: Agent;
2524
public KODIK_API_URL: string;
2625

2726
constructor({ token, kodikApiUrl }: ClientOptions) {

src/errors/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
export * from './parse';
21
export * from './video-links';

src/errors/parse.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/errors/video-links.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,42 @@
1+
export interface VideoLinksErrorOptions {
2+
code: string;
3+
description: string;
4+
data?: unknown;
5+
cause?: unknown;
6+
}
7+
18
export class VideoLinksError extends Error {
2-
name: string = 'VideoLinksError';
9+
/** Error code */
10+
code: string;
11+
/** Error stack */
12+
stack!: string;
13+
/** Error data */
14+
data?: unknown;
15+
/** Error cause */
16+
cause?: unknown;
17+
18+
constructor ({ code, description, data, cause }: VideoLinksErrorOptions) {
19+
super(description);
20+
21+
this.code = code;
22+
this.data = data;
23+
this.name = this.constructor.name;
24+
this.cause = cause;
25+
26+
Error.captureStackTrace(this, this.constructor);
27+
}
28+
29+
get [Symbol.toStringTag] () {
30+
return this.constructor.name;
31+
}
32+
33+
toJSON (): Pick<this, keyof this> {
34+
const json = {} as Pick<this, keyof this>;
35+
36+
for (const key of Object.getOwnPropertyNames(this)) {
37+
json[key as keyof this] = this[key as keyof this];
38+
}
39+
40+
return json;
41+
}
342
}

src/resources/index.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
export * from './countries';
2-
export * from './genres';
3-
export * from './list';
4-
export * from './qualities';
5-
export * from './search';
6-
export * from './translations';
7-
export * from './years';
8-
export * from './shared-types';
1+
export type * from './countries';
2+
export type * from './genres';
3+
export type * from './list';
4+
export type * from './qualities';
5+
export type * from './search';
6+
export type * from './translations';
7+
export type * from './years';
8+
export type * from './shared-types';

src/video-links.ts

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ParseError, VideoLinksError } from './errors';
1+
import { VideoLinksError } from './errors';
22
import type { ObjectOrUnknown } from './types';
33

44
export const KODIK_PLAYER_DOMAIN = 'kodik.info';
@@ -63,13 +63,22 @@ export const kodikPlayerLinkRegexp = /^(?<protocol>http[s]?:|)\/\/(?<host>[a-z0-
6363

6464
export class VideoLinks {
6565
static async parseLink<Extended extends boolean>({ extended, link }: VideoLinksParseParams<Extended>): Promise<KodikParsedLink<Extended>> {
66-
if (!link) throw new ParseError('link is undefined');
66+
if (!link)
67+
throw new VideoLinksError({
68+
code: 'parse-link-invalid',
69+
description: 'link is not provided',
70+
data: { link }
71+
});
6772

6873
const kodikLink = this.normalizeKodikLink(link);
69-
if (!kodikPlayerLinkRegexp.test(link)) throw new ParseError('kodikLink is not allowed');
74+
if (!kodikPlayerLinkRegexp.test(link))
75+
throw new VideoLinksError({
76+
code: 'parse-link-invalid',
77+
description: 'link is not valid',
78+
data: { link }
79+
});
7080

71-
const linkParams = kodikPlayerLinkRegexp.exec(kodikLink)?.groups;
72-
if (!linkParams) throw new ParseError('cannot get \'groups\' from \'linkParams\'');
81+
const linkParams = kodikPlayerLinkRegexp.exec(kodikLink)!.groups!;
7382

7483
const { host, hash, id, quality, type } = linkParams;
7584
const parsedLink: KodikParsedLink = {
@@ -85,8 +94,16 @@ export class VideoLinks {
8594
const skipButtons = page.match(/parseSkipButtons?\("(?<data>[^"]+)"\s*,\s*"(?<type>[^"]+)"\)/is)?.groups;
8695
const playerSingleUrl = page.match(/src="(?<link>\/assets\/js\/app\.player_single\.[a-z0-9]+\.js)"/is)?.groups?.link;
8796

88-
if (!urlParams) throw new ParseError('cannot get urlParams');
89-
if (!translation) throw new ParseError('cannot get translation');
97+
if (!urlParams) throw new VideoLinksError({
98+
code: 'parse-link-ex-invalid',
99+
description: 'cannot get url params',
100+
data: { link, page }
101+
});
102+
if (!translation) throw new VideoLinksError({
103+
code: 'parse-link-ex-invalid',
104+
description: 'cannot get translation',
105+
data: { link, page }
106+
});
90107

91108
const extendedParsedLink: KodikParsedLink<true> = {
92109
...parsedLink,
@@ -126,25 +143,38 @@ export class VideoLinks {
126143
);
127144
const videoInfoResponse = await fetch(url);
128145
if (videoInfoResponse.headers.get('content-type') !== 'application/json')
129-
throw new VideoLinksError('videoInfoResponse is not json');
146+
throw new VideoLinksError({
147+
code: 'get-links-invalid-response',
148+
description: 'videoInfoResponse is not json',
149+
data: { videoInfoResponse }
150+
});
130151

131152
const videoInfoJson = await videoInfoResponse.json();
132153

133154
if (typeof videoInfoJson !== 'object' || videoInfoJson === null)
134-
throw new VideoLinksError('videoInfoJson is not object');
155+
throw new VideoLinksError({
156+
code: 'get-links-invalid-response',
157+
description: 'videoInfoJson is not object',
158+
data: { videoInfoResponse, videoInfoJson }
159+
});
135160
if (typeof videoInfoJson.links !== 'object')
136-
throw new VideoLinksError('videoInfoJson.links is not object');
161+
throw new VideoLinksError({
162+
code: 'get-links-invalid-response',
163+
description: 'videoInfoJson.links is not object',
164+
data: { videoInfoResponse, videoInfoJson }
165+
});
137166

138167
const links = videoInfoJson.links as KodikVideoLinks;
139168
const zCharCode = 'Z'.charCodeAt(0);
140169

141170
// decrypt source links
142171
for (const [, sources] of Object.entries(links)) {
143172
for (const source of sources) {
144-
source.src = Buffer.from(source.src.replace(/[a-zA-Z]/g, e => {
173+
const decryptedBase64 = source.src.replace(/[a-zA-Z]/g, e => {
145174
let eCharCode = e.charCodeAt(0);
146175
return String.fromCharCode((eCharCode <= zCharCode ? 90 : 122) >= (eCharCode = eCharCode + 13) ? eCharCode : eCharCode - 26);
147-
}), 'base64').toString('utf8');
176+
});
177+
source.src = atob(decryptedBase64);
148178
}
149179
}
150180

0 commit comments

Comments
 (0)