PopcornFlixPuppet.groovy 10.4 KB
/*
 * Copyright (c) 2016 PuppetMaster.TV
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details:
 *
 *     https://www.gnu.org/licenses/gpl-2.0.txt
 */

/*
 * @author  MasterPuppeteer
 * @credit  learningit
 */

package tv.puppetmaster.usa

import org.json.JSONArray
import org.json.JSONObject
import tv.puppetmaster.data.BasePuppetIterator
import tv.puppetmaster.data.i.*
import tv.puppetmaster.data.i.Puppet.PuppetIterator
import tv.puppetmaster.data.i.SourcesPuppet.SourceDescription

import java.util.regex.Matcher

class PopcornFlixPuppet implements InstallablePuppet {

    static final int VERSION_CODE = 5

    static final DISPLAY_MAX_VIDEOS = 20

    ParentPuppet mParent
    String mUrl
    String mName
    String mDescription
    boolean mIsTopLevel
    String mImageUrl
    String mBackgroundImageUrl

    PopcornFlixPuppet() {
        this(
                null,
                "https://www.popcornflix.com",
                "Popcorn Flix",
                "Offers a broad collection of great movies you can watch right now.",
                true,
                "http://compass.xboxlive.com/assets/88/f9/88f9f3a7-51bf-4ad1-84aa-a4bf213abb45.jpg",
                "http://icdn2.digitaltrends.com/image/popcornflix-screen-1200x630-c.jpg"
        )
    }

    PopcornFlixPuppet(ParentPuppet parent, String url, String name, String description, boolean isTopLevel, String imageUrl, String backgroundImageUrl) {
        mParent = parent
        mUrl = url
        mName = name
        mDescription = description
        mIsTopLevel = isTopLevel
        mImageUrl = imageUrl
        mBackgroundImageUrl = backgroundImageUrl
    }

