@prisma/client#Episode TypeScript Examples

The following examples show how to use @prisma/client#Episode. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: media.ts    From frames with Mozilla Public License 2.0 6 votes vote down vote up
/**
     * @desc gets the next episode of a specific tv show in the database
     * @param mediaId - the id of the tv show to query the database for
     * @param episodeId - the id of the episode to query the database for
     * @param checkCase - whether to check if the episode is the first, next or last episode of the show
     */
    public async getNextEpisode(mediaId: number, episodeId: number, checkCase: 'next' | 'first' | 'last'): Promise<Episode | null> {
        const originalEpisode = await this.prisma.episode.findUnique({where: {id: episodeId}});
        const episodes = this.sortArray(await this.prisma.episode.findMany({where: {showId: mediaId}}), ['seasonId', 'episode'], ['asc', 'asc']);
        if ((originalEpisode && checkCase === 'next') || checkCase !== 'next') switch (checkCase) {
            case "next":
                const episodeIndex = episodes.findIndex(e => e.id === episodeId);
                return episodes.length > episodeIndex + 1 ? episodes[episodeIndex + 1] : null;

            case "first":
                return episodes[0] || null;

            case "last":
                return episodes[episodes.length - 1] || null;
        }

        return null;
    }
Example #2
Source File: scanner.ts    From frames with Mozilla Public License 2.0 6 votes vote down vote up
/**
     * @desc this is a recursive function that handles the subtitles logic
     * @param subs - the videos array to be scanned
     */
    protected async getSubs(subs: (Video & { media: Media, episode: Episode | null })[]) {
        if (this.OpenSubtitles) {

            while (subs.length) {
                await this.getSub(subs[0]);
                await new Promise<void>(resolve => {
                    setTimeout(() => {
                        subs.shift();
                        resolve();
                    }, 3000)
                })
            }
        }
    }
Example #3
Source File: middleware.ts    From frames with Mozilla Public License 2.0 5 votes vote down vote up
/**
     * @desc gets a file's location from the request
     * @param location - file location
     */
    public async getFileAndAndLocation(location: string) {
        let res: {location: string, download: boolean, name: string} = {
            location: '',
            download: false,
            name: ''
        };

        const { data, error } = await this.supabase
            .from<(View & {video: Video})>('View')
            .select('*,video:Video(*)')
            .eq('auth', location)
            .single();

        if (!error && data) {
            const { video } = data;

            res = {
                location: video.location,
                download: false,
                name: ''
            }

        } else {
            const { data, error } = await this.supabase
                .from<(Download & {view: (View & {episode: Episode, video: (Video & {media: Media})})})>('Download')
                .select('*,view:View(*,episode:Episode(*),video:Video(*,media:Media!Video_mediaId_fkey(*)))')
                .eq('location', location)
                .single();

            if (!error && data) {
                if (data.view.episode) {
                    const { episode, video } = data.view;
                    const { media } = video;
                    const episodeInfo = await this.getEpisode(media.tmdbId, episode.seasonId, episode.episode);
                    res = {
                        location: video.location,
                        download: true,
                        name: media.name + (/^Episode \d+/i.test(episodeInfo?.name || 'Episode 0') ? ` Season ${episode.seasonId} - Episode ${episode.episode}` : ` S${episode.seasonId} - E${episode.episode}: ${episodeInfo?.name}`)
                    }

                } else {
                    const { video } = data.view;
                    res = {
                        location: video.location,
                        download: true,
                        name: video.media.name
                    }
                }
            }
        }

        return res;
    }
Example #4
Source File: playback.ts    From frames with Mozilla Public License 2.0 5 votes vote down vote up
/**
     * @desc gets the next episode for playback based on user's activity
     * @param mediaId - the media id
     * @param userId - the user id
     * @protected
     */
    protected async getNextEpisodeForUser(mediaId: number, userId: string): Promise<{ episode: Episode, position: number } | null> {
        const watched = await this.prisma.watched.findMany({where: {userId, mediaId}, orderBy: {updated: 'desc'}});
        if (watched.length > 0) {
            if (watched[0].episodeId) {
                if (watched[0].position > 939) {
                    const firstEpisode = await this.mediaClass.getNextEpisode(mediaId, watched[0].episodeId, 'first');
                    const nextEpisode = await this.mediaClass.getNextEpisode(mediaId, watched[0].episodeId, 'next');
                    if (nextEpisode)
                        return {episode: nextEpisode, position: 0};

                    else if (firstEpisode) {
                        const episode = await this.prisma.episode.findMany({where: {showId: mediaId}});
                        const notWatched = episode.filter(e => watched.every(w => w.episodeId !== e.id));
                        const data = notWatched.map(e => {
                            return {
                                userId, mediaId,
                                videoId: e.videoId,
                                position: 1000,
                                episodeId: e.id,
                                finished: 2,
                                times: 1,
                                updated: new Date()
                            }
                        })

                        await this.prisma.watched.createMany({data});
                        await this.prisma.watched.updateMany({
                            where: {userId, mediaId, times: {lt: 1}},
                            data: {times: 1, finished: 2}
                        })
                        return {episode: firstEpisode, position: 0};
                    }

                } else {
                    const episode = await this.prisma.episode.findUnique({where: {id: watched[0].episodeId}});
                    if (episode)
                        return {episode, position: watched[0].position};
                }
            }

        } else {
            const episode = await this.mediaClass.getNextEpisode(mediaId, 0, 'first');
            if (episode)
                return {episode, position: 0};
        }

        return null;
    }
Example #5
Source File: scanner.ts    From frames with Mozilla Public License 2.0 5 votes vote down vote up
/**
     * @desc does the actual scan for the subtitles of a specific video file
     * @param video - the video file to be scanned
     * @param auth - the authentication object
     */
    public async getSub(video: (Video & { media: Media, episode: Episode | null }), auth?: string) {
        let returnSubs: { language: string, url: string, label: string, lang: string }[] = [];
        if (this.OpenSubtitles) {
            const file = await this.drive?.getFile(video.location) || null;
            if (file) {
                let obj: any = null;
                if (video.episode) {
                    const external = await this.tmdb?.getExternalId(video.media.tmdbId, MediaType.SHOW);
                    if (external) {
                        obj = {
                            season: video.episode.seasonId,
                            filesize: file.size,
                            filename: file.name,
                            episode: video.episode.episode,
                            imdbid: external.imdb_id
                        };
                    }
                } else {
                    const external = await this.tmdb?.getExternalId(video.media.tmdbId, MediaType.MOVIE);
                    if (external) obj = {filesize: file.size, filename: file.name, imdbid: external.imdb_id};
                }

                if (obj) {
                    obj.extensions = ['srt', 'vtt'];
                    const keys = ['en', 'fr', 'de'];
                    const lang = ['english', 'french', 'german'];
                    const labels = ['English', 'Français', 'Deutsch'];

                    const subs: { [p: string]: string | null } | null = await this.OpenSubtitles.search(obj)
                        .then((temp: { [x: string]: { url: any; }; } | undefined) => {
                            if (temp) {
                                let item: { [key: string]: string } = {};
                                keys.forEach((value, pos) => {
                                    item[lang[pos]] = temp[value] === undefined ? null : temp[value].url;
                                });
                                return item;
                            } else return null;
                        }).catch((error: any) => {
                            console.log(error)
                            return null;
                        })

                    if (subs) {
                        await this.prisma.video.update({where: {id: video.id}, data: subs});
                        if (auth)
                            returnSubs = keys.map((value, pos) => {
                                return {
                                    language: this.capitalize(lang[pos]),
                                    url: subs[lang[pos]] ? '/api/stream/subtitles?auth=' + auth + '&language=' + lang[pos] : '',
                                    label: labels[pos],
                                    lang: value
                                }
                            }).filter(x => x.url !== '');
                    }
                }

            }

        }

        return returnSubs;
    }
Example #6
Source File: middleware.ts    From frames with Mozilla Public License 2.0 4 votes vote down vote up
/**
     * @desc creates the SEO data for the page
     * @param type - type of the page
     * @param value - value of the page
     */
    public async getMetaTags(type: string, value: string) {
        if (type === 'movie' || type === 'show') {
            const {data} = await this.supabase
                .from<Modify<Media, {release: string}>>('Media')
                .select('*')
                .eq('type', type.toUpperCase())
                .ilike('name', `*${value}*`)

            if (data) {
                const response = data.map(item => {
                    const year = new Date(item.release).getFullYear();
                    const drift = item.name.Levenshtein(value);
                    return {...item, year, drift};
                })

                const info = this.sortArray(response, ['drift', 'year'], ['asc', 'desc'])[0];
                if (info)
                    return {
                        overview: info.overview,
                        name: info.name,
                        poster: info.poster
                    }
            }
        }

        if (type === 'watch' || type === 'frame' || type === 'room') {
            if (type === 'room') {
                const {data} = await this.supabase
                    .from<Room>('Room')
                    .select('*')
                    .eq('roomKey', value)
                    .single();

                value = data ? data.auth: value;
            }

            if (type === 'frame') {
                const {data} = await this.supabase
                    .from<Frame>('Frame')
                    .select('*')
                    .eq('cypher', value)
                    .single();

                value = data ? data.auth: value;
            }

            const {data} = await this.supabase
                .from<(View & {episode: Episode | null, video: (Video & {media: Media})})>('View')
                .select('*, episode:Episode(*), video:Video(*, media:Media!Video_mediaId_fkey(*))')
                .eq('auth', value)
                .single();

            if (data) {
                const {episode, video} = data;
                let {name, overview, poster, tmdbId} = video.media;

                if (episode) {
                    const episodeInfo = await this.getEpisode(tmdbId, episode.seasonId, episode.episode);
                    name = /^Episode \d+/i.test(episodeInfo?.name || 'Episode') ? `${name}: S${episode.seasonId}, E${episode.episode}` : `S${episode.seasonId}, E${episode.episode}: ${episodeInfo?.name}`;
                    overview = episodeInfo?.overview || overview;
                }

                return {
                    overview,
                    name,
                    poster
                }
            }
        }

        if (type === 'person') {
            const person = await this.findPerson(value);
            if (person)
                return {
                    overview: `See all media produced by ${person.name} available on Frames`,
                    name: person.name,
                    poster: 'https://image.tmdb.org/t/p/original' + person.profile_path
                }
        }

        /*if (type === 'collection') {
            const {data} = await this.supabase
                .from('Media')
                .select('name, poster, overview, cName:collection->>name')
                .ilike('cName', `*${value}*`)
                .single();

            console.log(data);
        }*/

        return {
            overview: 'Frames is a streaming service that offers a wide variety of TV shows, movies, anime, documentaries, and more on thousands straight to your browser',
            name: 'Frames - Watch FREE TV Shows and Movies Online',
            poster: '/meta.png'
        }
    }
Example #7
Source File: playback.ts    From frames with Mozilla Public License 2.0 4 votes vote down vote up
/**
     * @desc Handle the creation of the play back information
     * @param video - The video object
     * @param userId - The user identifier
     * @param playlistId - The playlist video identifier
     * @param episode - The episode object
     * @param inform - The inform? variable
     */
    private async handlePlayBackCreation(video: (Video & { media: Med }), userId: string, playlistId: number | null, episode: Episode | null, inform: boolean): Promise<SpringLoad | null> {
        const {media, english, french, german} = video;
        let episodeName: string | null = null;
        let location = this.createUUID();

        let {overview, backdrop, poster, logo, name} = media;
        if (episode) {
            const episodeInfo = await this.mediaClass.getEpisode(episode.id);
            if (episodeInfo) {
                overview = episodeInfo.overview || overview;
                episodeName = episodeInfo.name;
            }
        }

        let subs = [];
        if (!english && !french && !german)
            subs = await this.scanner.getSub({...video, episode}, location);

        else {
            if (english)
                subs.push({
                    language: 'English',
                    url: '/api/stream/subtitles?auth=' + location + '&language=english',
                    label: 'English',
                    lang: 'en'
                });

            if (french)
                subs.push({
                    language: 'French',
                    url: '/api/stream/subtitles?auth=' + location + '&language=french',
                    label: 'Français',
                    lang: 'fr'
                });

            if (german)
                subs.push({
                    language: 'German',
                    url: '/api/stream/subtitles?auth=' + location + '&language=german',
                    label: 'Deutsch',
                    lang: 'de'
                });
        }

        const user = await this.prisma.user.findFirst({where: {userId}});
        if (user) {
            inform = user.inform ? inform : false;
            const obj = {
                inform,
                playlistId,
                videoId: video.id,
                episodeId: episode?.id,
                auth: location, userId,
                created: new Date(),
                updated: new Date(),
            };

            const watched = await this.prisma.watched.findUnique({where: {seenByUser: {userId, videoId: video.id}}});

            await this.prisma.view.upsert({
                where: {auth: location},
                update: obj,
                create: obj
            });

            return {
                playlistId,
                videoId: video.id,
                mediaId: media.id,
                episodeId: episode?.id || null,
                autoPlay: user.autoplay,
                playerId: this.createUUID(), frame: false,
                location, inform, overview, activeSub: user.defaultLang,
                logo, backdrop, name, poster, cdn: this.regrouped.user?.cdn || '/api/streamVideo?auth=',
                position: inform ? (watched?.position || 0) > 939 ? 0 : (watched?.position || 0) : 0,
                episodeName, subs, guest: user.role === Role.GUEST
            };
        }

        return null;
    }
