Ejemplo n.º 1
0
 def validate_password(self, field, value):
     if not value:
         return value
     try:
         MyPlexUser.signin(self.fields.username.value, value)
         return value
     except Unauthorized:
         raise ValidationError('Invalid username or password.')
Ejemplo n.º 2
0
 def validate_password(self, field, value):
     if not value:
         return value
     try:
         MyPlexUser.signin(self.fields.username.value, value)
         return value
     except Unauthorized:
         raise ValidationError('Invalid username or password.')
Ejemplo n.º 3
0
    def __init__(self):
        self.config = get_config()
        self.config.verify()
        self._logger = get_logger(self.__class__.__name__)
        self.c_info = ClientInfo.from_config(self.config)
        self._monitor = ThreadMonitor()
        # self._monitor.start()
        self.registration_thread = ClientRegistration(self.c_info)
        # this call will block if XBMC is unresponsive, will resume when XBMC is UP
        self._xbmc_rpc = XbmcJSONRPC(self.config['xbmc_host'], self.config['xbmc_port']).wait()
        self._xbmc = XBMCPlexPlayer(self._xbmc_rpc, self)
        self.xbmc.notify('Plex', 'PlexMyXBMC Connected')
        self._user = MyPlexUser(self.config['plex_username'], self.config['plex_password'])
        self.xbmc.notify('Plex', 'Logged in as "%s"' % self.config['plex_username'])
        self.xbmc.notify('Plex', 'Master server is {0}'.format(self.config['plex_server']))
        try:
            self._server = self.get_coolest_server()
            self.xbmc.notify('Plex', 'using PMS %s' % self._server.friendlyName)
        except:
            self.xbmc.notify('Plex', 'failed to connect to master server')
            raise

        self.sub_mgr = PlexSubManager(self)
        self.event_mgr = PlexEventsManager(self)
        self.httpd = ThreadedAPIServer(self, ('', self.config['port']), PlexClientHandler)
        self.httpd.allow_reuse_address = True
        self.storage_mgr = PlexStorageManager(self, self.config['local_sync_cache'])
        self.sync_mgr = PlexSyncManager(self, self.storage_mgr)
        self._keep_running = Event()
        self._keep_running.clear()
        self._lock = Lock()
Ejemplo n.º 4
0
def main():
    config = __import__('config')
    user = MyPlexUser.signin(config.username, config.password)

    with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
        for resource in user.resources():
            executor.submit(parse_resource, user, resource)

    print('Servers data parsed')
    paris = pytz.timezone('Europe/Paris')
    ordered = reversed(sorted(data, key=lambda x: paris.localize(x.addedAt)))
    print('Media sorted')

    fg = FeedGenerator()
    fg.id('http://satreix.fr/feeds/plex.rss')
    fg.generator('plex-feed')
    fg.title('PLEX feed')
    fg.subtitle('Newly added media content')
    fg.author({'name': 'satreix', 'email': '*****@*****.**'})
    fg.link(href='http://satreix.fr', rel='alternate')
    fg.logo('https://plex.tv/assets/img/googleplus-photo-cb6f717c8cfd8b48df6dbb09aa369198.png')
    fg.link(href='http://satreix.fr/feeds/plex.rss', rel='self')
    fg.language('en')

    for elt in list(ordered)[:50]:
        fe = fg.add_entry()
        fe.id(elt.getStreamUrl())
        fe.title('{} - {}'.format(elt.title, elt.server.friendlyName))
        fe.pubdate(paris.localize(elt.addedAt))
        fe.description(elt.summary, True)

    fg.rss_file('plex.rss', pretty=True)
    print('File written')
Ejemplo n.º 5
0
 def _connect_plex(self):
     """
     Attempts to authenticate to the Plex API and returns the resulting MyPlexUser object
     :return: plexapi.MyPlexUser
     """
     try:
         return MyPlexUser.signin(self.plex_user, self.plex_password)
     except (Unauthorized, BadRequest) as error:
         sys.exit("Failed to authenticate to the Plex API: " + str(error))