    @Override
    PuppetIterator getChildren() {
        PuppetIterator children = new BasePuppetIterator()

        if (mParent == null) {
            String html = new URL(mUrl).getText(requestProperties: [
                    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
            ]).replaceAll("\n", "")
            Matcher matcher = html =~ /,\s*\{(.+?)\}\)\s*<\/script>/
            if (!matcher.find()) {
                return children
            }
            JSONObject json = new JSONObject("{${matcher.group(1)}}")
            JSONArray items = json.getJSONObject('layout').getJSONArray('leftMenu')
            for (int i = 0; i < items.length(); i++) {
                JSONObject it = items.getJSONObject(i)
                if (it.has('channels')) {
                    JSONArray channels = it.getJSONArray('channels')
                    for (int j = 0; j < channels.length(); j++) {
                        children.add(new PopcornFlixPuppet(
                                this,
                                "https://api.unreel.me/v1/videos/channel/${channels.getString(j).toLowerCase()}/0?__site=popcornflix&__source=web&max=${DISPLAY_MAX_VIDEOS}&videoSourceCombo=4",
                                channels.getString(j),
                                null,
                                true,
                                mImageUrl,
                                mBackgroundImageUrl
                        ))
                    }
                }
            }
        } else {
            JSONArray videos = new JSONObject(new URL(mUrl).getText()).getJSONArray('videos')
            for (int i = 0; i < videos.length(); i++) {
                JSONObject video = videos.getJSONObject(i)
                JSONObject thumbnails = video.getJSONObject('metadata').getJSONObject('providerThumbnails')
                children.add(
                        new PopcornFlixSourcesPuppet(
                                this,
                                video.getString('uid'),
                                video.getString('title'),
                                video.getString('description'),
                                video.getJSONObject('contentDetails').getLong('duration'),
                                thumbnails.has('default') ? thumbnails.getString('default') : mImageUrl,
                                thumbnails.has('standard') ? thumbnails.getString('standard') : mBackgroundImageUrl
                        )
                )
            }
            if (videos.length() == DISPLAY_MAX_VIDEOS) {
                Matcher matcher = mUrl =~ /.*\/(\d+)\\?.*/
                if (matcher.find()) {
                    String index = matcher.group(1)
                    int nextIndex = index.toInteger() + DISPLAY_MAX_VIDEOS
                    children.add(new PopcornFlixPuppet(
                            this,
                            mUrl.replace("/${index}?", "/${nextIndex}?"),
                            'Next',
                            null,
                            false,
                            mImageUrl,
                            mBackgroundImageUrl

                    ))
                }
            }
        }
        return children
    }

    @Override
    boolean isTopLevel() {
        return mIsTopLevel
    }

    @Override
    String getName() {
        return mName
    }

    @Override
    String getCategory() {
        return "Entertainment"
    }

    @Override
    String getShortDescription() {
        return mDescription
    }

    @Override
    String getImageUrl() {
        return mImageUrl
    }

    @Override
    String getBackgroundImageUrl() {
        return mBackgroundImageUrl
    }

    @Override
    boolean isUnavailableIn(String region) {
        return false
    }

    @Override
    String getPreferredRegion() {
        return null
    }

    @Override
    int getShieldLevel() {
        return 0
    }

    @Override
    ParentPuppet getParent() {
        return null
    }

    @Override
    SearchesPuppet getSearchProvider() {
        return null
    }

    @Override
    SettingsPuppet getSettingsProvider() {
        return null
    }

    @Override
    int getFastlaneBackgroundColor() {
        return 0xFFFE3200
    }

    @Override
    int getSearchAffordanceBackgroundColor() {
        return 0xFF00B4F9
    }

    @Override
    int getSelectedBackgroundColor() {
        return 0xFFFE3200
    }

    @Override
    int getPlayerBackgroundColor() {
        return 0xFFFE3200
    }

    @Override
    List<Map<String, String>> getLiveChannelsMetaData() {
        return null
    }

    @Override
    PuppetIterator getRelated() {
        return null
    }

    void setUrl(String url) {
        mUrl = url
    }

    @Override
    String toString() {
        return mParent == null ? getName() : mParent.toString() + " < " + getName()
    }

    @Override
    int getVersionCode() {
        return VERSION_CODE
    }

    def static class PopcornFlixSourcesPuppet implements SourcesPuppet {

        ParentPuppet mParent
        String mId
        String mName
        String mShortDescription
        long mDuration
        String mImageUrl
        String mBackgroundImageUrl

        PopcornFlixSourcesPuppet(parent, id, name, shortDescription, duration, imageUrl, backgroundImageUrl) {
            mParent = parent
            mId = id
            mName = name
            mShortDescription = shortDescription
            mDuration = duration * 1000l
            mImageUrl = imageUrl
            mBackgroundImageUrl = backgroundImageUrl
        }

        @Override
        String getPublicationDate() {
            return null
        }

        @Override
        long getDuration() {
            return mDuration
        }

        @Override
        SourcesPuppet.SourceIterator getSources() {
            return new PopcornFlixSourceIterator()
        }

        @Override
        boolean isLive() {
            return false
        }

        @Override
        List<SourcesPuppet.SubtitleDescription> getSubtitles() {
            return null
        }

        @Override
        String getName() {
            return mName
        }

        @Override
        String getCategory() {
            return null
        }

        @Override
        String getShortDescription() {
            return mShortDescription
        }

        @Override
        String getImageUrl() {
            return mImageUrl
        }

        @Override
        String getBackgroundImageUrl() {
            return mBackgroundImageUrl
        }

        @Override
        boolean isUnavailableIn(String region) {
            return !(region in ['ca', 'us'])
        }

        @Override
        String getPreferredRegion() {
            return 'us'
        }

        @Override
        int getShieldLevel() {
            return 0
        }

        @Override
        ParentPuppet getParent() {
            return mParent
        }

        @Override
        PuppetIterator getRelated() {
            return null
        }

        @Override
        String toString() {
            return mParent == null ? getName() : mParent.toString() + " < " + getName()
        }

        def class PopcornFlixSourceIterator implements SourcesPuppet.SourceIterator {

            List<SourceDescription> mSources
            int currentIndex = 0

            @Override
            boolean hasNext() {
                if (mSources == null) {
                    mSources = new ArrayList<SourceDescription>()

                    JSONObject json = new JSONObject(new URL("https://api.unreel.me/v2/sites/popcornflix/videos/${mId}/play-url?__site=popcornflix&__source=web&protocol=https").getText(
                            requestProperties: [
                                    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11'
                            ]
                    ))
                    SourceDescription source = new SourceDescription()
                    source.url = json.getString('url')
                    mSources.add(source)
                }
                return currentIndex < mSources.size()
            }

            @Override
            SourceDescription next() {
                return mSources.get(currentIndex++)
            }

            @Override
            void remove() {

            }
        }
    }
}