UPnP-ContentDirectory 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ �D>�5������~�T�S�|�D�'��)�����B�f��b�ʕ�~�bt�������9B�x#d��-�{#9�T�~�3�C���r�"Dϔ��*��
2
+ MŰld�Y�q)��g�L��
3
+ �~1����ʒ=B�Ca&O���V^,'����!�3���h'�}�j��\��0�;���M±��>���!!����s0Lۚ���j�ۤ�D��!٥-)@�zor��7��g��_F�w�x�B�t��
4
+ �w�oJ�Fl�*N
@@ -0,0 +1,5 @@
1
+ === 1.0.0 / 2008-07-23
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
5
+
@@ -0,0 +1,5 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/UPnP/service/content_directory.rb
@@ -0,0 +1,83 @@
1
+ = UPnP-ContentDirectory
2
+
3
+ * http://seattlerb.org/UPnP-ContentDirectory
4
+ * http://upnp.org
5
+ * Bugs: http://rubyforge.org/tracker/?func=add&group_id=1513&atid=5921
6
+
7
+ == DESCRIPTION:
8
+
9
+ A UPnP ContentDirectory service with some DLNA extensions. Currently this is
10
+ a work in progress, and is only adequate for viewing images on a PlayStation
11
+ 3.
12
+
13
+ == FEATURES/PROBLEMS:
14
+
15
+ * Only direct filesystem representations currently supported
16
+ * Largely undocumented
17
+ * Only tested on PlayStation 3
18
+ * Only images known to work
19
+ * Partially implemented:
20
+ * Browse
21
+ * GetSystemUpdateID
22
+ * Not implemented:
23
+ * CreateObject
24
+ * CreateReference
25
+ * DeleteResource
26
+ * DestroyObject
27
+ * ExportResource
28
+ * GetSearchCapabilities
29
+ * GetSortCapabilities
30
+ * GetTransferProgress
31
+ * ImportResource
32
+ * Search
33
+ * StopTransferResource
34
+ * UpdateObject
35
+
36
+ == SYNOPSIS:
37
+
38
+ In a UPnP::Device::create block:
39
+
40
+ your_device.add_service 'ContentDirectory' do |cd|
41
+ cd.add_directory Dir.pwd
42
+ end
43
+
44
+ See UPnP::Device::MediaServer for an example of usage.
45
+
46
+ == REQUIREMENTS:
47
+
48
+ * A filesystem with files on it
49
+ * A UPnP control point
50
+
51
+ == INSTALL:
52
+
53
+ sudo gem install UPnP-ContentDirectory
54
+
55
+ == LICENSE:
56
+
57
+ Copyright 2008 Eric Hodel. All rights reserved.
58
+
59
+ Redistribution and use in source and binary forms, with or without
60
+ modification, are permitted provided that the following conditions
61
+ are met:
62
+
63
+ 1. Redistributions of source code must retain the above copyright
64
+ notice, this list of conditions and the following disclaimer.
65
+ 2. Redistributions in binary form must reproduce the above copyright
66
+ notice, this list of conditions and the following disclaimer in the
67
+ documentation and/or other materials provided with the distribution.
68
+ 3. Neither the names of the authors nor the names of their contributors
69
+ may be used to endorse or promote products derived from this software
70
+ without specific prior written permission.
71
+
72
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
73
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
74
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
75
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
76
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
77
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
78
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
79
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
80
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
81
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
82
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
83
+
@@ -0,0 +1,14 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/UPnP/service/content_directory'
6
+
7
+ Hoe.new 'UPnP-ContentDirectory', UPnP::Service::ContentDirectory::VERSION do |p|
8
+ p.rubyforge_name = 'seattlerb'
9
+ p.developer 'Eric Hodel', 'drbrain@segment7.net'
10
+
11
+ p.extra_deps << ['UPnP', '>= 1.1.0']
12
+ end
13
+
14
+ # vim: syntax=Ruby
@@ -0,0 +1,401 @@
1
+ require 'open3'
2
+ require 'uri'
3
+
4
+ require 'rubygems'
5
+ require 'UPnP/service'
6
+
7
+ ##
8
+ # A UPnP ContentDirectory service. See upnp.org for specifications.
9
+
10
+ class UPnP::Service::ContentDirectory < UPnP::Service
11
+
12
+ VERSION = '1.0'
13
+
14
+ ##
15
+ # Returns the searching capabilities supported by the device
16
+
17
+ add_action 'GetSearchCapabilities',
18
+ [OUT, 'SearchCaps', 'SearchCapabilities']
19
+
20
+ ##
21
+ # Returns the CSV list of metadata tags that can be used in sortCriteria
22
+
23
+ add_action 'GetSortCapabilities',
24
+ [OUT, 'SortCaps', 'SortCapabilities']
25
+
26
+ add_action 'GetSystemUpdateID',
27
+ [OUT, 'Id', 'SystemUpdateID']
28
+
29
+ add_action 'Browse',
30
+ [IN, 'ObjectID', 'A_ARG_TYPE_ObjectID'],
31
+ [IN, 'BrowseFlag', 'A_ARG_TYPE_BrowseFlag'],
32
+ [IN, 'Filter', 'A_ARG_TYPE_Filter'],
33
+ [IN, 'StartingIndex', 'A_ARG_TYPE_Index'],
34
+ [IN, 'RequestedCount', 'A_ARG_TYPE_Count'],
35
+ [IN, 'SortCriteria', 'A_ARG_TYPE_SortCriteria'],
36
+
37
+ [OUT, 'Result', 'A_ARG_TYPE_Result'],
38
+ [OUT, 'NumberReturned', 'A_ARG_TYPE_Count'],
39
+ [OUT, 'TotalMatches', 'A_ARG_TYPE_Count'],
40
+ [OUT, 'UpdateID', 'A_ARG_TYPE_UpdateID']
41
+
42
+ # optional actions
43
+
44
+ add_action 'Search',
45
+ [IN, 'ContainerID', 'A_ARG_TYPE_ObjectID'],
46
+ [IN, 'SearchCriteria', 'A_ARG_TYPE_SearchCriteria'],
47
+ [IN, 'Filter', 'A_ARG_TYPE_Filter'],
48
+ [IN, 'StartingIndex', 'A_ARG_TYPE_Index'],
49
+ [IN, 'RequestedCount', 'A_ARG_TYPE_Count'],
50
+ [IN, 'SortCriteria', 'A_ARG_TYPE_SortCriteria'],
51
+
52
+ [OUT, 'Result', 'A_ARG_TYPE_Result'],
53
+ [OUT, 'NumberReturned', 'A_ARG_TYPE_Count'],
54
+ [OUT, 'TotalMatches', 'A_ARG_TYPE_Count'],
55
+ [OUT, 'UpdateID', 'A_ARG_TYPE_UpdateID']
56
+
57
+ add_action 'CreateObject',
58
+ [IN, 'ContainerID', 'A_ARG_TYPE_ObjectID'],
59
+ [IN, 'Elements', 'A_ARG_TYPE_Result'],
60
+
61
+ [OUT, 'ObjectID', 'A_ARG_TYPE_ObjectID'],
62
+ [OUT, 'Result', 'A_ARG_TYPE_Result']
63
+
64
+ add_action 'DestroyObject',
65
+ [IN, 'ObjectID', 'A_ARG_TYPE_ObjectID']
66
+
67
+ add_action 'UpdateObject',
68
+ [IN, 'ObjectID', 'A_ARG_TYPE_ObjectID'],
69
+ [IN, 'CurrentTagValue', 'A_ARG_TYPE_TagValueList'],
70
+ [IN, 'NewTagValue', 'A_ARG_TYPE_TagValueList']
71
+
72
+ add_action 'ImportResource',
73
+ [IN, 'SourceURI', 'A_ARG_TYPE_URI'],
74
+ [IN, 'DestinationURI', 'A_ARG_TYPE_URI'],
75
+
76
+ [OUT, 'TransferID', 'A_ARG_TYPE_TransferID']
77
+
78
+ add_action 'ExportResource',
79
+ [IN, 'SourceURI', 'A_ARG_TYPE_URI'],
80
+ [IN, 'DestinationURI', 'A_ARG_TYPE_URI'],
81
+
82
+ [OUT, 'TransferID', 'A_ARG_TYPE_TransferID']
83
+
84
+ add_action 'StopTransferResource',
85
+ [IN, 'TransferID', 'A_ARG_TYPE_TransferID']
86
+
87
+ add_action 'GetTransferProgress',
88
+ [IN, 'TransferID', 'A_ARG_TYPE_TransferID'],
89
+
90
+ [OUT, 'TransferStatus', 'A_ARG_TYPE_TransferStatus'],
91
+ [OUT, 'TransferLength', 'A_ARG_TYPE_TransferLength'],
92
+ [OUT, 'TransferTotal', 'A_ARG_TYPE_TransferTotal']
93
+
94
+ add_action 'DeleteResource',
95
+ [IN, 'ResourceURI', 'A_ARG_TYPE_URI']
96
+
97
+ add_action 'CreateReference',
98
+ [IN, 'ContainerID', 'A_ARG_TYPE_ObjectID'],
99
+ [IN, 'ObjectID', 'A_ARG_TYPE_ObjectID'],
100
+ [OUT, 'NewID', 'A_ARG_TYPE_ObjectID']
101
+
102
+ add_variable 'TransferIDs', 'string', nil, nil, true
103
+ add_variable 'A_ARG_TYPE_ObjectID', 'string'
104
+ add_variable 'A_ARG_TYPE_Result', 'string' # 2.5.4 - DIDL-Lite
105
+ add_variable 'A_ARG_TYPE_SearchCriteria', 'string' # 2.5.5
106
+ add_variable 'A_ARG_TYPE_BrowseFlag', 'string',
107
+ %w[BrowseMetadata BrowseDirectChildren]
108
+ add_variable 'A_ARG_TYPE_Filter', 'string' # 2.5.7
109
+ add_variable 'A_ARG_TYPE_SortCriteria', 'string' # 2.5.8
110
+ add_variable 'A_ARG_TYPE_Index', 'ui4' # 2.5.9
111
+ add_variable 'A_ARG_TYPE_Count', 'ui4' # 2.5.10
112
+ add_variable 'A_ARG_TYPE_UpdateID', 'ui4' # 2.5.11
113
+ add_variable 'A_ARG_Type_TransferID', 'ui4' # 2.5.12
114
+ add_variable 'A_ARG_Type_TransferStatus', 'string' # 2.5.13
115
+ add_variable 'A_ARG_Type_TransferLength', 'string' # 2.5.14
116
+ add_variable 'A_ARG_Type_TransferTotal', 'string' # 2.5.15
117
+ add_variable 'A_ARG_TYPE_TagValueList', 'string' # 2.5.16
118
+ add_variable 'A_ARG_TYPE_URI', 'uri' # 2.5.17
119
+ add_variable 'SearchCapabilities', 'string' # 2.5.18
120
+ add_variable 'SortCapabilities', 'string' # 2.5.19
121
+ add_variable 'SystemUpdateID', 'ui4', nil, nil, true # 2.5.20
122
+ add_variable 'ContainerUpdateIDs', 'string', nil, nil, true # 2.5.21
123
+
124
+ def initialize(*args)
125
+ @directories = []
126
+
127
+ super
128
+ end
129
+
130
+ def on_init
131
+ @SystemUpdateID = 0
132
+
133
+ @object_count = 0
134
+ @objects = {}
135
+ @parents = {}
136
+
137
+ add_object 'root', -1
138
+ WEBrick::HTTPUtils::DefaultMimeTypes['mp3'] = 'audio/mpeg'
139
+ end
140
+
141
+ # :section: ContentServer implementation
142
+
143
+ ##
144
+ # Allows the caller to incrementally browse the hierarchy of the content
145
+ # directory, including information listing the classes of objects available
146
+ # in any container.
147
+
148
+ def Browse(object_id, browse_flag, filter, starting_index, requested_count,
149
+ sort_criteria)
150
+ filter = filter.split ','
151
+ object_id = object_id.to_i
152
+ update_id = 0
153
+
154
+ case browse_flag
155
+ when 'BrowseMetadata' then
156
+ number_returned = 1
157
+ total_matches = 1
158
+
159
+ result = metadata_result object_id
160
+ when 'BrowseDirectChildren' then
161
+ number_returned, total_matches, result = children_result object_id
162
+ else
163
+ raise "unknown BrowseFlag #{browse_flag}"
164
+ end
165
+
166
+ [nil, result, number_returned, total_matches, update_id]
167
+ end
168
+
169
+ ##
170
+ # Returns the current value of the SystemUpdateID state variable. For use
171
+ # by clients that want to poll for any changes in the content directory
172
+ # instead of subscribing to events.
173
+
174
+ def GetSystemUpdateID
175
+ [nil, @SystemUpdateID]
176
+ end
177
+
178
+ # :section: Support implementation
179
+
180
+ ##
181
+ # Adds object +name+ to the directory tree under +parent+
182
+
183
+ def add_object(name, parent)
184
+ object_id = @object_count
185
+ @object_count += 1
186
+
187
+ @objects[object_id] = name
188
+ @objects[name] = object_id
189
+
190
+ @parents[object_id] = parent
191
+
192
+ object_id
193
+ end
194
+
195
+ ##
196
+ # Adds +directory+ as a path searched by the content server
197
+
198
+ def add_directory(directory)
199
+ return self if @directories.include? directory
200
+
201
+ add_object directory, 0
202
+ @directories << directory
203
+
204
+ self
205
+ end
206
+
207
+ def children_result(object_id)
208
+ object = get_object object_id
209
+
210
+ children = if object_id == 0 then
211
+ @directories
212
+ else
213
+ Dir[File.join(object, '*')]
214
+ end
215
+
216
+ result = make_result do |xml|
217
+ children.each do |child|
218
+ child_id = get_object child, object_id
219
+
220
+ result_object xml, child, child_id, File.basename(child)
221
+ end
222
+ end
223
+
224
+ [children.length, children.length, result]
225
+ end
226
+
227
+ def get_object(name, parent_id = nil)
228
+ if @objects.key? name then
229
+ @objects[name]
230
+ elsif parent_id.nil? then
231
+ raise Error, "object #{name} does not exist"
232
+ else
233
+ add_object name, parent_id
234
+ end
235
+ end
236
+
237
+ def get_parent(object_id)
238
+ if @parents.key? object_id then
239
+ @parents[object_id]
240
+ else
241
+ raise Error, "invalid object id #{object_id}"
242
+ end
243
+ end
244
+
245
+ def item_class(mime_type)
246
+ case mime_type
247
+ when /^image/ then
248
+ 'object.item.imageItem'
249
+ when /^audio/ then
250
+ 'object.item.audioItem'
251
+ else
252
+ puts "unhandled mime type #{mime_type}"
253
+ 'object.item'
254
+ end
255
+ end
256
+
257
+ def make_result
258
+ result = []
259
+
260
+ xml = Builder::XmlMarkup.new :indent => 2, :target => result
261
+ xml.tag! 'DIDL-Lite',
262
+ 'xmlns' => 'urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/',
263
+ 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
264
+ 'xmlns:upnp' => 'urn:schemas-upnp-org:metadata-1-0/upnp/' do
265
+ yield xml
266
+ end
267
+
268
+ result.join
269
+ end
270
+
271
+ def metadata_result(object_id)
272
+ object = get_object object_id
273
+ parent = get_parent object_id
274
+
275
+ title = File.basename object
276
+
277
+ make_result do |xml|
278
+ result_object xml, object, object_id, title
279
+ end
280
+ end
281
+
282
+ def mount_extra(http_server)
283
+ super
284
+
285
+ @directories.each do |root|
286
+ root_id = get_object root
287
+ path = File.join service_path, root_id.to_s
288
+
289
+ http_server.mount path, WEBrick::HTTPServlet::FileHandler, root
290
+ end
291
+ end
292
+
293
+ def resource(xml, object, mime_type, stat)
294
+ info = nil
295
+ url = nil
296
+
297
+ case mime_type
298
+ when /^audio\/(.*)/ then
299
+ pn = case $1
300
+ when 'mpeg' then
301
+ 'MP3'
302
+ end
303
+
304
+ pn = "DLNA.ORG_PN=#{pn}"
305
+
306
+ additional = [pn, 'DLNA.ORG_OP=01', 'DLNA.ORG_CI=0'].compact.join ';'
307
+
308
+ info = ['http-get', '*', mime_type, additional]
309
+ when /^image\/(.*)/ then
310
+ pn = case $1
311
+ when 'jpeg' then
312
+ 'JPEG_LRG'
313
+ end
314
+
315
+ pn = "DLNA.ORG_PN=#{pn}"
316
+
317
+ additional = [pn, 'DLNA.ORG_OP=01', 'DLNA.ORG_CI=0'].compact.join ';'
318
+
319
+ info = ['http-get', '*', mime_type, additional]
320
+ end
321
+
322
+ if info then
323
+ url = resource_url object
324
+
325
+ attributes = {
326
+ :protocolInfo => info.join(':'),
327
+ :size => stat.size,
328
+ }
329
+
330
+ xml.res attributes, URI.escape(url)
331
+ end
332
+ end
333
+
334
+ ##
335
+ # A URL to this object on this server. Correctly handles multi-homed
336
+ # servers.
337
+
338
+ def resource_url(object)
339
+ _, port, host, addr = Thread.current[:WEBrickSocket].addr
340
+
341
+ root = root_for object
342
+ root_id = get_object root
343
+
344
+ object = object.sub root, ''
345
+
346
+ File.join "http://#{addr}:#{port}", service_path, root_id.to_s, object
347
+ end
348
+
349
+ def result_object(xml, object, object_id, title)
350
+ if object_id == 0 then
351
+ result_container xml, object, object_id, @directories.length, title
352
+ elsif File.directory? object then
353
+ children = Dir[File.join(object, '*/')].length
354
+
355
+ result_container xml, object, object_id, children, title
356
+ else
357
+ result_item xml, object, object_id, title
358
+ end
359
+ end
360
+
361
+ def result_container(xml, object, object_id, children, title)
362
+ xml.tag! 'container', :id => object_id, :parentID => get_parent(object_id),
363
+ :restricted => true, :childCount => children do
364
+ xml.dc :title, title
365
+ xml.upnp :class, 'object.container'
366
+ end
367
+ end
368
+
369
+ def result_item(xml, object, object_id, title)
370
+ inn, out, = Open3.popen3('file', '-bI', object)
371
+ inn.close
372
+
373
+ mime_type = out.read.strip
374
+
375
+ stat = File.stat object
376
+
377
+ xml.tag! 'item', :id => object_id, :parentID => get_parent(object_id),
378
+ :restricted => true, :childCount => 0 do
379
+ xml.dc :title, title
380
+ xml.dc :date, stat.ctime.iso8601
381
+ xml.upnp :class, item_class(mime_type)
382
+
383
+ resource xml, object, mime_type, stat
384
+ end
385
+ end
386
+
387
+ ##
388
+ # Returns the root for +object_id+
389
+
390
+ def root_for(object_id)
391
+ object_id = get_object object_id unless Integer === object_id
392
+
393
+ while (parent_id = get_parent(object_id)) != 0 do
394
+ object_id = parent_id
395
+ end
396
+
397
+ get_object object_id
398
+ end
399
+
400
+ end
401
+
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: UPnP-ContentDirectory
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.0"
5
+ platform: ruby
6
+ authors:
7
+ - Eric Hodel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMRAwDgYDVQQDDAdkcmJy
14
+ YWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZFgNu
15
+ ZXQwHhcNMDcxMjIxMDIwNDE0WhcNMDgxMjIwMDIwNDE0WjBBMRAwDgYDVQQDDAdk
16
+ cmJyYWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZ
17
+ FgNuZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbbgLrGLGIDE76
18
+ LV/cvxdEzCuYuS3oG9PrSZnuDweySUfdp/so0cDq+j8bqy6OzZSw07gdjwFMSd6J
19
+ U5ddZCVywn5nnAQ+Ui7jMW54CYt5/H6f2US6U0hQOjJR6cpfiymgxGdfyTiVcvTm
20
+ Gj/okWrQl0NjYOYBpDi+9PPmaH2RmLJu0dB/NylsDnW5j6yN1BEI8MfJRR+HRKZY
21
+ mUtgzBwF1V4KIZQ8EuL6I/nHVu07i6IkrpAgxpXUfdJQJi0oZAqXurAV3yTxkFwd
22
+ g62YrrW26mDe+pZBzR6bpLE+PmXCzz7UxUq3AE0gPHbiMXie3EFE0oxnsU3lIduh
23
+ sCANiQ8BAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
24
+ BBS5k4Z75VSpdM0AclG2UvzFA/VW5DANBgkqhkiG9w0BAQUFAAOCAQEAHagT4lfX
25
+ kP/hDaiwGct7XPuVGbrOsKRVD59FF5kETBxEc9UQ1clKWngf8JoVuEoKD774dW19
26
+ bU0GOVWO+J6FMmT/Cp7nuFJ79egMf/gy4gfUfQMuvfcr6DvZUPIs9P/TlK59iMYF
27
+ DIOQ3DxdF3rMzztNUCizN4taVscEsjCcgW6WkUJnGdqlu3OHWpQxZBJkBTjPCoc6
28
+ UW6on70SFPmAy/5Cq0OJNGEWBfgD9q7rrs/X8GGwUWqXb85RXnUVi/P8Up75E0ag
29
+ 14jEc90kN+C7oI/AGCBN0j6JnEtYIEJZibjjDJTSMWlUKKkj30kq7hlUC2CepJ4v
30
+ x52qPcexcYZR7w==
31
+ -----END CERTIFICATE-----
32
+
33
+ date: 2008-07-23 00:00:00 -07:00
34
+ default_executable:
35
+ dependencies:
36
+ - !ruby/object:Gem::Dependency
37
+ name: UPnP
38
+ type: :runtime
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 1.1.0
45
+ version:
46
+ - !ruby/object:Gem::Dependency
47
+ name: hoe
48
+ type: :development
49
+ version_requirement:
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.7.0
55
+ version:
56
+ description: A UPnP ContentDirectory service with some DLNA extensions. Currently this is a work in progress, and is only adequate for viewing images on a PlayStation 3.
57
+ email:
58
+ - drbrain@segment7.net
59
+ executables: []
60
+
61
+ extensions: []
62
+
63
+ extra_rdoc_files:
64
+ - History.txt
65
+ - Manifest.txt
66
+ - README.txt
67
+ files:
68
+ - History.txt
69
+ - Manifest.txt
70
+ - README.txt
71
+ - Rakefile
72
+ - lib/UPnP/service/content_directory.rb
73
+ has_rdoc: true
74
+ homepage: http://seattlerb.org/UPnP-ContentDirectory
75
+ post_install_message:
76
+ rdoc_options:
77
+ - --main
78
+ - README.txt
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ version:
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ version:
93
+ requirements: []
94
+
95
+ rubyforge_project: seattlerb
96
+ rubygems_version: 1.2.0
97
+ signing_key:
98
+ specification_version: 2
99
+ summary: A UPnP ContentDirectory service with some DLNA extensions
100
+ test_files: []
101
+
@@ -0,0 +1,4 @@
1
+ Κ�����h.�H?ؠ+�Q�3 �x��!��he�.�рNY@@3��~ؑ�ł����d"6̈�*o�
2
+ ��j��+��@G�4�a4"���K�ŽVц�yQ�N�P C�Ľ*�i,w��.~�mѡȡ�4��@*�����a�Z$�y̱���� �x��ʼn5c�;�����;X����&�E��V�~T����6^u����{֢�����
3
+
4
+ 淅w:N��q��w��X|b�}���3ya�n�K�N�AH��L�kN�d