@iptv/xtream-api
Version:
Standardized access to Xtream compatible player API
452 lines (451 loc) • 11.6 kB
JavaScript
import h from "camelcase-keys";
import { defineSerializers as H } from "./index.js";
const W = H("JSON:API", {
profile: (e) => {
const { auth: n, expDate: s, maxConnections: i, activeCons: d, createdAt: a, ...t } = h(e);
return {
data: {
type: "user-profile",
id: t.username,
attributes: {
...t,
isTrial: t.isTrial === "1",
maxConnections: Number(i),
activeConnections: Number(d),
createdAt: new Date(Number(a) * 1e3),
expiresAt: new Date(Number(s) * 1e3)
}
}
};
},
serverInfo: (e) => {
const { timestampNow: n, ...s } = h(e);
return {
data: {
type: "server-info",
id: e.url,
attributes: {
...s,
timeNow: new Date(Number(n) * 1e3)
}
}
};
},
channelCategories: (e) => x(e, "channel-category"),
movieCategories: (e) => x(e, "movie-category"),
showCategories: (e) => x(e, "show-category"),
channels: (e) => ({
data: h(e).map((s) => {
const { added: i, num: d, streamId: a, categoryIds: t, streamIcon: m, epgChannelId: p, tvArchive: u, name: l, tvArchiveDuration: b, url: v } = s;
return {
type: "channel",
id: a.toString(),
attributes: {
name: l,
number: d,
tvArchive: u === 1,
tvArchiveDuration: b,
logo: m,
epgId: p,
createdAt: new Date(Number(i) * 1e3),
url: v
},
...t.length > 0 && {
relationships: {
categories: {
data: t.map((y) => ({
type: "channel-category",
id: y.toString()
}))
}
}
}
};
})
}),
movies: (e) => ({
data: h(e).map((s) => {
const {
streamIcon: i,
streamId: d,
releaseDate: a,
rating: t,
added: m,
categoryIds: p,
episodeRunTime: u,
genre: l,
cast: b,
director: v,
youtubeTrailer: y,
title: w,
plot: N,
url: D
} = s;
return {
type: "movie",
id: d.toString(),
attributes: {
name: w,
plot: N,
genre: l?.split(",").map((o) => o.trim()) ?? [],
cast: b?.split(",").map((o) => o.trim()) ?? [],
director: v?.split(",").map((o) => o.trim()) ?? [],
poster: i,
voteAverage: Number(t),
duration: Number(u) * 60,
youtubeId: y,
releaseDate: a ? new Date(a) : null,
createdAt: new Date(Number(m) * 1e3),
url: D
},
...p.length > 0 && {
relationships: {
categories: {
data: p.map((o) => ({
type: "movie-category",
id: o.toString()
}))
}
}
}
};
})
}),
movie: (e) => {
const n = h(e, { deep: !0 }), {
director: s,
actors: i,
genre: d,
cast: a,
oName: t,
releaseDate: m,
mpaaRating: p,
age: u,
rating: l,
duration: b,
durationSecs: v,
backdropPath: y,
movieImage: w,
kinopoiskUrl: N,
youtubeTrailer: D,
tmdbId: o,
name: f,
description: T,
plot: S,
country: k,
subtitles: r,
bitrate: I
} = n.info, { categoryIds: g, streamId: C, added: A } = n.movieData;
return {
data: {
type: "movie",
id: C.toString(),
attributes: {
name: f,
originalName: t,
description: T,
plot: S,
informationUrl: N,
cover: y[0],
poster: w,
duration: v,
durationFormatted: b,
country: k,
voteAverage: l,
director: s?.split(",").map((c) => c.trim()) ?? [],
actors: i?.split(",").map((c) => c.trim()) ?? [],
cast: a?.split(",").map((c) => c.trim()) ?? [],
genre: d?.split(",").map((c) => c.trim()) ?? [],
youtubeId: D,
tmdbId: o?.toString(),
rating: {
mpaa: p,
age: Number(u)
},
subtitles: r,
bitrate: I,
releaseDate: m ? new Date(m) : null,
createdAt: new Date(Number(A) * 1e3)
},
...g.length > 0 && {
relationships: {
categories: {
data: g.map((c) => ({
type: "movie-category",
id: c.toString()
}))
}
}
}
}
};
},
shows: (e) => ({
data: h(e).map((s) => {
const {
rating: i,
seriesId: d,
cover: a,
categoryIds: t,
backdropPath: m,
releaseDate: p,
episodeRunTime: u,
lastModified: l,
cast: b,
director: v,
genre: y,
youtubeTrailer: w,
title: N,
plot: D
} = s;
return {
type: "show",
id: d.toString(),
attributes: {
name: N,
plot: D,
cast: b?.split(",").map((o) => o.trim()) ?? [],
director: v?.split(",").map((o) => o.trim()) ?? [],
genre: y?.split(",").map((o) => o.trim()) ?? [],
voteAverage: Number(i),
poster: a,
cover: m[0],
duration: Number(u) * 60,
youtubeId: w,
releaseDate: p ? new Date(p) : null,
updatedAt: new Date(Number(l) * 1e3)
},
...t.length > 0 && {
relationships: {
categories: {
data: t.map((o) => ({
type: "show-category",
id: o.toString()
}))
}
}
}
};
})
}),
show: (e) => {
const { seasons: n, info: s, episodes: i } = h(e, {
deep: !0
}), {
rating: d,
seriesId: a,
cover: t,
categoryIds: m,
backdropPath: p,
releaseDate: u,
episodeRunTime: l,
lastModified: b,
cast: v,
director: y,
genre: w,
youtubeTrailer: N,
title: D,
plot: o
} = s;
if (typeof a > "u")
throw new Error("seriesId is required");
const f = Object.values(i).flat(), T = f.map((r) => {
const { id: I, season: g, title: C, subtitles: A, url: c, episodeNum: O, added: P, info: E } = r, { releaseDate: B, rating: J, movieImage: M, coverBig: R, durationSecs: j, duration: z, tmdbId: F, plot: G, video: L, audio: U, bitrate: q } = E, K = n.find(($) => $.seasonNumber === g)?.id.toString() || g.toString();
return {
type: "episode",
id: I,
attributes: {
number: Number(O),
title: C,
plot: G,
tmdbId: F?.toString(),
poster: M,
cover: R,
voteAverage: Number(J),
duration: j,
durationFormatted: z,
releaseDate: B ? new Date(B) : null,
createdAt: new Date(Number(P) * 1e3),
subtitles: A,
url: c,
video: L,
audio: U,
bitrate: q
},
relationships: {
season: {
data: { type: "season", id: K }
},
show: {
data: { type: "show", id: a.toString() }
}
}
};
});
let S = n;
S.length === 0 && (S = Object.keys(i).map((r) => {
const I = r, g = i[r][0];
return {
id: Number(I),
name: `Season ${I}`,
episodeCount: i[r].length,
overview: "",
airDate: g.info.releaseDate,
cover: g.info.movieImage,
seasonNumber: Number(I),
voteAverage: Number(g.info.rating),
coverBig: g.info.movieImage
};
}));
const k = S.map((r) => {
const { id: I, seasonNumber: g, cover: C, coverBig: A, airDate: c, ...O } = r;
return {
type: "season",
id: I.toString(),
attributes: {
...O,
releaseDate: c ? new Date(c) : null,
number: g,
cover: A
},
relationships: {
show: {
data: { type: "show", id: a.toString() }
},
episodes: {
data: f.filter((P) => P.season === g).map((P) => ({
type: "episode",
id: P.id.toString()
}))
}
}
};
});
return {
data: {
type: "show",
id: a.toString(),
attributes: {
name: D,
plot: o,
voteAverage: Number(d),
poster: t,
cover: p[0],
duration: Number(l) * 60,
cast: v?.split(",").map((r) => r.trim()) ?? [],
director: y?.split(",").map((r) => r.trim()) ?? [],
genre: w?.split(",").map((r) => r.trim()) ?? [],
youtubeId: N,
releaseDate: u ? new Date(u) : null,
updatedAt: new Date(Number(b) * 1e3)
},
relationships: {
categories: {
data: m.map((r) => ({
type: "show-category",
id: r.toString()
}))
},
seasons: {
data: S.map((r) => ({
type: "season",
id: r.id.toString()
}))
},
episodes: {
data: f.map((r) => ({
type: "episode",
id: r.id.toString()
}))
}
}
},
included: [...k, ...T]
};
},
shortEPG: (e) => {
const { epgListings: n } = h(e, { deep: !0 });
return {
data: n.map((s) => {
const { id: i, channelId: d, lang: a, start: t, end: m, title: p, description: u, epgId: l } = s;
return {
type: "epg-listing",
id: i.toString(),
attributes: {
epgId: l,
start: new Date(t),
end: new Date(Number(m) * 1e3),
title: atob(p),
description: atob(u),
language: a
},
relationships: {
channel: {
data: {
type: "channel",
id: d.toString()
}
}
}
};
})
};
},
fullEPG: (e) => {
const { epgListings: n } = h(e, { deep: !0 });
return {
data: n.map((s) => {
const { id: i, channelId: d, start: a, end: t, title: m, description: p, nowPlaying: u, hasArchive: l, lang: b, epgId: v } = s;
return {
type: "epg-listing",
id: i.toString(),
attributes: {
epgId: v,
start: new Date(a),
end: new Date(t),
title: atob(m),
description: atob(p),
language: b,
nowPlaying: !!u,
hasArchive: !!l
},
relationships: {
channel: {
data: {
type: "channel",
id: d.toString()
}
}
}
};
})
};
}
});
function x(e, n) {
return {
data: h(e).map((i) => {
const { categoryId: d, categoryName: a, parentId: t } = i;
return {
type: n,
id: d.toString(),
attributes: {
name: a
},
...t && {
relationships: {
parent: {
data: {
type: n,
id: t.toString()
}
}
}
}
};
})
};
}
export {
W as JSONAPISerializer
};