Ejemplo n.º 6
0
 def _connect_plex(self):
     """
     Attempts to authenticate to the Plex API and returns the resulting MyPlexUser object
     :return: plexapi.MyPlexUser
     """
     try:
         return MyPlexUser.signin(self.plex_user, self.plex_password)
     except (Unauthorized, BadRequest) as error:
         sys.exit("Failed to authenticate to the Plex API: " + str(error))
Ejemplo n.º 7
0
def fetch_plex_instance(pkmeter, username=None, password=None, host=None):
    username = username or pkmeter.config.get('plexserver', 'username', from_keyring=True)
    password = password or pkmeter.config.get('plexserver', 'password', from_keyring=True)
    host = host or pkmeter.config.get('plexserver', 'host', '')
    if username:
        log.info('Logging into MyPlex with user %s', username)
        user = MyPlexUser.signin(username, password)
        return user.getResource(host).connect()
    log.info('Connecting to Plex host: %s', host)
    return PlexServer(host)
Ejemplo n.º 8
0
def fetch_server(args):
    if args.resource and args.username and args.password:
        log(0, 'Signing in as MyPlex user %s..' % args.username)
        user = MyPlexUser.signin(args.username, args.password)
        log(0, 'Connecting to Plex server %s..' % args.resource)
        return user.resource(args.resource).connect(), user
    elif args.baseurl and args.token:
        log(0, 'Connecting to Plex server %s..' % args.baseurl)
        return server.PlexServer(args.baseurl, args.token), None
    return server.PlexServer(), None
Ejemplo n.º 9
0
def myPlex(servercfg):
    logger = logging.getLogger(__name__)

    from plexapi.myplex import MyPlexUser
    from plexapi.server import PlexServer

    user = MyPlexUser(servercfg['username'], servercfg['password'])
    for key in user.keys():
        logger.debug("\tKey: %s\tValue: %s" % (key, user[key]))

    server = user.getServer(servercfg['server']).connect

    for server in user.servers():
        logger.info("Server: %s" % (server))

    plex = PlexServer(servercfg['host'], servercfg['port'],
                      user['authenticationToken'])
    for section in plex.library.sections():
        logger.info("Section: %s" % (section.title))
Ejemplo n.º 10
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """ Sets up the plex platform. """
    from plexapi.myplex import MyPlexUser
    from plexapi.exceptions import BadRequest

    name = config.get('name', '')
    user = config.get('user', '')
    password = config.get('password', '')
    plexuser = MyPlexUser.signin(user, password)
    plexserver = plexuser.getResource(name).connect()
    plex_clients = {}
    plex_sessions = {}

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update_devices():
        """ Updates the devices objects. """
        try:
            devices = plexuser.devices()
        except BadRequest:
            _LOGGER.exception("Error listing plex devices")
            return

        new_plex_clients = []
        for device in devices:
            if (all(x not in ['client', 'player'] for x in device.provides)
                    or 'PlexAPI' == device.product):
                continue

            if device.clientIdentifier not in plex_clients:
                new_client = PlexClient(device, plex_sessions, update_devices,
                                        update_sessions)
                plex_clients[device.clientIdentifier] = new_client
                new_plex_clients.append(new_client)
            else:
                plex_clients[device.clientIdentifier].set_device(device)

        if new_plex_clients:
            add_devices(new_plex_clients)

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update_sessions():
        """ Updates the sessions objects. """
        try:
            sessions = plexserver.sessions()
        except BadRequest:
            _LOGGER.exception("Error listing plex sessions")
            return

        plex_sessions.clear()
        for session in sessions:
            plex_sessions[session.player.machineIdentifier] = session

    update_devices()
    update_sessions()
