diff --git a/ovos_plugin_common_play/ocp/__init__.py b/ovos_plugin_common_play/ocp/__init__.py index 9d5dcf3..f08c036 100644 --- a/ovos_plugin_common_play/ocp/__init__.py +++ b/ovos_plugin_common_play/ocp/__init__.py @@ -11,7 +11,6 @@ from ovos_bus_client.message import Message from ovos_workshop import OVOSAbstractApplication from padacioso import IntentContainer -from ovos_utils.intents.intent_service_interface import IntentQueryApi from threading import Event, Lock @@ -104,19 +103,6 @@ def handle_home(self, message=None): def register_ocp_intents(self, message=None): with self._intent_registration_lock: if not self._intents_event.is_set(): - missing = True - LOG.debug("Intents register event not set") - else: - # check list of registered intents - # if needed register ocp intents again - # this accounts for restarts etc - i = IntentQueryApi(self.bus) - intents = i.get_padatious_manifest() - missing = not any((e.startswith(f"{self.skill_id}:") - for e in intents)) - LOG.debug(f'missing={missing} | {intents}') - - if missing: LOG.info(f"OCP intents missing, registering for {self}") self.register_intent("play.intent", self.handle_play) self.register_intent("read.intent", self.handle_read) diff --git a/test/unittests/ovos_tskill_mycroft_cps/README.md b/test/unittests/ovos_tskill_mycroft_cps/README.md deleted file mode 100644 index 1738ca2..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Playback Control - -This skill is used in unittests for OCP, it replicates the official mycroft skill - -you do not want to install this, it's meant for our automations diff --git a/test/unittests/ovos_tskill_mycroft_cps/__init__.py b/test/unittests/ovos_tskill_mycroft_cps/__init__.py deleted file mode 100644 index 5ef7663..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/__init__.py +++ /dev/null @@ -1,180 +0,0 @@ -import random -import re -from threading import Lock - -from adapt.intent import IntentBuilder -from mycroft.skills.core import MycroftSkill, intent_handler - -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_extensions = {} # maintains query timeout extensions - self.has_played = False - self.lock = Lock() - - def initialize(self): - self.add_event('play:query.response', - self.handle_play_query_response) - - # Handle common audio intents. 'Audio' skills should listen for the - # common messages: - # self.add_event('mycroft.audio.service.next', SKILL_HANDLER) - # self.add_event('mycroft.audio.service.prev', SKILL_HANDLER) - # self.add_event('mycroft.audio.service.pause', SKILL_HANDLER) - # self.add_event('mycroft.audio.service.resume', SKILL_HANDLER) - - @intent_handler(IntentBuilder('').require('Next').require("Track")) - def handle_next(self, message): - self.log.info('common play: next') - - @intent_handler(IntentBuilder('').require('Prev').require("Track")) - def handle_prev(self, message): - self.log.info('common play: prev') - - @intent_handler(IntentBuilder('').require('Pause')) - def handle_pause(self, message): - self.log.info('common play: pause') - - @intent_handler(IntentBuilder('').one_of('PlayResume', 'Resume')) - def handle_play(self, message): - """Resume playback if paused""" - self.log.info('common play: resume') - - def stop(self, message=None): - self.log.info('common play: stop') - - @intent_handler(IntentBuilder('').require('Play').require('Phrase')) - def play(self, message): - # Remove everything up to and including "Play" - # NOTE: This requires a Play.voc which holds any synomyms for 'Play' - # and a .rx that contains each of those synonyms. E.g. - # Play.voc - # play - # bork - # phrase.rx - # play (?P.*) - # bork (?P.*) - # This really just hacks around limitations of the Adapt regex system, - # 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) - - # Now we place a query on the messsagebus for anyone who wants to - # attempt to service a 'play.request' message. E.g.: - # { - # "type": "play.query", - # "phrase": "the news" / "tom waits" / "madonna on Pandora" - # } - # - # One or more skills can reply with a 'play.request.reply', e.g.: - # { - # "type": "play.request.response", - # "target": "the news", - # "skill_id": "", - # "conf": "0.7", - # "callback_data": "" - # } - # This means the skill has a 70% confidence they can handle that - # request. The "callback_data" is optional, but can provide data - # that eliminates the need to re-parse if this reply is chosen. - # - self.query_replies[phrase] = [] - self.query_extensions[phrase] = [] - self.bus.emit(message.forward('play:query', data={"phrase": phrase})) - - self.schedule_event(self._play_query_timeout, 1, - data={"phrase": phrase}, - name='PlayQueryTimeout') - - def handle_play_query_response(self, message): - with self.lock: - search_phrase = message.data["phrase"] - - if ("searching" in message.data and - search_phrase in self.query_extensions): - # Manage requests for time to complete searches - skill_id = message.data["skill_id"] - if message.data["searching"]: - # extend the timeout by 5 seconds - self.cancel_scheduled_event("PlayQueryTimeout") - self.schedule_event(self._play_query_timeout, 5, - data={"phrase": search_phrase}, - name='PlayQueryTimeout') - - # TODO: Perhaps block multiple extensions? - if skill_id not in self.query_extensions[search_phrase]: - self.query_extensions[search_phrase].append(skill_id) - else: - # Search complete, don't wait on this skill any longer - if skill_id in self.query_extensions[search_phrase]: - self.query_extensions[search_phrase].remove(skill_id) - if not self.query_extensions[search_phrase]: - self.cancel_scheduled_event("PlayQueryTimeout") - self.schedule_event(self._play_query_timeout, 0, - data={"phrase": search_phrase}, - name='PlayQueryTimeout') - - elif search_phrase in self.query_replies: - # Collect all replies until the timeout - self.query_replies[message.data["phrase"]].append(message.data) - - def _play_query_timeout(self, message): - with self.lock: - # Prevent any late-comers from retriggering this query handler - search_phrase = message.data["phrase"] - self.query_extensions[search_phrase] = [] - self.enclosure.mouth_reset() - - # Look at any replies that arrived before the timeout - # Find response(s) with the highest confidence - best = None - ties = [] - self.log.debug("CommonPlay Resolution: {}".format(search_phrase)) - for handler in self.query_replies[search_phrase]: - self.log.debug(" {} using {}".format(handler["conf"], - handler["skill_id"])) - if not best or handler["conf"] > best["conf"]: - best = handler - ties = [] - elif handler["conf"] == best["conf"]: - ties.append(handler) - - if best: - if ties: - # select randomly - self.log.info("Skills tied, choosing randomly") - skills = ties + [best] - self.log.debug("Skills: " + - str([s["skill_id"] for s in skills])) - selected = random.choice(skills) - # TODO: Ask user to pick between ties or do it - # automagically - else: - selected = best - - # invoke best match - self.log.info("Playing with: {}".format(selected["skill_id"])) - start_data = {"skill_id": selected["skill_id"], - "phrase": search_phrase, - "callback_data": selected.get("callback_data")} - self.bus.emit(message.forward('play:start', start_data)) - self.has_played = True - elif self.voc_match(search_phrase, "Music"): - self.speak_dialog("setup.hints") - else: - self.log.info(" No matches") - self.speak_dialog("cant.play", data={"phrase": search_phrase}) - - if search_phrase in self.query_replies: - del self.query_replies[search_phrase] - if search_phrase in self.query_extensions: - del self.query_extensions[search_phrase] - - -def create_skill(): - return PlaybackControlSkill() diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/.gitkeep b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Music.voc b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Music.voc deleted file mode 100644 index b213197..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Music.voc +++ /dev/null @@ -1,4 +0,0 @@ -music -tunes -song -radio diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Next.voc b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Next.voc deleted file mode 100644 index 3f92790..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Next.voc +++ /dev/null @@ -1,2 +0,0 @@ -next -skip diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Pause.voc b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Pause.voc deleted file mode 100644 index 45fc3c5..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Pause.voc +++ /dev/null @@ -1 +0,0 @@ -pause diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Play.voc b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Play.voc deleted file mode 100644 index 8dfb2a8..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Play.voc +++ /dev/null @@ -1,3 +0,0 @@ -play -start -bork \ No newline at end of file diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/PlayResume.voc b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/PlayResume.voc deleted file mode 100644 index 8e0e24c..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/PlayResume.voc +++ /dev/null @@ -1,2 +0,0 @@ -play resume -resume play diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Prev.voc b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Prev.voc deleted file mode 100644 index 579142e..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Prev.voc +++ /dev/null @@ -1,3 +0,0 @@ -previous -go back -go back one \ No newline at end of file diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Resume.voc b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Resume.voc deleted file mode 100644 index 3246f80..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Resume.voc +++ /dev/null @@ -1,2 +0,0 @@ -resume -unpause diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Track.voc b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Track.voc deleted file mode 100644 index 12c847d..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/Track.voc +++ /dev/null @@ -1,2 +0,0 @@ -track -song \ No newline at end of file diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/cant.play.dialog b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/cant.play.dialog deleted file mode 100644 index 8ff07a2..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/cant.play.dialog +++ /dev/null @@ -1,2 +0,0 @@ -Sorry, I don't know how to play {{phrase}} -I'm not sure how to play {{phrase}} diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/converse_resume.voc b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/converse_resume.voc deleted file mode 100644 index e134a7b..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/converse_resume.voc +++ /dev/null @@ -1,6 +0,0 @@ -play -resume -resume playing -restart -restart music -resume music diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/just.one.moment.dialog b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/just.one.moment.dialog deleted file mode 100644 index 34ca7b8..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/just.one.moment.dialog +++ /dev/null @@ -1,4 +0,0 @@ -Just one moment while I look for that -Give me a moment to check for that -Just a second - diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/phrase.rx b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/phrase.rx deleted file mode 100644 index 62c0f2e..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/phrase.rx +++ /dev/null @@ -1,3 +0,0 @@ -play (?P.*) -start (?P.*) -bork (?P.*) \ No newline at end of file diff --git a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/setup.hints.dialog b/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/setup.hints.dialog deleted file mode 100644 index 954903b..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/locale/en-us/setup.hints.dialog +++ /dev/null @@ -1,2 +0,0 @@ -I'm not configured to play music yet. You can setup music services such as Pandora and Spotify at home dot mycroft dot ai. -It sounds like you are trying to listen to some music, but you have not yet set up any music skills. Please go to market.mycroft.ai to install and configure a music service skill. diff --git a/test/unittests/ovos_tskill_mycroft_cps/setup.py b/test/unittests/ovos_tskill_mycroft_cps/setup.py deleted file mode 100755 index c5a1f55..0000000 --- a/test/unittests/ovos_tskill_mycroft_cps/setup.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python3 -from setuptools import setup - -# skill_id=package_name:SkillClass -PLUGIN_ENTRY_POINT = 'skill-playback-control.mycroftai=ovos_tskill_mycroft_cps:PlaybackControlSkill' - -setup( - # this is the package name that goes on pip - name='ovos-tskill-mycroft-cps', - version='0.0.1', - description='this is a OVOS test skill for the mycroft common play framework', - url='https://github.com/MycroftAI/skill-playback-control', - author='JarbasAi', - author_email='jarbasai@mailfence.com', - license='Apache-2.0', - package_dir={"ovos_tskill_mycroft_cps": ""}, - package_data={'ovos_tskill_mycroft_cps': ['locale/*']}, - packages=['ovos_tskill_mycroft_cps'], - include_package_data=True, - keywords='ovos skill plugin', - entry_points={'ovos.plugin.skill': PLUGIN_ENTRY_POINT} -) diff --git a/test/unittests/test_audio_backends.py b/test/unittests/test_audio_backends.py index 118c7eb..cc02106 100644 --- a/test/unittests/test_audio_backends.py +++ b/test/unittests/test_audio_backends.py @@ -2,7 +2,7 @@ import unittest from unittest.mock import patch -from ovos_utils.skills.audioservice import ClassicAudioServiceInterface +from ovos_audio.service import AudioService from ovos_config.config import Configuration from ovos_utils.messagebus import FakeBus @@ -49,7 +49,7 @@ def get_msg(msg): self.bus.on("message", get_msg) - self.audio = ClassicAudioServiceInterface(self.bus) + self.audio = AudioService(self.bus) def test_native_ocp(self): # assert that OCP is the selected default backend @@ -66,8 +66,10 @@ def test_native_ocp(self): # NOTE: "service" is a list, should be named "services" # not renamed for backwards compat but its a typo! loaded_services = [s.name for s in self.audio.service] - self.assertIn("mycroft_test", loaded_services) - self.assertIn("ovos_test", loaded_services) + self.assertIn("OCP", loaded_services) + # TODO fix me, add dummy plugins + #self.assertIn("mycroft_test", loaded_services) + #self.assertIn("ovos_test", loaded_services) def tearDown(self) -> None: self.audio.shutdown() diff --git a/test/unittests/test_mycroft.py b/test/unittests/test_mycroft.py deleted file mode 100644 index f74e70c..0000000 --- a/test/unittests/test_mycroft.py +++ /dev/null @@ -1,199 +0,0 @@ -import json -import unittest -from os.path import dirname, join -from unittest.mock import patch - -from ovos_bus_client import Message - -from ovos_config.config import Configuration -from mycroft.skills.intent_service import IntentService -from mycroft.skills.skill_loader import SkillLoader -from ovos_utils.messagebus import FakeBus - -import ovos_plugin_common_play -from ovos_plugin_common_play import OCPAudioBackend - -BASE_CONF = {"Audio": - { - "native_sources": ["debug_cli", "audio"], - "default-backend": "OCP", # only used by mycroft-core - "preferred_audio_services": ["ovos_test", "mycroft_test"], - "backends": { - "OCP": { - "type": "ovos_common_play", - "active": True, - "mode": "auto", - "disable_mpris": True - }, - "mycroft_test": { - "type": "mycroft_test", - "active": True - }, - "ovos_test": { - "type": "ovos_test", - "active": True - } - } - } -} - - -class TestCPS(unittest.TestCase): - bus = FakeBus() - - @classmethod - def setUpClass(cls) -> None: - cls.bus.emitted_msgs = [] - - def get_msg(msg): - msg = json.loads(msg) - msg.pop("context") - cls.bus.emitted_msgs.append(msg) - - cls.bus.on("message", get_msg) - - @patch.dict(Configuration._Configuration__patch, BASE_CONF) - def test_auto_unload(self): - intents = IntentService(self.bus) - skill = SkillLoader(self.bus, f"{dirname(__file__)}/ovos_tskill_mycroft_cps") - skill.skill_id = "skill-playback-control.mycroftai" - skill.load() - - # assert that mycroft common play intents registered - cps_msgs = [ - {'type': 'register_intent', - 'data': {'name': 'skill-playback-control.mycroftai:play', - 'requires': [['skill_playback_control_mycroftaiPlay', - 'skill_playback_control_mycroftaiPlay'], - ['skill_playback_control_mycroftaiPhrase', - 'skill_playback_control_mycroftaiPhrase']], - 'at_least_one': [], 'optional': []}}, - {'type': 'register_intent', - 'data': {'name': 'skill-playback-control.mycroftai:handle_prev', - 'requires': [['skill_playback_control_mycroftaiPrev', - 'skill_playback_control_mycroftaiPrev'], - ['skill_playback_control_mycroftaiTrack', - 'skill_playback_control_mycroftaiTrack']], - 'at_least_one': [], 'optional': []}}, - {'type': 'register_intent', - 'data': {'name': 'skill-playback-control.mycroftai:handle_pause', - 'requires': [['skill_playback_control_mycroftaiPause', - 'skill_playback_control_mycroftaiPause']], - 'at_least_one': [], 'optional': []}}, - {'type': 'register_intent', - 'data': {'name': 'skill-playback-control.mycroftai:handle_next', - 'requires': [['skill_playback_control_mycroftaiNext', - 'skill_playback_control_mycroftaiNext'], - ['skill_playback_control_mycroftaiTrack', - 'skill_playback_control_mycroftaiTrack']], - 'at_least_one': [], 'optional': []}}, - {'type': 'register_intent', - 'data': {'name': 'skill-playback-control.mycroftai:handle_play', 'requires': [], - 'at_least_one': [['skill_playback_control_mycroftaiPlayResume', - 'skill_playback_control_mycroftaiResume']], 'optional': []}} - ] - for intent in cps_msgs: - match = (msg for msg in self.bus.emitted_msgs if - msg['type'] == intent['type'] and - msg['data'] == intent['data']) - self.assertTrue(any(match)) - - # assert that mycroft common play intents loaded - cps_intents = [ - {'name': 'skill-playback-control.mycroftai:handle_prev', - 'requires': [('skill_playback_control_mycroftaiPrev', 'skill_playback_control_mycroftaiPrev'), - ('skill_playback_control_mycroftaiTrack', 'skill_playback_control_mycroftaiTrack')], - 'at_least_one': [], 'optional': []}, - {'name': 'skill-playback-control.mycroftai:handle_play', 'requires': [], - 'at_least_one': [('skill_playback_control_mycroftaiPlayResume', 'skill_playback_control_mycroftaiResume')], - 'optional': []}, - {'name': 'skill-playback-control.mycroftai:handle_pause', - 'requires': [('skill_playback_control_mycroftaiPause', 'skill_playback_control_mycroftaiPause')], - 'at_least_one': [], 'optional': []}, - {'name': 'skill-playback-control.mycroftai:play', - 'requires': [('skill_playback_control_mycroftaiPlay', 'skill_playback_control_mycroftaiPlay'), - ('skill_playback_control_mycroftaiPhrase', 'skill_playback_control_mycroftaiPhrase')], - 'at_least_one': [], 'optional': []}, - {'name': 'skill-playback-control.mycroftai:handle_next', - 'requires': [('skill_playback_control_mycroftaiNext', 'skill_playback_control_mycroftaiNext'), - ('skill_playback_control_mycroftaiTrack', 'skill_playback_control_mycroftaiTrack')], - 'at_least_one': [], 'optional': []} - ] - for intent in cps_intents: - self.assertIn(intent, intents.registered_intents) - - # load ocp - self.bus.emitted_msgs = [] - cfg = {} - ocp = OCPAudioBackend(cfg, self.bus) - self.bus.emit(Message("mycroft.ready")) - # assert that mycroft common play was deregistered - disable_msgs = [ - {'type': 'skillmanager.deactivate', - 'data': {'skill': 'skill-playback-control.mycroftai'}}, - {'type': 'skillmanager.deactivate', - 'data': {'skill': 'mycroft-playback-control.mycroftai'}}, - {'type': 'skillmanager.deactivate', - 'data': {'skill': 'mycroft-playback-control'}}, - {'type': 'skillmanager.deactivate', - 'data': {'skill': 'skill-playback-control'}} - ] # possible skill-ids for mycroft skill - for disable in disable_msgs: - match = (msg for msg in self.bus.emitted_msgs if - msg['type'] == disable['type'] and - msg['data'] == disable['data']) - self.assertTrue(any(match)) - # skill manager would call this if connected to bus - if disable["data"]["skill"] == skill.skill_id: - skill.deactivate() - - # assert that OCP intents registered - locale_folder = join(dirname(ovos_plugin_common_play.__file__), - "ocp", "res", "locale", "en-us") - ocp_msgs = [ - {'type': 'padatious:register_intent', - 'data': { - 'file_name': f'{locale_folder}/play.intent', - 'name': 'ovos.common_play:play.intent', 'lang': 'en-us'}}, - {'type': 'padatious:register_intent', - 'data': { - 'file_name': f'{locale_folder}/read.intent', - 'name': 'ovos.common_play:read.intent', 'lang': 'en-us'}}, - {'type': 'padatious:register_intent', - 'data': { - 'file_name': f'{locale_folder}/open.intent', - 'name': 'ovos.common_play:open.intent', 'lang': 'en-us'}}, - {'type': 'padatious:register_intent', - 'data': { - 'file_name': f'{locale_folder}/next.intent', - 'name': 'ovos.common_play:next.intent', 'lang': 'en-us'}}, - {'type': 'padatious:register_intent', - 'data': { - 'file_name': f'{locale_folder}/prev.intent', - 'name': 'ovos.common_play:prev.intent', 'lang': 'en-us'}}, - {'type': 'padatious:register_intent', - 'data': { - 'file_name': f'{locale_folder}/pause.intent', - 'name': 'ovos.common_play:pause.intent', 'lang': 'en-us'}}, - {'type': 'padatious:register_intent', - 'data': { - 'file_name': f'{locale_folder}/resume.intent', - 'name': 'ovos.common_play:resume.intent', 'lang': 'en-us'}}, - {'type': 'ovos.common_play.skills.get', - 'data': {}} - ] - for intent in ocp_msgs: - self.assertNotIn(intent, intents.registered_intents) - - # assert that mycroft common play intents unloaded - detach_msg = {'type': 'detach_skill', - 'data': {'skill_id': 'skill-playback-control.mycroftai:'}} - self.assertIn(detach_msg, self.bus.emitted_msgs) - for intent in cps_intents: - self.assertNotIn(intent, intents.registered_intents) - - ocp.shutdown() - - -if __name__ == '__main__': - unittest.main()