@omss/framework 1.1.0

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 (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +516 -0
  3. package/dist/controllers/content.controller.d.ts +37 -0
  4. package/dist/controllers/content.controller.d.ts.map +1 -0
  5. package/dist/controllers/content.controller.js +37 -0
  6. package/dist/controllers/content.controller.js.map +1 -0
  7. package/dist/controllers/health.controller.d.ts +11 -0
  8. package/dist/controllers/health.controller.d.ts.map +1 -0
  9. package/dist/controllers/health.controller.js +18 -0
  10. package/dist/controllers/health.controller.js.map +1 -0
  11. package/dist/controllers/proxy.controller.d.ts +17 -0
  12. package/dist/controllers/proxy.controller.d.ts.map +1 -0
  13. package/dist/controllers/proxy.controller.js +32 -0
  14. package/dist/controllers/proxy.controller.js.map +1 -0
  15. package/dist/core/cache.d.ts +29 -0
  16. package/dist/core/cache.d.ts.map +1 -0
  17. package/dist/core/cache.js +95 -0
  18. package/dist/core/cache.js.map +1 -0
  19. package/dist/core/errors.d.ts +27 -0
  20. package/dist/core/errors.d.ts.map +1 -0
  21. package/dist/core/errors.js +42 -0
  22. package/dist/core/errors.js.map +1 -0
  23. package/dist/core/server.d.ts +46 -0
  24. package/dist/core/server.d.ts.map +1 -0
  25. package/dist/core/server.js +210 -0
  26. package/dist/core/server.js.map +1 -0
  27. package/dist/core/types.d.ts +123 -0
  28. package/dist/core/types.d.ts.map +1 -0
  29. package/dist/core/types.js +4 -0
  30. package/dist/core/types.js.map +1 -0
  31. package/dist/index.d.ts +19 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +48 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/middleware/error-handler.d.ts +4 -0
  36. package/dist/middleware/error-handler.d.ts.map +1 -0
  37. package/dist/middleware/error-handler.js +57 -0
  38. package/dist/middleware/error-handler.js.map +1 -0
  39. package/dist/middleware/logger.d.ts +3 -0
  40. package/dist/middleware/logger.d.ts.map +1 -0
  41. package/dist/middleware/logger.js +34 -0
  42. package/dist/middleware/logger.js.map +1 -0
  43. package/dist/middleware/validation.d.ts +33 -0
  44. package/dist/middleware/validation.d.ts.map +1 -0
  45. package/dist/middleware/validation.js +93 -0
  46. package/dist/middleware/validation.js.map +1 -0
  47. package/dist/providers/base-provider.d.ts +91 -0
  48. package/dist/providers/base-provider.d.ts.map +1 -0
  49. package/dist/providers/base-provider.js +170 -0
  50. package/dist/providers/base-provider.js.map +1 -0
  51. package/dist/providers/provider-registry.d.ts +56 -0
  52. package/dist/providers/provider-registry.d.ts.map +1 -0
  53. package/dist/providers/provider-registry.js +182 -0
  54. package/dist/providers/provider-registry.js.map +1 -0
  55. package/dist/services/health.service.d.ts +16 -0
  56. package/dist/services/health.service.d.ts.map +1 -0
  57. package/dist/services/health.service.js +44 -0
  58. package/dist/services/health.service.js.map +1 -0
  59. package/dist/services/proxy.service.d.ts +56 -0
  60. package/dist/services/proxy.service.d.ts.map +1 -0
  61. package/dist/services/proxy.service.js +224 -0
  62. package/dist/services/proxy.service.js.map +1 -0
  63. package/dist/services/source.service.d.ts +57 -0
  64. package/dist/services/source.service.d.ts.map +1 -0
  65. package/dist/services/source.service.js +226 -0
  66. package/dist/services/source.service.js.map +1 -0
  67. package/dist/services/tmdb.service.d.ts +67 -0
  68. package/dist/services/tmdb.service.d.ts.map +1 -0
  69. package/dist/services/tmdb.service.js +237 -0
  70. package/dist/services/tmdb.service.js.map +1 -0
  71. package/package.json +90 -0
@@ -0,0 +1,57 @@
1
+ import { ProviderRegistry } from '../providers/provider-registry';
2
+ import { CacheService } from '../core/cache';
3
+ import { SourceResponse, ResponseIdMapping } from '../core/types';
4
+ import { TMDBService } from '../services/tmdb.service';
5
+ export declare class SourceService {
6
+ private registry;
7
+ private cache;
8
+ private tmdbService;
9
+ private cacheTTL;
10
+ private tmdbValidator;
11
+ private responseIdMap;
12
+ constructor(registry: ProviderRegistry, cache: CacheService, tmdbService: TMDBService, cacheTTL?: {
13
+ sources: number;
14
+ subtitles: number;
15
+ });
16
+ /**
17
+ * Get movie sources from all providers
18
+ */
19
+ getMovieSources(tmdbId: string): Promise<SourceResponse>;
20
+ /**
21
+ * Get TV episode sources from all providers
22
+ */
23
+ getTVSources(tmdbId: string, season: number, episode: number): Promise<SourceResponse>;
24
+ /**
25
+ * Refresh cached sources by responseId
26
+ */
27
+ refreshSource(responseId: string): Promise<void>;
28
+ /**
29
+ * Store responseId to cacheKey mapping
30
+ */
31
+ private storeResponseIdMapping;
32
+ /**
33
+ * Cleanup expired responseId mappings
34
+ */
35
+ private cleanupExpiredMappings;
36
+ /**
37
+ * Fetch results from all providers concurrently
38
+ */
39
+ private fetchFromProviders;
40
+ /**
41
+ * Build final response from provider results
42
+ */
43
+ private buildResponse;
44
+ /**
45
+ * Get mapping info for debugging
46
+ */
47
+ getMappingInfo(responseId: string): ResponseIdMapping | undefined;
48
+ /**
49
+ * Get all mappings count
50
+ */
51
+ getMappingsCount(): number;
52
+ /**
53
+ * Cleanup on service shutdown
54
+ */
55
+ destroy(): void;
56
+ }
57
+ //# sourceMappingURL=source.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.service.d.ts","sourceRoot":"","sources":["../../src/services/source.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAkB,iBAAiB,EAAuB,MAAM,cAAc,CAAC;AAGtG,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,qBAAa,aAAa;IAKlB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,QAAQ;IAPpB,OAAO,CAAC,aAAa,CAAyC;IAC9D,OAAO,CAAC,aAAa,CAA6C;gBAGtD,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,WAAW,EACxB,QAAQ;;;KAAsC;IAM1D;;OAEG;IACG,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA2C9D;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA6C5F;;OAEG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBtD;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAK9B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAiB9B;;OAEG;YACW,kBAAkB;IAmDhC;;OAEG;IACH,OAAO,CAAC,aAAa;IA0BrB;;OAEG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIjE;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,OAAO,IAAI,IAAI;CAIlB"}
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SourceService = void 0;
4
+ const validation_1 = require("../middleware/validation");
5
+ const errors_1 = require("../core/errors");
6
+ const uuid_1 = require("uuid");
7
+ class SourceService {
8
+ registry;
9
+ cache;
10
+ tmdbService;
11
+ cacheTTL;
12
+ tmdbValidator;
13
+ responseIdMap = new Map();
14
+ constructor(registry, cache, tmdbService, cacheTTL = { sources: 7200, subtitles: 86400 }) {
15
+ this.registry = registry;
16
+ this.cache = cache;
17
+ this.tmdbService = tmdbService;
18
+ this.cacheTTL = cacheTTL;
19
+ setInterval(() => this.cleanupExpiredMappings(), 60 * 60 * 1000);
20
+ this.tmdbValidator = (0, validation_1.createTMDBValidator)(tmdbService);
21
+ }
22
+ /**
23
+ * Get movie sources from all providers
24
+ */
25
+ async getMovieSources(tmdbId) {
26
+ await this.tmdbValidator.validateMovie(tmdbId);
27
+ const cacheKey = `movie:${tmdbId}`;
28
+ // Check cache first
29
+ const cached = await this.cache.get(cacheKey);
30
+ if (cached) {
31
+ console.log(`[SourceService] Cache HIT for ${cacheKey}`);
32
+ return cached;
33
+ }
34
+ console.log(`[SourceService] Cache MISS for ${cacheKey}`);
35
+ // Build media object for providers
36
+ const media = await this.tmdbService.getMediaObject('movie', tmdbId);
37
+ // Try to get IMDB ID
38
+ media.imdbId = await this.tmdbService.getImdbId(tmdbId, 'movie');
39
+ // Fetch from providers
40
+ const results = await this.fetchFromProviders('movie', media);
41
+ const response = this.buildResponse(results);
42
+ // Throw error if no sources found
43
+ if (response.sources.length === 0) {
44
+ throw errors_1.OMSSErrors.noSourcesAvailable(tmdbId, this.registry.count);
45
+ }
46
+ // Store responseId mapping
47
+ this.storeResponseIdMapping(response.responseId, {
48
+ cacheKey,
49
+ type: 'movie',
50
+ tmdbId,
51
+ createdAt: Date.now(),
52
+ });
53
+ // Cache the response
54
+ await this.cache.set(cacheKey, response, this.cacheTTL.sources);
55
+ return response;
56
+ }
57
+ /**
58
+ * Get TV episode sources from all providers
59
+ */
60
+ async getTVSources(tmdbId, season, episode) {
61
+ await this.tmdbValidator.validateTVEpisode(tmdbId, season, episode);
62
+ const cacheKey = `tv:${tmdbId}:s${season}:e${episode}`;
63
+ // Check cache
64
+ const cached = await this.cache.get(cacheKey);
65
+ if (cached) {
66
+ console.log(`[SourceService] Cache HIT for ${cacheKey}`);
67
+ return cached;
68
+ }
69
+ console.log(`[SourceService] Cache MISS for ${cacheKey}`);
70
+ // Build media object for providers
71
+ const media = await this.tmdbService.getMediaObject('tv', tmdbId, season, episode);
72
+ // Try to get IMDB ID
73
+ media.imdbId = await this.tmdbService.getImdbId(tmdbId, 'tv');
74
+ // Fetch from providers
75
+ const results = await this.fetchFromProviders('tv', media);
76
+ const response = this.buildResponse(results);
77
+ // Throw error if no sources found
78
+ if (response.sources.length === 0) {
79
+ throw errors_1.OMSSErrors.noSourcesAvailable(`${tmdbId}/S${season}E${episode}`, this.registry.count);
80
+ }
81
+ // Store responseId mapping
82
+ this.storeResponseIdMapping(response.responseId, {
83
+ cacheKey,
84
+ type: 'tv',
85
+ tmdbId,
86
+ season,
87
+ episode,
88
+ createdAt: Date.now(),
89
+ });
90
+ // Cache the response
91
+ await this.cache.set(cacheKey, response, this.cacheTTL.sources);
92
+ return response;
93
+ }
94
+ /**
95
+ * Refresh cached sources by responseId
96
+ */
97
+ async refreshSource(responseId) {
98
+ if (!/^[a-zA-Z0-9_-]{1,128}$/.test(responseId)) {
99
+ throw errors_1.OMSSErrors.invalidResponseId(responseId);
100
+ }
101
+ const mapping = this.responseIdMap.get(responseId);
102
+ if (!mapping) {
103
+ console.warn(`[SourceService] No mapping found for responseId: ${responseId}`);
104
+ throw errors_1.OMSSErrors.responseIdNotFound(responseId);
105
+ }
106
+ console.log(`[SourceService] Refreshing cache for ${mapping.cacheKey} (responseId: ${responseId})`);
107
+ await this.cache.delete(mapping.cacheKey);
108
+ this.responseIdMap.delete(responseId);
109
+ console.log(`[SourceService] Successfully refreshed cache for ${mapping.cacheKey}`);
110
+ }
111
+ /**
112
+ * Store responseId to cacheKey mapping
113
+ */
114
+ storeResponseIdMapping(responseId, mapping) {
115
+ this.responseIdMap.set(responseId, mapping);
116
+ console.log(`[SourceService] Stored mapping: ${responseId} -> ${mapping.cacheKey}`);
117
+ }
118
+ /**
119
+ * Cleanup expired responseId mappings
120
+ */
121
+ cleanupExpiredMappings() {
122
+ const now = Date.now();
123
+ const maxAge = this.cacheTTL.sources * 1000;
124
+ let cleaned = 0;
125
+ for (const [responseId, mapping] of this.responseIdMap.entries()) {
126
+ if (now - mapping.createdAt > maxAge) {
127
+ this.responseIdMap.delete(responseId);
128
+ cleaned++;
129
+ }
130
+ }
131
+ if (cleaned > 0) {
132
+ console.log(`[SourceService] Cleaned up ${cleaned} expired responseId mapping(s)`);
133
+ }
134
+ }
135
+ /**
136
+ * Fetch results from all providers concurrently
137
+ */
138
+ async fetchFromProviders(type, media) {
139
+ const providers = this.registry.getProviders();
140
+ if (providers.length === 0) {
141
+ console.warn('[SourceService] No providers registered');
142
+ return [];
143
+ }
144
+ // Filter providers by capability
145
+ const supportedProviders = providers.filter((p) => p.capabilities.supportedContentTypes.includes(type === 'movie' ? 'movies' : 'tv'));
146
+ console.log(`[SourceService] Fetching from ${supportedProviders.length} provider(s) ` + `(${providers.length - supportedProviders.length} filtered out)`);
147
+ const promises = supportedProviders.map(async (provider) => {
148
+ try {
149
+ const startTime = Date.now();
150
+ let result;
151
+ if (type === 'movie') {
152
+ result = await provider.getMovieSources(media);
153
+ }
154
+ else {
155
+ result = await provider.getTVSources(media);
156
+ }
157
+ const duration = Date.now() - startTime;
158
+ console.log(`[SourceService] Provider '${provider.name}' returned ${result.sources.length} source(s) in ${duration}ms`);
159
+ return result;
160
+ }
161
+ catch (error) {
162
+ console.error(`[SourceService] Provider '${provider.name}' failed:`, error);
163
+ return {
164
+ sources: [],
165
+ subtitles: [],
166
+ diagnostics: [
167
+ {
168
+ code: 'PROVIDER_ERROR',
169
+ message: `Provider '${provider.name}' failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
170
+ field: '',
171
+ severity: 'error',
172
+ },
173
+ ],
174
+ };
175
+ }
176
+ });
177
+ const results = await Promise.allSettled(promises);
178
+ return results.filter((r) => r.status === 'fulfilled').map((r) => r.value);
179
+ }
180
+ /**
181
+ * Build final response from provider results
182
+ */
183
+ buildResponse(results) {
184
+ const allSources = results.flatMap((r) => r.sources);
185
+ const allSubtitles = results.flatMap((r) => r.subtitles);
186
+ const allDiagnostics = results.flatMap((r) => r.diagnostics);
187
+ const failedProviders = results.filter((r) => r.sources.length === 0).length;
188
+ if (failedProviders > 0 && allSources.length > 0) {
189
+ allDiagnostics.push({
190
+ code: 'PARTIAL_SCRAPE',
191
+ message: `Only ${results.length - failedProviders} of ${results.length} providers returned results`,
192
+ field: '',
193
+ severity: 'warning',
194
+ });
195
+ }
196
+ const expiresAt = new Date(Date.now() + 2 * 60 * 60 * 1000).toISOString();
197
+ return {
198
+ responseId: (0, uuid_1.v4)(),
199
+ expiresAt,
200
+ sources: allSources,
201
+ subtitles: allSubtitles,
202
+ diagnostics: allDiagnostics,
203
+ };
204
+ }
205
+ /**
206
+ * Get mapping info for debugging
207
+ */
208
+ getMappingInfo(responseId) {
209
+ return this.responseIdMap.get(responseId);
210
+ }
211
+ /**
212
+ * Get all mappings count
213
+ */
214
+ getMappingsCount() {
215
+ return this.responseIdMap.size;
216
+ }
217
+ /**
218
+ * Cleanup on service shutdown
219
+ */
220
+ destroy() {
221
+ this.responseIdMap.clear();
222
+ console.log('[SourceService] Destroyed and cleared all mappings');
223
+ }
224
+ }
225
+ exports.SourceService = SourceService;
226
+ //# sourceMappingURL=source.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.service.js","sourceRoot":"","sources":["../../src/services/source.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import { CacheService } from '../core/cache';
2
+ import { ProviderMediaObject } from '../core/types';
3
+ export interface TMDBMovieResponse {
4
+ id: number;
5
+ title: string;
6
+ release_date: string;
7
+ status: 'Rumored' | 'Planned' | 'In Production' | 'Post Production' | 'Released' | 'Canceled';
8
+ adult: boolean;
9
+ }
10
+ export interface TMDBTVResponse {
11
+ id: number;
12
+ name: string;
13
+ first_air_date: string;
14
+ status: 'Returning Series' | 'Planned' | 'In Production' | 'Ended' | 'Canceled' | 'Pilot';
15
+ adult: boolean;
16
+ number_of_seasons: number;
17
+ seasons: Array<{
18
+ season_number: number;
19
+ episode_count: number;
20
+ air_date: string;
21
+ }>;
22
+ }
23
+ export interface TMDBSeasonResponse {
24
+ id: number;
25
+ season_number: number;
26
+ air_date: string;
27
+ episodes: Array<{
28
+ episode_number: number;
29
+ air_date: string | null;
30
+ name: string;
31
+ }>;
32
+ }
33
+ export interface TMDBValidationResult {
34
+ exists: boolean;
35
+ released: boolean;
36
+ releaseDate?: string;
37
+ title?: string;
38
+ message?: string;
39
+ }
40
+ export declare class TMDBService {
41
+ private cache;
42
+ private readonly baseUrl;
43
+ private readonly apiKey;
44
+ private readonly cacheTTL;
45
+ constructor(apiKey: string, cache: CacheService, cacheTTL?: number);
46
+ /**
47
+ * Validate a movie exists and has been released
48
+ */
49
+ validateMovie(tmdbId: string): Promise<TMDBValidationResult>;
50
+ /**
51
+ * Validate a TV show exists and has aired
52
+ */
53
+ validateTV(tmdbId: string): Promise<TMDBValidationResult>;
54
+ /**
55
+ * Validate a specific TV episode exists and has aired
56
+ */
57
+ validateTVEpisode(tmdbId: string, season: number, episode: number): Promise<TMDBValidationResult>;
58
+ /**
59
+ * Get media object for provider
60
+ */
61
+ getMediaObject(type: 'movie' | 'tv', tmdbId: string, season?: number, episode?: number): Promise<ProviderMediaObject>;
62
+ /**
63
+ * Get IMDB ID if available (cached)
64
+ */
65
+ getImdbId(tmdbId: string, type: 'movie' | 'tv'): Promise<string | undefined>;
66
+ }
67
+ //# sourceMappingURL=tmdb.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmdb.service.d.ts","sourceRoot":"","sources":["../../src/services/tmdb.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,eAAe,GAAG,iBAAiB,GAAG,UAAU,GAAG,UAAU,CAAC;IAC9F,KAAK,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,kBAAkB,GAAG,SAAS,GAAG,eAAe,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;IAC1F,KAAK,EAAE,OAAO,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,KAAK,CAAC;QACX,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;QACtB,QAAQ,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACN;AAED,MAAM,WAAW,kBAAkB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC;QACZ,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACN;AAED,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,WAAW;IAOhB,OAAO,CAAC,KAAK;IANjB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAC1D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAG9B,MAAM,EAAE,MAAM,EACN,KAAK,EAAE,YAAY,EAC3B,QAAQ,SAAQ;IASpB;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAiDlE;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAiD/D;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAoFvG;;OAEG;IACG,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAuB3H;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAwBrF"}
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TMDBService = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ class TMDBService {
9
+ cache;
10
+ baseUrl = 'https://api.themoviedb.org/3';
11
+ apiKey;
12
+ cacheTTL;
13
+ constructor(apiKey, cache, cacheTTL = 86400 // 24 hours default
14
+ ) {
15
+ this.cache = cache;
16
+ if (!apiKey || apiKey === 'your_tmdb_api_key_here') {
17
+ throw new Error('TMDB_API_KEY is not configured. Get one at https://www.themoviedb.org/settings/api');
18
+ }
19
+ this.apiKey = apiKey;
20
+ this.cacheTTL = cacheTTL;
21
+ }
22
+ /**
23
+ * Validate a movie exists and has been released
24
+ */
25
+ async validateMovie(tmdbId) {
26
+ const cacheKey = `tmdb:movie:${tmdbId}`;
27
+ // Check cache first
28
+ const cached = await this.cache.get(cacheKey);
29
+ if (cached) {
30
+ return cached;
31
+ }
32
+ try {
33
+ const response = await axios_1.default.get(`${this.baseUrl}/movie/${tmdbId}`, {
34
+ params: { api_key: this.apiKey },
35
+ timeout: 5000,
36
+ });
37
+ const movie = response.data;
38
+ const releaseDate = new Date(movie.release_date);
39
+ const now = new Date();
40
+ const released = releaseDate <= now && movie.status === 'Released';
41
+ const result = {
42
+ exists: true,
43
+ released,
44
+ releaseDate: movie.release_date,
45
+ title: movie.title,
46
+ message: released ? undefined : `Movie "${movie.title}" has not been released yet (release date: ${movie.release_date})`,
47
+ };
48
+ // Cache the result
49
+ await this.cache.set(cacheKey, result, this.cacheTTL);
50
+ return result;
51
+ }
52
+ catch (error) {
53
+ if (axios_1.default.isAxiosError(error) && error.response?.status === 404) {
54
+ const result = {
55
+ exists: false,
56
+ released: false,
57
+ message: `Movie with TMDB ID ${tmdbId} does not exist`,
58
+ };
59
+ // Cache 404s for shorter time (1 hour)
60
+ await this.cache.set(cacheKey, result, 3600);
61
+ return result;
62
+ }
63
+ console.error('[TMDBService] Error validating movie:', error);
64
+ throw error;
65
+ }
66
+ }
67
+ /**
68
+ * Validate a TV show exists and has aired
69
+ */
70
+ async validateTV(tmdbId) {
71
+ const cacheKey = `tmdb:tv:${tmdbId}`;
72
+ // Check cache first
73
+ const cached = await this.cache.get(cacheKey);
74
+ if (cached) {
75
+ return cached;
76
+ }
77
+ try {
78
+ const response = await axios_1.default.get(`${this.baseUrl}/tv/${tmdbId}`, {
79
+ params: { api_key: this.apiKey },
80
+ timeout: 5000,
81
+ });
82
+ const tv = response.data;
83
+ const firstAirDate = new Date(tv.first_air_date);
84
+ const now = new Date();
85
+ const aired = firstAirDate <= now;
86
+ const result = {
87
+ exists: true,
88
+ released: aired,
89
+ releaseDate: tv.first_air_date,
90
+ title: tv.name,
91
+ message: aired ? undefined : `TV show "${tv.name}" has not aired yet (first air date: ${tv.first_air_date})`,
92
+ };
93
+ // Cache the result
94
+ await this.cache.set(cacheKey, result, this.cacheTTL);
95
+ return result;
96
+ }
97
+ catch (error) {
98
+ if (axios_1.default.isAxiosError(error) && error.response?.status === 404) {
99
+ const result = {
100
+ exists: false,
101
+ released: false,
102
+ message: `TV show with TMDB ID ${tmdbId} does not exist`,
103
+ };
104
+ // Cache 404s for shorter time (1 hour)
105
+ await this.cache.set(cacheKey, result, 3600);
106
+ return result;
107
+ }
108
+ console.error('[TMDBService] Error validating TV show:', error);
109
+ throw error;
110
+ }
111
+ }
112
+ /**
113
+ * Validate a specific TV episode exists and has aired
114
+ */
115
+ async validateTVEpisode(tmdbId, season, episode) {
116
+ const cacheKey = `tmdb:tv:${tmdbId}:s${season}:e${episode}`;
117
+ // Check cache first
118
+ const cached = await this.cache.get(cacheKey);
119
+ if (cached) {
120
+ return cached;
121
+ }
122
+ try {
123
+ // First validate the TV show exists
124
+ const tvResult = await this.validateTV(tmdbId);
125
+ if (!tvResult.exists || !tvResult.released) {
126
+ return tvResult;
127
+ }
128
+ // Get season details
129
+ const response = await axios_1.default.get(`${this.baseUrl}/tv/${tmdbId}/season/${season}`, {
130
+ params: { api_key: this.apiKey },
131
+ timeout: 5000,
132
+ });
133
+ const seasonData = response.data;
134
+ const episodeData = seasonData.episodes.find((ep) => ep.episode_number === episode);
135
+ if (!episodeData) {
136
+ const result = {
137
+ exists: false,
138
+ released: false,
139
+ message: `Episode ${episode} does not exist in season ${season}`,
140
+ };
141
+ // Cache for 1 hour
142
+ await this.cache.set(cacheKey, result, 3600);
143
+ return result;
144
+ }
145
+ // Check if episode has aired
146
+ if (!episodeData.air_date) {
147
+ const result = {
148
+ exists: true,
149
+ released: false,
150
+ title: episodeData.name,
151
+ message: `Episode "${episodeData.name}" (S${season}E${episode}) does not have an air date yet`,
152
+ };
153
+ // Cache for 1 hour (might get updated soon)
154
+ await this.cache.set(cacheKey, result, 3600);
155
+ return result;
156
+ }
157
+ const airDate = new Date(episodeData.air_date);
158
+ const now = new Date();
159
+ const aired = airDate <= now;
160
+ const result = {
161
+ exists: true,
162
+ released: aired,
163
+ releaseDate: episodeData.air_date,
164
+ title: episodeData.name,
165
+ message: aired ? undefined : `Episode "${episodeData.name}" (S${season}E${episode}) has not aired yet (air date: ${episodeData.air_date})`,
166
+ };
167
+ // Cache the result
168
+ await this.cache.set(cacheKey, result, this.cacheTTL);
169
+ return result;
170
+ }
171
+ catch (error) {
172
+ if (axios_1.default.isAxiosError(error) && error.response?.status === 404) {
173
+ const result = {
174
+ exists: false,
175
+ released: false,
176
+ message: `Season ${season} does not exist for TV show ${tmdbId}`,
177
+ };
178
+ // Cache 404s for 1 hour
179
+ await this.cache.set(cacheKey, result, 3600);
180
+ return result;
181
+ }
182
+ console.error('[TMDBService] Error validating episode:', error);
183
+ throw error;
184
+ }
185
+ }
186
+ /**
187
+ * Get media object for provider
188
+ */
189
+ async getMediaObject(type, tmdbId, season, episode) {
190
+ if (type === 'movie') {
191
+ const validation = await this.validateMovie(tmdbId);
192
+ return {
193
+ type: 'movie',
194
+ tmdbId,
195
+ title: validation.title,
196
+ releaseYear: validation.releaseDate ? new Date(validation.releaseDate).getFullYear().toString() : undefined,
197
+ };
198
+ }
199
+ else {
200
+ const validation = await this.validateTVEpisode(tmdbId, season, episode);
201
+ return {
202
+ type: 'tv',
203
+ tmdbId,
204
+ s: season,
205
+ e: episode,
206
+ title: validation.title,
207
+ };
208
+ }
209
+ }
210
+ /**
211
+ * Get IMDB ID if available (cached)
212
+ */
213
+ async getImdbId(tmdbId, type) {
214
+ const cacheKey = `tmdb:imdb:${type}:${tmdbId}`;
215
+ const cached = await this.cache.get(cacheKey);
216
+ if (cached)
217
+ return cached;
218
+ try {
219
+ const endpoint = type === 'movie' ? 'movie' : 'tv';
220
+ const response = await axios_1.default.get(`${this.baseUrl}/${endpoint}/${tmdbId}/external_ids`, {
221
+ params: { api_key: this.apiKey },
222
+ timeout: 5000,
223
+ });
224
+ const imdbId = response.data.imdb_id;
225
+ if (imdbId) {
226
+ await this.cache.set(cacheKey, imdbId, this.cacheTTL);
227
+ }
228
+ return imdbId;
229
+ }
230
+ catch (error) {
231
+ console.error('[TMDBService] Failed to get IMDB ID:', error);
232
+ return undefined;
233
+ }
234
+ }
235
+ }
236
+ exports.TMDBService = TMDBService;
237
+ //# sourceMappingURL=tmdb.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmdb.service.js","sourceRoot":"","sources":["../../src/services/tmdb.service.ts"],"names":[],"mappings":"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"}