Ejemplo n.º 11
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """ Sets up the plex platform. """
    from plexapi.myplex import MyPlexUser
    from plexapi.exceptions import BadRequest

    name = config.get('name', '')
    user = config.get('user', '')
    password = config.get('password', '')
    plexuser = MyPlexUser.signin(user, password)
    plexserver = plexuser.getResource(name).connect()
    plex_clients = {}
    plex_sessions = {}

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update_devices():
        """ Updates the devices objects """
        try:
            devices = plexuser.devices()
        except BadRequest:
            _LOGGER.exception("Error listing plex devices")
            return

        new_plex_clients = []
        for device in devices:
            if (all(x not in ['client', 'player'] for x in device.provides)
                    or 'PlexAPI' == device.product):
                continue

            if device.clientIdentifier not in plex_clients:
                new_client = PlexClient(device, plex_sessions, update_devices,
                                        update_sessions)
                plex_clients[device.clientIdentifier] = new_client
                new_plex_clients.append(new_client)
            else:
                plex_clients[device.clientIdentifier].set_device(device)

        if new_plex_clients:
            add_devices(new_plex_clients)

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update_sessions():
        """ Updates the sessions objects """
        try:
            sessions = plexserver.sessions()
        except BadRequest:
            _LOGGER.exception("Error listing plex sessions")
            return

        plex_sessions.clear()
        for session in sessions:
            plex_sessions[session.player.machineIdentifier] = session

    update_devices()
    update_sessions()
Ejemplo n.º 12
0
def fetch_plex_instance(pkmeter, username=None, password=None, host=None):
    username = username or pkmeter.config.get(
        'plexserver', 'username', from_keyring=True)
    password = password or pkmeter.config.get(
        'plexserver', 'password', from_keyring=True)
    host = host or pkmeter.config.get('plexserver', 'host', '')
    if username:
        log.info('Logging into MyPlex with user %s', username)
        user = MyPlexUser.signin(username, password)
        return user.getResource(host).connect()
    log.info('Connecting to Plex host: %s', host)
    return PlexServer(host)
Ejemplo n.º 13
0
    def __init__(self, name, plex_url, plex_user, plex_password, plex_server):
        """Initialize the sensor."""
        self._name = name
        self._state = 0
        self._now_playing = []

        if plex_user and plex_password:
            from plexapi.myplex import MyPlexUser
            user = MyPlexUser.signin(plex_user, plex_password)
            server = plex_server if plex_server else user.resources()[0].name
            self._server = user.getResource(server).connect()
        else:
            from plexapi.server import PlexServer
            self._server = PlexServer(plex_url)

        self.update()
Ejemplo n.º 14
0
    def __init__(self, name, plex_url, plex_user, plex_password, plex_server):
        """Initialize the sensor."""
        self._name = name
        self._state = 0
        self._now_playing = []

        if plex_user and plex_password:
            from plexapi.myplex import MyPlexUser
            user = MyPlexUser.signin(plex_user, plex_password)
            server = plex_server if plex_server else user.resources()[0].name
            self._server = user.getResource(server).connect()
        else:
            from plexapi.server import PlexServer
            self._server = PlexServer(plex_url)

        self.update()
Ejemplo n.º 15
0
def get_server(uri=DEFAULT_URI, username=None, password=None, servername=None):
    """ Get Plex server object for further processing.

    :param uri: Server URI. Expects "http://IP-ADDRESS:PORT", where IP-ADDRESS can be a hostname, and PORT is usually 32400
    :param username: Plex username. Needed if uri fails. User is prompted if parameter is not provided. $PLEX_USERNAME
    :param password: Plex password. Recommended practice is to leave this as None and respond to the prompt. $PLEX_PASSWORD
    :param servername: Server name. User is prompted with a list of servers available to their username if parameter is not provided
    :returns: Server object
    :rtype: plexapi.server.PlexServer
    """

    try:
        return PlexServer(uri)
    except NotFound:
        pass
    if not username and not password:
        info("Could not get server object, maybe you need to be authenticated?")
    username = username if username else os.environ.get("PLEX_USERNAME", None) or prompt("Plex username: "******"PLEX_PASSWORD", None) or getpass("Plex password: "******"Servers: " + ", ".join(a.name for a in user.resources()))
        servername = prompt("Please enter server name (or specify with --servername). If you don't know it, press enter and I'll (very slowly!) search for the correct server: ") or None
    if servername:
        return user.getResource(servername).connect()
    else:
        info("OK, beginning the search process.")
    # necessary to match correct server
    if uri.count(":") >= 2:
        ip = ":".join(urlparse(uri).netloc.split(":")[:-1])
    else:
        ip = urlparse(uri).netloc
    info("Getting IP for {}".format(ip))
    ip = gethostbyname(ip)
    info("Got IP from hostname: {}".format(ip) if ip not in uri else "Searching for {}".format(ip))
    for srv in user.resources():
        try:
            server = srv.connect()
            if ip in server.baseuri:
                info("Found server: {}".format(srv.name))
                return server
        except NotFound:
            info("Couldn't connect to {}".format(srv.name))
    info("Couldn't find server in your user's server list.")
    return 10
