sony_camera_remote_api 0.1.1

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.
@@ -0,0 +1,646 @@
1
+ require 'sony_camera_remote_api'
2
+ require 'sony_camera_remote_api/logging'
3
+ require 'sony_camera_remote_api/scripts'
4
+ require 'sony_camera_remote_api/client/config'
5
+ require 'fileutils'
6
+ require 'thor'
7
+ require 'highline/import'
8
+ require 'yaml'
9
+ require 'time'
10
+ require 'pp'
11
+
12
+
13
+ module SonyCameraRemoteAPI
14
+ # CLI client module
15
+ module Client
16
+
17
+ # Default config file saved in home directory.
18
+ GLOBAL_CONFIG_FILE = File.expand_path('~/.sonycamconf')
19
+
20
+ class Main < Thor
21
+ include Utils
22
+ include Scripts
23
+ include ConfigUtils
24
+
25
+ register Config, 'config', 'config [commands] [options]', 'Configure camera connections'
26
+
27
+ # Global options
28
+ class_option :setting, type: :boolean, desc: 'Show current camera settings'
29
+ class_option :output, type: :string, desc: 'Output filename', banner: 'FILE'
30
+ class_option :dir, type: :string, desc: 'Output directory', banner: 'DIR'
31
+ class_option :config, aliases: '-c', type: :string, desc: 'Config file path', banner: 'FILE'
32
+ class_option :ssid, type: :string, desc: 'SSID of the camera to connect'
33
+ class_option :pass, type: :string, desc: 'Password of camera to connect'
34
+ class_option :interface, type: :string, desc: 'Interface by which camera is connected'
35
+ class_option :verbose, type: :numeric, desc: 'Increase verbosity', banner: 'LEVEL'
36
+
37
+ no_tasks do
38
+ def config_file
39
+ options[:config] || GLOBAL_CONFIG_FILE
40
+ end
41
+
42
+ def load_camera_config
43
+ # Check connection configuration is given by options
44
+ if [options[:ssid], options[:pass], options[:interface]].any?
45
+ if [options[:ssid], options[:pass], options[:interface]].all?
46
+ return { 'ssid' => options[:ssid], 'pass' => options[:pass], 'interface' => options[:interface] }
47
+ else
48
+ puts "'--ssid', '--pass', '--interface' must be present all at a time!"
49
+ return
50
+ end
51
+ else
52
+ config = default_camera config_file
53
+ config
54
+ end
55
+ end
56
+
57
+ # Load camera config and connect
58
+ def load_and_connect
59
+ config = load_camera_config
60
+ return if config.nil?
61
+ # Connect to camera by external script
62
+ unless Scripts.connect(config['interface'], config['ssid'], config['pass'])
63
+ puts 'Failed to connect!'
64
+ return
65
+ end
66
+ config
67
+ end
68
+
69
+ # Initialize camera instance
70
+ def init_camera
71
+ config = load_and_connect
72
+ exit(1) if config.nil?
73
+
74
+ puts 'Initializing camera...'
75
+ if config['endpoints'].nil?
76
+ @cam = SonyCameraRemoteAPI::Camera.new reconnect_by: method(:load_and_connect)
77
+ save_ssdp_config config_file, @cam.endpoints
78
+ puts 'SSDP configuration saved.'
79
+ else
80
+ @cam = SonyCameraRemoteAPI::Camera.new endpoints: config['endpoints'],
81
+ reconnect_by: method(:load_and_connect)
82
+ end
83
+ puts 'Camera initialization finished.'
84
+
85
+ # Change directory if --dir options specified
86
+ @cwd = Dir.getwd
87
+ if options[:dir]
88
+ FileUtils.mkdir_p options[:dir]
89
+ Dir.chdir options[:dir]
90
+ end
91
+ end
92
+
93
+ # Finalizer
94
+ def finalize
95
+ Dir.chdir @cwd
96
+ end
97
+
98
+ # Get supported/available/current camera parameters and show them
99
+ def get_parameter_and_show(param_name, **opts)
100
+ param_title = param_name.to_s.split(/(?=[A-Z])/).join(' ')
101
+ result = @cam.get_parameter! param_name, timeout: 0
102
+ # nil current value means it is unsupported parameter.
103
+ return if result[:current].nil?
104
+
105
+ puts "#{param_title}:"
106
+ case param_name
107
+ when :WhiteBalance
108
+ show_WhiteBalance result
109
+ else
110
+ show_normal result
111
+ end
112
+ result
113
+ end
114
+
115
+ # Show for other parameter
116
+ def show_normal(result)
117
+ array = []
118
+ if result[:supported].empty?
119
+ # If current value is present but NO supported value, it is immutable.
120
+ result[:supported] = [result[:current]]
121
+ end
122
+ result[:supported].each_with_index do |v, i|
123
+ if v == result[:current]
124
+ array << " => #{v} "
125
+ elsif result[:available].include? v
126
+ array << " * #{v} "
127
+ else
128
+ array << " x #{v}"
129
+ end
130
+ end
131
+ print_array_in_columns(array, 120, 10, 5)
132
+ end
133
+
134
+ # Show for WhiteBalance parameter
135
+ def show_WhiteBalance(result)
136
+ array = []
137
+ if result[:supported].empty?
138
+ # If current value is present but NO supported value, it is immutable.
139
+ result[:supported] = [result[:current]]
140
+ end
141
+ result[:supported].each_with_index do |v, i|
142
+ if v.key?('colorTemperature')
143
+ range = "#{v['colorTemperature'][0]}-#{v['colorTemperature'][-1]}K"
144
+ step = v['colorTemperature'][1] - v['colorTemperature'][0]
145
+ if v['whiteBalanceMode'] == result[:current]['whiteBalanceMode']
146
+ str = "#{v['whiteBalanceMode']}, #{result[:current]['colorTemperature']}K (#{range}, step=#{step})"
147
+ else
148
+ str = "#{v['whiteBalanceMode']} (#{range}, step=#{step})"
149
+ end
150
+ else
151
+ str = "#{v['whiteBalanceMode']}"
152
+ end
153
+ if v['whiteBalanceMode'] == result[:current]['whiteBalanceMode']
154
+ array << " => #{str}"
155
+ elsif result[:available].include? v
156
+ array << " * #{str}"
157
+ else
158
+ array << " x #{str}"
159
+ end
160
+ end
161
+ print_array_in_columns(array, 120, 10, 5)
162
+ end
163
+
164
+ # Set parameter if value is set
165
+ def set_parameter(param_name, value, **opts)
166
+ return if value.is_a?(Hash) && value.values.none?
167
+ return unless value
168
+ @cam.set_parameter! param_name, value, timeout: 0
169
+ end
170
+ end
171
+
172
+ #----------------------------------------PARAMETER CONFIGURATORS----------------------------------------
173
+
174
+ no_tasks do
175
+ # Set common options for all shooting modes
176
+ def set_common_options
177
+ set_parameter :ZoomSetting, options[:zoom_mode]
178
+ set_parameter :FocusMode, options[:focus_mode]
179
+ set_parameter :ExposureMode, options[:exposure]
180
+ set_parameter :ExposureCompensation, options[:ev].to_f if options[:ev]
181
+ set_parameter :FNumber, options[:fnum]
182
+ set_parameter :ShutterSpeed, options[:shutter]
183
+ set_parameter :IsoSpeedRate, options[:iso]
184
+ if options[:temp]
185
+ set_parameter :WhiteBalance, whiteBalanceMode: options[:wb], colorTemperature: options[:temp]
186
+ else
187
+ set_parameter :WhiteBalance, whiteBalanceMode: options[:wb]
188
+ end
189
+
190
+ set_parameter :SceneSelection, options[:scene]
191
+ set_parameter :FlipSetting, options[:flip]
192
+ set_parameter :TvColorSystem, options[:tv]
193
+ set_parameter :InfraredRemoteControl, options[:ir]
194
+ set_parameter :AutoPowerOff, options[:apo]
195
+ set_parameter :BeepMode, options[:beep]
196
+ end
197
+
198
+ # Set common options for all shooting modes
199
+ def get_common_options
200
+ get_parameter_and_show :ZoomSetting
201
+ get_parameter_and_show :FocusMode
202
+ get_parameter_and_show :ExposureMode
203
+ get_parameter_and_show :ExposureCompensation
204
+ get_parameter_and_show :FNumber
205
+ get_parameter_and_show :ShutterSpeed
206
+ get_parameter_and_show :IsoSpeedRate
207
+ get_parameter_and_show :WhiteBalance
208
+ get_parameter_and_show :SceneSelection
209
+ get_parameter_and_show :FlipSetting
210
+ get_parameter_and_show :TvColorSystem
211
+ get_parameter_and_show :InfraredRemoteControl
212
+ get_parameter_and_show :AutoPowerOff
213
+ get_parameter_and_show :BeepMode
214
+ end
215
+
216
+ # Set common options for still/intervalstill shooting modes
217
+ def set_still_common_options
218
+ set_parameter :TrackingFocus, options[:track]
219
+ set_parameter :SelfTimer, options[:self]
220
+ set_parameter :FlashMode, options[:flash]
221
+ if options[:aspect] && options[:size]
222
+ set_parameter :StillSize, aspect: options[:aspect], size: options[:size]
223
+ end
224
+ set_parameter :StillQuality, options[:quality]
225
+ set_parameter :PostviewImageSize, options[:postview]
226
+ set_parameter :ViewAngle, options[:angle]
227
+ end
228
+
229
+ # Get common options for still/intervalstill shooting modes
230
+ def get_still_common_options
231
+ get_parameter_and_show :TrackingFocus
232
+ get_parameter_and_show :SelfTimer
233
+ get_parameter_and_show :FlashMode
234
+ get_parameter_and_show :StillSize
235
+ get_parameter_and_show :StillQuality
236
+ get_parameter_and_show :PostviewImageSize
237
+ get_parameter_and_show :ViewAngle
238
+ end
239
+
240
+ # Set common options for movie/looprec shooting modes
241
+ def set_movie_common_options
242
+ set_parameter :MovieFileFormat, options[:format]
243
+ set_parameter :MovieQuality, options[:quality]
244
+ set_parameter :SteadyMode, options[:steady]
245
+ set_parameter :ColorSetting, options[:color]
246
+ set_parameter :WindNoiseReduction, options[:noise]
247
+ set_parameter :AudioRecording, options[:audio]
248
+ end
249
+
250
+ # Get common options for movie/looprec shooting modes
251
+ def get_movie_common_options
252
+ get_parameter_and_show :MovieFileFormat
253
+ get_parameter_and_show :MovieQuality
254
+ get_parameter_and_show :SteadyMode
255
+ get_parameter_and_show :ColorSetting
256
+ get_parameter_and_show :WindNoiseReduction
257
+ get_parameter_and_show :AudioRecording
258
+ end
259
+ end
260
+
261
+ #----------------------------------------COMMAND OPTIONS----------------------------------------
262
+
263
+ # Common options for all shooting modes
264
+ def self.common_options
265
+ option :zoom, type: :numeric, desc: 'Zoom position (0-99)', banner: 'POSITION'
266
+ option :zoom_mode, type: :string, desc: 'Zoom setting', banner: 'MODE'
267
+ option :focus_mode, type: :string, desc: 'Focus mode', banner: 'MODE'
268
+ option :exposure, type: :string, desc: 'Exposure mode', banner: 'MODE'
269
+ option :ev, type: :string, desc: 'Exposure compensation', banner: 'EV'
270
+ option :fnum, type: :string, desc: 'F number', banner: 'NUM'
271
+ option :shutter, type: :string, desc: 'Shutter speed', banner: 'NSEC'
272
+ option :iso, type: :string, desc: 'ISO speed rate', banner: 'NUM'
273
+ option :wb, type: :string, desc: 'White balance mode', banner: 'MODE'
274
+ option :temp, type: :numeric, desc: 'Color temperature', banner: 'K'
275
+ option :scene, type: :string, desc: 'Scene selection', banner: 'MODE'
276
+ option :flip, type: :string, desc: 'Flip', banner: 'MODE'
277
+ option :tv, type: :string, desc: 'TV color system', banner: 'MODE'
278
+ option :ir, type: :string, desc: 'IR remote control', banner: 'MODE'
279
+ option :apo, type: :string, desc: 'Auto power off', banner: 'MODE'
280
+ option :beep, type: :string, desc: 'Beep mode', banner: 'MODE'
281
+ end
282
+
283
+ # Common options for still/intervalstill shooting modes
284
+ def self.still_common_options
285
+ option :track, type: :string, desc: 'Tracking focus', banner: 'MODE'
286
+ option :self, type: :numeric, desc: 'Self timer', banner: 'NSEC'
287
+ option :flash, type: :string, desc: 'Flash mode', banner: 'MODE'
288
+ option :size, type: :string, desc: 'Still size', banner: 'PIXEL'
289
+ option :aspect, type: :string, desc: 'Still aspect', banner: 'MODE'
290
+ option :quality, type: :string, desc: 'Still quality', banner: 'MODE'
291
+ option :postview, type: :string, desc: 'Postview image size', banner: 'PIXEL'
292
+ option :angle, type: :numeric, desc: 'View angle', banner: 'DEGREE'
293
+ end
294
+
295
+ # Common options for movie/looprec shooting modes
296
+ def self.movie_common_options
297
+ option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
298
+ option :format, type: :string, desc: 'Movie Format', banner: 'MODE'
299
+ option :quality, type: :string, desc: 'Movie Quality', banner: 'MODE'
300
+ option :steady, type: :string, desc: 'Steady Mode', banner: 'MODE'
301
+ option :color, type: :string, desc: 'Color setting', banner: 'MODE'
302
+ option :noise, type: :string, desc: 'Wind noise reduction', banner: 'MODE'
303
+ option :audio, type: :string, desc: 'Audio recording', banner: 'MODE'
304
+ end
305
+
306
+
307
+ #----------------------------------------COMMAND DEFINITIONS----------------------------------------
308
+
309
+ desc 'still [options]', 'Capture still images'
310
+ option :interval, type: :numeric, desc: 'Interval of capturing (sec)', banner: 'NSEC'
311
+ option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
312
+ still_common_options
313
+ common_options
314
+ option :transfer, type: :boolean, desc: 'Transfer postview image', default: true
315
+ def still
316
+ init_camera
317
+ @cam.change_function_to_shoot 'still', 'Single'
318
+
319
+ # Set/Get options
320
+ set_still_common_options
321
+ set_common_options
322
+ if options[:setting]
323
+ get_still_common_options
324
+ get_common_options
325
+ return
326
+ end
327
+
328
+ @cam.act_zoom absolute: options[:zoom]
329
+
330
+ # Interval option resembles Intervalrec shooting mode.
331
+ # The advantage is that we can transfer captured stills each time, meanwhile Intervalrec shooting mode cannot.
332
+ # However, the interval time tends to be longer than that of Intervalrec mode.
333
+ if options[:interval]
334
+ if options[:output]
335
+ # Generate sequencial filenames based on --output option
336
+ generator = generate_sequencial_filenames options[:output], 'JPG'
337
+ end
338
+
339
+ # Capture forever until trapped by SIGINT
340
+ trapped = false
341
+ trap(:INT) { trapped = true }
342
+ puts "Capturing stills by #{options[:interval]} sec. Type C-c (SIGINT) to quit capturing."
343
+ start_time = Time.now
344
+ loop do
345
+ loop_start = Time.now
346
+ if options[:output]
347
+ @cam.capture_still filename: generator.next, transfer: options[:transfer]
348
+ else
349
+ @cam.capture_still transfer: options[:transfer]
350
+ end
351
+ if trapped
352
+ puts 'Trapped!'
353
+ break
354
+ end
355
+ loop_end = Time.now
356
+ # If total time exceeds, quit capturing.
357
+ if options[:time] && options[:time] < loop_end - start_time
358
+ puts 'Time expired!'
359
+ break
360
+ end
361
+ # Wait until specified interval elapses
362
+ elapsed = loop_end - loop_start
363
+ if options[:interval] - elapsed > 0
364
+ sleep(options[:interval] - elapsed)
365
+ end
366
+ end
367
+ trap(:INT, 'DEFAULT')
368
+ else
369
+ @cam.capture_still filename: options[:output], transfer: options[:transfer]
370
+ end
371
+ finalize
372
+ end
373
+
374
+
375
+ desc 'cont [options]', 'Capture still images continuously'
376
+ option :mode, type: :string, desc: 'Continuous shooting mode', banner: 'MODE', default: 'Single'
377
+ option :speed, type: :string, desc: 'Continuous shooting speed', banner: 'MODE'
378
+ option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
379
+ still_common_options
380
+ common_options
381
+ option :transfer, type: :boolean, desc: 'Transfer postview image', default: false
382
+ def cont
383
+ init_camera
384
+ unless @cam.support_group? :ContShootingMode
385
+ puts 'This camera does not support continuous shooting mode. Exiting...'
386
+ exit 1
387
+ end
388
+ @cam.change_function_to_shoot('still', options[:mode])
389
+
390
+ # Set/Get options
391
+ set_parameter :ContShootingMode, options[:mode]
392
+ set_parameter :ContShootingSpeed, options[:speed]
393
+ set_still_common_options
394
+ set_common_options
395
+ if options[:setting]
396
+ get_parameter_and_show :ContShootingMode
397
+ # ContShootingSpeed API will fail when ContShootingMode = 'Single'
398
+ get_parameter_and_show :ContShootingSpeed
399
+ get_still_common_options
400
+ get_common_options
401
+ return
402
+ end
403
+
404
+ @cam.act_zoom absolute: options[:zoom]
405
+
406
+ case options[:mode]
407
+ when 'Single', 'MotionShot', 'Burst'
408
+ @cam.capture_still filename: options[:output], transfer: options[:transfer]
409
+ when 'Continuous', 'Spd Priority Cont.'
410
+ @cam.start_continuous_shooting
411
+ if options[:time]
412
+ sleep options[:time]
413
+ puts 'Time expired!'
414
+ else
415
+ # Continue forever until trapped by SIGINT
416
+ trapped = false
417
+ trap(:INT) { trapped = true }
418
+ puts 'Type C-c (SIGINT) to quit recording.'
419
+ loop do
420
+ break if trapped
421
+ sleep 0.1
422
+ end
423
+ puts 'Trapped!'
424
+ trap(:INT, 'DEFAULT')
425
+ end
426
+ @cam.stop_continuous_shooting prefix: options[:output], transfer: options[:transfer]
427
+ end
428
+ finalize
429
+ end
430
+
431
+
432
+ desc 'movie [options]', 'Record movies'
433
+ option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
434
+ movie_common_options
435
+ common_options
436
+ option :transfer, type: :boolean, desc: 'Transfer recorded movie immediately'
437
+ def movie
438
+ init_camera
439
+ @cam.change_function_to_shoot('movie')
440
+
441
+ # Set/Get options
442
+ set_movie_common_options
443
+ set_common_options
444
+ if options[:setting]
445
+ get_movie_common_options
446
+ get_common_options
447
+ return
448
+ end
449
+
450
+ @cam.act_zoom absolute: options[:zoom]
451
+
452
+ @cam.start_movie_recording
453
+ if options[:time]
454
+ sleep options[:time]
455
+ puts 'Time expired!'
456
+ else
457
+ # record forever until trapped by SIGINT
458
+ trapped = false
459
+ trap(:INT) { trapped = true }
460
+ puts 'Type C-c (SIGINT) to quit recording.'
461
+ loop do
462
+ break if trapped
463
+ sleep 0.1
464
+ end
465
+ puts 'Trapped!'
466
+ trap(:INT, 'DEFAULT')
467
+ end
468
+ @cam.stop_movie_recording filename: options[:output], transfer: options[:transfer]
469
+ finalize
470
+ end
471
+
472
+
473
+ desc 'intrec [options]', 'Do interval recording'
474
+ option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
475
+ option :interval, type: :string, desc: 'Interval (sec)', banner: 'NSEC'
476
+ still_common_options
477
+ common_options
478
+ option :transfer, type: :boolean, desc: 'Transfer selected contents '
479
+ def intrec
480
+ init_camera
481
+ @cam.change_function_to_shoot('intervalstill')
482
+
483
+ # Set/Get options
484
+ set_parameter :IntervalTime, options[:interval]
485
+ set_still_common_options
486
+ set_common_options
487
+ if options[:setting]
488
+ get_parameter_and_show :IntervalTime
489
+ get_still_common_options
490
+ get_common_options
491
+ return
492
+ end
493
+
494
+ @cam.act_zoom absolute: options[:zoom]
495
+
496
+ @cam.start_interval_recording
497
+ if options[:time]
498
+ sleep options[:time]
499
+ puts 'Time expired!'
500
+ else
501
+ # continue forever until trapped by SIGINT
502
+ trapped = false
503
+ trap(:INT) { trapped = true }
504
+ puts 'Type C-c (SIGINT) to quit recording.'
505
+ loop do
506
+ break if trapped
507
+ sleep 0.1
508
+ end
509
+ puts 'Trapped!'
510
+ trap(:INT, 'DEFAULT')
511
+ end
512
+ @cam.stop_interval_recording transfer: options[:transfer]
513
+ finalize
514
+ end
515
+
516
+
517
+ desc 'looprec [options]', 'Do loop recording'
518
+ option :time, type: :numeric, desc: 'Recording time (min)', banner: 'NMIN'
519
+ option :loop_time, type: :string, desc: 'Loop recording time (min)', banner: 'NMIN'
520
+ movie_common_options
521
+ common_options
522
+ option :transfer, type: :boolean, desc: 'Transfer selected contents '
523
+ def looprec
524
+ init_camera
525
+ @cam.change_function_to_shoot('looprec')
526
+
527
+ # Set/Get options
528
+ set_parameter :LoopRecTime, options[:loop_time]
529
+ set_movie_common_options
530
+ set_common_options
531
+ if options[:setting]
532
+ get_parameter_and_show :LoopRecTime
533
+ get_movie_common_options
534
+ get_common_options
535
+ return
536
+ end
537
+
538
+ @cam.act_zoom absolute: options[:zoom]
539
+
540
+ @cam.start_loop_recording
541
+ if options[:time]
542
+ sleep(options[:time] * 60)
543
+ puts 'Time expired!'
544
+ else
545
+ # record forever until trapped by SIGINT
546
+ trapped = false
547
+ trap(:INT) { trapped = true }
548
+ puts 'Type C-c (SIGINT) to quit recording.'
549
+ loop do
550
+ break if trapped
551
+ sleep 0.1
552
+ end
553
+ puts 'Trapped!'
554
+ trap(:INT, 'DEFAULT')
555
+ end
556
+ @cam.stop_loop_recording filename: options[:output], transfer: options[:transfer]
557
+ finalize
558
+ end
559
+
560
+
561
+ desc 'liveview [options]', 'Stream liveview images'
562
+ option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
563
+ option :size, type: :string, desc: 'Liveview size', banner: 'SIZE'
564
+ common_options
565
+ def liveview
566
+ init_camera
567
+ # Set/Get options
568
+ set_common_options
569
+ if options[:setting]
570
+ get_parameter_and_show :LiveviewSize
571
+ get_common_options
572
+ return
573
+ end
574
+
575
+ @cam.act_zoom absolute: options[:zoom]
576
+
577
+ th = @cam.start_liveview_thread(time: options[:time], size: options[:size]) do |img, info|
578
+ filename = "#{img.sequence_number}.jpg"
579
+ File.write filename, img.jpeg_data
580
+ puts "Wrote: #{filename}."
581
+ end
582
+ trap(:INT) { th.kill }
583
+ puts 'Liveview download started. Type C-c (SIGINT) to quit.'
584
+ th.join
585
+ trap(:INT, 'DEFAULT')
586
+ puts 'Finished.'
587
+ finalize
588
+ end
589
+
590
+
591
+ desc 'contents [options]', 'List contents and transfer them from camera storage'
592
+ option :type, type: :array, desc: 'Contents types (still/movie_mp4/movie_xavcs)', default: nil
593
+ option :datelist, type: :boolean, desc: 'List Dates and number of contents'
594
+ option :date, type: :string, desc: 'Date (yyyyMMdd)'
595
+ option :sort, type: :string, desc: 'Sorting order [ascend/descend]', default: 'descending'
596
+ option :count, type: :numeric, desc: 'Number of contents'
597
+ option :transfer, type: :boolean, desc: 'Transfer selected contents'
598
+ option :delete, type: :boolean, desc: 'Delete contents'
599
+ def contents
600
+ init_camera
601
+ @cam.change_function_to_transfer
602
+
603
+ puts 'Retrieving...'
604
+ if options[:datelist]
605
+ dates = @cam.get_date_list date_count: options[:count]
606
+ num_contents = dates.map { |d, c| c }.inject(:+)
607
+ puts "#{dates.size} date folders / #{num_contents} contents found."
608
+ puts "Dates\t\tN-Contents"
609
+ dates.each do |date, count|
610
+ puts "#{date['title']}\t#{count}"
611
+ end
612
+ return
613
+ end
614
+
615
+ if options[:date]
616
+ contents = @cam.get_content_list type: options[:type], date: options[:date], sort: options[:sort], count: options[:count]
617
+ else
618
+ contents = @cam.get_content_list type: options[:type], sort: options[:sort], count: options[:count]
619
+ end
620
+
621
+ if contents.blank?
622
+ puts 'No contents!'
623
+ else
624
+ puts "#{contents.size} contents found."
625
+ puts "File name\t\tKind\t\tCreated time\t\tURL"
626
+ contents.each do |c|
627
+ filename = c['content']['original'][0]['fileName']
628
+ kind = c['contentKind']
629
+ ctime = c['createdTime']
630
+ url = c['content']['original'][0]['url']
631
+ puts "#{filename}\t\t#{kind}\t\t#{ctime}\t\t#{url}"
632
+ end
633
+ if options[:transfer]
634
+ @cam.transfer_contents contents
635
+ end
636
+ if options[:delete]
637
+ answer = $terminal.ask('All contents listed above are deleted. Continue? [y/N]') { |q| q.validate = /[yn]/i; q.default = 'n' }
638
+ @cam.delete_contents contents if answer == 'y'
639
+ end
640
+ end
641
+ finalize
642
+ end
643
+
644
+ end
645
+ end
646
+ end
@@ -0,0 +1,41 @@
1
+ module SonyCameraRemoteAPI
2
+ # Camera is not compatible to Camera Remote API.
3
+ class ServerNotCompatible < StandardError; end
4
+ # Given version for the API is invalid
5
+ class APIVersionInvalid < StandardError; end
6
+ # Given service type for the API is invalid
7
+ class ServiceTypeInvalid < StandardError; end
8
+ # API is proviced by multiple services, but user did not specified it
9
+ class ServiceTypeNotGiven < StandardError; end
10
+
11
+ # Waiting for event notification of camera parameter change timed out
12
+ class EventTimeoutError < StandardError; end
13
+
14
+ # Base Error class having some information as object.
15
+ class StandardErrorWithObj < StandardError
16
+ attr_reader :object
17
+ def initialize(object = nil)
18
+ @object = object
19
+ end
20
+ end
21
+
22
+ # This API is not supported by the camera
23
+ class APINotSupported < StandardErrorWithObj; end
24
+ # This API is supported but not available now
25
+ class APINotAvailable < StandardErrorWithObj; end
26
+ # Given argument is not available
27
+ class IllegalArgument < StandardErrorWithObj; end
28
+ # This API is forbidden to the general users
29
+ class APIForbidden < StandardErrorWithObj; end
30
+
31
+ # API returned error response
32
+ class APIExecutionError < StandardError
33
+ attr_reader :method, :request, :err_code, :err_msg
34
+ def initialize(method, request, response)
35
+ @method = method
36
+ @request = request
37
+ @err_code = response['error'][0]
38
+ @err_msg = response['error'][1]
39
+ end
40
+ end
41
+ end