Hello community,
here is the log from the commit of package pithos for openSUSE:Factory checked in at 2014-12-05 21:04:45
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/pithos (Old)
and /work/SRC/openSUSE:Factory/.pithos.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "pithos"
Changes:
--------
--- /work/SRC/openSUSE:Factory/pithos/pithos.changes 2014-09-30 19:36:15.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.pithos.new/pithos.changes 2014-12-05 21:05:00.000000000 +0100
@@ -1,0 +2,17 @@
+Sun Nov 30 05:27:22 UTC 2014 - malcolmlewis@opensuse.org
+
+- Update to version 1.0.1:
+ + Automatically install missing codecs if supported.
+ + Save window position between sessions.
+ + Fix saving last station on quit.
+ + Fix pacparser support.
+ + Improve pandora module docs.
+ + Add setup.py command to build docs.
+ + Add appdata file.
+ + Notification_icon: Make toggling visibility more reliable.
+ + mpris: Fix exception when querying positon.
+ + mpris: Implement setting volume.
+- Update fixes Pandora stream and hangs at "loading songs" This
+ occurs randomly, sometimes very frequently (boo#907701).
+
+-------------------------------------------------------------------
Old:
----
1.0.0.tar.gz
New:
----
1.0.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ pithos.spec ++++++
--- /var/tmp/diff_new_pack.OC3zRt/_old 2014-12-05 21:05:01.000000000 +0100
+++ /var/tmp/diff_new_pack.OC3zRt/_new 2014-12-05 21:05:01.000000000 +0100
@@ -18,13 +18,13 @@
Name: pithos
-Version: 1.0.0
+Version: 1.0.1
Release: 0
Summary: Native Pandora Radio client for Linux
License: GPL-3.0
Group: Productivity/Multimedia/Other
Url: http://pithos.github.io/
-Source0: https://github.com/pithos/pithos/archive/1.0.0.tar.gz
+Source0: https://github.com/pithos/pithos/archive/1.0.1.tar.gz
BuildRequires: fdupes
# Needed for automatic typelib() Requires.
BuildRequires: gobject-introspection
@@ -78,5 +78,7 @@
%{python3_sitelib}/pithos-%{version}-py%{py3_ver}.egg-info
%{_datadir}/applications/pithos.desktop
%{_datadir}/icons/hicolor/*/apps/pithos*
+%dir %{_datadir}/appdata/
+%{_datadir}/appdata/pithos.appdata.xml
%changelog
++++++ 1.0.0.tar.gz -> 1.0.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/MANIFEST.in new/pithos-1.0.1/MANIFEST.in
--- old/pithos-1.0.0/MANIFEST.in 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/MANIFEST.in 2014-09-21 12:30:03.000000000 +0200
@@ -1,4 +1,4 @@
include README.md
-recursive-include data *.svg pithos.desktop
+recursive-include data *.svg pithos.desktop *.xml
recursive-include pithos/data/ui *.ui *.xml
recursive-include pithos/data/media *.png *.svg
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/data/pithos.appdata.xml new/pithos-1.0.1/data/pithos.appdata.xml
--- old/pithos-1.0.0/data/pithos.appdata.xml 1970-01-01 01:00:00.000000000 +0100
+++ new/pithos-1.0.1/data/pithos.appdata.xml 2014-09-21 12:30:03.000000000 +0200
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<application>
+ <id type="desktop">pithos.desktop</id>
+ CC0
+ GPL-3.0+
+ <description>
+ <p>Pithos is a easy to use native Pandora Radio client that is more lightweight than the pandora.com web client and integrates with the desktop.</p>
+ <p>It supports most functionality of pandora.com such as rating songs, creating/managing stations, quickmix, etc. On top of that it has features such as last.fm scrobbling, media keys, notifications, proxies, and mpris support.</p>
+ </description>
+ <url type="homepage">https://pithos.github.io</url>
+ <screenshots>
+ <screenshot type="default">https://i.imgur.com/1vl3Dsk.png</screenshot>
+ </screenshots>
+ <updatecontact>tingping_at_fedoraproject.org</updatecontact>
+</application>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/docs/conf.py new/pithos-1.0.1/docs/conf.py
--- old/pithos-1.0.0/docs/conf.py 1970-01-01 01:00:00.000000000 +0100
+++ new/pithos-1.0.1/docs/conf.py 2014-09-21 12:30:03.000000000 +0200
@@ -0,0 +1,234 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Pithos documentation build configuration file, created by
+# sphinx-quickstart on Mon Sep 15 20:13:58 2014.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'Pithos'
+copyright = '2014, Kevin Mehall'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Pithosdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'Pithos.tex', 'Pithos Documentation',
+ 'Kevin Mehall', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'pithos', 'Pithos Documentation',
+ ['Kevin Mehall'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'Pithos', 'Pithos Documentation',
+ 'Kevin Mehall', 'Pithos', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/docs/index.rst new/pithos-1.0.1/docs/index.rst
--- old/pithos-1.0.0/docs/index.rst 1970-01-01 01:00:00.000000000 +0100
+++ new/pithos-1.0.1/docs/index.rst 2014-09-21 12:30:03.000000000 +0200
@@ -0,0 +1,38 @@
+.. Pithos documentation master file, created by
+ sphinx-quickstart on Mon Sep 15 20:13:58 2014.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to Pithos's documentation!
+==================================
+
+Pandora
+-------
+
+.. autoclass:: pithos.pandora.Pandora
+ :members:
+ :undoc-members:
+
+.. autoclass:: pithos.pandora.Station
+ :members:
+ :undoc-members:
+
+.. autoclass:: pithos.pandora.Song
+ :members:
+ :undoc-members:
+
+.. autoclass:: pithos.pandora.SearchResult
+ :members:
+ :undoc-members:
+
+.. autoclass:: pithos.pandora.PandoraError
+ :members:
+ :undoc-members:
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/PreferencesPithosDialog.py new/pithos-1.0.1/pithos/PreferencesPithosDialog.py
--- old/pithos-1.0.0/pithos/PreferencesPithosDialog.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/PreferencesPithosDialog.py 2014-09-21 12:30:03.000000000 +0200
@@ -87,6 +87,8 @@
self.__preferences = {
"username":'',
"password":'',
+ "x_pos": None,
+ "y_pos": None,
"notify":True,
"last_station_id":None,
"proxy":'',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/__main__.py new/pithos-1.0.1/pithos/__main__.py
--- old/pithos-1.0.0/pithos/__main__.py 1970-01-01 01:00:00.000000000 +0100
+++ new/pithos-1.0.1/pithos/__main__.py 2014-09-21 12:30:03.000000000 +0200
@@ -0,0 +1,3 @@
+from pithos.pithos import main
+
+main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/data/ui/PithosWindow.ui new/pithos-1.0.1/pithos/data/ui/PithosWindow.ui
--- old/pithos-1.0.0/pithos/data/ui/PithosWindow.ui 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/data/ui/PithosWindow.ui 2014-09-21 12:30:03.000000000 +0200
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.16.0 -->
+<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.6"/>
- <requires lib="pithos_window" version="1.0"/>
+ <!-- interface-requires pithos_window 1.0 -->
<object class="GtkAdjustment" id="adjustment1">
<property name="upper">100</property>
<property name="step_increment">1</property>
@@ -17,6 +17,7 @@
<property name="icon_name">pithos</property>
<signal name="destroy" handler="on_destroy" swapped="no"/>
<signal name="key-press-event" handler="on_kb_playpause" swapped="no"/>
+ <signal name="configure-event" handler="on_configure_event" swapped="no"/>
<child>
<object class="GtkBox" id="vbox1">
<property name="visible">True</property>
@@ -243,7 +244,6 @@
<object class="GtkMessageDialog" id="api_update_dialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
- <property name="type">popup</property>
<property name="modal">True</property>
<property name="type_hint">dialog</property>
<property name="transient_for">pithos_window</property>
@@ -308,7 +308,6 @@
<object class="GtkMessageDialog" id="fatal_error_dialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
- <property name="type">popup</property>
<property name="modal">True</property>
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/mpris.py new/pithos-1.0.1/pithos/mpris.py
--- old/pithos-1.0.0/pithos/mpris.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/mpris.py 2014-09-21 12:30:03.000000000 +0200
@@ -96,8 +96,11 @@
def _get_volume(self):
return self.window.player.get_property("volume")
+ def _set_volume(self, new_volume):
+ self.window.player.set_property('volume', new_volume)
+
def _get_position(self):
- return self.window.player.query_position(self.window.time_format, None)[0] / 1000
+ return self.window.player.query_position(self.window.time_format)[0] / 1000
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v')
def Get(self, interface_name, property_name):
@@ -112,7 +115,8 @@
if interface_name == self.MEDIA_PLAYER2_IFACE:
pass
elif interface_name == self.MEDIA_PLAYER2_PLAYER_IFACE:
- pass # TODO: volume
+ if property_name == 'Volume':
+ self._set_volume(new_value)
else:
raise dbus.exceptions.DBusException(
'org.mpris.MediaPlayer2.pithos',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/pandora/__init__.py new/pithos-1.0.1/pithos/pandora/__init__.py
--- old/pithos-1.0.0/pithos/pandora/__init__.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/pandora/__init__.py 2014-09-21 12:30:03.000000000 +0200
@@ -14,7 +14,7 @@
#with this program. If not, see http://www.gnu.org/licenses/.
### END LICENSE
-from pithos.pandora.pandora import *
+from .pandora import *
def make_pandora(testing=False):
if testing:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/pandora/fake.py new/pithos-1.0.1/pithos/pandora/fake.py
--- old/pithos-1.0.0/pithos/pandora/fake.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/pandora/fake.py 2014-09-21 12:30:03.000000000 +0200
@@ -14,7 +14,7 @@
#with this program. If not, see http://www.gnu.org/licenses/.
### END LICENSE
-from pithos.pandora.pandora import *
+from .pandora import *
from gi.repository import Gtk
import logging
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/pandora/pandora.py new/pithos-1.0.1/pithos/pandora/pandora.py
--- old/pithos-1.0.0/pithos/pandora/pandora.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/pandora/pandora.py 2014-09-21 12:30:03.000000000 +0200
@@ -15,6 +15,11 @@
#with this program. If not, see http://www.gnu.org/licenses/.
### END LICENSE
+"""Pandora JSON v5 API
+
+See http://6xq.net/playground/pandora-apidoc/json/ for API documentation.
+"""
+
from .blowfish import Blowfish
# from Crypto.Cipher import Blowfish
from xml.dom import minidom
@@ -25,10 +30,6 @@
import urllib.request, urllib.parse, urllib.error
import codecs
-# This is an implementation of the Pandora JSON API using Android partner
-# credentials.
-# See http://pan-do-ra-api.wikia.com/wiki/Json/5 for API documentation.
-
HTTP_TIMEOUT = 30
USER_AGENT = 'pithos'
@@ -65,6 +66,17 @@
return s + b'\0' * (l - len(s))
class Pandora(object):
+ """Access the Pandora API
+
+ To use the Pandora class, make sure to call :py:meth:`set_audio_quality`
+ and :py:meth:`connect` methods.
+
+ Get information from Pandora using:
+
+ - :py:meth:`get_stations` which populates the :py:attr:`stations` attribute
+ - :py:meth:`search` to find songs to add to stations or create a new station with
+ - :py:meth:`json_call` call into the JSON API directly
+ """
def __init__(self):
self.opener = urllib.request.build_opener()
pass
@@ -131,7 +143,7 @@
raise PandoraAuthTokenInvalid(msg)
elif code == API_ERROR_COUNTRY_NOT_SUPPORTED:
raise PandoraError("Pandora not available", code,
- submsg="Pandora is not available outside the United States.")
+ submsg="Pandora is not available in your country.")
elif code == API_ERROR_API_VERSION_NOT_SUPPORTED:
raise PandoraAPIVersionError(msg)
elif code == API_ERROR_INSUFFICIENT_CONNECTIVITY:
@@ -158,12 +170,24 @@
return tree['result']
def set_audio_quality(self, fmt):
+ """Set the desired audio quality
+
+ Used by the :py:attr:`Song.audioUrl` property.
+
+ :param fmt: An audio quality format from :py:data:`pithos.pandora.data.valid_audio_formats`
+ """
self.audio_quality = fmt
def set_url_opener(self, opener):
self.opener = opener
def connect(self, client, user, password):
+ """Connect to the Pandora API and log the user in
+
+ :param client: The client ID from :py:data:`pithos.pandora.data.client_keys`
+ :param user: The user's login email
+ :param password: The user's login password
+ """
self.partnerId = self.userId = self.partnerAuthToken = None
self.userAuthToken = self.time_offset = None
@@ -201,6 +225,8 @@
if i.id in self.quickMixStationIds:
i.useQuickMix = True
+ return self.stations
+
def save_quick_mix(self):
stationIds = []
for i in self.stations:
@@ -281,6 +307,14 @@
logging.info("pandora: Deleting Station")
self.pandora.json_call('station.deleteStation', {'stationToken': self.idToken})
+ def __repr__(self):
+ return '<{}.{} {} "{}">'.format(
+ __name__,
+ __class__.__name__,
+ self.id,
+ self.name,
+ )
+
class Song(object):
def __init__(self, pandora, d):
self.pandora = pandora
@@ -378,6 +412,16 @@
def is_still_valid(self):
return (time.time() - self.playlist_time) < PLAYLIST_VALIDITY_TIME
+ def __repr__(self):
+ return '<{}.{} {} "{}" by "{}" from "{}">'.format(
+ __name__,
+ __class__.__name__,
+ self.trackToken,
+ self.songName,
+ self.artist,
+ self.album,
+ )
+
class SearchResult(object):
def __init__(self, resultType, d):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/pithos.py new/pithos-1.0.1/pithos/pithos.py
--- old/pithos-1.0.0/pithos/pithos.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/pithos.py 2014-09-21 12:30:03.000000000 +0200
@@ -23,7 +23,7 @@
import gi
gi.require_version('Gst', '1.0')
-from gi.repository import Gst, GObject, Gtk, Gdk, Pango, GdkPixbuf, Gio, GLib
+from gi.repository import Gst, GstPbutils, GObject, Gtk, Gdk, Pango, GdkPixbuf, Gio, GLib
import contextlib
import html
import math
@@ -201,6 +201,7 @@
bus.connect("message::eos", self.on_gst_eos)
bus.connect("message::buffering", self.on_gst_buffering)
bus.connect("message::error", self.on_gst_error)
+ bus.connect("message::element", self.on_gst_element)
bus.connect("message::tag", self.on_gst_tag)
self.player.connect("notify::volume", self.on_gst_volume)
self.player.connect("notify::source", self.on_gst_source)
@@ -284,6 +285,8 @@
self.stations_combo.add_attribute(render_text, "text", 1)
self.stations_combo.set_row_separator_func(lambda model, iter, data=None: model.get_value(iter, 0) is None, None)
+ self.set_initial_pos()
+
def worker_run(self, fn, args=(), callback=None, message=None, context='net'):
if context and message:
self.statusbar.push(self.statusbar.get_context_id(context), message)
@@ -353,15 +356,24 @@
elif control_proxy_pac and pacparser_imported:
pacparser.init()
- pacparser.parse_pac_string(urllib.request.urlopen(control_proxy_pac).read())
- proxies = pacparser.find_proxy("http://pandora.com", "pandora.com").split(";")
- for proxy in proxies:
- match = re.search("PROXY (.*)", proxy)
- if match:
- control_proxy = match.group(1)
- break
+ with urllib.request.urlopen(control_proxy_pac) as f:
+ pacstring = f.read().decode('utf-8')
+ try:
+ pacparser.parse_pac_string(pacstring)
+ except:
+ logging.warning('Failed to parse PAC.')
+ try:
+ proxies = pacparser.find_proxy("http://pandora.com", "pandora.com").split(";")
+ for proxy in proxies:
+ match = re.search("PROXY (.*)", proxy)
+ if match:
+ control_proxy = match.group(1)
+ break
+ except:
+ logging.warning('Failed to find proxy via PAC.')
+ pacparser.cleanup()
elif control_proxy_pac and not pacparser_imported:
- logging.warn("Disabled proxy auto-config support because python-pacparser module was not found.")
+ logging.warning("Disabled proxy auto-config support because python-pacparser module was not found.")
self.worker_run('set_url_opener', (control_opener,))
@@ -572,6 +584,10 @@
dialog.props.secondary_text = submsg
dialog.set_default_response(3)
+ if retry_cb is None:
+ btn = self.builder.get_object("button2")
+ btn.hide()
+
response = dialog.run()
dialog.hide()
@@ -622,19 +638,34 @@
logging.info("EOS")
self.next_song()
+ def on_gst_plugin_installed(self, result, userdata):
+ if result == GstPbutils.InstallPluginsReturn.SUCCESS:
+ self.fatal_error_dialog("Codec installation successful",
+ submsg="The required codec was installed, please restart Pithos.")
+ else:
+ self.error_dialog("Codec installation failed", None,
+ submsg="The required codec failed to install. Either manually install it or try another quality setting.")
+
+ def on_gst_element(self, bus, message):
+ if GstPbutils.is_missing_plugin_message(message):
+ if GstPbutils.install_plugins_supported():
+ details = GstPbutils.missing_plugin_message_get_installer_detail(message)
+ GstPbutils.install_plugins_async([details,], None, self.on_gst_plugin_installed, None)
+ else:
+ self.error_dialog("Missing codec", None,
+ submsg="GStreamer is missing a plugin and it could not be automatically installed. Either manually install it or try another quality setting.")
+
def on_gst_error(self, bus, message):
err, debug = message.parse_error()
logging.error("Gstreamer error: %s, %s, %s" % (err, debug, err.code))
if self.current_song:
self.current_song.message = "Error: "+str(err)
- #if err.code is int(Gst.CORE_ERROR_MISSING_PLUGIN):
- # self.fatal_error_dialog("Missing codec", submsg="GStreamer is missing a plugin")
- # return
-
self.gstreamer_error = str(err)
self.gstreamer_errorcount_1 += 1
- self.next_song()
+
+ if not GstPbutils.install_plugins_installation_in_progress():
+ self.next_song()
def gst_tag_handler(self, tag_info):
def handler(_x, tag, _y):
@@ -951,10 +982,20 @@
def refresh_stations(self, *ignore):
self.worker_run(self.pandora.get_stations, (), self.process_stations, "Refreshing stations...")
+ def set_initial_pos(self):
+ """ Moves window to position stored in preferences """
+ x, y = self.preferences['x_pos'], self.preferences['y_pos']
+ if not x is None and not y is None:
+ self.move(int(x), int(y))
+
def bring_to_top(self, *ignore):
+ self.set_initial_pos()
self.show()
self.present()
+ def on_configure_event(self, widget, event):
+ self.preferences['x_pos'], self.preferences['y_pos'] = event.x, event.y
+
def on_kb_playpause(self, widget=None, data=None):
if not isinstance(widget.get_focus(), Gtk.Button) and data.keyval == 32:
self.playpause()
@@ -1053,7 +1094,7 @@
def do_shutdown(self):
Gtk.Application.do_shutdown(self)
- self.quit()
+ self.window.destroy()
def stations_cb(self, action, param):
self.window.show_stations()
@@ -1065,7 +1106,7 @@
self.window.show_about()
def quit_cb(self, action, param):
- self.quit()
+ self.window.destroy()
def main():
app = PithosApplication()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/pithosconfig.py new/pithos-1.0.1/pithos/pithosconfig.py
--- old/pithos-1.0.0/pithos/pithosconfig.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/pithosconfig.py 2014-09-21 12:30:03.000000000 +0200
@@ -19,7 +19,7 @@
__pithos_data_directory__ = 'data/'
__license__ = 'GPL-3'
-VERSION = '1.0.0'
+VERSION = '1.0.1'
import os
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/plugins/mediakeys.py new/pithos-1.0.1/pithos/plugins/mediakeys.py
--- old/pithos-1.0.0/pithos/plugins/mediakeys.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/plugins/mediakeys.py 2014-09-21 12:30:03.000000000 +0200
@@ -22,7 +22,7 @@
class MediaKeyPlugin(PithosPlugin):
preference = 'enable_mediakeys'
-
+
def bind_dbus(self):
try:
import dbus
@@ -86,12 +86,42 @@
self.hookman.KeyDown = self.kbevent
self.hookman.HookKeyboard()
return True
+
+ def osx_playpause_handler(self):
+ self.window.playpause_notify()
+ return False # Don't let others get event
+
+ def osx_skip_handler(self):
+ self.window.next_song()
+ return False
+
+ def bind_osx(self):
+ try:
+ import osxmmkeys
+ except ImportError:
+ logging.warning('Please install osxmmkeys: https://github.com/pushrax/osxmmkeys')
+ return False
+ except RuntimeError as e:
+ logging.warning('osxmmkeys failed to import: {}'.format(e))
+ return False
+
+ tap = osxmmkeys.Tap()
+ tap.on('play_pause', self.osx_playpause_handler)
+ tap.on('next_track', self.osx_skip_handler)
+ tap.start()
+
+ return True
def on_enable(self):
if sys.platform == 'win32':
- self.bind_win32() or logging.error("Could not bind media keys")
+ loaded = self.bind_win32()
+ elif sys.platform == 'darwin':
+ loaded = self.bind_osx()
else:
- self.bind_dbus() or self.bind_keybinder() or logging.error("Could not bind media keys")
+ loaded = self.bind_dbus() or self.bind_keybinder()
+
+ if not loaded:
+ logging.error("Could not bind media keys")
def on_disable(self):
logging.error("Not implemented: Can't disable media keys")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/plugins/notification_icon.py new/pithos-1.0.1/pithos/plugins/notification_icon.py
--- old/pithos-1.0.0/pithos/plugins/notification_icon.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/plugins/notification_icon.py 2014-09-21 12:30:03.000000000 +0200
@@ -40,7 +40,6 @@
get_data_file('media'))
def on_enable(self):
- self.visible = True
self.delete_callback_handle = self.window.connect("delete-event", self.toggle_visible)
self.state_callback_handle = self.window.connect("play-state-changed", self.play_state_changed)
self.song_callback_handle = self.window.connect("song-changed", self.song_changed)
@@ -131,16 +130,14 @@
self.statusicon.set_tooltip_text("%s by %s"%(song.title, song.artist))
def _toggle_visible(self, *args):
- if self.visible:
- self.window.hide()
- else:
+ self.window.set_visible(not self.window.get_visible())
+
+ if self.window.get_visible(): # Ensure it's on top
self.window.bring_to_top()
- self.visible = not self.visible
-
def toggle_visible(self, *args):
if hasattr(self, 'visible_check'):
- self.visible_check.set_active(not self.visible)
+ self.visible_check.set_active(not self.window.get_visible())
else:
self._toggle_visible()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/plugins/notify.py new/pithos-1.0.1/pithos/plugins/notify.py
--- old/pithos-1.0.0/pithos/plugins/notify.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/plugins/notify.py 2014-09-21 12:30:03.000000000 +0200
@@ -16,6 +16,7 @@
import logging
import html
+from sys import platform
from pithos.plugin import PithosPlugin
from pithos.pithosconfig import get_data_file
from gi.repository import (GLib, Gtk)
@@ -23,13 +24,29 @@
class NotifyPlugin(PithosPlugin):
preference = 'notify'
- has_notify = False
+ has_notifications = False
supports_actions = False
def on_prepare(self):
+ if platform == 'darwin':
+ self.prepare_osx()
+ else:
+ self.prepare_notify()
+
+ def prepare_osx(self):
+ try:
+ from pync import Notifier
+ self.has_notifications = True
+ except ImportError:
+ logging.warning("pync not found.")
+ return
+
+ self.notifier = Notifier
+
+ def prepare_notify(self):
try:
from gi.repository import Notify
- self.has_notify = True
+ self.has_notifications = True
except ImportError:
logging.warning ("libnotify not found.")
return
@@ -62,7 +79,7 @@
# self.notification.set_hint('resident', GLib.Variant.new_boolean(True))
def on_enable(self):
- if self.has_notify:
+ if self.has_notifications:
self.song_callback_handle = self.window.connect("song-changed", self.song_changed)
self.state_changed_handle = self.window.connect("user-changed-play-state", self.playstate_changed)
@@ -87,7 +104,7 @@
self.notification.add_action(skip_action, 'Skip',
self.notification_skip_cb, None)
- def set_notification(self, song, playing=True):
+ def set_notification_notify(self, song, playing):
if self.supports_actions:
self.set_actions(playing)
@@ -100,6 +117,18 @@
self.notification.update(song.title, msg, 'audio-x-generic')
self.notification.show()
+ def set_notification_osx(self, song, playing):
+ # TODO: Icons (buttons not possible?)
+ if playing:
+ self.notifier.notify('by {} from {}'.format(song.artist, song.album),
+ title=song.title)
+
+ def set_notification(self, song, playing=True):
+ if platform == 'darwin':
+ self.set_notification_osx(song, playing)
+ else:
+ self.set_notification_notify(song, playing)
+
def notification_playpause_cb(self, notification, action, data, ignore=None):
self.window.playpause_notify()
@@ -115,6 +144,6 @@
GLib.idle_add(self.set_notification, window.current_song, state)
def on_disable(self):
- if self.has_notify:
+ if self.has_notifications:
self.window.disconnect(self.song_callback_handle)
self.window.disconnect(self.state_changed_handle)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/pithos/plugins/screensaver_pause.py new/pithos-1.0.1/pithos/plugins/screensaver_pause.py
--- old/pithos-1.0.0/pithos/plugins/screensaver_pause.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/pithos/plugins/screensaver_pause.py 2014-09-21 12:30:03.000000000 +0200
@@ -1,29 +1,30 @@
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
### BEGIN LICENSE
# Copyright (C) 2010-2012 Kevin Mehall
-#This program is free software: you can redistribute it and/or modify it
-#under the terms of the GNU General Public License version 3, as published
+#This program is free software: you can redistribute it and/or modify it
+#under the terms of the GNU General Public License version 3, as published
#by the Free Software Foundation.
#
-#This program is distributed in the hope that it will be useful, but
-#WITHOUT ANY WARRANTY; without even the implied warranties of
-#MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+#This program is distributed in the hope that it will be useful, but
+#WITHOUT ANY WARRANTY; without even the implied warranties of
+#MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
#PURPOSE. See the GNU General Public License for more details.
#
-#You should have received a copy of the GNU General Public License along
+#You should have received a copy of the GNU General Public License along
#with this program. If not, see http://www.gnu.org/licenses/.
### END LICENSE
from pithos.plugin import PithosPlugin
import logging
-
+dbus = None
class ScreenSaverPausePlugin(PithosPlugin):
preference = 'enable_screensaverpause'
session_bus = None
-
+
def bind_session_bus(self):
+ global dbus
try:
import dbus
except ImportError:
@@ -34,13 +35,16 @@
return True
except dbus.DBusException:
return False
-
+
def on_enable(self):
if not self.bind_session_bus():
logging.error("Could not bind session bus")
return
self.connect_events() or logging.error("Could not connect events")
+ self.locked = 0
+ self.wasplaying = False
+
def on_disable(self):
if self.session_bus:
self.disconnect_events()
@@ -49,9 +53,16 @@
def connect_events(self):
try:
- self.session_bus.add_signal_receiver(self.playPause, 'ActiveChanged', 'org.gnome.ScreenSaver')
- self.session_bus.add_signal_receiver(self.playPause, 'ActiveChanged', 'org.cinnamon.ScreenSaver')
- self.session_bus.add_signal_receiver(self.playPause, 'ActiveChanged', 'org.freedesktop.ScreenSaver')
+ self.receivers = [
+ self.session_bus.add_signal_receiver(*args)
+ for args in ((self.playPause, 'ActiveChanged', 'org.gnome.ScreenSaver'),
+ (self.playPause, 'ActiveChanged', 'org.cinnamon.ScreenSaver'),
+ (self.playPause, 'ActiveChanged', 'org.freedesktop.ScreenSaver'),
+ (self.pause, 'Locked', 'com.canonical.Unity.Session'),
+ (self.play, 'Unlocked', 'com.canonical.Unity.Session'),
+ )
+ ]
+
return True
except dbus.DBusException:
logging.info("Enable failed")
@@ -59,18 +70,27 @@
def disconnect_events(self):
try:
- self.session_bus.remove_signal_receiver(self.playPause, 'ActiveChanged', 'org.gnome.ScreenSaver')
- self.session_bus.remove_signal_receiver(self.playPause, 'ActiveChanged', 'org.cinnamon.ScreenSaver')
- self.session_bus.remove_signal_receiver(self.playPause, 'ActiveChanged', 'org.freedesktop.ScreenSaver')
+ for r in self.receivers:
+ r.remove()
return True
except dbus.DBusException:
return False
-
-
- def playPause(self,state):
- if not state:
- if self.wasplaying:
- self.window.user_play()
- else:
+
+ def play(self):
+ self.locked -= 1
+ if self.locked < 0:
+ self.locked = 0
+ if not self.locked and self.wasplaying:
+ self.window.user_play()
+
+ def pause(self):
+ if not self.locked:
self.wasplaying = self.window.playing
self.window.pause()
+ self.locked += 1
+
+ def playPause(self, screensaver_on):
+ if screensaver_on:
+ self.pause()
+ else:
+ self.play()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/requirements-osx.txt new/pithos-1.0.1/requirements-osx.txt
--- old/pithos-1.0.0/requirements-osx.txt 1970-01-01 01:00:00.000000000 +0100
+++ new/pithos-1.0.1/requirements-osx.txt 2014-09-21 12:30:03.000000000 +0200
@@ -0,0 +1,11 @@
+# scrobble
+pylast
+
+# notify
+pync
+
+# mediakeys
+pyobjc-core
+pyobjc-framework-Cocoa
+pyobjc-framework-Quartz
+osxmmkeys
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pithos-1.0.0/setup.py new/pithos-1.0.1/setup.py
--- old/pithos-1.0.0/setup.py 2014-05-02 00:33:16.000000000 +0200
+++ new/pithos-1.0.1/setup.py 2014-09-21 12:30:03.000000000 +0200
@@ -18,11 +18,27 @@
###################### DO NOT TOUCH THIS (HEAD TO THE SECOND PART) ######################
try:
- from setuptools import setup, find_packages
+ from setuptools import setup, find_packages, Command
except ImportError:
import ez_setup
ez_setup.use_setuptools()
- from setuptools import setup, find_packages
+ from setuptools import setup, find_packages, Command
+
+try:
+ from sphinx.setup_command import BuildDoc
+except ImportError:
+ class BuildDoc(Command):
+ description = "Build documentation with Sphinx."
+ user_options = []
+ version = None
+ release = None
+
+ def initialize_options(self):
+ pass
+ def finalize_options(self):
+ pass
+ def run(self):
+ print("Error: Sphinx not found!")
import os
import sys
@@ -41,6 +57,7 @@
('/usr/share/icons/hicolor/48x48/apps', ['data/icons/hicolor/pithos-tray-icon.png']),
('/usr/share/icons/ubuntu-mono-dark/apps/16', ['data/icons/ubuntu-mono-dark/pithos-tray-icon.svg']),
('/usr/share/icons/ubuntu-mono-light/apps/16', ['data/icons/ubuntu-mono-light/pithos-tray-icon.svg']),
+ ('/usr/share/appdata', ['data/pithos.appdata.xml']),
('/usr/share/applications', ['data/pithos.desktop'])
]
else:
@@ -64,6 +81,15 @@
'Programming Language :: Python',
'Programming Language :: Python :: 3'
],
+ cmdclass={
+ 'build_doc': BuildDoc
+ },
+ command_options={
+ 'build_doc': {
+ 'version': ('setup.py', VERSION),
+ 'release': ('setup.py', VERSION)
+ }
+ },
data_files=data_files,
package_data={
'pithos': [
--
To unsubscribe, e-mail: opensuse-commit+unsubscribe@opensuse.org
For additional commands, e-mail: opensuse-commit+help@opensuse.org