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

Commit

Permalink
feat/better_CPS
Browse files Browse the repository at this point in the history
  • Loading branch information
JarbasAl committed Mar 6, 2021
1 parent 797879a commit c8627be
Show file tree
Hide file tree
Showing 24 changed files with 2,597 additions and 308 deletions.
454 changes: 452 additions & 2 deletions ovos_utils/gui.py

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions ovos_utils/playback/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from ovos_utils.playback.cps import CPSPlayback, CPSMatchConfidence, \
CPSMatchLevel, CPSTrackStatus, CPSMatchType, CommonPlayInterface, BetterCommonPlayInterface
from ovos_utils.playback.youtube import get_youtube_metadata, \
get_youtube_video_stream, get_youtube_audio_stream, is_youtube
from ovos_utils.playback.utils import get_duration_from_url
648 changes: 648 additions & 0 deletions ovos_utils/playback/cps.py

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions ovos_utils/playback/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from ovos_utils.playback.youtube import get_youtube_metadata, is_youtube
import requests


def get_duration_from_url(url):
""" return stream duration in milliseconds """
if not url:
return 0
if is_youtube(url):
data = get_youtube_metadata(url)
dur = data.get("length", 0)
else:
headers = requests.head(url).headers
#print(headers)
#dur = int(headers.get("Content-Length", 0))
dur = 0
return dur


def get_title_from_url(url):
""" return stream duration in milliseconds """
if url and is_youtube(url):
data = get_youtube_metadata(url)
return data.get("title")
return url
99 changes: 99 additions & 0 deletions ovos_utils/playback/youtube.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import subprocess
from os.path import exists, join
from tempfile import gettempdir
from ovos_utils.log import LOG

try:
import pafy
except ImportError:
pafy = None


def get_youtube_audio_stream(url, download=False, convert=False):
if pafy is None:
LOG.error("can not extract audio stream, pafy is not available")
LOG.info("pip install youtube-dl")
LOG.info("pip install pafy")
return url
try:
stream = pafy.new(url)
except:
return None
stream = stream.getbestaudio()
if not stream:
return None

if download:
path = join(gettempdir(),
url.split("watch?v=")[-1] + "." + stream.extension)

if not exists(path):
stream.download(path)

if convert:
mp3 = join(gettempdir(), url.split("watch?v=")[-1] + ".mp3")
if not exists(mp3):
# convert file to mp3
command = ["ffmpeg", "-n", "-i", path, "-acodec",
"libmp3lame", "-ab", "128k", mp3]
subprocess.call(command)
return mp3

return path

return stream.url


def get_youtube_video_stream(url, download=False):
if pafy is None:
LOG.error("can not extract audio stream, pafy is not available")
LOG.info("pip install youtube-dl")
LOG.info("pip install pafy")
return url
try:
stream = pafy.new(url)
except:
return None
stream = stream.getbest()
if not stream:
return None

if download:
path = join(gettempdir(),
url.split("watch?v=")[-1] + "." + stream.extension)
if not exists(path):
stream.download(path)
return path
return stream.url


def is_youtube(url):
# TODO localization
if not url:
return False
return "youtube.com/" in url or "youtu.be/" in url


def get_youtube_metadata(url):
if pafy is None:
LOG.error("can not extract audio stream, pafy is not available")
LOG.info("pip install youtube-dl")
LOG.info("pip install pafy")
return url
try:
stream = pafy.new(url)
except:
return {}
return {
"url": url,
#"audio_stream": stream.getbestaudio().url,
#"stream": stream.getbest().url,
"title": stream.title,
"author": stream.author,
"image": stream.getbestthumb().split("?")[0],
# "description": stream.description,
"length": stream.length * 1000,
"category": stream.category,
# "upload_date": stream.published,
# "tags": stream.keywords
}
171 changes: 171 additions & 0 deletions ovos_utils/res/ui/disambiguation.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* Copyright 2020 by Aditya Mehra <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

