From 18d55ec34a866ced6595e5ae5e94a45afd9d1031 Mon Sep 17 00:00:00 2001 From: jarbasal Date: Tue, 18 Aug 2020 20:58:02 +0100 Subject: [PATCH 1/7] cps track status --- __init__.py | 57 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/__init__.py b/__init__.py index 6d127e8..3333650 100644 --- a/__init__.py +++ b/__init__.py @@ -14,6 +14,7 @@ import re from adapt.intent import IntentBuilder from mycroft.skills.core import MycroftSkill, intent_handler +from mycroft.skills.common_play_skill import CPSTrackStatus from mycroft.skills.audioservice import AudioService from mycroft.util import wait_while_speaking from os.path import join, exists @@ -30,6 +31,9 @@ def __init__(self): self.query_extensions = {} # maintains query timeout extensions self.has_played = False self.lock = Lock() + self.playback_data = {"playing": None, + "playlist": [], + "disambiguation": []} # TODO: Make this an option for voc_match()? Only difference is the # comparison using "==" instead of "in" @@ -80,7 +84,7 @@ def initialize(self): self.add_event('play:query.response', self.handle_play_query_response) self.add_event('play:status', - self.handle_song_info) + self.handle_cps_status) self.gui.register_handler('next', self.handle_next) self.gui.register_handler('prev', self.handle_prev) @@ -97,6 +101,9 @@ def clear_gui_info(self): # Initialize track info variables for k in STATUS_KEYS: self.gui[k] = '' + self.playback_data = {"playing": None, + "playlist": [], + "disambiguation": []} @intent_handler(IntentBuilder('').require('Next').require("Track")) def handle_next(self, message): @@ -262,17 +269,45 @@ def _play_query_timeout(self, message): if search_phrase in self.query_extensions: del self.query_extensions[search_phrase] - def handle_song_info(self, message): - changed = False + def update_current_song(self, data): + self.playback_data["playing"] = data for key in STATUS_KEYS: - val = message.data.get(key, '') - changed = changed or self.gui[key] != val - self.gui[key] = val - - if changed: - self.log.info('\n-->Track: {}\n-->Artist: {}\n-->Image: {}' - ''.format(self.gui['track'], self.gui['artist'], - self.gui['image'])) + self.gui[key] = data.get(key, '') + + def handle_cps_status(self, message): + status = message.data["status"] + if status == CPSTrackStatus.PLAYING: + # skill is handling playback internally + self.update_current_song(message.data) + elif status == CPSTrackStatus.PLAYING_AUDIOSERVICE: + # audio service is handling playback + self.update_current_song(message.data) + elif status == CPSTrackStatus.PLAYING_GUI: + # gui is handling playback + self.update_current_song(message.data) + elif status == CPSTrackStatus.DISAMBIGUATION: + # alternative results + self.playback_data["disambiguation"].append(data) + elif status == CPSTrackStatus.QUEUED: + # skill is handling playback and this is in playlist + self.playback_data["playlist"].append(data) + elif status == CPSTrackStatus.QUEUED_GUI: + # gui is handling playback and this is in playlist + self.playback_data["playlist"].append(data) + elif status == CPSTrackStatus.QUEUED_AUDIOSERVICE: + # audio service is handling playback and this is in playlist + self.playback_data["playlist"].append(data) + elif status == CPSTrackStatus.BUFFERING: + # media is buffering, might want to show in ui + # a new PLAYING status should be sent once playback resumes + pass + elif status == CPSTrackStatus.STALLED: + # media is stalled, might want to show in ui + # a new PLAYING status should be sent once playback resumes + pass + elif status == CPSTrackStatus.END_OF_MEDIA: + # if we add a repeat/loop flag this is the place to check for it + pass def create_skill(): From abf9c6dbf61b669eb7b863a4b11da9612ef3e0b7 Mon Sep 17 00:00:00 2001 From: jarbasal Date: Wed, 19 Aug 2020 00:35:38 +0100 Subject: [PATCH 2/7] paused status --- __init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/__init__.py b/__init__.py index 3333650..e46c529 100644 --- a/__init__.py +++ b/__init__.py @@ -297,6 +297,10 @@ def handle_cps_status(self, message): elif status == CPSTrackStatus.QUEUED_AUDIOSERVICE: # audio service is handling playback and this is in playlist self.playback_data["playlist"].append(data) + elif status == CPSTrackStatus.PAUSED: + # media is not being played, but can be resumed anytime + # a new PLAYING status should be sent once playback resumes + pass elif status == CPSTrackStatus.BUFFERING: # media is buffering, might want to show in ui # a new PLAYING status should be sent once playback resumes From a32c36fea4ff93fbdedd640f6dbaed899c44a193 Mon Sep 17 00:00:00 2001 From: jarbasal Date: Wed, 19 Aug 2020 01:04:03 +0100 Subject: [PATCH 3/7] self.playback_status --- __init__.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/__init__.py b/__init__.py index e46c529..80f1c00 100644 --- a/__init__.py +++ b/__init__.py @@ -31,6 +31,7 @@ def __init__(self): self.query_extensions = {} # maintains query timeout extensions self.has_played = False self.lock = Lock() + self.playback_status = CPSTrackStatus.END_OF_MEDIA self.playback_data = {"playing": None, "playlist": [], "disambiguation": []} @@ -104,6 +105,7 @@ def clear_gui_info(self): self.playback_data = {"playing": None, "playlist": [], "disambiguation": []} + self.playback_status = CPSTrackStatus.END_OF_MEDIA @intent_handler(IntentBuilder('').require('Next').require("Track")) def handle_next(self, message): @@ -279,12 +281,15 @@ def handle_cps_status(self, message): if status == CPSTrackStatus.PLAYING: # skill is handling playback internally self.update_current_song(message.data) + self.playback_status = status elif status == CPSTrackStatus.PLAYING_AUDIOSERVICE: # audio service is handling playback self.update_current_song(message.data) + self.playback_status = status elif status == CPSTrackStatus.PLAYING_GUI: # gui is handling playback self.update_current_song(message.data) + self.playback_status = status elif status == CPSTrackStatus.DISAMBIGUATION: # alternative results self.playback_data["disambiguation"].append(data) @@ -300,18 +305,18 @@ def handle_cps_status(self, message): elif status == CPSTrackStatus.PAUSED: # media is not being played, but can be resumed anytime # a new PLAYING status should be sent once playback resumes - pass + self.playback_status = status elif status == CPSTrackStatus.BUFFERING: # media is buffering, might want to show in ui # a new PLAYING status should be sent once playback resumes - pass + self.playback_status = status elif status == CPSTrackStatus.STALLED: # media is stalled, might want to show in ui # a new PLAYING status should be sent once playback resumes - pass + self.playback_status = status elif status == CPSTrackStatus.END_OF_MEDIA: # if we add a repeat/loop flag this is the place to check for it - pass + self.playback_status = status def create_skill(): From ae112efaa667177927653bc60981cd675b071a78 Mon Sep 17 00:00:00 2001 From: jarbasal Date: Wed, 19 Aug 2020 02:36:19 +0100 Subject: [PATCH 4/7] status query --- __init__.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/__init__.py b/__init__.py index 80f1c00..ede77a5 100644 --- a/__init__.py +++ b/__init__.py @@ -86,6 +86,8 @@ def initialize(self): self.handle_play_query_response) self.add_event('play:status', self.handle_cps_status) + self.add_event('play:status.query', + self.handle_cps_status_query) self.gui.register_handler('next', self.handle_next) self.gui.register_handler('prev', self.handle_prev) @@ -276,8 +278,19 @@ def update_current_song(self, data): for key in STATUS_KEYS: self.gui[key] = data.get(key, '') + def update_playlist(self, data): + self.set_context("Playlist", "playlist exists") + self.playback_data["playlist"].append(data) + # sort playlist by requested order + self.playback_data["playlist"] = sorted( + self.playback_data["playlist"], + key = lambda i: int(i['playlist_position']) or 0) + + + # playback status def handle_cps_status(self, message): status = message.data["status"] + if status == CPSTrackStatus.PLAYING: # skill is handling playback internally self.update_current_song(message.data) @@ -290,18 +303,20 @@ def handle_cps_status(self, message): # gui is handling playback self.update_current_song(message.data) self.playback_status = status + elif status == CPSTrackStatus.DISAMBIGUATION: # alternative results - self.playback_data["disambiguation"].append(data) + self.playback_data["disambiguation"].append(message.data) elif status == CPSTrackStatus.QUEUED: # skill is handling playback and this is in playlist - self.playback_data["playlist"].append(data) + self.update_playlist(message.data) elif status == CPSTrackStatus.QUEUED_GUI: # gui is handling playback and this is in playlist - self.playback_data["playlist"].append(data) + self.update_playlist(message.data) elif status == CPSTrackStatus.QUEUED_AUDIOSERVICE: # audio service is handling playback and this is in playlist - self.playback_data["playlist"].append(data) + self.update_playlist(message.data) + elif status == CPSTrackStatus.PAUSED: # media is not being played, but can be resumed anytime # a new PLAYING status should be sent once playback resumes @@ -318,6 +333,11 @@ def handle_cps_status(self, message): # if we add a repeat/loop flag this is the place to check for it self.playback_status = status - + def handle_cps_status_query(self, message): + # update playlist / current song in audio service, + # audio service should also react to 'play:status' for live updates + # but it can sync anytime with 'play:status.query' + self.bus.emit(message.reply('play:status.response', + self.playback_data)) def create_skill(): return PlaybackControlSkill() From 0633609307b5cbb8e9ca82663d05fa8929e34dd0 Mon Sep 17 00:00:00 2001 From: jarbasal Date: Wed, 19 Aug 2020 02:37:19 +0100 Subject: [PATCH 5/7] pep8 --- __init__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/__init__.py b/__init__.py index ede77a5..172a13d 100644 --- a/__init__.py +++ b/__init__.py @@ -20,14 +20,13 @@ from os.path import join, exists from threading import Lock - STATUS_KEYS = ['track', 'artist', 'album', 'image'] class PlaybackControlSkill(MycroftSkill): def __init__(self): super(PlaybackControlSkill, self).__init__('Playback Control Skill') - self.query_replies = {} # cache of received replies + self.query_replies = {} # cache of received replies self.query_extensions = {} # maintains query timeout extensions self.has_played = False self.lock = Lock() @@ -69,7 +68,7 @@ def voc_match_exact(self, utt, voc_filename, lang=None): if not voc or not exists(voc): raise FileNotFoundError( - 'Could not find {}.voc file'.format(voc_filename)) + 'Could not find {}.voc file'.format(voc_filename)) with open(voc) as f: self.voc_match_cache[cache_key] = f.read().splitlines() @@ -92,6 +91,7 @@ def initialize(self): self.gui.register_handler('prev', self.handle_prev) self.clear_gui_info() + # Handle common audio intents. 'Audio' skills should listen for the # common messages: # self.add_event('mycroft.audio.service.next', SKILL_HANDLER) @@ -164,7 +164,7 @@ def play(self, message): # which will only return the first word of the target phrase utt = message.data.get('utterance') phrase = re.sub('^.*?' + message.data['Play'], '', utt).strip() - self.log.info("Resolving Player for: "+phrase) + self.log.info("Resolving Player for: " + phrase) wait_while_speaking() self.enclosure.mouth_think() @@ -279,13 +279,11 @@ def update_current_song(self, data): self.gui[key] = data.get(key, '') def update_playlist(self, data): - self.set_context("Playlist", "playlist exists") self.playback_data["playlist"].append(data) # sort playlist by requested order self.playback_data["playlist"] = sorted( self.playback_data["playlist"], - key = lambda i: int(i['playlist_position']) or 0) - + key=lambda i: int(i['playlist_position']) or 0) # playback status def handle_cps_status(self, message): @@ -339,5 +337,7 @@ def handle_cps_status_query(self, message): # but it can sync anytime with 'play:status.query' self.bus.emit(message.reply('play:status.response', self.playback_data)) + + def create_skill(): return PlaybackControlSkill() From 138ee217e441fdcb6a761a2452f0cc91bb636faa Mon Sep 17 00:00:00 2001 From: jarbasal Date: Thu, 27 Aug 2020 12:39:40 +0100 Subject: [PATCH 6/7] enclosure status --- __init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/__init__.py b/__init__.py index 172a13d..c8461a5 100644 --- a/__init__.py +++ b/__init__.py @@ -301,6 +301,10 @@ def handle_cps_status(self, message): # gui is handling playback self.update_current_song(message.data) self.playback_status = status + elif status == CPSTrackStatus.PLAYING_ENCLOSURE: + # enclosure is handling playback + self.update_current_song(message.data) + self.playback_status = status elif status == CPSTrackStatus.DISAMBIGUATION: # alternative results @@ -314,6 +318,10 @@ def handle_cps_status(self, message): elif status == CPSTrackStatus.QUEUED_AUDIOSERVICE: # audio service is handling playback and this is in playlist self.update_playlist(message.data) + elif status == CPSTrackStatus.QUEUED_ENCLOSURE: + # enclosure is handling playback and this is in playlist + self.update_current_song(message.data) + self.playback_status = status elif status == CPSTrackStatus.PAUSED: # media is not being played, but can be resumed anytime From e929455f7988ce408f01394d922b15d438138619 Mon Sep 17 00:00:00 2001 From: jarbasal Date: Thu, 27 Aug 2020 12:54:27 +0100 Subject: [PATCH 7/7] remove api --- __init__.py | 63 +++++++++-------------------------------------------- 1 file changed, 10 insertions(+), 53 deletions(-) diff --git a/__init__.py b/__init__.py index c8461a5..5f36e2d 100644 --- a/__init__.py +++ b/__init__.py @@ -30,7 +30,6 @@ def __init__(self): self.query_extensions = {} # maintains query timeout extensions self.has_played = False self.lock = Lock() - self.playback_status = CPSTrackStatus.END_OF_MEDIA self.playback_data = {"playing": None, "playlist": [], "disambiguation": []} @@ -85,8 +84,6 @@ def initialize(self): self.handle_play_query_response) self.add_event('play:status', self.handle_cps_status) - self.add_event('play:status.query', - self.handle_cps_status_query) self.gui.register_handler('next', self.handle_next) self.gui.register_handler('prev', self.handle_prev) @@ -289,62 +286,22 @@ def update_playlist(self, data): def handle_cps_status(self, message): status = message.data["status"] - if status == CPSTrackStatus.PLAYING: - # skill is handling playback internally - self.update_current_song(message.data) - self.playback_status = status - elif status == CPSTrackStatus.PLAYING_AUDIOSERVICE: - # audio service is handling playback - self.update_current_song(message.data) - self.playback_status = status - elif status == CPSTrackStatus.PLAYING_GUI: - # gui is handling playback + if status == CPSTrackStatus.PLAYING or \ + status == CPSTrackStatus.PLAYING_AUDIOSERVICE or \ + status == CPSTrackStatus.PLAYING_GUI or \ + status == CPSTrackStatus.PLAYING_ENCLOSURE: self.update_current_song(message.data) - self.playback_status = status - elif status == CPSTrackStatus.PLAYING_ENCLOSURE: - # enclosure is handling playback - self.update_current_song(message.data) - self.playback_status = status elif status == CPSTrackStatus.DISAMBIGUATION: # alternative results self.playback_data["disambiguation"].append(message.data) - elif status == CPSTrackStatus.QUEUED: - # skill is handling playback and this is in playlist - self.update_playlist(message.data) - elif status == CPSTrackStatus.QUEUED_GUI: - # gui is handling playback and this is in playlist - self.update_playlist(message.data) - elif status == CPSTrackStatus.QUEUED_AUDIOSERVICE: - # audio service is handling playback and this is in playlist - self.update_playlist(message.data) - elif status == CPSTrackStatus.QUEUED_ENCLOSURE: + + elif status == CPSTrackStatus.QUEUED or \ + status == CPSTrackStatus.QUEUED_GUI or \ + status == CPSTrackStatus.QUEUED_AUDIOSERVICE or \ + status == CPSTrackStatus.QUEUED_ENCLOSURE: # enclosure is handling playback and this is in playlist - self.update_current_song(message.data) - self.playback_status = status - - elif status == CPSTrackStatus.PAUSED: - # media is not being played, but can be resumed anytime - # a new PLAYING status should be sent once playback resumes - self.playback_status = status - elif status == CPSTrackStatus.BUFFERING: - # media is buffering, might want to show in ui - # a new PLAYING status should be sent once playback resumes - self.playback_status = status - elif status == CPSTrackStatus.STALLED: - # media is stalled, might want to show in ui - # a new PLAYING status should be sent once playback resumes - self.playback_status = status - elif status == CPSTrackStatus.END_OF_MEDIA: - # if we add a repeat/loop flag this is the place to check for it - self.playback_status = status - - def handle_cps_status_query(self, message): - # update playlist / current song in audio service, - # audio service should also react to 'play:status' for live updates - # but it can sync anytime with 'play:status.query' - self.bus.emit(message.reply('play:status.response', - self.playback_data)) + self.update_playlist(message.data) def create_skill():