Skip to content
This repository has been archived by the owner on Oct 24, 2021. It is now read-only.

Commit

Permalink
cps
Browse files Browse the repository at this point in the history
  • Loading branch information
JarbasAl committed Mar 7, 2021
1 parent f8df07a commit 43e99f9
Show file tree
Hide file tree
Showing 8 changed files with 346 additions and 136 deletions.
174 changes: 88 additions & 86 deletions ovos_utils/playback/cps.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@ def search(self, phrase, media_type=CPSMatchType.GENERIC):
# life cycle but instead delegate to the skill
if self.old_cps:
old_style = self.old_cps.get_results(phrase)
self.query_replies[phrase] += self._convert_to_new_style(old_style, media_type)
self.query_replies[phrase] += self._convert_to_new_style(old_style,
media_type)

if self.query_replies.get(phrase):
return [s for s in self.query_replies[phrase] if s.get("results")]
Expand All @@ -289,6 +290,14 @@ def search(self, phrase, media_type=CPSMatchType.GENERIC):
return self.search(phrase, media_type=CPSMatchType.GENERIC)
return []

def process_search(self, selected, results):
# TODO playlist
self._update_current_media(selected)
self._update_disambiguation(results)
self._set_search_results(results, best=selected)
self._set_now_playing(selected)
self.play()

@staticmethod
def _convert_to_new_style(results, media_type=CPSMatchType.GENERIC):
new_style = []
Expand Down Expand Up @@ -394,16 +403,13 @@ def update_status(self, status):
self.bus.emit(Message('better_cps.status.update', status))

# playback control
def play(self, data):
def play(self):
data = self.playback_data.get("playing") or {}
uri = data.get("stream") or data.get("uri") or data.get("url")
skill_id = self.active_skill = data["skill_id"]
if data["playback"] == CPSPlayback.AUDIO:
data["status"] = CPSTrackStatus.PLAYING_AUDIOSERVICE
real_url = uri
if is_youtube(uri):
real_url = get_youtube_audio_stream(uri)
if not real_url:
real_url = get_youtube_video_stream(uri)
real_url = self.get_stream(uri)
self.audio_service.play(real_url)

elif data["playback"] == CPSPlayback.SKILL:
Expand All @@ -420,9 +426,20 @@ def play(self, data):
else:
raise ValueError("invalid playback request")
self.update_status(data)
self.display_ui(media=data)
self._set_now_playing(data)
self.display_ui()
self.update_player_status("Playing")

@staticmethod
def get_stream(uri, video=False):
real_url = None
if is_youtube(uri):
if not video:
real_url = get_youtube_audio_stream(uri)
if video or not real_url:
real_url = get_youtube_video_stream(uri)
return real_url or uri

def play_next(self):
# TODO playlist handling
if self.active_backend == CPSTrackStatus.PLAYING_GUI:
Expand Down Expand Up @@ -477,87 +494,82 @@ def stop(self):
# ######### GUI integration ###############
def register_gui_handlers(self):
# All Handlers For Player QML
self.gui.register_handler('better-cps.gui.playAction', self.handle_click_resume)
self.gui.register_handler('better-cps.gui.pauseAction', self.handle_click_pause)
self.gui.register_handler('better-cps.gui.nextAction', self.handle_click_next)
self.gui.register_handler('better-cps.gui.previousAction', self.handle_click_previous)
self.gui.register_handler('better-cps.gui.playerSeekAction', self.handle_click_seek)
self.gui.register_handler('better-cps.gui.play',
self.handle_click_resume)
self.gui.register_handler('better-cps.gui.pause',
self.handle_click_pause)
self.gui.register_handler('better-cps.gui.next',
self.handle_click_next)
self.gui.register_handler('better-cps.gui.previous',
self.handle_click_previous)
self.gui.register_handler('better-cps.gui.seek',
self.handle_click_seek)

# All Handlers For Playlist QML
self.gui.register_handler('better-cps.gui.playlistPlay', self.handle_play_from_playlist)
self.gui.register_handler('better-cps.gui.searchPlay',
self.gui.register_handler('better-cps.gui.playlist.play',
self.handle_play_from_playlist)
self.gui.register_handler('better-cps.gui.search.play',
self.handle_play_from_search)

def update_search_results(self, results, best=None):
best = best or results[0]
for idx, data in enumerate(results):
url = data.get("stream") or \
data.get("url") or \
data.get("uri")
results[idx]["length"] = data.get("length") or \
data.get("track_length") or \
data.get("duration") #or \
#get_duration_from_url(url)
self._search_results = results
# send all results for disambiguation
# this can be used in GUI or any other use facing interface to
# override the final selection
for r in self._search_results:
status = dict(r)
status["status"] = CPSTrackStatus.DISAMBIGUATION
self.bus.emit(Message('better_cps.status.update', status))
results = sorted(results, key=lambda k: k.get("match_confidence"),
reverse=True)[:100]
results = self._res2playlist(results)
playlist = self._res2playlist([best]) # TODO cps playlist
self.display_ui(media=best, playlist=playlist, search=results)
def update_player_status(self, status, page=0):
self.gui["media"]["status"] = status
self.display_ui(page=page)

def display_ui(self, search=None, media=None, playlist=None, page=0):
search_qml = "disambiguation.qml"
player_qml = "player_simple.qml"
video_qml = "videoplayer.qml"
player_no_seek_qml = "player_basic.qml"
video_player_qml = "videoplayer.qml"
playlist_qml = "playlist.qml"

media = media or self.gui.get("media") or {}
media["status"] = media.get("status", "Paused")
media["position"] = media.get("position", 0)
search = search or self.gui.get("searchModel", {}).get("data") \
or {}
playlist = playlist or self.gui.get("playlistModel", {}).get("data") \
or {}

self.update_disambiguation(search)
self.update_media(media)
self.update_playlist(playlist)
search = search or self.gui.get("searchModel", {}).get("data") or {}
playlist = playlist or self.gui.get("playlistModel", {}).get("data") or {}

# change "now playing" page depending on media type
if media.get("playback", -1) == CPSPlayback.GUI:

url = media.get("stream") or \
uri = media.get("stream") or \
media.get("url") or \
media.get("uri")
#if is_youtube(url):
# url = get_youtube_video_stream(url)
#self.gui.remove_page(player_qml)
#self.gui.play_video(url, media.get("title"))
#self.gui["playStatus"] = "play"
"""
self.gui["video"] = url
self.gui["stream"] = self.get_stream(uri, video=True)
self.gui["title"] = media.get("title", "")
self.gui["playerRepeat"] = False
self.gui.show_pages([video_qml, search_qml, playlist_qml], page,
override_idle=True)
"""
self.gui.show_pages([player_qml, search_qml, playlist_qml], page,
override_idle=True)
self.gui["playStatus"] = "play"
pages = [video_player_qml, search_qml, playlist_qml]
# display "now playing" page seekbar depending on duration info
elif not media.get("length"):
pages = [player_no_seek_qml, search_qml, playlist_qml]
# display default pages
else:
self.gui.show_pages([player_qml, search_qml, playlist_qml], page,
override_idle=True)
pages = [player_qml, search_qml, playlist_qml]

def update_player_status(self, status, page=0):
self.gui["media"]["status"] = status
self.display_ui(page=page)
self.gui["searchModel"] = {"data": search}
self.gui["playlistModel"] = {"data": playlist}
self.gui.show_pages(pages, page, override_idle=True)

def _set_search_results(self, results, best=None):
best = best or results[0]
for idx, data in enumerate(results):
results[idx]["length"] = data.get("length") or \
data.get("track_length") or \
data.get("duration")
self._search_results = results
# send all results for disambiguation
# this can be used in GUI or any other use facing interface to
# override the final selection
for r in self._search_results:
status = dict(r)
status["status"] = CPSTrackStatus.DISAMBIGUATION
self.bus.emit(Message('better_cps.status.update', status))
results = sorted(results, key=lambda k: k.get("match_confidence"),
reverse=True)[:100]
results = self._res2playlist(results)
playlist = self._res2playlist([best]) # TODO cps playlist
self.display_ui(media=best, playlist=playlist, search=results)

def _res2playlist(self, res):
@staticmethod
def _res2playlist(res):
playlist_data = []
for r in res:
playlist_data.append({
Expand All @@ -569,26 +581,20 @@ def _res2playlist(self, res):
})
return playlist_data

def update_disambiguation(self, playlist_data):
self.gui["searchModel"] = {"data": playlist_data}

def update_playlist(self, playlist_data):
self.gui["playlistModel"] = {"data": playlist_data}

def update_media(self, data):
def _set_now_playing(self, data):
if data.get("bg_image", "").startswith("/"):
data["bg_image"] = "file:/" + data["bg_image"]
data["skill"] = data.get("skill_id", "better-cps")
data["position"] = data.get("position", 0)

url = data.get("stream") or data.get("url") or data.get("uri")
data["length"] = data.get("length") or data.get("track_length") or \
data.get("duration") #or get_duration_from_url(url)
data.get("duration") # or get_duration_from_url(url)

self.gui["media"] = data
self.gui["bg_image"] = data.get("bg_image",
"https://source.unsplash.com/weekly?music")

# gui events
def handle_click_pause(self, message):
self.audio_service.pause()
self.update_player_status("Paused")
Expand All @@ -612,7 +618,6 @@ def handle_click_seek(self, message):
self.display_ui()

def handle_play_from_playlist(self, message):
# Do whatever processing here to play song
playlist_data = message.data["playlistData"]
self.__play(playlist_data)

Expand All @@ -624,12 +629,9 @@ def handle_play_from_search(self, message):

def __play(self, media):
playlist = self._res2playlist([media]) # TODO cps playlist
self.update_playlist(playlist)
self.update_media(media)
self.play(media)



self.gui["playlistModel"] = {"data": playlist}
self._update_current_media(media)
self.play()


if __name__ == "__main__":
Expand All @@ -638,8 +640,8 @@ def __play(self, media):
cps = BetterCommonPlayInterface(max_timeout=10, min_timeout=2)

# test lovecraft skills
#pprint(cps.search("dagon"))
pprint(cps.search("horror story"))
# pprint(cps.search("dagon"))
pprint(cps.search("astronaut problems"))
exit()
pprint(cps.search("the thing in the doorstep"))

Expand Down
39 changes: 1 addition & 38 deletions ovos_utils/res/ui/SeekControl.qml
Original file line number Diff line number Diff line change
Expand Up @@ -62,44 +62,7 @@ Item {
RowLayout {
id: mainLayout2
Layout.fillHeight: true
Controls.RoundButton {
id: backButton
Layout.preferredWidth: parent.width > 600 ? Kirigami.Units.iconSizes.large : Kirigami.Units.iconSizes.medium
Layout.preferredHeight: Layout.preferredWidth
highlighted: focus ? 1 : 0
z: 1000

background: Rectangle {
radius: 200
color: "#1a1a1a"
border.width: 1.25
border.color: "white"
}

contentItem: Item {
Image {
width: parent.width - Kirigami.Units.largeSpacing
height: width
anchors.centerIn: parent
source: "images/back.svg"
}
}

onClicked: {
Mycroft.MycroftController.sendRequest("mycroft.gui.screen.close", {});
video.stop();
}
KeyNavigation.up: video
KeyNavigation.right: button
Keys.onReturnPressed: {
hideTimer.restart();
Mycroft.MycroftController.sendRequest("mycroft.gui.screen.close", {});
video.stop();
}
onFocusChanged: {
hideTimer.restart();
}
}

Controls.RoundButton {
id: button
Layout.preferredWidth: parent.width > 600 ? Kirigami.Units.iconSizes.large : Kirigami.Units.iconSizes.medium
Expand Down
Binary file removed ovos_utils/res/ui/images/Sources/Bandcamp.png
Binary file not shown.
Binary file removed ovos_utils/res/ui/images/Sources/Soundcloud.png
Binary file not shown.
Binary file removed ovos_utils/res/ui/images/Sources/Spotify.png
Binary file not shown.
Loading

0 comments on commit 43e99f9

Please sign in to comment.