Skip to content

Instantly share code, notes, and snippets.

@bibich
Created May 21, 2014 04:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bibich/34915615d68ad050a27c to your computer and use it in GitHub Desktop.
Save bibich/34915615d68ad050a27c to your computer and use it in GitHub Desktop.
Qobuz player for linux
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2014 Bibichette.com Ltd.
#
# Authors: Julien Chanseaume <@bibichette>
#
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# Version 2, December 2004
#
# Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
#
# Everyone is permitted to copy and distribute verbatim or modified
# copies of this license document, and changing it is allowed as long
# as the name is changed.
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
# 0. You just DO WHAT THE FUCK YOU WANT TO.
#
#
"""
A really simple player for Qobuz on Linux. It uses the Qobuz
web player but in a native window.
Why ? why not. I've just added basic support for media keys and
notifications.
There is some dependecies like python-webkit, pynotify, appindicator
you could already have installed. just try.
install
---------------
sudo cp qobuz.py /usr/local/bin/qobuz
sudo chmod +x /usr/local/bin/qobuz
qobuz
"""
import gobject
import gtk
import appindicator
import webkit
import dbus
import pynotify
import json
#import pprint
from datetime import datetime
from dbus.mainloop.glib import DBusGMainLoop
class Qobuz(gtk.Window):
"""Quobuz"""
def __init__(self):
super(Qobuz, self).__init__()
self.js_injected = False
self.quobuz_title = "Qobuz"
self.old_title = "Qobuz"
self.set_title(self.quobuz_title)
self.connect("destroy", gtk.main_quit)
self.maximize()
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.add(scroll)
self.browser = webkit.WebView()
self.browser.get_settings().set_property("enable-webgl", True)
scroll.add(self.browser)
self.browser.open("http://player.qobuz.com");
self.browser.connect('title-changed', self.title_changed)
self.browser.connect('load-finished', self.init_updater)
def trigger_action(self, action):
print "trigger action {}".format(action)
if (action == "play"):
self.browser.execute_script(
"jQuery('#player-play-button').click();")
elif (action == "pause"):
self.browser.execute_script(
"jQuery('#player-play-button').click();")
elif (action == "next"):
self.browser.execute_script(
"jQuery('#player-next-button').click();")
elif (action == "previous"):
self.browser.execute_script(
"jQuery('#player-previous-button').click();")
else:
print "Unknow action"
def title_changed(self, widget, frame, title):
if not self.js_injected:
return
if title.startswith("{\"app\":"):
try:
metadata = json.loads(title)
self.metadata = metadata.get("app", None)
self.handle_metadata()
except Exception as inst:
print inst
else:
print "title changed {}".format(title)
clean_title = title.replace(" - Qobuz Player", "")
if clean_title != self.old_title:
self.old_title = clean_title
self.browser.execute_script("qbAppUpdate();")
def init_updater(self, webview, webframe):
if self.js_injected:
return
self.js_injected = True
print "inject script"
script = """
function qbAppUpdate(){
var data = {};
if (qbPlayer.playerManager.currentTrack){
data["isPlaying"] = qbPlayer.playerManager.isPlaying();
data["song"] = qbPlayer.playerManager.currentTrack;
document.title = JSON.stringify({app: data});
}
}
"""
webview.execute_script(script)
def handle_metadata(self):
#print pprint.pprint(self.metadata)
if self.metadata is None:
print "no Metadata"
return
#if not self.metadata[u"isPlaying"]:
# return
if self.metadata[u"song"] is None:
print "no Song"
return
song = self.metadata[u"song"]
metadata = song.get(u"metadata", None)
if metadata is None:
print "no Song metadata"
return
self.notify(
'''<b>song: {title}</b>
<br />album: {albumTitle}
<br />artist: {artistName}'''
.format(**metadata))
self.set_title("{title} {albumTitle} {artistName} - Qobuz"
.format(**metadata))
def notify(self, message, image=None):
"""Display a notification using pynotify
"""
notification = pynotify.Notification('Qobuz', message, image)
notification.set_urgency(pynotify.URGENCY_NORMAL)
notification.set_timeout(pynotify.EXPIRES_DEFAULT)
notification.show()
class MediaKeyHandler():
def __init__(self, qobuz):
self.qobuz = qobuz
self.keys = {
"Play" : "play",
"Pause" : "pause",
"Next" : "next",
"Previous" : "previous",
}
try:
self.bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
self.bus_object = self.bus.get_object(
'org.gnome.SettingsDaemon',
'/org/gnome/SettingsDaemon/MediaKeys'
)
except:
print "Gnome SettingsDaemon not found, multimedia keys will not interact with Qobuz"
return
try:
self.bus_object.GrabMediaPlayerKeys(
"Qobuz",
0,
dbus_interface='org.gnome.SettingsDaemon.MediaKeys'
)
except:
pass
self.bus_object.connect_to_signal(
'MediaPlayerKeyPressed',
self.handle_mediakey
)
def handle_mediakey(self, *mmkeys):
for key in mmkeys:
if not key in self.keys or not self.keys[key]:
continue
self.qobuz.trigger_action(self.keys[key])
def set_loop(self, loop):
self.bus.set_default_main_loop(loop)
class QobuzIndicator(appindicator.Indicator):
def __init__(self, qobuz):
pynotify.init('Qobuz')
super(QobuzIndicator, self).__init__(
"quobuz-client",
"sound-icon",
appindicator.CATEGORY_APPLICATION_STATUS)
self.qobuz = qobuz
self.set_status(appindicator.STATUS_ACTIVE)
self.set_attention_icon("multimedia-audio-player")
# create a menu
menu = gtk.Menu()
# buttons
buttons = (
('previous', 'Previous'),
('pause', 'Play / Pause'),
('next', 'Next'),
('quit', 'Quit'),
)
for button in buttons:
menu_item = gtk.MenuItem(button[1])
menu.append(menu_item)
menu_item.connect("activate", self.menu_activated,
button[0])
menu_item.show()
self.set_menu(menu)
def menu_activated(self, widget, action):
if action == 'quit':
print "bye bye"
gtk.main_quit()
else:
self.qobuz.trigger_action(action)
if __name__ == "__main__":
DBusGMainLoop(set_as_default=True)
qobuz = Qobuz()
qobuz.show_all()
print "Media Key Support"
mediakey = MediaKeyHandler(qobuz)
print "Indicator Support"
indicator = QobuzIndicator(qobuz)
gtk.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment