UNPKG

panjareh

Version:

Panjareh using aparat and phoenix-video-player to play videos on desktops and tvs.

436 lines (408 loc) 12.8 kB
import { GishehAPI, ProductAPI, UserApi } from "../../api"; import { resolveImage } from "../../api/product"; import consts from "../../config/consts"; import playerConsts from "../../config/playerConsts"; import cookiesName from "../../enums/cookies-name"; import { appendUuidOnUrls, getAds, getCollectDataConfig, } from "../../services/player-service"; class DesktopPlayerController { alias; isAuthenticated; userToken; uuid; product; returnUrl; constructor(data) { const { alias, isAuthenticated, token: userToken, uuid, product, return_url, } = data; this.alias = alias; this.isAuthenticated = isAuthenticated; this.userToken = userToken; this.uuid = uuid; this.product = product; this.returnUrl = return_url; } getAdvertisement = async (productResponse) => { const config = { ...productResponse }; try { return await getAds() .then((responseAds) => { if (responseAds.data && responseAds.data.length > 0) { const { ad_bank } = responseAds.data[0]; config.ads = ad_bank; } return config; }) .catch(() => { return productResponse; // console.error(`ADS: Failed load ads. ${e?.message}`); }); } catch { return productResponse; } }; fetchStreamLink = async () => { if (!this.product) throw new Error("product is required"); return await ProductAPI.getStreamUrl(this.product.getToken()) .then( async (response) => { return await this.getAdvertisement(response); }, (err) => { console.error( `PLAYER : Failed load movie for alias : ${this.alias}, message:${err.message}` ); return null; } ) .catch((err) => { console.error(`PLAYER : ${err?.message}`); return null; }); }; checkTicketStatus = async () => { try { const response = await GishehAPI.checkStatus(this.product.getId()); if (response) { const { status, token } = response.body; if (status === 1 && token) { return { ticketStatus: 1, hasTicket: true, gishehToken: token }; } } return { ticketStatus: 0, hasTicket: false, gishehToken: null }; } catch (error) { const { status } = error; if (status === 404) { return { ticketStatus: 0, hasTicket: false, gishehToken: null }; } return { ticketStatus: 0, hasTicket: false, gishehToken: null }; } }; fetchEkranStreamLink = async () => { const { ticketStatus, hasTicket, gishehToken } = await this.checkTicketStatus(); if (hasTicket) { const data = await ProductAPI.getEkranStreamUrl( this.product.getToken(), gishehToken ) .then( async (response) => { return await this.getAdvertisement(response); }, (err) => { console.error( `PLAYER : EKRAN - Failed load movie for alias : ${this.alias}, message:${err.message}` ); return null; } ) .catch((err) => { console.error(`PLAYER : EKRAN - ${err?.message}`); return { ticketStatus, hasTicket }; }); return { ...data, ticketStatus, hasTicket }; } else { return { ticketStatus, hasTicket }; } }; getUserInternetInfo = async () => { try { return await UserApi.checkInternet() .then((response) => { if (response) { const { body } = response; if (body) { return { title: body.message_title, message: body.message, }; } } return null; }) .catch((e) => { console.info( `Failed fetch Dana(ips) data for movie alias: ${ this.alias }. Message:${e.message || e}` ); }); } catch (e) { console.info( `Failed fetch Dana(ips) data for movie alias: ${this.alias}. Message:${ e.message || e }` ); } return null; }; getNeshanehInfo = async () => { // region fetch Neshane data try { return await ProductAPI.neshaneh(this.product.nid).then((response) => { if (response) { const { body } = response; if (body) { const markers = { markerTip: { display: false, skip: true, }, markers: null, }; markers.markers = body.map((mark) => { return { time: mark.start, duration: mark.end - mark.start, }; }); return markers; } } return null; }); } catch (e) { if (e === 404) { console.info( `Movie with alias: ${this.alias}, doesn't have Neshane Tags.` ); } else { console.info( `Failed fetch Neshane data for movie alias: ${this.alias}.` ); } } return null; }; getNextEpisodeInfo = () => { // next epsidoe plugin with auto advance const nextEpisode = this.product.getNextEpisode(); if (nextEpisode && this.product.titration) { const { lastStart } = this.product.titration; const nextEpisodeLink = `${nextEpisode.alias}?return_url=${consts.SITE_URL}/p${nextEpisode.alias}`; return { url: nextEpisodeLink, autoAdvance: true, showAutoAdvanceButton: true, autoAdvanceButtonText: "قسمت بعدی", nextEpisodeDisplayTime: lastStart, nextEpisodeDisplayDuration: 15, dialogData: { title: nextEpisode.getTitle(), description: `${nextEpisode.getFullTitle()} . ${nextEpisode.getDuration( true )}`, url: nextEpisode.getImage("hs"), link: nextEpisodeLink, }, dialogTemplate: ({ title, description, url, link }) => { const container = document.createElement("a"); container.className = "vjs-next-episode-dialog-content"; container.href = link; const img = document.createElement("img"); img.className = "vjs-next-episode-dialog-poster"; img.src = url; container.appendChild(img); const episodeContent = document.createElement("div"); episodeContent.className = "vjs-next-episode-content"; container.appendChild(episodeContent); const titleEl = document.createElement("span"); titleEl.className = "vjs-next-episode-dialog-title"; titleEl.innerHTML = title; episodeContent.appendChild(titleEl); const descriptionEl = document.createElement("span"); descriptionEl.className = "vjs-next-episode-dialog-description"; descriptionEl.innerHTML = description; episodeContent.appendChild(descriptionEl); return container; }, }; } return null; }; getSeassonInfo = () => { // seasons playlist plugin const seasons = this.product.getSeasons(); if (seasons) { const transformEpisodesData = (episodes) => { return episodes.map((episode) => ({ alias: episode.alias, title: episode.serialSpecialTitle, season: episode.serialSeason, part: episode.serialPart, thumbnail: resolveImage( episode.specialImagePart || episode.horizontalSmallPoster ), duration: episode.duration, link: `${episode.alias}`, })); }; return { seasons: seasons, getEpisode: (season, page, callback) => { ProductAPI.episodes({ alias: this.alias, season: season, page: page - 1, }) .then((response) => { if (response && response.body) { const { result } = response.body; const tranformedEpisodes = transformEpisodesData(result || []); //transformEpisodesData(product.getNextEpisode()); callback(tranformedEpisodes); } return []; }) .catch((error) => { console.info( `SEASON : Fetch episode error, ${error.message ?? error}` ); }); }, }; } return null; }; getVoteInfo = () => { // next vote plugin if (this.isAuthenticated) { if (this.product.titration) { const { lastStart } = this.product.titration; const VOTE_CARD_DURATION = 60; // sec return { submitVote: ({ likeStatus, callback }) => { if (likeStatus === 1) { ProductAPI.like(this.product.nid) .then( () => { callback(); }, () => { callback(); } ) .catch((error) => { (error.message || error) && console.info( `VOTE : Vote plugin error, ${error.message ?? error}` ); }); } else if (likeStatus === 2) { ProductAPI.disLike(this.product.nid) .then(() => { callback(); }) .catch((error) => { (error.message || error) && console.info( `VOTE : Vote plugin error, ${error.message ?? error}` ); }); } }, from: lastStart - VOTE_CARD_DURATION, to: lastStart, }; } } return null; }; getResumeInfo = async () => { if (this.product.getDuration() > playerConsts.THRESHOLD.SHORT_MOVIE) { try { return await ProductAPI.resume(this.product.nid).then((response) => { const { body } = response; if (body) { return body?.minute; } return null; }); } catch { console.info("PLAYER : It hasnt't any resume data."); } } return null; }; preparePlayerConfig = async (streamDataReq) => { const streamData = streamDataReq?.body; const { ads } = streamDataReq; let config = {}, pluginConfig = {}; config.sources = appendUuidOnUrls( streamData.source, cookiesName.UuidUnderLine, this.uuid ); console.log("streamData", streamData.source); config.poster = this.product.getImage("mb"); if (this.product.isSeries()) { config.info = { title: this.product.getTitle(), subtitle: this.product.getFullTitle(), }; } else { config.info = { subtitle: this.product.getFullTitle(), }; } config.returnUrl = this.returnUrl ? this.returnUrl : consts.SITE_URL; // seekbuttons plugin reqired pluginConfig.seekButtons = {}; // subtitle settings if (streamData.subtitle) { pluginConfig.subtitleSettings = { subtitles: streamData.subtitle }; } // skip button plugin if (this.product.titration) { const { firstStart, firstEnd } = this.product.titration; pluginConfig.skipButton = { from: firstStart === 0 ? 1 : firstStart, to: firstEnd, }; } // seek thubmnail plugin if (streamData.tooltip_url) { pluginConfig.seekThumbnailSrc = streamData.tooltip_url; } // collect data plugin // Todo : configure collect data plugin; if (this.product.getToken()) { pluginConfig.collectData = getCollectDataConfig( this.product.getToken(), this.userToken, this.uuid ); } if (this.uuid) { config.extraData = {}; config.extraData[cookiesName.UuidUnderLine] = this.uuid; } if (this.product.isAdultContent() && this.product.haveAds && ads) { pluginConfig.vast = { url: ads.tag_url, skip: 5, withCredentials: false, }; } // Plugins voting and continue watching are only enabled for login users. pluginConfig.trafficUsage = await this.getUserInternetInfo(); pluginConfig.markers = await this.getNeshanehInfo(); pluginConfig.nextEpisode = await this.getNextEpisodeInfo(); pluginConfig.seasonPlaylist = await this.getSeassonInfo(); pluginConfig.vote = await this.getVoteInfo(); config.resumeFrom = await this.getResumeInfo(); config.pluginOptions = pluginConfig; return { loading: false, config }; }; } export default DesktopPlayerController;