metadata

Check-in [3d69813d77]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Bringup; getting metadata from Radio Paradise out to clients
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:3d69813d770fdcce266a738b3acddaf8e6e68f7cde58240b23c34de6b2260fca
User & Date: vashon 2018-06-18 23:53:47
Context
2018-06-19
16:55
Tighten whitespace stripping. Test idle timeout. check-in: a0023c3b13 user: vashon tags: trunk
2018-06-18
23:53
Bringup; getting metadata from Radio Paradise out to clients check-in: 3d69813d77 user: vashon tags: trunk
22:58
Bringup check-in: 9e3a6abf61 user: vashon tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to stream.py.

1
2
3
4
5



6
7
8
9
10
11
12
13
14
15
16
17
18
..
65
66
67
68
69
70
71


















72
73
74
75
76
77
78
79
80
81
82



83
84
85
86
87
88
89
90
91
92
93

94
95
96
97
98
99
100
...
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
...
124
125
126
127
128
129
130
131
132
133
134
135
136

137
138
139
140
141
142
143
144
145
146
147
148



149
150
151
152
153
154
155
...
156
157
158
159
160
161
162

163
164



165
166
167
168
169
170
171
172
173
174
175
176
177
178
#
# stream.py
#	Code for serving metadata on a  given stream
#
import sys, threading, json, urlparse, time, socket




# How many seconds of non-use of a stream before we shut it down
IDLE=600.0

# HTTP headers to get Icecast metadata
Args = """icy-metadata: 1\r
User-Agent: mplayer-metadata\r
"""


# All the state for a given stream
class Stream(object):
    def __init__(self, sym, url):
................................................................................

    # Wake up all waiters
    def wakeups(self):
	ws = tuple(self.waiters)
	del self.waiters[:]
	for sema in ws:
	    sema.release()



















    # Pull from a stream with Icecast metadata.
    # Because Icecast metadata is kind of a hairball of legacy and
    #  modern, we just talk TCP to it ourselves.
    # This function only returns on errors like aborted streams.
    # On idle timeout, it simply exits after clearing itself
    #  from the stream state.
    def watch(self):
	global IDLE

	# Request it



	s.send("GET %s HTTP/1.0\r\n%s\r\n" %
	    (self.path, Args))

	# Assemble the HTTP response headers.  We'll likely have
	#  more than that, which will be passed down to the loop
	#  below.
	res = ""
	headers = {}
	hdone = False
	while not hdone:
	    l = self.readline()

	    if l is None:
		return
	    if not l:
		# Empty line, followed by HTTP response body
		break

	    # Malformed line
................................................................................

	    # key: value...
	    idx = l.index(':')
	    k = l[:idx].strip().lower()
	    v = l[idx+1:].strip()

	    # Register another header line
	    res[k] = v


	# See if this stream does indeed supply Icecast metadata
	if "icy-metaint" not in headers:
	    sys.stderr.write("No icy-metaint for %s\n" % (self.host,))
	    return
	try:
	    mi = headers["icy-metaint"]
................................................................................
	    sys.stderr.write("Spurious icy-metaint for %s: %d\n" %
		(self.host, intvl))
	    return

	# Now scoop up parcels of "intvl", then grab a metadata update
	while True:
	    # Skip this much
	    try:
		buf = s.recv(intvl)
	    except:
		return
	    if len(buf) != intvl:
		sys.stderr.write("Skipping data got %d\n" % (len(buf),))

		return

	    # An initial byte is the number of 16-byte chunks in
	    #  the stream.
	    try:
		c = s.recv(1)
	    except:
		return
	    if not c:
		sys.stderr.write("No metadata size byte\n")
		return
	    paksize = (ord(c) << 4)




	    # No metadata update needed yet
	    if not paksize:
		continue
	    try:
		buf = s.recv(paksize)
	    except:
................................................................................
		return
	    if len(buf) != paksize:
		sys.stderr.write("metadata got %d\n" % (len(buf),))
		return
	    buf = buf.strip()

	    # Decode metadata into a dict for JSON purposes

	    res = {}
	    for s in buf.split(';'):



		if '=' not in s:
		    sys.stderr.write("Malformed %s from %s\n" %
			(s, self.host))
		    continue
		idx = s.index('=')
		k = s[:idx].strip()
		v = s[idx+1:].strip()
		if v[0] == "'":
		    v = v[1:]
		    if v[-1] == "'":
			v = v[:-1]
		res[k] = v
	    
	    if not res:




