Add support for Premium streams in di.fm
This commit is contained in:
parent
c6d724f53a
commit
52550acb75
11
scripts/digitallyimported-radio/common.py
Normal file
11
scripts/digitallyimported-radio/common.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# These have to be in the same order as in the settings dialog
|
||||||
|
PLAYLISTS = [
|
||||||
|
{"premium": False, "url": "http://listen.di.fm/public3/%s.pls"},
|
||||||
|
{"premium": True, "url": "http://www.di.fm/listen/%s/premium.pls"},
|
||||||
|
{"premium": False, "url": "http://listen.di.fm/public2/%s.pls"},
|
||||||
|
{"premium": True, "url": "http://www.di.fm/listen/%s/64k.pls"},
|
||||||
|
{"premium": True, "url": "http://www.di.fm/listen/%s/128k.pls"},
|
||||||
|
{"premium": False, "url": "http://listen.di.fm/public5/%s.asx"},
|
||||||
|
{"premium": True, "url": "http://www.di.fm/listen/%s/64k.asx"},
|
||||||
|
{"premium": True, "url": "http://www.di.fm/listen/%s/128k.asx"},
|
||||||
|
]
|
@ -18,11 +18,11 @@ class Plugin:
|
|||||||
self.service.SettingsDialogRequested.connect(self.ShowSettings)
|
self.service.SettingsDialogRequested.connect(self.ShowSettings)
|
||||||
|
|
||||||
def ShowSettings(self):
|
def ShowSettings(self):
|
||||||
# Create the dialog the first time it's shown
|
|
||||||
if not self.settings_dialog:
|
if not self.settings_dialog:
|
||||||
|
# Create the dialog the first time it's shown
|
||||||
self.settings_dialog = SettingsDialog()
|
self.settings_dialog = SettingsDialog()
|
||||||
|
self.settings_dialog.accepted.connect(self.service.ReloadSettings)
|
||||||
|
|
||||||
# Show the dialog
|
|
||||||
self.settings_dialog.show()
|
self.settings_dialog.show()
|
||||||
|
|
||||||
plugin = Plugin()
|
plugin = Plugin()
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
import common
|
||||||
|
|
||||||
import clementine
|
import clementine
|
||||||
|
|
||||||
from PyQt4.QtCore import QSettings, QUrl
|
from PyQt4.QtCore import QSettings, QUrl
|
||||||
from PyQt4.QtGui import QAction, QDesktopServices, QIcon, QMenu, \
|
from PyQt4.QtGui import QAction, QDesktopServices, QIcon, QMenu, \
|
||||||
QStandardItem
|
QStandardItem
|
||||||
from PyQt4.QtNetwork import QNetworkRequest
|
from PyQt4.QtNetwork import QNetworkCookie, QNetworkCookieJar, QNetworkRequest
|
||||||
import PyQt4.QtCore
|
import PyQt4.QtCore
|
||||||
|
|
||||||
import json
|
import json
|
||||||
@ -15,18 +17,6 @@ class DigitallyImportedService(clementine.RadioService):
|
|||||||
HOMEPAGE_URL = QUrl("http://www.di.fm/")
|
HOMEPAGE_URL = QUrl("http://www.di.fm/")
|
||||||
STREAM_LIST_URL = QUrl("http://listen.di.fm/")
|
STREAM_LIST_URL = QUrl("http://listen.di.fm/")
|
||||||
|
|
||||||
# These have to be in the same order as in the settings dialog
|
|
||||||
PLAYLISTS = [
|
|
||||||
{"premium": False, "url": "http://listen.di.fm/public3/%s.pls"},
|
|
||||||
{"premium": True, "url": "http://www.di.fm/listen/%s/premium.pls"},
|
|
||||||
{"premium": False, "url": "http://listen.di.fm/public2/%s.pls"},
|
|
||||||
{"premium": True, "url": "http://www.di.fm/listen/%s/64k.pls"},
|
|
||||||
{"premium": True, "url": "http://www.di.fm/listen/%s/128k.pls"},
|
|
||||||
{"premium": False, "url": "http://listen.di.fm/public5/%s.asx"},
|
|
||||||
{"premium": True, "url": "http://www.di.fm/listen/%s/64k.asx"},
|
|
||||||
{"premium": True, "url": "http://www.di.fm/listen/%s/128k.asx"},
|
|
||||||
]
|
|
||||||
|
|
||||||
SettingsDialogRequested = PyQt4.QtCore.pyqtSignal()
|
SettingsDialogRequested = PyQt4.QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, model):
|
def __init__(self, model):
|
||||||
@ -36,6 +26,7 @@ class DigitallyImportedService(clementine.RadioService):
|
|||||||
self.path = os.path.dirname(__file__)
|
self.path = os.path.dirname(__file__)
|
||||||
|
|
||||||
self.audio_type = 0
|
self.audio_type = 0
|
||||||
|
|
||||||
self.context_index = None
|
self.context_index = None
|
||||||
self.last_original_url = None
|
self.last_original_url = None
|
||||||
self.menu = None
|
self.menu = None
|
||||||
@ -50,6 +41,20 @@ class DigitallyImportedService(clementine.RadioService):
|
|||||||
settings.beginGroup(self.SERVICE_NAME)
|
settings.beginGroup(self.SERVICE_NAME)
|
||||||
|
|
||||||
self.audio_type = int(settings.value("audio_type", 0).toPyObject())
|
self.audio_type = int(settings.value("audio_type", 0).toPyObject())
|
||||||
|
username = unicode(settings.value("username", "").toPyObject().toUtf8())
|
||||||
|
password = unicode(settings.value("password", "").toPyObject().toUtf8())
|
||||||
|
|
||||||
|
# If a username and password were set by the user then set them in the
|
||||||
|
# cookies we pass to www.di.fm
|
||||||
|
cookie_jar = None
|
||||||
|
if len(username) and len(password):
|
||||||
|
cookie_jar = QNetworkCookieJar()
|
||||||
|
cookie_jar.setCookiesFromUrl([
|
||||||
|
QNetworkCookie("_amember_ru", username),
|
||||||
|
QNetworkCookie("_amember_rp", password),
|
||||||
|
], QUrl("http://www.di.fm/"))
|
||||||
|
|
||||||
|
self.network.setCookieJar(cookie_jar)
|
||||||
|
|
||||||
def CreateRootItem(self):
|
def CreateRootItem(self):
|
||||||
self.root = QStandardItem(QIcon(os.path.join(self.path, "icon-small.png")),
|
self.root = QStandardItem(QIcon(os.path.join(self.path, "icon-small.png")),
|
||||||
@ -80,7 +85,7 @@ class DigitallyImportedService(clementine.RadioService):
|
|||||||
self.menu.addSeparator()
|
self.menu.addSeparator()
|
||||||
|
|
||||||
self.menu.addAction(clementine.IconLoader.Load("configure"),
|
self.menu.addAction(clementine.IconLoader.Load("configure"),
|
||||||
self.tr("Configure Digitally Imported..."), self.SettingsDialogRequested)
|
self.tr("Configure Digitally Imported..."), self.SettingsDialogRequested.emit)
|
||||||
|
|
||||||
self.context_index = index
|
self.context_index = index
|
||||||
self.menu.popup(global_pos)
|
self.menu.popup(global_pos)
|
||||||
@ -152,12 +157,12 @@ class DigitallyImportedService(clementine.RadioService):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
key = original_url.host()
|
key = original_url.host()
|
||||||
playlist_url = self.PLAYLISTS[self.audio_type]["url"] % key
|
playlist_url = common.PLAYLISTS[self.audio_type]["url"] % key
|
||||||
|
|
||||||
# Start fetching the playlist
|
# Start fetching the playlist. Can't use a SongLoader to do this because
|
||||||
self.song_loader = clementine.SongLoader(clementine.library)
|
# we have to use the cookies we set in ReloadSettings()
|
||||||
self.song_loader.LoadFinished.connect(self.LoadPlaylistFinished)
|
reply = self.network.get(QNetworkRequest(QUrl(playlist_url)))
|
||||||
self.song_loader.Load(QUrl(playlist_url))
|
reply.finished.connect(self.LoadPlaylistFinished)
|
||||||
|
|
||||||
# Save the original URL so we can emit it in the finished signal later
|
# Save the original URL so we can emit it in the finished signal later
|
||||||
self.last_original_url = original_url
|
self.last_original_url = original_url
|
||||||
@ -167,10 +172,13 @@ class DigitallyImportedService(clementine.RadioService):
|
|||||||
|
|
||||||
result.type_ = clementine.PlaylistItem.SpecialLoadResult.WillLoadAsynchronously
|
result.type_ = clementine.PlaylistItem.SpecialLoadResult.WillLoadAsynchronously
|
||||||
result.original_url_ = original_url
|
result.original_url_ = original_url
|
||||||
print result
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def LoadPlaylistFinished(self, success):
|
def LoadPlaylistFinished(self):
|
||||||
|
# Get the QNetworkReply that called this slot
|
||||||
|
reply = self.sender()
|
||||||
|
reply.deleteLater()
|
||||||
|
|
||||||
if self.task_id is None:
|
if self.task_id is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -178,16 +186,20 @@ class DigitallyImportedService(clementine.RadioService):
|
|||||||
clementine.task_manager.SetTaskFinished(self.task_id)
|
clementine.task_manager.SetTaskFinished(self.task_id)
|
||||||
self.task_id = None
|
self.task_id = None
|
||||||
|
|
||||||
|
# Try to parse the playlist
|
||||||
|
parser = clementine.PlaylistParser(clementine.library)
|
||||||
|
songs = parser.Load(reply)
|
||||||
|
|
||||||
# Failed to get the playlist?
|
# Failed to get the playlist?
|
||||||
if not success:
|
if len(songs) == 0:
|
||||||
self.StreamError.emit("Error loading playlist '%s'" % self.song_loader.url().toString())
|
self.StreamError.emit("Error loading playlist '%s'" % self.song_loader.url().toString())
|
||||||
return
|
return
|
||||||
|
|
||||||
result = clementine.PlaylistItem.SpecialLoadResult()
|
result = clementine.PlaylistItem.SpecialLoadResult()
|
||||||
result.original_url_ = self.last_original_url
|
result.original_url_ = self.last_original_url
|
||||||
if len(self.song_loader.songs()) > 0:
|
|
||||||
# Take the first track in the playlist
|
# Take the first track in the playlist
|
||||||
result.type_ = clementine.PlaylistItem.SpecialLoadResult.TrackAvailable
|
result.type_ = clementine.PlaylistItem.SpecialLoadResult.TrackAvailable
|
||||||
result.media_url_ = QUrl(self.song_loader.songs()[0].filename())
|
result.media_url_ = QUrl(songs[0].filename())
|
||||||
|
|
||||||
self.AsyncLoadFinished.emit(result)
|
self.AsyncLoadFinished.emit(result)
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
from PyQt4.QtGui import QDialog, QIcon
|
from service import DigitallyImportedService
|
||||||
|
|
||||||
|
from PyQt4.QtCore import QSettings
|
||||||
|
from PyQt4.QtGui import QDialog, QIcon
|
||||||
import PyQt4.uic
|
import PyQt4.uic
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
@ -12,5 +15,25 @@ class SettingsDialog(QDialog):
|
|||||||
# Set up the user interface
|
# Set up the user interface
|
||||||
PyQt4.uic.loadUi(os.path.join(self.path, "settingsdialog.ui"), self)
|
PyQt4.uic.loadUi(os.path.join(self.path, "settingsdialog.ui"), self)
|
||||||
|
|
||||||
# Set the icon
|
# Set the window icon
|
||||||
self.setWindowIcon(QIcon(os.path.join(self.path, "icon-small.png")))
|
self.setWindowIcon(QIcon(os.path.join(self.path, "icon-small.png")))
|
||||||
|
|
||||||
|
def showEvent(self, event):
|
||||||
|
# Load the settings
|
||||||
|
settings = QSettings()
|
||||||
|
settings.beginGroup(DigitallyImportedService.SERVICE_NAME)
|
||||||
|
self.type.setCurrentIndex(int(settings.value("audio_type", 0).toPyObject()))
|
||||||
|
self.username.setText(settings.value("username", "").toPyObject())
|
||||||
|
self.password.setText(settings.value("password", "").toPyObject())
|
||||||
|
|
||||||
|
QDialog.showEvent(self, event)
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
# Save the settings
|
||||||
|
settings = QSettings()
|
||||||
|
settings.beginGroup(DigitallyImportedService.SERVICE_NAME)
|
||||||
|
settings.setValue("audio_type", self.type.currentIndex())
|
||||||
|
settings.setValue("username", self.username.text())
|
||||||
|
settings.setValue("password", self.password.text())
|
||||||
|
|
||||||
|
QDialog.accept(self)
|
||||||
|
@ -16,9 +16,6 @@
|
|||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
@ -63,7 +60,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="0" colspan="2">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><a href="http://www.di.fm/premium/">Upgrade to Premium now</a></string>
|
<string><a href="http://www.di.fm/premium/">Upgrade to Premium now</a></string>
|
||||||
@ -71,6 +68,9 @@
|
|||||||
<property name="openExternalLinks">
|
<property name="openExternalLinks">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user