Example #8
Source File: scanner.ts    From frames with Mozilla Public License 2.0 4 votes vote down vote up
/**
     * @desc scans the show folder and adds new episodes to be added to the database
     * @param mediaId - the id of the show to be scanned
     * @param thoroughScan - whether to scan the entire library thoroughly or quickly
     * @param ignoreScan - whether to add ignore irregular files to the database
     */
    public async scanShow(mediaId: number, thoroughScan: boolean, ignoreScan: boolean) {
        const media = await this.prisma.media.findUnique({
            where: {id: mediaId},
            include: {folder: true, episodes: {include: {video: true}}}
        });
        console.log(`Scanning ${media?.name}`, thoroughScan, ignoreScan);

        const tmdbMedia = await this.tmdb?.getMedia(media?.tmdbId || -1, 'SHOW');
        if (media && media.folder && tmdbMedia) {
            const episodes = media.episodes;

            if (episodes.length === tmdbMedia.number_of_episodes && !thoroughScan) {
                console.log(`${media.name} is up to date`);
                return;
            }

            let episodeResults = [] as FrameEpisodeScan[];
            let episodeFiles = (await this.drive?.recursiveReadFolder(media.folder.location)) || [];
            episodeFiles = thoroughScan ? episodeFiles : episodeFiles.filter(f => episodes.every(e => e.video.location !== f.id));
            const episodesToScan = episodeFiles.filter(e => e.name?.endsWith('.m4v') || e.name?.endsWith('.mp4') || e.name?.endsWith('.webm'));
            const toDelete = episodeFiles.filter(e => !e.name?.endsWith('.m4v') && !e.name?.endsWith('.mp4') && !e.name?.endsWith('.webm'));

            const Promises: any[] = [];
            toDelete.forEach(file => Promises.push(this.drive?.deleteFile(file.id!)));

            let tmdbSeasons = await this.tmdb?.getAllEpisodes(tmdbMedia.id) || {episodes: [], tmdbId: media.tmdbId};
            const seasons = (await this.drive?.readFolder(media.folder.location)) || [];
            let tmdbEpisodes = this.sortArray(tmdbSeasons.episodes.map(e => e.season).flat(), ['season_number', 'episode_number'], ['asc', 'asc']);

            episodesToScan.forEach(episode => Promises.push(this.scanEpisode(episode, seasons, tmdbEpisodes, episodeResults, ignoreScan)));
            await Promise.all(Promises);

            episodeResults = thoroughScan ? episodeResults : episodeResults.filter(e => !episodes.some(ep => ep.video.location === e.location && ep.seasonId === e.seasonId && ep.episode === e.episode));
            const failedEpisodes = episodes.filter(e => episodeResults.some(r => r.seasonId === e.seasonId && r.episode === e.episode && e.video.location !== r.location));

            let videoLocations = failedEpisodes.map(e => e.video.location);
            videoLocations = videoLocations.concat(episodeResults.map(e => e.location));

            try {
                await this.prisma.video.deleteMany({
                    where: {
                        location: {in: videoLocations},
                    }
                });
                const data: Omit<Video, 'id'>[] = episodeResults.map(e => {
                    return {
                        english: null, french: null, german: null,
                        mediaId: media.id, location: e.location,
                    }
                })
                await this.prisma.video.createMany({data});

                const videos = await this.prisma.video.findMany({
                    where: {
                        location: {in: videoLocations},
                    },
                    include: {media: true, episode: true},
                    orderBy: {id: 'desc'}
                });
                const episodes: Omit<Episode, 'id'>[] = episodeResults.map(e => {
                    const video = videos.find(v => v.location === e.location);
                    return {
                        backdrop: e.backdrop, episode: e.episode,
                        overview: e.overview, seasonId: e.seasonId,
                        showId: media.id, videoId: video!.id, name: e.name,
                        created: new Date(), updated: new Date(),
                    }
                });
                await this.prisma.episode.createMany({data: episodes});

                if (videoLocations.length > 0) {
                    await this.prisma.media.update({
                        where: {id: media.id},
                        data: {
                            updated: new Date(),
                        }
                    });
                }
            } catch (e) {
                console.log(e);
            }

        }
    }