import QtQuick 2.9
import QtQuick.Controls 2.3 as Controls
import QtQuick.Layouts 1.3
import org.kde.kirigami 2.8 as Kirigami
import QtGraphicalEffects 1.0
import Mycroft 1.0 as Mycroft


Mycroft.Delegate {
id: delegate

property var playlistModel: sessionData.searchModel
property Component emptyHighlighter: Item{}
fillWidth: true

skillBackgroundSource: sessionData.bg_image

onPlaylistModelChanged: {
playlistListView.forceLayout()
}

Keys.onBackPressed: {
parent.parent.parent.currentIndex--
parent.parent.parent.currentItem.contentItem.forceActiveFocus()
}

function formatedDuration(millis){
var minutes = Math.floor(millis / 60000);
var seconds = ((millis % 60000) / 1000).toFixed(0);
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
}

ColumnLayout {
id: playlistPlayerColumn
anchors.fill: parent
spacing: Kirigami.Units.smallSpacing

Kirigami.Heading {
id: watchItemList
text: "Search Results"
level: 2
}

Kirigami.Separator {
id: sept2
Layout.fillWidth: true
Layout.preferredHeight: 1
z: 100
}

ListView {
id: playlistListView
keyNavigationEnabled: true
model: playlistModel.data
focus: false
interactive: true
bottomMargin: delegate.controlBarItem.height + Kirigami.Units.largeSpacing
Layout.fillWidth: true
Layout.fillHeight: true
spacing: Kirigami.Units.largeSpacing
currentIndex: 0
clip: true
highlightRangeMode: ListView.StrictlyEnforceRange
snapMode: ListView.SnapToItem

delegate: Controls.ItemDelegate {
width: parent.width
height: Kirigami.Units.gridUnit * 5

background: Rectangle {
Kirigami.Theme.colorSet: Kirigami.Theme.Button
color: Qt.rgba(0.2, 0.2, 0.2, 1)
layer.enabled: true
layer.effect: DropShadow {
horizontalOffset: 1
verticalOffset: 2
}
}


contentItem: Item {
width: parent.width
height: parent.height

RowLayout {
id: delegateItem
anchors.fill: parent
anchors.margins: Kirigami.Units.smallSpacing
spacing: Kirigami.Units.largeSpacing

Image {
id: videoImage
source: modelData.image
Layout.preferredHeight: parent.height
Layout.preferredWidth: Kirigami.Units.gridUnit * 4
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
fillMode: Image.Stretch
}

ColumnLayout {
Layout.fillWidth: true

Controls.Label {
id: videoLabel
Layout.fillWidth: true
text: modelData.track
wrapMode: Text.WordWrap
color: "white"
}
Controls.Label {
id: artistLabel
Layout.fillWidth: true
text: modelData.album
opacity: 0.8
color: "white"
}
}

Controls.Label {
id: durationTime
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
color: "white"
opacity: 0.8
text: formatedDuration(modelData.duration)
}

Kirigami.Separator {
Layout.fillHeight: true
Layout.preferredWidth: 1
}

Image {
id: songSource
Layout.preferredHeight: Kirigami.Units.iconSizes.huge + Kirigami.Units.largeSpacing
Layout.preferredWidth: Kirigami.Units.iconSizes.huge + Kirigami.Units.largeSpacing
Layout.alignment: Qt.AlignHCenter
fillMode: Image.PreserveAspectFit
source: modelData.source
}
}
}

onClicked: {
triggerGuiEvent("better-cps.gui.searchPlay",
{"playlistData": modelData})
}
}
}
}

Component.onCompleted: {
playlistListView.forceActiveFocus()
}
}
Binary file added ovos_utils/res/ui/images/Sources/Bandcamp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ovos_utils/res/ui/images/Sources/Soundcloud.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ovos_utils/res/ui/images/Sources/Spotify.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 7 additions & 60 deletions ovos_utils/res/ui/images/media-playback-pause.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit c8627be

Please sign in to comment.