コード例 #1
0
def stop_show():
    """
    Tells Kodi to stop playing
    :return: None
    """
    kodi = KodiResource()
    kodi.player_stop()
コード例 #2
0
async def event_listener():
    """
    This makes a websocket connection to Kodi and listens to all events raised, for each event raised,
    a JSON object is formatted as string adn is stored as a line in a log file.
    The log file naming convention is yyyy-mm-dd.txt adn the new file is created sunday 00:00 of every week

    Our websocket connection was based of this example:
    https://pypi.org/project/websockets/

    :return: None
    """
    async with websockets.connect(parameters.KODI_WEBSOCKET_URL,
                                  ping_interval=None) as websocket:
        print('Kodi connected')
        await websocket.send(
            '{"jsonrpc":"2.0","method":"JSONRPC.NotifyAll","params": { "sender": "tom", "message": "x" }}'
        )
        log = None
        kodi = KodiResource()

        async for message in websocket:
            event = await websocket.recv()
            now = datetime.datetime.now()

            event_data = kodi.player_get_item()

            row = '{"date": "' + now.strftime(
                "%Y-%m-%d %H:%M:%S"
            ) + '", "event": ' + event + ', "item": ' + json.dumps(
                event_data) + '}'

            # calculate name of the file, this row should be saved to,
            # sunday 00:00 of every week
            week_start = now - datetime.timedelta(days=now.isoweekday() % 7)
            file_name = week_start.strftime("%Y-%m-%d") + ".txt"
            print(file_name, row)

            if log is None or file_name != log.name:
                if log:
                    #  the currently open file is no the log we want to save to, so close it
                    log.close()
                # open the new file in 'append' mode
                log = open(parameters.EVENT_LOG_PATH + file_name, 'a')

            log.write(row + '\n')
            # flush contents of python file writing buffer to file,
            # makes sure what we've written is immediately inserted
            log.flush()
コード例 #3
0
class RecordBroadcast(EventLogReader):
    """
    Used to automatically add timers, if the show is being watched by the user
    """
    def __init__(self, offset_filename):
        super(RecordBroadcast, self).__init__(offset_filename)
        self.db = DatabaseResource()
        self.kodi = KodiResource()

    def on_event(self, event_dict):
        """
        If we get a Player.OnAvChange and the user is watching a live broadcast, and assuming  its not a disliked show,
        we add a timer.

        :param event_dict: Contains 3 elements; date, event, item
        :return: None
        """
        if event_dict['event']['method'] == "Player.OnAVChange":
            print('---\n%s' % event_dict['event']['method'])
            tv_show = True
            try:
                if event_dict['event']['params']['data']['type'] == "channel":
                    pass
                else:
                    tv_show = False
            except KeyError:
                if event_dict['event']['params']['data']['item'][
                        'type'] == "channel":
                    pass
                else:
                    tv_show = False

            if tv_show:
                channel_id = event_dict['event']['params']['data']['item'][
                    'id']
                broadcastdetails_json = self.kodi.pvr_get_channel_details(
                    channel_id)
                if not broadcastdetails_json:
                    # this is an old record. Skip it
                    print('Broadcast details not found. No Timer added')
                    pass
                elif 'broadcastnow' not in broadcastdetails_json:
                    # this is an old record. Skip it
                    print('Broadcast details not found. No Timer added')
                    pass
                else:
                    title = broadcastdetails_json['broadcastnow']['title']
                    broadcast_id = broadcastdetails_json['broadcastnow'][
                        'broadcastid']
                    dislikes = Dislikes(self.db.connection.cursor())
                    if not dislikes.is_disliked(title):
                        TimerManager().add_timer(title, broadcast_id)
                    else:
                        print("%s is a disliked show, no timer created" %
                              title)
            else:
                print("This is not a live broadcast")
コード例 #4
0
def watched_recording():
    """
    When a recording that is being played has already been seen by the user, this method will delete the recording.
    Steps taken:
    1) Ask Kodi what is being played
    2) Find and delete recording using TVHeadend

    :return: None
    """
    kodi = KodiResource()
    tv = TvHeadEndResource()
    item_dict = kodi.player_get_item()

    title = item_dict['title']
    plot = item_dict['plot']

    if title == "":
        print("Current Kodi player doesn't have a title")
    else:
        tv.find_and_delete_recordings(title, plot=plot)

        print(title, plot)
    return title
