def get_active_streams(self):

        log.info('Attempting to get active sessions')
        active_streams = {}
        for server in self.plex_servers:
            active_sessions = server.sessions()
            active_streams[server._baseurl] = active_sessions

        self._process_active_streams(active_streams)
    def run(self):

        log.info('Starting Monitoring Loop')
        while True:
            self.get_recently_added()
            self.get_library_data()
            self.get_active_streams()
            if self.single_run:
                return
            time.sleep(self.delay)
    def get_auth_token(self, username, password):
        """
        Make a reqest to plex.tv to get an authentication token for future requests
        :param username: Plex Username
        :param password: Plex Password
        :return: str
        """

        log.info('Getting Auth Token For User {}'.format(username))

        auth_string = '{}:{}'.format(username, password)
        base_auth = base64.encodebytes(bytes(auth_string, 'utf-8'))
        req = Request('https://plex.tv/users/sign_in.json')
        req = self._set_default_headers(req)
        req.add_header('Authorization',
                       'Basic {}'.format(base_auth[:-1].decode('utf-8')))

        try:
            result = urlopen(req, data=b'').read()
        except HTTPError as e:
            print('Failed To Get Authentication Token')
            if e.code == 401:
                log.error('Failed to get token due to bad username/password')
            else:
                print('Maybe this will help:')
                print(e)
                log.error('Failed to get authentication token.  No idea why')
            sys.exit(1)

        output = json.loads(result.decode('utf-8'))

        # Make sure we actually got a token back
        if 'authToken' in output['user']:
            log.debug('Successfully Retrieved Auth Token')
            return output['user']['authToken']
        else:
            print(
                'Something Broke \n We got a valid response but for some reason there\'s no auth token'
            )
            sys.exit(1)
    def get_library_data(self):

        lib_data = {}

        for server in self.plex_servers:
            libs = server.library.sections()
            log.info('We found {} libraries for server {}'.format(
                str(len(libs)), server))
            host_libs = []
            for lib in libs:
                log.info('Adding data for library %s', lib.title)
                host_lib = {'name': lib.title, 'items': len(lib.search())}

                if lib.title == 'TV Shows':
                    log.info(
                        'Processing TV Shows.  This can take awhile for large libraries'
                    )
                    seasons = 0
                    episodes = 0
                    shows = lib.search()
                    for show in shows:
                        log.debug('Checking TV Show: %s', show.title)
                        seasons += len(show.seasons())
                        episodes += len(show.episodes())
                    host_lib['episodes'] = episodes
                    host_lib['seasons'] = seasons

                host_libs.append(host_lib)

            lib_data[server._baseurl] = host_libs

        self._process_library_data(lib_data)
    def _process_library_data(self, lib_data):
        """
        Breakdown the provided library data and format for InfluxDB
        """

        log.info('Processing Library Data')

        for host, data in lib_data.items():
            for lib in data:
                fields = {
                    'items': lib['items'],
                }
                for key in ['episodes', 'seasons']:
                    if key in lib:
                        fields[key] = lib[key]
                lib_points = [{
                    'measurement': 'libraries',
                    'fields': fields,
                    'tags': {
                        'lib_name': lib['name'],
                        'host': host
                    }
                }]
                self.write_influx_data(lib_points)
    def _process_active_streams(self, stream_data):
        """
        Take an object of stream data and create Influx JSON data
        :param stream_data:
        :return:
        """

        log.info('Processing Active Streams')

        combined_streams = 0
        session_ids = []  # Active Session IDs for this run

        for host, streams in stream_data.items():

            combined_streams += len(streams)

            # Record total streams
            total_stream_points = [{
                'measurement': 'active_streams',
                'fields': {
                    'active_streams': len(streams)
                },
                'tags': {
                    'host': host
                }
            }]

            self.write_influx_data(total_stream_points)

            for stream in streams:
                player = stream.players[0]
                user = stream.usernames[0]
                session_id = stream.session[0].id
                transcode = stream.transcodeSessions if stream.transcodeSessions else None
                session_ids.append(session_id)

                if session_id in self.active_streams:
                    start_time = self.active_streams[session_id]['start_time']
                else:
                    start_time = time.time()
                    self.active_streams[session_id] = {}
                    self.active_streams[session_id]['start_time'] = start_time

                if stream.type == 'movie':
                    media_type = 'Movie'
                elif stream.type == 'episode':
                    media_type = 'TV Show'
                elif stream.type == 'track':
                    media_type = 'Music'
                else:
                    media_type = 'Unknown'

                # Build the title. TV and Music Have a root title plus episode/track name.  Movies don't
                if hasattr(stream, 'grandparentTitle'):
                    full_title = stream.grandparentTitle + ' - ' + stream.title
                else:
                    full_title = stream.title

                if media_type != 'Music':
                    resolution = stream.media[0].videoResolution
                else:
                    resolution = str(stream.media[0].bitrate) + 'Kbps'

                playing_points = [{
                    'measurement': 'now_playing',
                    'fields': {
                        'stream_title': full_title,
                        'player': player.title,
                        'state': player.state,
                        'user': user,
                        'resolution': resolution,
                        'media_type': media_type,
                        'playback': 'transcode' if transcode else 'direct',
                        'duration': time.time() - start_time,
                    },
                    'tags': {
                        'host': host,
                        'player_address': player.address,
                        'session_id': session_id
                    }
                }]

                self.write_influx_data(playing_points)

        if config.report_combined:
            combined_stream_points = [{
                'measurement': 'active_streams',
                'fields': {
                    'active_streams': combined_streams
                },
                'tags': {
                    'host': 'All'
                }
            }]

            self.write_influx_data(combined_stream_points)
            self._remove_dead_streams(session_ids)