Ejemplo n.º 16
0
async def invite_member(member):
    server_id = '503c85f2d47514dbfc3260c2a29ccb9cb113b071'
    account = plex.signin(environ.get('PLEX_EMAIL'), environ.get('PLEX_PASSWORD'))

    headers = plexapi.BASE_HEADERS
    headers['X-Plex-Token'] = account.authenticationToken
    print(account.authenticationToken)
    headers['Content-Type'] = 'application/json'
    data = {
        'server_id': server_id,
        'shared_server': {
            'library_section_ids': [],
            'invited_email': member
        },
        'shared_settings': []
    }

    res = await post('https://plex.tv/api/servers/%s/shared_servers' % server_id, headers=headers, data=dumps(data))
    data = await res.text()
Ejemplo n.º 17
0
async def invite_member(member):
    server_id = '503c85f2d47514dbfc3260c2a29ccb9cb113b071'
    account = plex.signin(environ.get('PLEX_EMAIL'),
                          environ.get('PLEX_PASSWORD'))

    headers = plexapi.BASE_HEADERS
    headers['X-Plex-Token'] = account.authenticationToken
    print(account.authenticationToken)
    headers['Content-Type'] = 'application/json'
    data = {
        'server_id': server_id,
        'shared_server': {
            'library_section_ids': [],
            'invited_email': member
        },
        'shared_settings': []
    }

    res = await post('https://plex.tv/api/servers/%s/shared_servers' %
                     server_id,
                     headers=headers,
                     data=dumps(data))
    data = await res.text()
Ejemplo n.º 18
0
 def _findUser(self, data):
     elem = data.find('User')
     if elem is not None:
         from plexapi.myplex import MyPlexUser
         return MyPlexUser(elem, self.initpath)
     return None
Ejemplo n.º 19
0
from __future__ import print_function

import logging

import dotenv
from getenv import env
from plexapi.myplex import MyPlexUser

from alexa import Response

dotenv.read_dotenv()

logger = logging.getLogger(__name__)

APP_ID = 'amzn1.echo-sdk-ams.app.{}'.format(env('ALEXA_APP_ID'))
PLEX_USER = MyPlexUser.signin(env('PMS_USERNAME'), env('PMS_PASSWORD'))
PLEX_SERVER = PLEX_USER.getResource(env('PMS_SERVERNAME')).connect()
PLEX_CLIENT = PLEX_SERVER.client(env('PMS_CLIENT'))


def get_welcome_response():
    '''
    Get the welcome response when waiting for more.
    '''
    return Response(
        'Plex is listening..',
        'Welcome',
        should_end_session=False,
    ).to_dict()