コード例 #5
0
ファイル: dislike_show.py プロジェクト: freemans13/KodiTV
def dislike_show():
    """
    Marks a shows as 'disliked'. This method takes several steps:
    1) asks Kodi what is being watched
    2) searches the Shows table for the same show
    3) updates the Show record with disliked = 1
    4) delete all recordings of the show
    5) delete any timers associated with the show

    :return:
            None
    """
    connection = mysql.connector.connect(user=parameters.DB_USER,
                                         database=parameters.DB_NAME)
    cursor = connection.cursor()

    kodi = KodiResource()
    item_dict = kodi.player_get_item()

    update_shows_with_dislikes = ("UPDATE shows "
                                  "SET disliked = 1 "
                                  "WHERE title = %s")

    title = item_dict['title']

    cursor.execute(update_shows_with_dislikes, (title, ))
    connection.commit()

    tv = TvHeadEndResource()
    tv.find_and_delete_recordings(title)
    print(title)

    timer = TimerManager()
    timer_ids = timer.find_timer_ids(title)
    if len(timer_ids) > 0:
        print("deleting : ", title)
        timer.delete_timers(timer_ids)
コード例 #6
0
 def __init__(self, offset_filename):
     super(RecordBroadcast, self).__init__(offset_filename)
     self.db = DatabaseResource()
     self.kodi = KodiResource()
コード例 #7
0
def play_something():
    """
    Finds a recording to play and tells kodi to play it, the steps are;
    1) Get a list of all recordings from Kodi
    2) Grab the title of the first recording
    3) Get the last season/episode watched from the database
    4) Find the next episode to watch in the recordings list
    5) Flay the net episode

    :param title: Optionally a specific title to watch
    :return: None
    """
    kodi = KodiResource()
    tv = TvHeadEndResource()
    record_dict = kodi.pvr_get_recordings()

    if len(record_dict) == 0:
        return

    title = record_dict[0]['label']

    connection = mysql.connector.connect(user=parameters.DB_USER,
                                         database=parameters.DB_NAME)
    cursor = connection.cursor()

    select_season_info = (
        "select s.show_id, e.season, max(e.episode) last_episode "
        "from shows s "
        "inner join episodes e on s.show_id = e.show_id "
        "where s.title = %s "
        "group by s.show_id, e.season "
        "order by e.season desc "
        "limit 1; ")

    cursor.execute(select_season_info, (title, ))
    next_episode = 0
    for (show_id, season, last_episode) in cursor:
        next_episode = last_episode + 1
        print("seen", season, last_episode, "looking for", season,
              next_episode)

    resume_current = False
    player_recording = None
    recording_ids = []
    print("Check for new episode...")
    for record in record_dict:
        # print(record)
        if record['label'].lower() == title.lower():
            # print(record['label'], record['recordingid'])
            recording_ids.append(record['recordingid'])
    record_details_dict = kodi.pvr_get_recording_details_batch(recording_ids)

    for line in record_details_dict:
        episode_dict = series_info(line['plot'])

        if episode_dict['episode'] < next_episode - 2:
            tv.find_and_delete_recordings(line['label'], plot=line['plot'])

        if episode_dict['episode'] == next_episode - 1 and line['resume'][
                'position'] > 0:
            print("Resume current episode", next_episode - 1)
            player_recording = {
                "id": line['recordingid'],
                "title": line['label']
            }
            resume_current = True

        if episode_dict['episode'] == next_episode:
            print("Found next episode", next_episode)
            player_recording = {
                "id": line['recordingid'],
                "title": line['label']
            }

    if not player_recording:
        print("No unwatched future episodes")

    if player_recording:
        print('Playing', player_recording['title'])
        if resume_current:
            # Kodi asks user if they want to start from beginning or to resume, by default it highlights the resume
            # option, therefore we want send a post to "select" current choice. This is my hack for getting around
            # Kodi's api limitation in that there is no command to skip the option. The delay is because our player.open
            # post doesnt give a response until the set programme is being played, so we create a timer delay ,rather
            # than a time.sleep, for the select request to run despite there no request
            # after given seconds for Kodi to catch up
            t = Timer(2.0, kodi.input_select)
            t.start()
            print("play")
            kodi.player_open(player_recording['id'])

        else:
            kodi.player_open(player_recording['id'])
        return player_recording['title']
    return "nothing"
