Merge lp:~ahayzen/cappella/cappella10_play_stream_2 into lp:cappella

Proposed by Andrew Hayzen
Status: Merged
Approved by: Andrew Hayzen
Approved revision: 99
Merged at revision: 99
Proposed branch: lp:~ahayzen/cappella/cappella10_play_stream_2
Merge into: lp:cappella
Diff against target: 314 lines (+145/-28)
8 files modified
cappella/data/default/format.js (+2/-0)
cappella/data/glade/open_file_dialogs.ui (+1/-1)
cappella/gui/widget/play_queue.py (+3/-3)
cappella/library/podcast_web.py (+1/-13)
cappella/library/stream.py (+90/-6)
cappella/management/media.py (+3/-3)
cappella/tool/media.py (+8/-2)
cappella/tool/parser.py (+37/-0)
To merge this branch: bzr merge lp:~ahayzen/cappella/cappella10_play_stream_2
Reviewer Review Type Date Requested Status
Andrew Hayzen Approve
Review via email: mp+161356@code.launchpad.net

Description of the change

* Added basic support for .asx and .m3u formats

To post a comment you must log in.
Revision history for this message
Andrew Hayzen (ahayzen) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cappella/data/default/format.js'
2--- cappella/data/default/format.js 2013-04-28 18:40:19 +0000
3+++ cappella/data/default/format.js 2013-04-29 03:13:27 +0000
4@@ -1,8 +1,10 @@
5 {
6 "aac": {"audio": true, "video": false},
7+ "asx": {"audio": true, "video": false},
8 "avi": {"audio": false, "video": true},
9 "flac": {"audio": true, "video": false},
10 "flv": {"audio": false, "video": true},
11+ "m3u": {"audio": true, "video": false},
12 "m4a": {"audio": true, "video": false},
13 "mp3": {"audio": true, "video": false},
14 "mp4": {"audio": false, "video": true},
15
16=== modified file 'cappella/data/glade/open_file_dialogs.ui'
17--- cappella/data/glade/open_file_dialogs.ui 2013-04-28 19:00:58 +0000
18+++ cappella/data/glade/open_file_dialogs.ui 2013-04-29 03:13:27 +0000
19@@ -188,7 +188,7 @@
20 <property name="skip_taskbar_hint">True</property>
21 <property name="buttons">ok-cancel</property>
22 <property name="text" translatable="yes">Please enter the address of the stream</property>
23- <property name="secondary_text" translatable="yes">This should either be a .pls file or a direct stream</property>
24+ <property name="secondary_text" translatable="yes">This should either be a .asx, .m3u, .pls or a direct stream</property>
25 <child internal-child="vbox">
26 <object class="GtkBox" id="messagedialog-vbox">
27 <property name="can_focus">False</property>
28
29=== modified file 'cappella/gui/widget/play_queue.py'
30--- cappella/gui/widget/play_queue.py 2013-04-28 18:40:19 +0000
31+++ cappella/gui/widget/play_queue.py 2013-04-29 03:13:27 +0000
32@@ -22,7 +22,7 @@
33 from ...config.cappella import settings
34 from ...signalhandler import signal
35 from ...tool import skipx, thread_safe
36-from ...tool.media import process_pls
37+from ...tool.media import is_playlist, process_playlist
38
39
40 class PlayQueue():
41@@ -129,8 +129,8 @@
42
43 @thread_safe
44 def on_playqueue_add_int(self, uri, library, view):
45- if uri.endswith(".pls"):
46- uri = process_pls(uri)
47+ if is_playlist(uri):
48+ uri = process_playlist(uri)
49
50 if type(uri) is list:
51 # Add uris to play queue
52
53=== modified file 'cappella/library/podcast_web.py'
54--- cappella/library/podcast_web.py 2013-04-02 22:48:35 +0000
55+++ cappella/library/podcast_web.py 2013-04-29 03:13:27 +0000
56@@ -20,7 +20,6 @@
57
58 from gi.repository import GdkPixbuf
59 from html.parser import HTMLParser
60-from xml.dom import minidom
61 from xml.etree import ElementTree
62 from urllib.request import urlopen
63
64@@ -28,21 +27,10 @@
65 from ..management.library import (LibraryType, LibraryPurpose, LibraryMode,
66 LibraryFileType)
67 from ..tool.metatag import MetaParser
68+from ..tool.parser import FeedToXml
69
70
71 #-------------------------------------- Helper classes for RSS->Dict Conversion
72-class FeedToXml():
73- """ Read XML and parse from URL """
74- def __init__(self, url):
75- self.stream = urlopen(url)
76-
77- self.obj = minidom.parse(self.stream)
78-
79- *proc, dom = self.obj.childNodes
80-
81- self.xml = dom.toprettyxml()
82-
83-
84 class XmlToInfo():
85 def __init__(self, xml_stream, uri):
86 self.root = ElementTree.fromstring(xml_stream)
87
88=== modified file 'cappella/library/stream.py'
89--- cappella/library/stream.py 2013-04-28 18:49:59 +0000
90+++ cappella/library/stream.py 2013-04-29 03:13:27 +0000
91@@ -20,7 +20,10 @@
92
93 from ..management.library import LibraryType, LibraryPurpose, LibraryMode
94 from ..signalhandler import signal
95+from ..tool.media import is_playlist
96+from ..tool.parser import FeedToXml
97 from urllib.request import urlopen
98+from xml.etree import ElementTree
99
100
101 class StreamLibrary():
102@@ -53,9 +56,10 @@
103 def copy(self, uri):
104 """ Get a stream for the uri in the library (name) specified """
105
106- if (not uri.startswith("http://") and
107- (not uri.startswith("file://") and not ".pls" not in uri)):
108- raise ValueError("URI should start with http:// or ends with .pls")
109+ if (not uri.startswith("http://") and not uri.startswith("mms://") and
110+ (not uri.startswith("file://") and is_playlist(uri))):
111+ raise ValueError("URI should start with http:// or contains .pls, "
112+ ".asx, .m3u")
113
114 f = urlopen(uri)
115
116@@ -86,9 +90,10 @@
117 def get(self, uri):
118 """ Get the info about a uri in the library (name) specified """
119
120- if (not uri.startswith("http://") and
121- (not uri.startswith("file://") and ".pls" not in uri)):
122- raise ValueError("URI should start with http:// or ends with .pls")
123+ if (not uri.startswith("http://") and not uri.startswith("mms://") and
124+ (not uri.startswith("file://") and is_playlist(uri))):
125+ raise ValueError("URI should start with http:// or contains .pls, "
126+ ".asx, .m3u")
127
128 files = {}
129
130@@ -134,6 +139,85 @@
131 return {"title": uri, "uri": uri}
132 else:
133 return output
134+ elif ".asx" in uri:
135+ # Read .asx file
136+ if uri.startswith("http://"):
137+ stream = urlopen(uri)
138+ else:
139+ stream = open(uri[7:])
140+
141+ xml_stream = FeedToXml(data=stream).xml
142+
143+ root = ElementTree.fromstring(xml_stream)
144+
145+ try:
146+ title = root.find("TITLE").text
147+ except AttributeError:
148+ title = None
149+
150+ try:
151+ artist = root.find("AUTHOR").text
152+ except AttributeError:
153+ artist = None
154+
155+ output = []
156+
157+ for item in root.findall("Entry"):
158+ info = {"title": title, "artist": artist}
159+
160+ try:
161+ ref = item.find("ref")
162+
163+ try:
164+ info["uri"] = ref.attrib["href"]
165+ except KeyError:
166+ continue
167+ except AttributeError:
168+ continue
169+
170+ output.append(info)
171+
172+ self.cache[info["uri"]] = {"raw_uri": uri, "title": title,
173+ "artist": artist}
174+
175+ if len(output) > 0:
176+ return output
177+ elif ".m3u" in uri:
178+ # Read .pls file
179+ if uri.startswith("http://"):
180+ data = urlopen(uri).read().decode("utf")
181+ else:
182+ data = open(uri[7:]).read()
183+
184+ # Read data from the .pls file
185+ title, artist = None, None
186+ output = []
187+
188+ for line in data.split("\n"):
189+ if line.startswith("#EXTINF"):
190+ value = line.split(",")[1].split("-")
191+
192+ if len(value) == 2:
193+ artist, title = value
194+ else:
195+ title = value[0]
196+ elif line.startswith("#"):
197+ continue
198+ elif line.strip() == "":
199+ continue
200+ else:
201+ info = {"title": title or uri, "artist": artist,
202+ "uri": line}
203+
204+ output.append(info)
205+ self.cache[line] = {"title": title or uri,
206+ "artist": artist,
207+ "raw_uri": uri}
208+
209+ title, artist = None, None
210+
211+ if len(output) > 0:
212+ return output
213
214 if uri in self.cache:
215 info = self.cache[uri]
216
217=== modified file 'cappella/management/media.py'
218--- cappella/management/media.py 2013-04-28 18:56:14 +0000
219+++ cappella/management/media.py 2013-04-29 03:13:27 +0000
220@@ -21,7 +21,7 @@
221 from ..config.cappella import settings
222 from ..signalhandler import signal
223 from ..tool import skipx
224-from ..tool.media import process_pls
225+from ..tool.media import is_playlist, process_playlist
226
227
228 class Management():
229@@ -273,8 +273,8 @@
230 signal.emit("_musicengine_stop_") # Stop playing items
231
232 # Check is playable file (eg get uri from pls)
233- if ".pls" in uri:
234- uri = process_pls(uri)
235+ if is_playlist(uri):
236+ uri = process_playlist(uri)
237 library = "stream_library"
238
239 if type(uri) is list:
240
241=== modified file 'cappella/tool/media.py'
242--- cappella/tool/media.py 2013-04-28 18:49:59 +0000
243+++ cappella/tool/media.py 2013-04-29 03:13:27 +0000
244@@ -73,6 +73,12 @@
245 return False
246
247
248+def is_playlist(uri):
249+ """ Check if the uri is a playlist """
250+
251+ return ".pls" in uri or ".asx" in uri or ".m3u" in uri
252+
253+
254 def is_video(uri):
255 """ Return True is uri is video """
256
257@@ -92,12 +98,12 @@
258 return False
259
260
261-def process_pls(uri):
262+def process_playlist(uri):
263 # Get files from .pls
264 library = "stream_library"
265 info = signal.get_object("library").get(library, uri)
266
267- if type(info) is list: # Some pls are playlists
268+ if type(info) is list: # Some multisong
269 return info
270 else:
271 uri = info["uri"]
272
273=== added file 'cappella/tool/parser.py'
274--- cappella/tool/parser.py 1970-01-01 00:00:00 +0000
275+++ cappella/tool/parser.py 2013-04-29 03:13:27 +0000
276@@ -0,0 +1,37 @@
277+#!/usr/bin/env python3
278+'''
279+ Copyright (C) 2011-2013 Andrew Hayzen and Simon Bull.
280+
281+ Cappella is a simple media player based on PyGObject for Ubuntu.
282+
283+ This file is free software: you can redistribute it and/or modify it
284+ under the terms of the GNU General Public License as published by the
285+ Free Software Foundation, either version 3 of the License,
286+ or (at your option) any later version.
287+
288+ This file is distributed in the hope that it will be useful, but WITHOUT
289+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
290+ FITNESS FOR A PARTICULAR PURPOSE. See the
291+ GNU General Public License for more details.
292+
293+ You should have received a copy of the GNU General Public License along with
294+ this file. If not, see <http://www.gnu.org/licenses/>.
295+'''
296+
297+from urllib.request import urlopen
298+from xml.dom import minidom
299+
300+
301+class FeedToXml():
302+ """ Read XML and parse from URL """
303+ def __init__(self, url=None, data=None):
304+ if url is not None:
305+ self.stream = urlopen(url)
306+ else:
307+ self.stream = data
308+
309+ self.obj = minidom.parse(self.stream)
310+
311+ *proc, dom = self.obj.childNodes
312+
313+ self.xml = dom.toprettyxml()
314\ No newline at end of file

Subscribers

People subscribed via source and target branches

to all changes: