bbc_redux 0.4.7.pre → 0.4.8.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +0 -2
- data/bbc_redux.gemspec +4 -0
- data/bin/bbc-redux +325 -0
- data/lib/bbc/redux/channel.rb +2 -0
- data/lib/bbc/redux/serializers.rb +5 -0
- data/lib/bbc/redux/version.rb +1 -1
- data/lib/bbc/redux.rb +1 -0
- metadata +22 -4
data/README.md
CHANGED
data/bbc_redux.gemspec
CHANGED
@@ -29,6 +29,8 @@ Gem::Specification.new do |gem|
|
|
29
29
|
|
30
30
|
# Files / paths
|
31
31
|
|
32
|
+
gem.executables << 'bbc-redux'
|
33
|
+
|
32
34
|
gem.files = FileList[
|
33
35
|
'AUTHORS',
|
34
36
|
'COPYING',
|
@@ -36,6 +38,7 @@ Gem::Specification.new do |gem|
|
|
36
38
|
'README.md',
|
37
39
|
'Rakefile',
|
38
40
|
'bbc_redux.gemspec',
|
41
|
+
'bin/*',
|
39
42
|
'lib/**/*'
|
40
43
|
]
|
41
44
|
|
@@ -54,6 +57,7 @@ Gem::Specification.new do |gem|
|
|
54
57
|
|
55
58
|
gem.add_dependency 'nokogiri'
|
56
59
|
gem.add_dependency 'representable'
|
60
|
+
gem.add_dependency 'terminal-table'
|
57
61
|
gem.add_dependency 'typhoeus', '>= 0.6.8'
|
58
62
|
gem.add_dependency 'virtus', '>= 0.5.0'
|
59
63
|
|
data/bin/bbc-redux
ADDED
@@ -0,0 +1,325 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# vim: set filetype=ruby:
|
4
|
+
|
5
|
+
$LOAD_PATH << File.join( File.dirname(__FILE__), '..', 'lib' )
|
6
|
+
|
7
|
+
require 'fileutils'
|
8
|
+
require 'logger'
|
9
|
+
require 'optparse'
|
10
|
+
|
11
|
+
require 'bbc/redux'
|
12
|
+
require 'terminal-table'
|
13
|
+
|
14
|
+
################################################################################
|
15
|
+
# OPTIONS PARSER
|
16
|
+
|
17
|
+
def parse_options( input )
|
18
|
+
|
19
|
+
options = { :command => :assets }
|
20
|
+
|
21
|
+
parser = OptionParser.new do |opts|
|
22
|
+
|
23
|
+
opts.banner = 'usage: ' + File.basename(__FILE__) + ' [options]'
|
24
|
+
|
25
|
+
opts.separator ''
|
26
|
+
opts.separator 'asset download options:'
|
27
|
+
|
28
|
+
opts.on( '-a', '--after DATE', 'Filter by after date' ) do |d|
|
29
|
+
options[:after] = DateTime.parse( d )
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on( '-b', '--before DATE', 'Filter by before date' ) do |d|
|
33
|
+
options[:before] = DateTime.parse( d )
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.on( '-c', '--channels CHANNEL,...', 'Filter by channel name' ) do |c|
|
37
|
+
options[:channel] = c.split(',')
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on( '-i', '--id ID', 'Filter by asset id' ) do |i|
|
41
|
+
options[:id] = i
|
42
|
+
end
|
43
|
+
|
44
|
+
opts.on( '-m', '--metadata', 'Download json metadata' ) do |metadata|
|
45
|
+
options[:metadata] = metadata
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.on( '-o', '--output-directory DIR', 'Save to directory' ) do |d|
|
49
|
+
options[:output_directory] = d
|
50
|
+
end
|
51
|
+
|
52
|
+
opts.on( '-p', '--profiles PROFILE,...', 'Fetch asset with profile' ) do |p|
|
53
|
+
options[:profiles] = p.split(',')
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.on( '-q', '--query QUERY', 'Filter by query' ) do |q|
|
57
|
+
options[:q] = q
|
58
|
+
end
|
59
|
+
|
60
|
+
opts.on( '--[no]-repeats', 'Include / exclude repeats' ) do |repeats|
|
61
|
+
options[:repeats] = repeats
|
62
|
+
end
|
63
|
+
|
64
|
+
opts.separator ''
|
65
|
+
opts.separator 'channel info commands:'
|
66
|
+
|
67
|
+
opts.on( '--list-channels', 'List available channels' ) do
|
68
|
+
options[:command] = :list_channels
|
69
|
+
end
|
70
|
+
|
71
|
+
opts.on( '--list-categories', 'List available channel categories' ) do
|
72
|
+
options[:command] = :list_categories
|
73
|
+
end
|
74
|
+
|
75
|
+
opts.separator ''
|
76
|
+
opts.separator 'common options:'
|
77
|
+
|
78
|
+
opts.on_tail( '-h', '--help', 'Show this message' ) do
|
79
|
+
puts opts
|
80
|
+
puts DATA.read
|
81
|
+
exit
|
82
|
+
end
|
83
|
+
|
84
|
+
opts.on_tail( '-v', '--verbose', 'Enable verbose logging' ) do
|
85
|
+
options[:verbose] = true
|
86
|
+
end
|
87
|
+
|
88
|
+
opts.on_tail( '-V', '--version', 'Show version' ) do
|
89
|
+
puts BBC::Redux::VERSION
|
90
|
+
exit
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
parser.parse!( input )
|
96
|
+
|
97
|
+
return options
|
98
|
+
|
99
|
+
rescue ArgumentError,
|
100
|
+
OptionParser::InvalidOption,
|
101
|
+
OptionParser::MissingArgument => e
|
102
|
+
$stderr.puts e.message
|
103
|
+
exit 1
|
104
|
+
end
|
105
|
+
|
106
|
+
################################################################################
|
107
|
+
# APPLICATION
|
108
|
+
|
109
|
+
class BBC::Redux::CLI
|
110
|
+
|
111
|
+
attr_reader :options
|
112
|
+
|
113
|
+
def initialize( options )
|
114
|
+
@options = options
|
115
|
+
end
|
116
|
+
|
117
|
+
def run
|
118
|
+
|
119
|
+
valid_commands = [ :assets, :list_channels, :list_categories ]
|
120
|
+
|
121
|
+
if valid_commands.include? options[:command]
|
122
|
+
self.send( options[:command] )
|
123
|
+
else
|
124
|
+
fail "Unrecognized command #{options[:command]}, see --help"
|
125
|
+
end
|
126
|
+
|
127
|
+
if options[:token].nil?
|
128
|
+
logger.debug 'Logging out of redux'
|
129
|
+
redux_client.logout
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
def logger
|
135
|
+
if @logger.nil?
|
136
|
+
@logger = Logger.new( $stderr )
|
137
|
+
|
138
|
+
if options[:verbose]
|
139
|
+
@logger.level = Logger::DEBUG
|
140
|
+
else
|
141
|
+
@logger.level = Logger::INFO
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
@logger
|
146
|
+
end
|
147
|
+
|
148
|
+
def redux_client
|
149
|
+
if @redux_client.nil?
|
150
|
+
if options[:token]
|
151
|
+
credentials = { :token => options[:token] }
|
152
|
+
elsif options[:username] && options[:password]
|
153
|
+
credentials = {
|
154
|
+
:username => options[:username],
|
155
|
+
:password => options[:password],
|
156
|
+
}
|
157
|
+
else
|
158
|
+
$stderr.puts 'You need to set either the REDUX_TOKEN or REDUX_USERNAME'
|
159
|
+
$stderr.puts 'and REDUX_PASSWORD environment variables'
|
160
|
+
fail
|
161
|
+
end
|
162
|
+
|
163
|
+
@redux_client = BBC::Redux::Client.new( credentials )
|
164
|
+
end
|
165
|
+
|
166
|
+
@redux_client
|
167
|
+
end
|
168
|
+
|
169
|
+
def fail( message = '' )
|
170
|
+
$stderr.puts message
|
171
|
+
exit 1
|
172
|
+
end
|
173
|
+
|
174
|
+
def print_table( headings, rows )
|
175
|
+
puts Terminal::Table.new :headings => headings, :rows => rows
|
176
|
+
end
|
177
|
+
|
178
|
+
def assets
|
179
|
+
|
180
|
+
disk_references = [ ]
|
181
|
+
output_directory = options[:output_directory] || '.'
|
182
|
+
|
183
|
+
FileUtils.mkdir_p output_directory
|
184
|
+
|
185
|
+
if options[:id]
|
186
|
+
disk_references << options[:id]
|
187
|
+
else
|
188
|
+
|
189
|
+
search_params = options.select do |key,_|
|
190
|
+
[ :after, :before, :channel, :q ].include? key
|
191
|
+
end
|
192
|
+
|
193
|
+
unless options[:repeats] == false
|
194
|
+
search_params[:repeats] = true
|
195
|
+
end
|
196
|
+
|
197
|
+
search_params = search_params.merge({
|
198
|
+
:offset => 0,
|
199
|
+
:sort_by =>'time',
|
200
|
+
:sort_order => 'ascending'
|
201
|
+
})
|
202
|
+
|
203
|
+
logger.info 'Searching for references'
|
204
|
+
|
205
|
+
results = redux_client.search( search_params )
|
206
|
+
|
207
|
+
while true do
|
208
|
+
results.assets.each { |a| disk_references << a.disk_reference }
|
209
|
+
|
210
|
+
if results.has_more?
|
211
|
+
next_query = results.query.merge({
|
212
|
+
:offset => results.query[:offset] + 10
|
213
|
+
})
|
214
|
+
|
215
|
+
logger.debug "Searching for references, offset #{next_query[:offset]}"
|
216
|
+
|
217
|
+
results = redux_client.search(next_query)
|
218
|
+
else
|
219
|
+
break
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
disk_references.each do |disk_reference|
|
225
|
+
|
226
|
+
logger.info 'Fetching data for asset ' + disk_reference
|
227
|
+
|
228
|
+
asset = redux_client.asset( disk_reference )
|
229
|
+
|
230
|
+
if options[:metadata]
|
231
|
+
logger.debug 'Saving metadata for asset ' + disk_reference
|
232
|
+
|
233
|
+
serializer = BBC::Redux::Serializers::Asset.new( asset )
|
234
|
+
file_path = File.join( output_directory, disk_reference + '.json' )
|
235
|
+
|
236
|
+
File.open( file_path, 'w' ) { |f| f << serializer.to_json }
|
237
|
+
end
|
238
|
+
|
239
|
+
if options[:profiles]
|
240
|
+
options[:profiles].each do |profile|
|
241
|
+
|
242
|
+
logger.debug "Saving profile #{profile} for asset #{disk_reference}"
|
243
|
+
|
244
|
+
url = asset.send( profile + '_url' ).end_point
|
245
|
+
fname = File.basename( url )
|
246
|
+
file_path = File.join( output_directory, fname )
|
247
|
+
|
248
|
+
`wget --quiet -O "#{file_path}" "#{url}"`
|
249
|
+
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
def list_categories
|
258
|
+
logger.debug 'Listing categories'
|
259
|
+
|
260
|
+
headings = %w{ id description priority }
|
261
|
+
|
262
|
+
rows = redux_client.channel_categories.map do |category|
|
263
|
+
[ category.id, category.description, category.priority ]
|
264
|
+
end
|
265
|
+
|
266
|
+
print_table headings, rows
|
267
|
+
end
|
268
|
+
|
269
|
+
def list_channels
|
270
|
+
logger.debug 'Listing channels'
|
271
|
+
|
272
|
+
headings = %w{ category_id longname name sortorder }
|
273
|
+
|
274
|
+
rows = redux_client.channels.map do |channel|
|
275
|
+
[
|
276
|
+
channel.category_id,
|
277
|
+
channel.longname,
|
278
|
+
channel.name,
|
279
|
+
channel.sortorder
|
280
|
+
]
|
281
|
+
end
|
282
|
+
|
283
|
+
print_table headings, rows
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
287
|
+
|
288
|
+
################################################################################
|
289
|
+
# FIRE UP THE QUATTRO
|
290
|
+
|
291
|
+
options = parse_options( ARGV )
|
292
|
+
|
293
|
+
runner = BBC::Redux::CLI.new( options.merge({
|
294
|
+
:token => ENV['REDUX_TOKEN'],
|
295
|
+
:username => ENV['REDUX_USERNAME'],
|
296
|
+
:password => ENV['REDUX_PASSWORD'],
|
297
|
+
}))
|
298
|
+
|
299
|
+
runner.run
|
300
|
+
|
301
|
+
################################################################################
|
302
|
+
# EXTENDED USAGE INFO
|
303
|
+
|
304
|
+
__END__
|
305
|
+
|
306
|
+
examples:
|
307
|
+
|
308
|
+
To use the client you must have set one of these environment variables:
|
309
|
+
|
310
|
+
REDUX_TOKEN # A valid session token
|
311
|
+
REDUX_USERNAME & REDUX_PASSWORD # Your credentials
|
312
|
+
|
313
|
+
You may then us the client, some examples below:
|
314
|
+
|
315
|
+
# Listing channels
|
316
|
+
$: bbc-redux --list-channels
|
317
|
+
|
318
|
+
# Downloading json metadata for an asset
|
319
|
+
$: bbc-redux --metadata --id 6008591816398520492
|
320
|
+
|
321
|
+
# Downloading MP3 files for a week of The Archers
|
322
|
+
$: bbc-redux -p mp3 -q 'The Archers' -a 2014-W01 -b 2014-W02
|
323
|
+
|
324
|
+
# Downloading TS files for a day of BBC One
|
325
|
+
$: bbc-redux -p ts -c bbcone -a 2014-01-01 -b 2014-01-02
|
data/lib/bbc/redux/channel.rb
CHANGED
@@ -42,6 +42,11 @@ module BBC
|
|
42
42
|
|
43
43
|
end
|
44
44
|
|
45
|
+
class Assets < Representable::Decorator
|
46
|
+
include Representable::JSON::Collection
|
47
|
+
items extend: Asset, class: BBC::Redux::Asset
|
48
|
+
end
|
49
|
+
|
45
50
|
class Channel < Representable::Decorator
|
46
51
|
include Representable::JSON
|
47
52
|
property :category_id, :as => :category
|
data/lib/bbc/redux/version.rb
CHANGED
data/lib/bbc/redux.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bbc_redux
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.8.pre
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2015-03-
|
14
|
+
date: 2015-03-13 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rspec
|
@@ -109,6 +109,22 @@ dependencies:
|
|
109
109
|
- - ! '>='
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: terminal-table
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
type: :runtime
|
121
|
+
prerelease: false
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
112
128
|
- !ruby/object:Gem::Dependency
|
113
129
|
name: typhoeus
|
114
130
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,7 +161,8 @@ description: A gem to help navigate the BBC Redux API
|
|
145
161
|
email:
|
146
162
|
- james.harrison@bbc.co.uk
|
147
163
|
- matt.haynes@bbc.co.uk
|
148
|
-
executables:
|
164
|
+
executables:
|
165
|
+
- bbc-redux
|
149
166
|
extensions: []
|
150
167
|
extra_rdoc_files: []
|
151
168
|
files:
|
@@ -155,6 +172,7 @@ files:
|
|
155
172
|
- README.md
|
156
173
|
- Rakefile
|
157
174
|
- bbc_redux.gemspec
|
175
|
+
- bin/bbc-redux
|
158
176
|
- lib/bbc/redux/asset.rb
|
159
177
|
- lib/bbc/redux/channel.rb
|
160
178
|
- lib/bbc/redux/channel_category.rb
|
@@ -200,7 +218,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
200
218
|
version: '0'
|
201
219
|
segments:
|
202
220
|
- 0
|
203
|
-
hash:
|
221
|
+
hash: 2647790705023314369
|
204
222
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
205
223
|
none: false
|
206
224
|
requirements:
|