コード例 #8
0
async def event_listener():
    """
    This makes a websocket connection to Kodi and listens to all events raised, for each event raised,
    a JSON object is formatted as string adn is stored as a line in a log file.
    The log file naming convention is yyyy-mm-dd.txt adn the new file is created sunday 00:00 of every week

    Our websocket connection was based of this example:
    https://pypi.org/project/websockets/

    :return: None
    """
    async with websockets.connect(parameters.KODI_WEBSOCKET_URL,
                                  ping_interval=None) as websocket:
        print('Kodi connected')
        await websocket.send(
            '{"jsonrpc":"2.0","method":"JSONRPC.NotifyAll","params": { "sender": "tom", "message": "x" }}'
        )
        log = None
        kodi = KodiResource()

        async for message in websocket:
            if message == '':
                print('Skipping empty event')
                continue

            now = datetime.datetime.now()
            event = json.loads(message)

            event_data = event['params']['data'] or {}
            if 'item' in event_data:
                event_item = event_data['item'] or {}
            else:
                event_item = {}

            if 'channeltype' in event_item and event_item[
                    'channeltype'] == 'tv':
                data = kodi.pvr_get_channel_details(event_item['id'], [
                    "thumbnail", "channeltype", "hidden", "locked", "channel",
                    "lastplayed", "broadcastnow", "broadcastnext", "uniqueid",
                    "icon", "channelnumber", "subchannelnumber", "isrecording"
                ])
            else:
                data = {}

            item = kodi.player_get_item(quiet=True) or {}

            row = json.dumps({
                "date": now.strftime("%Y-%m-%d %H:%M:%S"),
                "event": event,
                "data": data,
                "item": item
            })

            # calculate name of the file, this row should be saved to,
            # sunday 00:00 of every week
            week_start = now - datetime.timedelta(days=now.isoweekday() % 7)
            file_name = week_start.strftime("%Y-%m-%d") + ".txt"
            print(file_name, row)

            if log is None or file_name != log.name:
                if log:
                    #  the currently open file is no the log we want to save to, so close it
                    log.close()
                # open the new file in 'append' mode
                log = open(parameters.EVENT_LOG_PATH + file_name, 'a')

            log.write(row + '\n')
            # flush contents of python file writing buffer to file,
            # makes sure what we've written is immediately inserted
            log.flush()
コード例 #9
0
 def __init__(self, offset_filename):
     super(RecordSimilarBroadcasts, self).__init__(offset_filename)
     self.db = DatabaseResource()
     self.kodi = KodiResource()
     self.tvdb = TheTvDbResource()