Ejemplo n.º 20
0
class PlexClient(object):
    def __init__(self):
        self.config = get_config()
        self.config.verify()
        self._logger = get_logger(self.__class__.__name__)
        self.c_info = ClientInfo.from_config(self.config)
        self._monitor = ThreadMonitor()
        # self._monitor.start()
        self.registration_thread = ClientRegistration(self.c_info)
        # this call will block if XBMC is unresponsive, will resume when XBMC is UP
        self._xbmc_rpc = XbmcJSONRPC(self.config['xbmc_host'], self.config['xbmc_port']).wait()
        self._xbmc = XBMCPlexPlayer(self._xbmc_rpc, self)
        self.xbmc.notify('Plex', 'PlexMyXBMC Connected')
        self._user = MyPlexUser(self.config['plex_username'], self.config['plex_password'])
        self.xbmc.notify('Plex', 'Logged in as "%s"' % self.config['plex_username'])
        self.xbmc.notify('Plex', 'Master server is {0}'.format(self.config['plex_server']))
        try:
            self._server = self.get_coolest_server()
            self.xbmc.notify('Plex', 'using PMS %s' % self._server.friendlyName)
        except:
            self.xbmc.notify('Plex', 'failed to connect to master server')
            raise

        self.sub_mgr = PlexSubManager(self)
        self.event_mgr = PlexEventsManager(self)
        self.httpd = ThreadedAPIServer(self, ('', self.config['port']), PlexClientHandler)
        self.httpd.allow_reuse_address = True
        self.storage_mgr = PlexStorageManager(self, self.config['local_sync_cache'])
        self.sync_mgr = PlexSyncManager(self, self.storage_mgr)
        self._keep_running = Event()
        self._keep_running.clear()
        self._lock = Lock()

    def __del__(self):
        self.stop()
        self.join()

    def _serve_loop(self):
        while self._keep_running.is_set() is True:
            self.httpd.handle_request()

    def serve(self):
        self.registration_thread.start()
        self.event_mgr.start()
        self.sync_mgr.start()
        self.publish_resources()
        self._keep_running.set()
        try:
            self._serve_loop()
        except KeyboardInterrupt:
            self._keep_running.clear()

    def stop(self):
        self._keep_running.clear()
        self.registration_thread.stop()
        self.event_mgr.stop()
        self._xbmc_rpc.stop()
        self.sync_mgr.stop()
        # self._monitor.stop()

    def join(self):
        if self.registration_thread.isAlive():
            self.registration_thread.join()
        if self._monitor.isAlive():
            self._monitor.join()
        if self.event_mgr.isAlive():
            self.event_mgr.join()
        if self.sync_mgr.isAlive():
            self.sync_mgr.join()

    def get_coolest_server(self):
        servers = self._user.servers()
        self._logger.info('MyPlex registered servers: %s', ', '.join(map(lambda x: x.name, servers)))

        master_server = self.config.get('plex_server', '')
        for server in servers:
            if server.name != master_server:
                continue

            return MyPlexServer(server).connect()
        raise NotFound('could not find master server {0}'.format(master_server))

    def authenticated_url(self, url):
        """

        :type url: str
        """
        url = self._server.url(url) if url.startswith('/') else url
        token = 'X-Plex-Token=' + self._user.authenticationToken
        return url + ('&' if '?' in url else '?') + token

    @property
    def headers(self):
        plex_headers = {
            "Content-Type": "application/x-www-form-urlencoded",
            'Access-Control-Expose-Headers': 'X-Plex-Client-Identifier',
            "Access-Control-Allow-Origin": "*",
            "X-Plex-Device": "PC",
            "X-Plex-Username": self._user.username,
            "X-Plex-Token": self._user.authenticationToken,
        }
        plex_headers.update(plexapi.BASE_HEADERS)
        return plex_headers

    @property
    def server(self):
        return self._server

    @property
    def user(self):
        return self._user

    @property
    def xbmc(self):
        return self._xbmc

    @property
    def local_address(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('www.google.com', 80))
        addr, port = s.getsockname()
        s.close()
        return addr, self.config['port']

    def publish_resources(self):
        addr, port = self.local_address
        connection = 'http://{0}:{1}/'.format(addr, port)
        data = {'Connection[][uri]': connection}
        url = 'https://plex.tv/devices/{0}'.format(self.config['uuid'])
        resp = requests.put(url, data=data, headers=self.headers)
        if resp.status_code == 200:
            self._logger.info('published device resources to plex.tv successfully')
        else:
            self._logger.warn('failed to publish devices resources to plex.tv')
Ejemplo n.º 21
0
def fetch_server(args):
    if args.resource:
        user = MyPlexUser.signin(args.username, args.password)
        return user.getResource(args.resource).connect(), user
    return server.PlexServer(), None
Ejemplo n.º 22
0
 def _find_user(self, data):
     elem = data.find('User')
     if elem is not None:
         return MyPlexUser(elem, self.initpath)
     return None
Ejemplo n.º 23
0
from plexapi.myplex import MyPlexUser
import argparse
from sort import Sorter

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Run demo script')
    parser.add_argument('-u', '--username', help='Username for the Plex server.')
    parser.add_argument('-p', '--password', help='Password for the Plex server.')
    args = parser.parse_args()

    user = MyPlexUser.signin(args.username, args.password)

    server_name = user.servers()[0].name
    server = user.getServer(server_name).connect()

    media_center = server.client('420-MediaCenter')
    up = server.library.section('Movies').get('Up')
    avatar = server.library.section('Movies').get('Avatar')

    bobs = server.library.section('TV Shows').search('Bob\'s Burgers')[0]

    sorter = Sorter()
    eps = bobs.episodes()
    sorter.sort(eps)

    queue = media_center.server.createPlayQueue(eps[0])
    queue.addList(eps[1:])
    media_center.playPlayQueue(queue, eps[0])