|
>
>
>





|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








|


>
>
>

|




<

<
|

>







 







|
>







 







<
|
<
<
<
<
>












>
>
>







 







>

|
>
>
>
|

|

|
|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

113

114
115
116
117
118
119
120
121
122
123
...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
...
148
149
150
151
152
153
154

155




156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#
# stream.py
#	Code for serving metadata on a  given stream
#
import sys, threading, json, urlparse, time, socket, string

# We want to strip null bytes as well
Whitespace = string.whitespace + "\x00"

# How many seconds of non-use of a stream before we shut it down
IDLE=600.0

# HTTP headers to get Icecast metadata
Args = """Icy-Metadata: 1\r
User-Agent: mplayer-metadata\r
"""


# All the state for a given stream
class Stream(object):
    def __init__(self, sym, url):
................................................................................

    # Wake up all waiters
    def wakeups(self):
	ws = tuple(self.waiters)
	del self.waiters[:]
	for sema in ws:
	    sema.release()

    # Pull this much data from socket
    def recv(self, nbyte):
	s = self.sock

	res = ""
	while nbyte:
	    try:
		buf = s.recv(nbyte)
	    except:
		sys.stderr.write("Network closed %s\n" % (self.host,))
		return None
	    if not buf:
		sys.stderr.write("EOF %s\n" % (self.host,))
		return None
	    res += buf
	    nbyte -= len(buf)
	return res

    # Pull from a stream with Icecast metadata.
    # Because Icecast metadata is kind of a hairball of legacy and
    #  modern, we just talk TCP to it ourselves.
    # This function only returns on errors like aborted streams.
    # On idle timeout, it simply exits after clearing itself
    #  from the stream state.
    def watch(self):
	global IDLE, Args, Whitespace

	# Request it
	s = self.sock
	sys.stderr.write("sending to %s\n" % (self.host,))
	args = Args + ("%s:%d" % (self.host, self.port)) + "\r\n"
	s.send("GET %s HTTP/1.0\r\n%s\r\n" %
	    (self.path, args))

	# Assemble the HTTP response headers.  We'll likely have
	#  more than that, which will be passed down to the loop
	#  below.

	headers = {}

	while True:
	    l = self.readline()
	    sys.stderr.write(" line %s\n" % (l,))
	    if l is None:
		return
	    if not l:
		# Empty line, followed by HTTP response body
		break

	    # Malformed line
................................................................................

	    # key: value...
	    idx = l.index(':')
	    k = l[:idx].strip().lower()
	    v = l[idx+1:].strip()

	    # Register another header line
	    headers[k] = v
	sys.stderr.write("headers: %s\n" % (headers,))

	# See if this stream does indeed supply Icecast metadata
	if "icy-metaint" not in headers:
	    sys.stderr.write("No icy-metaint for %s\n" % (self.host,))
	    return
	try:
	    mi = headers["icy-metaint"]
................................................................................
	    sys.stderr.write("Spurious icy-metaint for %s: %d\n" %
		(self.host, intvl))
	    return

	# Now scoop up parcels of "intvl", then grab a metadata update
	while True:
	    # Skip this much

	    buf = self.recv(intvl)




	    if buf is None:
		return

	    # An initial byte is the number of 16-byte chunks in
	    #  the stream.
	    try:
		c = s.recv(1)
	    except:
		return
	    if not c:
		sys.stderr.write("No metadata size byte\n")
		return
	    paksize = (ord(c) << 4)
	    if not paksize:
		sys.stderr.write(" no metadata update\n")
		continue

	    # No metadata update needed yet
	    if not paksize:
		continue
	    try:
		buf = s.recv(paksize)
	    except:
................................................................................
		return
	    if len(buf) != paksize:
		sys.stderr.write("metadata got %d\n" % (len(buf),))
		return
	    buf = buf.strip()

	    # Decode metadata into a dict for JSON purposes
	    sys.stderr.write(" metadata: %s\n" % (buf,))
	    res = {}
	    for p in buf.split(';'):
		p = p.strip(Whitespace)
		if not p:
		    continue
		if '=' not in p:
		    sys.stderr.write("Malformed %s from %s\n" %
			(p, self.host))
		    continue
		idx = p.index('=')
		k = p[:idx].strip()
		v = p[idx+1:].strip()
		if v[0] == "'":
		    v = v[1:]
		    if v[-1] == "'":
			v = v[:-1]
		res[k] = v
	    
	    if not res: