wyzie-lib 2.2.7 → 2.2.8

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/LICENSE CHANGED
@@ -1,7 +1,7 @@
1
- Copyright 2024 Bad Developer
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
-
5
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
-
1
+ Copyright 2024 Bad Developer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
7
  THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
- <p align="center">
2
- <a href="https://sub.wyzie.ru/">
3
- <img src="https://i.postimg.cc/L5ppKYC5/cclogo.png" height="120">
4
- <h1 align="center">Wyzie Lib</h1>
5
- </a>
6
- </p>
7
-
8
- Wyzie Lib is a package made for easily implementing [Wyzie Subs](https://sub.wyzie.ru) into your
9
- project without all the fuss. [Read the docs](https://docs.wyzie.ru/subs/usage/package).
1
+ <p align="center">
2
+ <a href="https://sub.wyzie.ru/">
3
+ <img src="https://i.postimg.cc/L5ppKYC5/cclogo.png" height="120">
4
+ <h1 align="center">Wyzie Lib</h1>
5
+ </a>
6
+ </p>
7
+
8
+ Wyzie Lib is a package made for easily implementing [Wyzie Subs](https://sub.wyzie.ru) into your
9
+ project without all the fuss. [Read the docs](https://docs.wyzie.ru/subs/usage/package).
@@ -0,0 +1,146 @@
1
+ define(["exports"], function(exports) {
2
+ "use strict";
3
+ const config = {
4
+ baseUrl: "https://sub.wyzie.ru"
5
+ };
6
+ function configure(options) {
7
+ if (options.baseUrl) {
8
+ config.baseUrl = options.baseUrl.replace(/\/$/, "");
9
+ }
10
+ }
11
+ async function constructUrl({
12
+ tmdb_id,
13
+ imdb_id,
14
+ season,
15
+ episode,
16
+ encoding,
17
+ language,
18
+ format,
19
+ source,
20
+ hi,
21
+ ...extraParams
22
+ }) {
23
+ if (!tmdb_id && !imdb_id) {
24
+ throw new Error("Either tmdb_id or imdb_id must be provided.");
25
+ }
26
+ const hasSeason = season !== void 0;
27
+ const hasEpisode = episode !== void 0;
28
+ if (hasSeason && !hasEpisode || !hasSeason && hasEpisode) {
29
+ throw new Error("Season and episode must be provided together or omitted together.");
30
+ }
31
+ const url = new URL(`${config.baseUrl}/search`);
32
+ const queryParams = {
33
+ id: String(tmdb_id || imdb_id),
34
+ season,
35
+ episode,
36
+ encoding: Array.isArray(encoding) ? encoding.join(",") : encoding,
37
+ language: Array.isArray(language) ? language.join(",") : language,
38
+ format: Array.isArray(format) ? format.join(",") : format,
39
+ source: Array.isArray(source) ? source.join(",") : source,
40
+ hi
41
+ };
42
+ Object.entries(queryParams).forEach(([key, value]) => {
43
+ if (value !== void 0) {
44
+ url.searchParams.append(key, String(value));
45
+ }
46
+ });
47
+ Object.entries(extraParams).forEach(([key, value]) => {
48
+ if (value !== void 0) {
49
+ if (Array.isArray(value)) {
50
+ url.searchParams.append(key, value.join(","));
51
+ } else {
52
+ url.searchParams.append(key, String(value));
53
+ }
54
+ }
55
+ });
56
+ return url;
57
+ }
58
+ async function fetchSubtitles(url) {
59
+ const response = await fetch(url.toString());
60
+ if (!response.ok) {
61
+ throw new Error(`HTTP error! status: ${response.status}`);
62
+ }
63
+ return response.json();
64
+ }
65
+ async function searchSubtitles(params) {
66
+ try {
67
+ const url = await constructUrl(params);
68
+ return await fetchSubtitles(url);
69
+ } catch (error) {
70
+ throw new Error(`Error fetching subtitles: ${error}`);
71
+ }
72
+ }
73
+ async function parseToVTT(subtitleUrl) {
74
+ try {
75
+ const response = await fetch(subtitleUrl);
76
+ if (!response.ok) {
77
+ throw new Error(`Failed to fetch subtitle content: ${response.status}`);
78
+ }
79
+ const content = await response.text();
80
+ const normalizedContent = content.replace(/\r\n|\r/g, "\n").trim();
81
+ const blocks = normalizedContent.split(/\n\n+/);
82
+ const timestampRegex = /^\d{1,2}:\d{2}:\d{2}[,.]\d{3}\s*-->\s*\d{1,2}:\d{2}:\d{2}[,.]\d{3}$/;
83
+ const hasValidSRTFormat = blocks.some((block) => {
84
+ const lines = block.split("\n").map((line) => line.trim());
85
+ return lines.some((line) => timestampRegex.test(line));
86
+ });
87
+ if (!hasValidSRTFormat) {
88
+ throw new Error("Invalid subtitle format: not SRT");
89
+ }
90
+ const vttLines = ["WEBVTT", ""];
91
+ for (const block of blocks) {
92
+ const lines = block.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
93
+ if (lines.length < 2)
94
+ continue;
95
+ const timestampIndex = lines.findIndex((line) => timestampRegex.test(line));
96
+ if (timestampIndex === -1)
97
+ continue;
98
+ const textLines = lines.slice(timestampIndex + 1).filter((line) => !/^\d+$/.test(line));
99
+ if (textLines.length === 0)
100
+ continue;
101
+ let timestampLine = lines[timestampIndex];
102
+ timestampLine = timestampLine.replace(/[,.](?=\s*-->)/, "").replace(/[,.]$/, "").replace(/,(\d{3})/g, ".$1");
103
+ vttLines.push(`${timestampLine}
104
+ ${textLines.join("\n")}
105
+ `);
106
+ }
107
+ return vttLines.join("\n").replace(/\n{3,}/g, "\n\n").trim() + "\n\n";
108
+ } catch (error) {
109
+ console.error("Error in parseToVTT:", error);
110
+ throw error;
111
+ }
112
+ }
113
+ async function searchTmdb(query, language = "en-US") {
114
+ const url = new URL(`${config.baseUrl}/api/tmdb/search`);
115
+ url.searchParams.append("q", query);
116
+ url.searchParams.append("language", language);
117
+ const response = await fetch(url.toString());
118
+ if (!response.ok) {
119
+ throw new Error(`Failed to search TMDB: ${response.status}`);
120
+ }
121
+ return response.json();
122
+ }
123
+ async function getTvDetails(id) {
124
+ const url = `${config.baseUrl}/api/tmdb/tv/${id}`;
125
+ const response = await fetch(url);
126
+ if (!response.ok) {
127
+ throw new Error(`Failed to fetch TV details: ${response.status}`);
128
+ }
129
+ return response.json();
130
+ }
131
+ async function getSeasonDetails(id, season) {
132
+ const url = `${config.baseUrl}/api/tmdb/tv/${id}/${season}`;
133
+ const response = await fetch(url);
134
+ if (!response.ok) {
135
+ throw new Error(`Failed to fetch season details: ${response.status}`);
136
+ }
137
+ return response.json();
138
+ }
139
+ exports.configure = configure;
140
+ exports.getSeasonDetails = getSeasonDetails;
141
+ exports.getTvDetails = getTvDetails;
142
+ exports.parseToVTT = parseToVTT;
143
+ exports.searchSubtitles = searchSubtitles;
144
+ exports.searchTmdb = searchTmdb;
145
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
146
+ });
package/lib/main.cjs ADDED
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const config = {
4
+ baseUrl: "https://sub.wyzie.ru"
5
+ };
6
+ function configure(options) {
7
+ if (options.baseUrl) {
8
+ config.baseUrl = options.baseUrl.replace(/\/$/, "");
9
+ }
10
+ }
11
+ async function constructUrl({
12
+ tmdb_id,
13
+ imdb_id,
14
+ season,
15
+ episode,
16
+ encoding,
17
+ language,
18
+ format,
19
+ source,
20
+ hi,
21
+ ...extraParams
22
+ }) {
23
+ if (!tmdb_id && !imdb_id) {
24
+ throw new Error("Either tmdb_id or imdb_id must be provided.");
25
+ }
26
+ const hasSeason = season !== void 0;
27
+ const hasEpisode = episode !== void 0;
28
+ if (hasSeason && !hasEpisode || !hasSeason && hasEpisode) {
29
+ throw new Error("Season and episode must be provided together or omitted together.");
30
+ }
31
+ const url = new URL(`${config.baseUrl}/search`);
32
+ const queryParams = {
33
+ id: String(tmdb_id || imdb_id),
34
+ season,
35
+ episode,
36
+ encoding: Array.isArray(encoding) ? encoding.join(",") : encoding,
37
+ language: Array.isArray(language) ? language.join(",") : language,
38
+ format: Array.isArray(format) ? format.join(",") : format,
39
+ source: Array.isArray(source) ? source.join(",") : source,
40
+ hi
41
+ };
42
+ Object.entries(queryParams).forEach(([key, value]) => {
43
+ if (value !== void 0) {
44
+ url.searchParams.append(key, String(value));
45
+ }
46
+ });
47
+ Object.entries(extraParams).forEach(([key, value]) => {
48
+ if (value !== void 0) {
49
+ if (Array.isArray(value)) {
50
+ url.searchParams.append(key, value.join(","));
51
+ } else {
52
+ url.searchParams.append(key, String(value));
53
+ }
54
+ }
55
+ });
56
+ return url;
57
+ }
58
+ async function fetchSubtitles(url) {
59
+ const response = await fetch(url.toString());
60
+ if (!response.ok) {
61
+ throw new Error(`HTTP error! status: ${response.status}`);
62
+ }
63
+ return response.json();
64
+ }
65
+ async function searchSubtitles(params) {
66
+ try {
67
+ const url = await constructUrl(params);
68
+ return await fetchSubtitles(url);
69
+ } catch (error) {
70
+ throw new Error(`Error fetching subtitles: ${error}`);
71
+ }
72
+ }
73
+ async function parseToVTT(subtitleUrl) {
74
+ try {
75
+ const response = await fetch(subtitleUrl);
76
+ if (!response.ok) {
77
+ throw new Error(`Failed to fetch subtitle content: ${response.status}`);
78
+ }
79
+ const content = await response.text();
80
+ const normalizedContent = content.replace(/\r\n|\r/g, "\n").trim();
81
+ const blocks = normalizedContent.split(/\n\n+/);
82
+ const timestampRegex = /^\d{1,2}:\d{2}:\d{2}[,.]\d{3}\s*-->\s*\d{1,2}:\d{2}:\d{2}[,.]\d{3}$/;
83
+ const hasValidSRTFormat = blocks.some((block) => {
84
+ const lines = block.split("\n").map((line) => line.trim());
85
+ return lines.some((line) => timestampRegex.test(line));
86
+ });
87
+ if (!hasValidSRTFormat) {
88
+ throw new Error("Invalid subtitle format: not SRT");
89
+ }
90
+ const vttLines = ["WEBVTT", ""];
91
+ for (const block of blocks) {
92
+ const lines = block.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
93
+ if (lines.length < 2)
94
+ continue;
95
+ const timestampIndex = lines.findIndex((line) => timestampRegex.test(line));
96
+ if (timestampIndex === -1)
97
+ continue;
98
+ const textLines = lines.slice(timestampIndex + 1).filter((line) => !/^\d+$/.test(line));
99
+ if (textLines.length === 0)
100
+ continue;
101
+ let timestampLine = lines[timestampIndex];
102
+ timestampLine = timestampLine.replace(/[,.](?=\s*-->)/, "").replace(/[,.]$/, "").replace(/,(\d{3})/g, ".$1");
103
+ vttLines.push(`${timestampLine}
104
+ ${textLines.join("\n")}
105
+ `);
106
+ }
107
+ return vttLines.join("\n").replace(/\n{3,}/g, "\n\n").trim() + "\n\n";
108
+ } catch (error) {
109
+ console.error("Error in parseToVTT:", error);
110
+ throw error;
111
+ }
112
+ }
113
+ async function searchTmdb(query, language = "en-US") {
114
+ const url = new URL(`${config.baseUrl}/api/tmdb/search`);
115
+ url.searchParams.append("q", query);
116
+ url.searchParams.append("language", language);
117
+ const response = await fetch(url.toString());
118
+ if (!response.ok) {
119
+ throw new Error(`Failed to search TMDB: ${response.status}`);
120
+ }
121
+ return response.json();
122
+ }
123
+ async function getTvDetails(id) {
124
+ const url = `${config.baseUrl}/api/tmdb/tv/${id}`;
125
+ const response = await fetch(url);
126
+ if (!response.ok) {
127
+ throw new Error(`Failed to fetch TV details: ${response.status}`);
128
+ }
129
+ return response.json();
130
+ }
131
+ async function getSeasonDetails(id, season) {
132
+ const url = `${config.baseUrl}/api/tmdb/tv/${id}/${season}`;
133
+ const response = await fetch(url);
134
+ if (!response.ok) {
135
+ throw new Error(`Failed to fetch season details: ${response.status}`);
136
+ }
137
+ return response.json();
138
+ }
139
+ exports.configure = configure;
140
+ exports.getSeasonDetails = getSeasonDetails;
141
+ exports.getTvDetails = getTvDetails;
142
+ exports.parseToVTT = parseToVTT;
143
+ exports.searchSubtitles = searchSubtitles;
144
+ exports.searchTmdb = searchTmdb;
package/lib/main.d.ts ADDED
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Type for the configuration options for the library.
3
+ */
4
+ export declare type ConfigurationOptions = {
5
+ /** The API's hostname (default: sub.wyzie.ru) */
6
+ baseUrl: string;
7
+ };
8
+
9
+ /**
10
+ * Configure the library settings.
11
+ *
12
+ * @param {ConfigurationOptions} options - Config options for the library.
13
+ * @throws {Error} Throws an error if the baseUrl is not provided.
14
+ */
15
+ export declare function configure(options: ConfigurationOptions): void;
16
+
17
+ /**
18
+ * Details of a TV Episode.
19
+ */
20
+ export declare type EpisodeDetails = {
21
+ air_date?: string;
22
+ episode_number: number;
23
+ id: number;
24
+ name: string;
25
+ overview?: string;
26
+ production_code?: string;
27
+ runtime?: number | null;
28
+ season_number: number;
29
+ show_id?: number;
30
+ still_path?: string | null;
31
+ vote_average?: number;
32
+ vote_count?: number;
33
+ [key: string]: any;
34
+ };
35
+
36
+ /**
37
+ * Fetches details for a specific season of a TV show from TMDB.
38
+ *
39
+ * @param {number} id - The TMDB ID of the TV show.
40
+ * @param {number} season - The season number.
41
+ * @returns {Promise<SeasonDetails>} A promise that resolves to the season details.
42
+ */
43
+ export declare function getSeasonDetails(id: number, season: number): Promise<SeasonDetails>;
44
+
45
+ /**
46
+ * Fetches details for a TV show from TMDB.
47
+ *
48
+ * @param {number} id - The TMDB ID of the TV show.
49
+ * @returns {Promise<TvDetails>} A promise that resolves to the TV show details.
50
+ */
51
+ export declare function getTvDetails(id: number): Promise<TvDetails>;
52
+
53
+ /**
54
+ * Parses subtitle content from a URL to VTT format.
55
+ *
56
+ * @param {string} subtitleUrl - The URL of the subtitle to parse.
57
+ * @returns {Promise<string>} A promise that resolves to the subtitle content in VTT format.
58
+ * @throws {Error} Throws an error if fetching or parsing the subtitle content fails.
59
+ */
60
+ export declare function parseToVTT(subtitleUrl: string): Promise<string>;
61
+
62
+ /**
63
+ * Parameters used to construct the URL for subtitle search (requires an ID).
64
+ */
65
+ export declare type QueryParams = {
66
+ /** Unique identifier (either TMDB or IMDB ID). */
67
+ id: string;
68
+ /** Season number if the content is a series. */
69
+ season?: number;
70
+ /** Episode number if the content is a series. */
71
+ episode?: number;
72
+ /** Encoding of the subtitle files. */
73
+ encoding?: string;
74
+ /** ISO 3166 code of the subtitle desired. */
75
+ language?: string;
76
+ /** Which subtitle file format you want */
77
+ format?: string;
78
+ /** Determines if you get a hearing impaired subtitles */
79
+ hi?: boolean;
80
+ /** The source where the subtitle will be scraped from. */
81
+ source?: string;
82
+ /** Filter by specific release group or name. */
83
+ release?: string;
84
+ /** Filter by filename. */
85
+ filename?: string;
86
+ };
87
+
88
+ /**
89
+ * Searches for subtitles based on the provided parameters.
90
+ *
91
+ * @param {SearchSubtitlesParams} params - The parameters for searching: SearchSubtitlesParams.
92
+ * @returns {Promise<SubtitleData[]>} A promise that resolves to an array of subtitle data.
93
+ * @throws {Error} Throws an error if fetching subtitles fails or something goes wrong.
94
+ */
95
+ export declare function searchSubtitles(params: SearchSubtitlesParams): Promise<SubtitleData[]>;
96
+
97
+ /**
98
+ * Parameters for searching subtitles.
99
+ * Either IMDB or TMDB ID is required and if episode is provided, season is also required.
100
+ */
101
+ export declare type SearchSubtitlesParams = (
102
+ /** The TMDB ID of the media you want subtitles for (either TMDB or IMDB ID). */
103
+ {
104
+ tmdb_id: number;
105
+ imdb_id?: never;
106
+ }
107
+ /** The IMDB ID of the media you want subtitles for (either TMDB or IMDB ID). */
108
+ | {
109
+ imdb_id: string;
110
+ tmdb_id?: never;
111
+ }) & {
112
+ /** ISO 3166 code or codes of the subtitle desired. */
113
+ language?: string | string[];
114
+ /** The subtitle file's character encoding or encodings. */
115
+ encoding?: string | string[];
116
+ /** Which subtitle file format(s) you want. */
117
+ format?: string | string[];
118
+ /** Determines if you get hearing impaired subtitles. */
119
+ hi?: boolean;
120
+ /** The source where the subtitle will be scraped. Accepts a single value or a list. */
121
+ source?: string | string[];
122
+ /** Filter by specific release group or name. */
123
+ release?: string | string[];
124
+ /** Filter by filename. */
125
+ filename?: string | string[];
126
+ /** Additional parameters that can be used for filtering or other purposes. */
127
+ [key: string]: any;
128
+ } & (
129
+ /** The number of the desired season you want subtitles for. */
130
+ {
131
+ season: number;
132
+ episode: number;
133
+ }
134
+ /** The number of the desired episode you want subtitles for. */
135
+ | {
136
+ season?: never;
137
+ episode?: never;
138
+ });
139
+
140
+ /**
141
+ * Searches TMDB for movies or TV shows.
142
+ *
143
+ * @param {string} query - The search query.
144
+ * @param {string} [language] - Optional language code (default: en-US).
145
+ * @returns {Promise<TmdbSearchResult[]>} A promise that resolves to an array of TMDB search results.
146
+ */
147
+ export declare function searchTmdb(query: string, language?: string): Promise<TmdbSearchResult[]>;
148
+
149
+ /**
150
+ * Details of a specific TV Season.
151
+ */
152
+ export declare type SeasonDetails = {
153
+ episodes: EpisodeDetails[];
154
+ season_number: number;
155
+ id: string;
156
+ };
157
+
158
+ /**
159
+ * Summary of a TV season.
160
+ */
161
+ export declare type SeasonSummary = {
162
+ air_date?: string;
163
+ episode_count?: number;
164
+ id: number;
165
+ name: string;
166
+ overview?: string;
167
+ poster_path?: string | null;
168
+ season_number: number;
169
+ vote_average?: number;
170
+ };
171
+
172
+ /**
173
+ * Data structure representing a single subtitle object.
174
+ */
175
+ export declare type SubtitleData = {
176
+ /** Unique identifier (either TMDB or IMDB ID). */
177
+ id: string;
178
+ /** The subtitle file's URL. */
179
+ url: string;
180
+ /** The format of the subtitle file. */
181
+ format: string;
182
+ /** The subtitle file's character encoding. (UTF-8, ASCII, ETC) */
183
+ encoding: string;
184
+ /** Boolean indicating if the subtitle's is hearing impaired. */
185
+ isHearingImpaired: boolean;
186
+ /** URL to a PNG of the flag of the subtitle's language. */
187
+ flagUrl: string;
188
+ /** The name/title of the media. */
189
+ media: string;
190
+ /** The display language; Example: English. */
191
+ display: string;
192
+ /** ISO 3166 code; Example: en (2 alphabetic letters). */
193
+ language: string;
194
+ /** The subtitle's source (ex: subdl, subf2m, opensubtitles). */
195
+ source?: string | string[];
196
+ /** The release name of the subtitle. */
197
+ release?: string;
198
+ /** List of releases compatible with this subtitle. */
199
+ releases?: string[];
200
+ /** The original filename of the subtitle. */
201
+ fileName?: string;
202
+ /** The origin of the subtitle (e.g. DVD, WEB, BluRay). */
203
+ origin?: string;
204
+ };
205
+
206
+ /**
207
+ * Result object from a TMDB search.
208
+ */
209
+ export declare type TmdbSearchResult = {
210
+ id: number;
211
+ media_type: string;
212
+ title?: string;
213
+ name?: string;
214
+ original_title?: string;
215
+ original_name?: string;
216
+ overview?: string;
217
+ release_date?: string;
218
+ first_air_date?: string;
219
+ poster_path?: string | null;
220
+ backdrop_path?: string | null;
221
+ popularity?: number;
222
+ vote_average?: number;
223
+ };
224
+
225
+ /**
226
+ * Details of a TV Show.
227
+ */
228
+ export declare type TvDetails = {
229
+ seasons: SeasonSummary[];
230
+ name: string;
231
+ id: number;
232
+ };
233
+
234
+ export { }
@@ -0,0 +1,147 @@
1
+ var main = function(exports) {
2
+ "use strict";
3
+ const config = {
4
+ baseUrl: "https://sub.wyzie.ru"
5
+ };
6
+ function configure(options) {
7
+ if (options.baseUrl) {
8
+ config.baseUrl = options.baseUrl.replace(/\/$/, "");
9
+ }
10
+ }
11
+ async function constructUrl({
12
+ tmdb_id,
13
+ imdb_id,
14
+ season,
15
+ episode,
16
+ encoding,
17
+ language,
18
+ format,
19
+ source,
20
+ hi,
21
+ ...extraParams
22
+ }) {
23
+ if (!tmdb_id && !imdb_id) {
24
+ throw new Error("Either tmdb_id or imdb_id must be provided.");
25
+ }
26
+ const hasSeason = season !== void 0;
27
+ const hasEpisode = episode !== void 0;
28
+ if (hasSeason && !hasEpisode || !hasSeason && hasEpisode) {
29
+ throw new Error("Season and episode must be provided together or omitted together.");
30
+ }
31
+ const url = new URL(`${config.baseUrl}/search`);
32
+ const queryParams = {
33
+ id: String(tmdb_id || imdb_id),
34
+ season,
35
+ episode,
36
+ encoding: Array.isArray(encoding) ? encoding.join(",") : encoding,
37
+ language: Array.isArray(language) ? language.join(",") : language,
38
+ format: Array.isArray(format) ? format.join(",") : format,
39
+ source: Array.isArray(source) ? source.join(",") : source,
40
+ hi
41
+ };
42
+ Object.entries(queryParams).forEach(([key, value]) => {
43
+ if (value !== void 0) {
44
+ url.searchParams.append(key, String(value));
45
+ }
46
+ });
47
+ Object.entries(extraParams).forEach(([key, value]) => {
48
+ if (value !== void 0) {
49
+ if (Array.isArray(value)) {
50
+ url.searchParams.append(key, value.join(","));
51
+ } else {
52
+ url.searchParams.append(key, String(value));
53
+ }
54
+ }
55
+ });
56
+ return url;
57
+ }
58
+ async function fetchSubtitles(url) {
59
+ const response = await fetch(url.toString());
60
+ if (!response.ok) {
61
+ throw new Error(`HTTP error! status: ${response.status}`);
62
+ }
63
+ return response.json();
64
+ }
65
+ async function searchSubtitles(params) {
66
+ try {
67
+ const url = await constructUrl(params);
68
+ return await fetchSubtitles(url);
69
+ } catch (error) {
70
+ throw new Error(`Error fetching subtitles: ${error}`);
71
+ }
72
+ }
73
+ async function parseToVTT(subtitleUrl) {
74
+ try {
75
+ const response = await fetch(subtitleUrl);
76
+ if (!response.ok) {
77
+ throw new Error(`Failed to fetch subtitle content: ${response.status}`);
78
+ }
79
+ const content = await response.text();
80
+ const normalizedContent = content.replace(/\r\n|\r/g, "\n").trim();
81
+ const blocks = normalizedContent.split(/\n\n+/);
82
+ const timestampRegex = /^\d{1,2}:\d{2}:\d{2}[,.]\d{3}\s*-->\s*\d{1,2}:\d{2}:\d{2}[,.]\d{3}$/;
83
+ const hasValidSRTFormat = blocks.some((block) => {
84
+ const lines = block.split("\n").map((line) => line.trim());
85
+ return lines.some((line) => timestampRegex.test(line));
86
+ });
87
+ if (!hasValidSRTFormat) {
88
+ throw new Error("Invalid subtitle format: not SRT");
89
+ }
90
+ const vttLines = ["WEBVTT", ""];
91
+ for (const block of blocks) {
92
+ const lines = block.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
93
+ if (lines.length < 2)
94
+ continue;
95
+ const timestampIndex = lines.findIndex((line) => timestampRegex.test(line));
96
+ if (timestampIndex === -1)
97
+ continue;
98
+ const textLines = lines.slice(timestampIndex + 1).filter((line) => !/^\d+$/.test(line));
99
+ if (textLines.length === 0)
100
+ continue;
101
+ let timestampLine = lines[timestampIndex];
102
+ timestampLine = timestampLine.replace(/[,.](?=\s*-->)/, "").replace(/[,.]$/, "").replace(/,(\d{3})/g, ".$1");
103
+ vttLines.push(`${timestampLine}
104
+ ${textLines.join("\n")}
105
+ `);
106
+ }
107
+ return vttLines.join("\n").replace(/\n{3,}/g, "\n\n").trim() + "\n\n";
108
+ } catch (error) {
109
+ console.error("Error in parseToVTT:", error);
110
+ throw error;
111
+ }
112
+ }
113
+ async function searchTmdb(query, language = "en-US") {
114
+ const url = new URL(`${config.baseUrl}/api/tmdb/search`);
115
+ url.searchParams.append("q", query);
116
+ url.searchParams.append("language", language);
117
+ const response = await fetch(url.toString());
118
+ if (!response.ok) {
119
+ throw new Error(`Failed to search TMDB: ${response.status}`);
120
+ }
121
+ return response.json();
122
+ }
123
+ async function getTvDetails(id) {
124
+ const url = `${config.baseUrl}/api/tmdb/tv/${id}`;
125
+ const response = await fetch(url);
126
+ if (!response.ok) {
127
+ throw new Error(`Failed to fetch TV details: ${response.status}`);
128
+ }
129
+ return response.json();
130
+ }
131
+ async function getSeasonDetails(id, season) {
132
+ const url = `${config.baseUrl}/api/tmdb/tv/${id}/${season}`;
133
+ const response = await fetch(url);
134
+ if (!response.ok) {
135
+ throw new Error(`Failed to fetch season details: ${response.status}`);
136
+ }
137
+ return response.json();
138
+ }
139
+ exports.configure = configure;
140
+ exports.getSeasonDetails = getSeasonDetails;
141
+ exports.getTvDetails = getTvDetails;
142
+ exports.parseToVTT = parseToVTT;
143
+ exports.searchSubtitles = searchSubtitles;
144
+ exports.searchTmdb = searchTmdb;
145
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
146
+ return exports;
147
+ }({});
package/lib/main.js ADDED
@@ -0,0 +1,144 @@
1
+ const config = {
2
+ baseUrl: "https://sub.wyzie.ru"
3
+ };
4
+ function configure(options) {
5
+ if (options.baseUrl) {
6
+ config.baseUrl = options.baseUrl.replace(/\/$/, "");
7
+ }
8
+ }
9
+ async function constructUrl({
10
+ tmdb_id,
11
+ imdb_id,
12
+ season,
13
+ episode,
14
+ encoding,
15
+ language,
16
+ format,
17
+ source,
18
+ hi,
19
+ ...extraParams
20
+ }) {
21
+ if (!tmdb_id && !imdb_id) {
22
+ throw new Error("Either tmdb_id or imdb_id must be provided.");
23
+ }
24
+ const hasSeason = season !== void 0;
25
+ const hasEpisode = episode !== void 0;
26
+ if (hasSeason && !hasEpisode || !hasSeason && hasEpisode) {
27
+ throw new Error("Season and episode must be provided together or omitted together.");
28
+ }
29
+ const url = new URL(`${config.baseUrl}/search`);
30
+ const queryParams = {
31
+ id: String(tmdb_id || imdb_id),
32
+ season,
33
+ episode,
34
+ encoding: Array.isArray(encoding) ? encoding.join(",") : encoding,
35
+ language: Array.isArray(language) ? language.join(",") : language,
36
+ format: Array.isArray(format) ? format.join(",") : format,
37
+ source: Array.isArray(source) ? source.join(",") : source,
38
+ hi
39
+ };
40
+ Object.entries(queryParams).forEach(([key, value]) => {
41
+ if (value !== void 0) {
42
+ url.searchParams.append(key, String(value));
43
+ }
44
+ });
45
+ Object.entries(extraParams).forEach(([key, value]) => {
46
+ if (value !== void 0) {
47
+ if (Array.isArray(value)) {
48
+ url.searchParams.append(key, value.join(","));
49
+ } else {
50
+ url.searchParams.append(key, String(value));
51
+ }
52
+ }
53
+ });
54
+ return url;
55
+ }
56
+ async function fetchSubtitles(url) {
57
+ const response = await fetch(url.toString());
58
+ if (!response.ok) {
59
+ throw new Error(`HTTP error! status: ${response.status}`);
60
+ }
61
+ return response.json();
62
+ }
63
+ async function searchSubtitles(params) {
64
+ try {
65
+ const url = await constructUrl(params);
66
+ return await fetchSubtitles(url);
67
+ } catch (error) {
68
+ throw new Error(`Error fetching subtitles: ${error}`);
69
+ }
70
+ }
71
+ async function parseToVTT(subtitleUrl) {
72
+ try {
73
+ const response = await fetch(subtitleUrl);
74
+ if (!response.ok) {
75
+ throw new Error(`Failed to fetch subtitle content: ${response.status}`);
76
+ }
77
+ const content = await response.text();
78
+ const normalizedContent = content.replace(/\r\n|\r/g, "\n").trim();
79
+ const blocks = normalizedContent.split(/\n\n+/);
80
+ const timestampRegex = /^\d{1,2}:\d{2}:\d{2}[,.]\d{3}\s*-->\s*\d{1,2}:\d{2}:\d{2}[,.]\d{3}$/;
81
+ const hasValidSRTFormat = blocks.some((block) => {
82
+ const lines = block.split("\n").map((line) => line.trim());
83
+ return lines.some((line) => timestampRegex.test(line));
84
+ });
85
+ if (!hasValidSRTFormat) {
86
+ throw new Error("Invalid subtitle format: not SRT");
87
+ }
88
+ const vttLines = ["WEBVTT", ""];
89
+ for (const block of blocks) {
90
+ const lines = block.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
91
+ if (lines.length < 2)
92
+ continue;
93
+ const timestampIndex = lines.findIndex((line) => timestampRegex.test(line));
94
+ if (timestampIndex === -1)
95
+ continue;
96
+ const textLines = lines.slice(timestampIndex + 1).filter((line) => !/^\d+$/.test(line));
97
+ if (textLines.length === 0)
98
+ continue;
99
+ let timestampLine = lines[timestampIndex];
100
+ timestampLine = timestampLine.replace(/[,.](?=\s*-->)/, "").replace(/[,.]$/, "").replace(/,(\d{3})/g, ".$1");
101
+ vttLines.push(`${timestampLine}
102
+ ${textLines.join("\n")}
103
+ `);
104
+ }
105
+ return vttLines.join("\n").replace(/\n{3,}/g, "\n\n").trim() + "\n\n";
106
+ } catch (error) {
107
+ console.error("Error in parseToVTT:", error);
108
+ throw error;
109
+ }
110
+ }
111
+ async function searchTmdb(query, language = "en-US") {
112
+ const url = new URL(`${config.baseUrl}/api/tmdb/search`);
113
+ url.searchParams.append("q", query);
114
+ url.searchParams.append("language", language);
115
+ const response = await fetch(url.toString());
116
+ if (!response.ok) {
117
+ throw new Error(`Failed to search TMDB: ${response.status}`);
118
+ }
119
+ return response.json();
120
+ }
121
+ async function getTvDetails(id) {
122
+ const url = `${config.baseUrl}/api/tmdb/tv/${id}`;
123
+ const response = await fetch(url);
124
+ if (!response.ok) {
125
+ throw new Error(`Failed to fetch TV details: ${response.status}`);
126
+ }
127
+ return response.json();
128
+ }
129
+ async function getSeasonDetails(id, season) {
130
+ const url = `${config.baseUrl}/api/tmdb/tv/${id}/${season}`;
131
+ const response = await fetch(url);
132
+ if (!response.ok) {
133
+ throw new Error(`Failed to fetch season details: ${response.status}`);
134
+ }
135
+ return response.json();
136
+ }
137
+ export {
138
+ configure,
139
+ getSeasonDetails,
140
+ getTvDetails,
141
+ parseToVTT,
142
+ searchSubtitles,
143
+ searchTmdb
144
+ };
@@ -0,0 +1,148 @@
1
+ (function(global, factory) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.main = {}));
3
+ })(this, function(exports2) {
4
+ "use strict";
5
+ const config = {
6
+ baseUrl: "https://sub.wyzie.ru"
7
+ };
8
+ function configure(options) {
9
+ if (options.baseUrl) {
10
+ config.baseUrl = options.baseUrl.replace(/\/$/, "");
11
+ }
12
+ }
13
+ async function constructUrl({
14
+ tmdb_id,
15
+ imdb_id,
16
+ season,
17
+ episode,
18
+ encoding,
19
+ language,
20
+ format,
21
+ source,
22
+ hi,
23
+ ...extraParams
24
+ }) {
25
+ if (!tmdb_id && !imdb_id) {
26
+ throw new Error("Either tmdb_id or imdb_id must be provided.");
27
+ }
28
+ const hasSeason = season !== void 0;
29
+ const hasEpisode = episode !== void 0;
30
+ if (hasSeason && !hasEpisode || !hasSeason && hasEpisode) {
31
+ throw new Error("Season and episode must be provided together or omitted together.");
32
+ }
33
+ const url = new URL(`${config.baseUrl}/search`);
34
+ const queryParams = {
35
+ id: String(tmdb_id || imdb_id),
36
+ season,
37
+ episode,
38
+ encoding: Array.isArray(encoding) ? encoding.join(",") : encoding,
39
+ language: Array.isArray(language) ? language.join(",") : language,
40
+ format: Array.isArray(format) ? format.join(",") : format,
41
+ source: Array.isArray(source) ? source.join(",") : source,
42
+ hi
43
+ };
44
+ Object.entries(queryParams).forEach(([key, value]) => {
45
+ if (value !== void 0) {
46
+ url.searchParams.append(key, String(value));
47
+ }
48
+ });
49
+ Object.entries(extraParams).forEach(([key, value]) => {
50
+ if (value !== void 0) {
51
+ if (Array.isArray(value)) {
52
+ url.searchParams.append(key, value.join(","));
53
+ } else {
54
+ url.searchParams.append(key, String(value));
55
+ }
56
+ }
57
+ });
58
+ return url;
59
+ }
60
+ async function fetchSubtitles(url) {
61
+ const response = await fetch(url.toString());
62
+ if (!response.ok) {
63
+ throw new Error(`HTTP error! status: ${response.status}`);
64
+ }
65
+ return response.json();
66
+ }
67
+ async function searchSubtitles(params) {
68
+ try {
69
+ const url = await constructUrl(params);
70
+ return await fetchSubtitles(url);
71
+ } catch (error) {
72
+ throw new Error(`Error fetching subtitles: ${error}`);
73
+ }
74
+ }
75
+ async function parseToVTT(subtitleUrl) {
76
+ try {
77
+ const response = await fetch(subtitleUrl);
78
+ if (!response.ok) {
79
+ throw new Error(`Failed to fetch subtitle content: ${response.status}`);
80
+ }
81
+ const content = await response.text();
82
+ const normalizedContent = content.replace(/\r\n|\r/g, "\n").trim();
83
+ const blocks = normalizedContent.split(/\n\n+/);
84
+ const timestampRegex = /^\d{1,2}:\d{2}:\d{2}[,.]\d{3}\s*-->\s*\d{1,2}:\d{2}:\d{2}[,.]\d{3}$/;
85
+ const hasValidSRTFormat = blocks.some((block) => {
86
+ const lines = block.split("\n").map((line) => line.trim());
87
+ return lines.some((line) => timestampRegex.test(line));
88
+ });
89
+ if (!hasValidSRTFormat) {
90
+ throw new Error("Invalid subtitle format: not SRT");
91
+ }
92
+ const vttLines = ["WEBVTT", ""];
93
+ for (const block of blocks) {
94
+ const lines = block.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
95
+ if (lines.length < 2)
96
+ continue;
97
+ const timestampIndex = lines.findIndex((line) => timestampRegex.test(line));
98
+ if (timestampIndex === -1)
99
+ continue;
100
+ const textLines = lines.slice(timestampIndex + 1).filter((line) => !/^\d+$/.test(line));
101
+ if (textLines.length === 0)
102
+ continue;
103
+ let timestampLine = lines[timestampIndex];
104
+ timestampLine = timestampLine.replace(/[,.](?=\s*-->)/, "").replace(/[,.]$/, "").replace(/,(\d{3})/g, ".$1");
105
+ vttLines.push(`${timestampLine}
106
+ ${textLines.join("\n")}
107
+ `);
108
+ }
109
+ return vttLines.join("\n").replace(/\n{3,}/g, "\n\n").trim() + "\n\n";
110
+ } catch (error) {
111
+ console.error("Error in parseToVTT:", error);
112
+ throw error;
113
+ }
114
+ }
115
+ async function searchTmdb(query, language = "en-US") {
116
+ const url = new URL(`${config.baseUrl}/api/tmdb/search`);
117
+ url.searchParams.append("q", query);
118
+ url.searchParams.append("language", language);
119
+ const response = await fetch(url.toString());
120
+ if (!response.ok) {
121
+ throw new Error(`Failed to search TMDB: ${response.status}`);
122
+ }
123
+ return response.json();
124
+ }
125
+ async function getTvDetails(id) {
126
+ const url = `${config.baseUrl}/api/tmdb/tv/${id}`;
127
+ const response = await fetch(url);
128
+ if (!response.ok) {
129
+ throw new Error(`Failed to fetch TV details: ${response.status}`);
130
+ }
131
+ return response.json();
132
+ }
133
+ async function getSeasonDetails(id, season) {
134
+ const url = `${config.baseUrl}/api/tmdb/tv/${id}/${season}`;
135
+ const response = await fetch(url);
136
+ if (!response.ok) {
137
+ throw new Error(`Failed to fetch season details: ${response.status}`);
138
+ }
139
+ return response.json();
140
+ }
141
+ exports2.configure = configure;
142
+ exports2.getSeasonDetails = getSeasonDetails;
143
+ exports2.getTvDetails = getTvDetails;
144
+ exports2.parseToVTT = parseToVTT;
145
+ exports2.searchSubtitles = searchSubtitles;
146
+ exports2.searchTmdb = searchTmdb;
147
+ Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
148
+ });
package/package.json CHANGED
@@ -1,76 +1,76 @@
1
- {
2
- "name": "wyzie-lib",
3
- "version": "2.2.7",
4
- "icon": "https://i.postimg.cc/L5ppKYC5/cclogo.png",
5
- "license": "MIT",
6
- "keywords": [
7
- "wyzie-subs",
8
- "wyzie subs",
9
- "wyzie api",
10
- "subtitle",
11
- "search",
12
- "library",
13
- "typescript",
14
- "vite",
15
- "fast",
16
- "scraper",
17
- "subtitle scraper",
18
- "open subtitles"
19
- ],
20
- "type": "module",
21
- "main": "./lib/main.js",
22
- "types": "./lib/main.d.ts",
23
- "files": [
24
- "./lib"
25
- ],
26
- "exports": {
27
- ".": {
28
- "import": {
29
- "types": "./lib/main.d.ts",
30
- "default": "./lib/main.js"
31
- },
32
- "require": {
33
- "types": "./lib/main.d.ts",
34
- "default": "./lib/main.cjs"
35
- },
36
- "umd": {
37
- "types": "./lib/main.d.ts",
38
- "default": "./lib/main.umd.cjs"
39
- },
40
- "es": {
41
- "types": "./lib/main.d.ts",
42
- "default": "./lib/main.js"
43
- },
44
- "cjs": {
45
- "types": "./lib/main.d.ts",
46
- "default": "./lib/main.cjs"
47
- },
48
- "iife": {
49
- "types": "./lib/main.d.ts",
50
- "default": "./lib/main.iife.js"
51
- },
52
- "amd": {
53
- "types": "./lib/main.d.ts",
54
- "default": "./lib/main.amd.js"
55
- }
56
- }
57
- },
58
- "repository": {
59
- "type": "git",
60
- "url": "git+https://github.com/itzcozi/wyzie-lib.git"
61
- },
62
- "devDependencies": {
63
- "prettier": "^3.7.4",
64
- "typescript": "^5.9.3",
65
- "vite": "^4.5.14",
66
- "vite-plugin-dts": "^4.5.4",
67
- "vitest": "^2.1.9"
68
- },
69
- "scripts": {
70
- "dev": "vite",
71
- "build": "vite build && tsc",
72
- "test": "npx vitest",
73
- "format": "prettier --log-level warn --write \"{src/**/*.{ts},*.{ts,js,html,css,json,md,xml}}\"",
74
- "preview": "vite preview"
75
- }
76
- }
1
+ {
2
+ "name": "wyzie-lib",
3
+ "version": "2.2.8",
4
+ "icon": "https://i.postimg.cc/L5ppKYC5/cclogo.png",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "wyzie-subs",
8
+ "wyzie subs",
9
+ "wyzie api",
10
+ "subtitle",
11
+ "search",
12
+ "library",
13
+ "typescript",
14
+ "vite",
15
+ "fast",
16
+ "scraper",
17
+ "subtitle scraper",
18
+ "open subtitles"
19
+ ],
20
+ "type": "module",
21
+ "main": "./lib/main.js",
22
+ "types": "./lib/main.d.ts",
23
+ "files": [
24
+ "./lib"
25
+ ],
26
+ "exports": {
27
+ ".": {
28
+ "import": {
29
+ "types": "./lib/main.d.ts",
30
+ "default": "./lib/main.js"
31
+ },
32
+ "require": {
33
+ "types": "./lib/main.d.ts",
34
+ "default": "./lib/main.cjs"
35
+ },
36
+ "umd": {
37
+ "types": "./lib/main.d.ts",
38
+ "default": "./lib/main.umd.cjs"
39
+ },
40
+ "es": {
41
+ "types": "./lib/main.d.ts",
42
+ "default": "./lib/main.js"
43
+ },
44
+ "cjs": {
45
+ "types": "./lib/main.d.ts",
46
+ "default": "./lib/main.cjs"
47
+ },
48
+ "iife": {
49
+ "types": "./lib/main.d.ts",
50
+ "default": "./lib/main.iife.js"
51
+ },
52
+ "amd": {
53
+ "types": "./lib/main.d.ts",
54
+ "default": "./lib/main.amd.js"
55
+ }
56
+ }
57
+ },
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "git+https://github.com/itzcozi/wyzie-lib.git"
61
+ },
62
+ "scripts": {
63
+ "dev": "vite",
64
+ "build": "vite build && tsc",
65
+ "test": "npx vitest",
66
+ "format": "prettier --log-level warn --write \"{src/**/*.{ts},*.{ts,js,html,css,json,md,xml}}\"",
67
+ "preview": "vite preview"
68
+ },
69
+ "devDependencies": {
70
+ "prettier": "^3.7.4",
71
+ "typescript": "^5.9.3",
72
+ "vite": "^4.5.14",
73
+ "vite-plugin-dts": "^4.5.4",
74
+ "vitest": "^2.1.9"
75
+ }
76
+ }