Ejemplo n.º 24
0
from __future__ import print_function

import logging

import dotenv
from getenv import env
from plexapi.myplex import MyPlexUser

from alexa import Response

dotenv.read_dotenv()

logger = logging.getLogger(__name__)

APP_ID = 'amzn1.echo-sdk-ams.app.{}'.format(env('ALEXA_APP_ID'))
PLEX_USER = MyPlexUser.signin(env('PMS_USERNAME'), env('PMS_PASSWORD'))
PLEX_SERVER = PLEX_USER.getResource(env('PMS_SERVERNAME')).connect()
PLEX_CLIENT = PLEX_SERVER.client(env('PMS_CLIENT'))


def get_welcome_response():
    '''
    Get the welcome response when waiting for more.
    '''
    return Response(
        'Plex is listening..',
        'Welcome',
        should_end_session=False,
    ).to_dict()

Ejemplo n.º 25
0
def fetch_server(args):
    if args.server:
        user = MyPlexUser.signin(args.username, args.password)
        return user.getServer(args.server).connect(), user
    return server.PlexServer(), None
def main():
    tvdb = tvdb_api.Tvdb()
    username = os.environ.get('plex_user') or raw_input("Plex username? ")
    password = os.environ.get('plex_pass') or getpass.getpass("{0} password? ".format(username))

    user = MyPlexUser(username, password)
    servers = user.servers()
    for i, server in enumerate(servers):
        print i, server.name

    server_id = int(os.environ.get('plex_server') or raw_input("Server ID? "))
    print
    server = servers[server_id].connect()

    sections = server.library.sections()
    for i, section in enumerate(sections):
        print i, section.title
    section_id = int(os.environ.get('plex_section') or raw_input("Section ID? "))
    print
    section = sections[section_id]
    shows = {}
    for show in section.all():
        seasons = {}
        for season in show.seasons():
            ep_list = []
            for episode in season.episodes():
                ep_list.append(episode.index)
            seasons[season.index] = ep_list
        shows[show.title] = seasons
#        break
    missing = []
    for show in sorted(shows):
        seasons = shows[show]
        try:
            tvdb_show = tvdb[show]
        except:
            print "Show named \"" + show + "\" not found on TVDB"
            continue

        for season in tvdb_show:
            if season == 0:
                continue
            for episode in tvdb_show[season].values():
                e = episode['episodenumber']
                s = episode['seasonnumber']
                fa = episode['firstaired']
#                print episode.keys(), episode.values()
                try:
                    aired = datetime.strptime(fa, "%Y-%m-%d %H:%M:%S")
                except:
                    try:
                        aired = datetime.strptime(fa, "%Y-%m-%d")
                    except:
                        aired = datetime(3000,1,1)
                if aired > datetime.today():
                    continue
                if not e in seasons.get(s, []):
                    missing.append((show, s.zfill(2), e.zfill(2), ))

    if len(missing):
        print "Missing episodes:"
        missing.append(('',0,0),)
        i = 0
        while i < len(missing) - 1:
            miss = missing[i]
            missing_end = missing[i+1:]
            last_inner_miss = None
            succession = 0
            for j, inner_miss in enumerate(missing_end):
                if miss[0] == inner_miss[0] and miss[1] == inner_miss[1] and \
                        (int(miss[2]) + j + 1) == int(inner_miss[2]):
                    succession += 1
                else:
                    if succession > 0:
                        i += succession + 1
                        print u"{0} S{1}E{2} - S{1}E{3}".format(miss[0], miss[1], miss[2], last_inner_miss[2])
                        break
                last_inner_miss = inner_miss
            else:
                print u"{0} S{1}E{2}".format(*miss)
                i += 1
    else:
        print "No missing episodes found!"