コード例 #10
0
class RecordSimilarBroadcasts(EventLogReader):
    """
    Take a look at what the user usually watches and
    find other shows for similar genres with the same channels in the kodi programme guide and
    score the results in an ordered list, make timers for these in this order
    """
    def __init__(self, offset_filename):
        super(RecordSimilarBroadcasts, self).__init__(offset_filename)
        self.db = DatabaseResource()
        self.kodi = KodiResource()
        self.tvdb = TheTvDbResource()

    def on_event(self, event_dict):
        """
        :param event_dict: Contains 3 elements; date, event, item
        :return: None
        """
        # needs a trigger event from log
        fav_channel = (
            "select c.channel, count(c.channel) "
            "from shows s "
            "inner join show_channel_map m on s.show_ID = m.show_ID "
            "inner join channels c on m.channel_ID = c.channel_ID "
            "where s.disliked = 0 "
            "group by c.channel "
            "order by 2 desc ")

        fav_genre = ("select g.genre, count(m.genre_id) "
                     "from genres g "
                     "inner join show_genre_map m on g.genre_id = m.genre_id "
                     "inner join shows s on s.show_ID = m.show_ID "
                     "where s.disliked = 0 "
                     "group by genre "
                     "order by 2 desc ")

        print('---\nScanning for similar broadcasts...')

        fav_channels = []
        self.db.cursor.execute(fav_channel)
        for (fav_channel, fav_channel_count) in self.db.cursor:
            fav_channels.append((fav_channel, fav_channel_count))
        print('Top channels', fav_channels)

        fav_genres = []
        self.db.cursor.execute(fav_genre)
        for (fav_genre, fav_genre_count) in self.db.cursor:
            fav_genres.append((fav_genre, fav_genre_count))
        print('Top genres', fav_genres)

        dislikes = Dislikes(self.db.cursor)

        # For each of the favourite channels find a valid Kodi PVR channel ID.
        # Store this in channel_ids
        channel_ids = []
        pvr_channels = self.kodi.pvr_get_channels()
        for pvr_channel in pvr_channels:
            for (fav_channel, fav_channel_count) in fav_channels:
                if pvr_channel['label'] == fav_channel:
                    channel_ids.append((pvr_channel, fav_channel_count))

        # Populate timer_dict with Kodi broadcasts matching a favourite channel and favourite genre
        # Make sure we also store in the timer_dict value, 'channel', 'channel_popularity' and 'genre_popularity'
        timer_dict = {}
        for (pvr_channel, fav_channel_count) in channel_ids:
            channel_id = pvr_channel['channelid']
            broadcasts = self.kodi.pvr_get_broadcasts(channel_id)

            if broadcasts:
                for broadcast in broadcasts:
                    if dislikes.is_disliked(broadcast['title']):
                        print('Skipping disliked show %s' % broadcast['title'])
                        continue
                    if not series_info(broadcast['plot'])['episode'] == 0:
                        genres = broadcast['genre']
                        genre_popularity = []
                        match = False
                        for (fav_genre, fav_genre_count) in fav_genres:
                            for genre in genres:
                                if fav_genre == genre:
                                    genre_popularity.append(fav_genre_count)
                                    match = True

                        if match:
                            broadcast['channel'] = pvr_channel['label']
                            broadcast['channel_popularity'] = fav_channel_count
                            broadcast['genre_popularity'] = genre_popularity
                            timer_dict[broadcast["label"]] = broadcast

        # add rating from tvdb to each value in timer_dict, default rating is 0.7
        for title in timer_dict.keys():
            series_rating = 0.7  # default rating, should there be no rating found on thetvdb.com
            series_dict = self.tvdb.search_series(title)
            if series_dict:
                series_id = series_dict[0]['id']
                series_info_dict = self.tvdb.series_info(series_id)
                if series_info_dict:
                    rating = series_info_dict['siteRating']
                    if rating > 0:
                        series_rating = rating / 10
            timer_dict[title]["rating"] = series_rating
            print("Rating for %s is %s/10" % (title, series_rating * 10))

        # Create a list of timer candidates. Create a score for each candidate
        candidates = []
        for broadcast in timer_dict.values():
            sum_genre_pop = 0
            for genre_pop in broadcast['genre_popularity']:
                sum_genre_pop += genre_pop
            avg_genre_popularity = sum_genre_pop / len(
                broadcast['genre_popularity'])
            score = (broadcast['channel_popularity'] +
                     avg_genre_popularity) / broadcast['rating']
            broadcast = {
                "title": broadcast['label'],
                "genre": broadcast['genre'],
                "channel": broadcast['channel'],
                "broadcastid": broadcast['broadcastid'],
                "score": score
            }
            candidates.append(broadcast)

        # Sort candidates by score, reverse order
        candidates = sorted(candidates,
                            key=lambda sugg_dict: sugg_dict['score'],
                            reverse=True)

        #        pprint(candidates)

        # Add timers for the top 10 candidates only
        final_list = candidates[:10]
        for broadcast in final_list:
            print(
                'Found similar broadcast "%s" %s on %s' %
                (broadcast['title'], broadcast['genre'], broadcast['channel']))