awslive-inputlooper 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,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5d419767541f1dad5b2d78c48e6bfbcaa2ddd5696927db79776182257457b8fa
4
+ data.tar.gz: 3756e17fd1a8e81ff61fbeab5864bff7ec7417778a6d1e96d0f82215f3f95ea5
5
+ SHA512:
6
+ metadata.gz: 5ebee223608ff8c27b0ce0498f180cf13cb44fd5bb0a909f067b2a0c56c95c3a91e1ee95f7e1effb3f686e51b49a73f7a4dd1e196e9cae97002a0461879e3b55
7
+ data.tar.gz: 6711775e948903d5b0d21463598c152e0fe9339c5defbf84917e0f8b7c76568b612f76a86d88f2c1b45fa9e10665c2f625391434228448a6b5284930449426a9
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "awslive-inputlooper"
5
+ require 'optimist'
6
+
7
+
8
+ global_opts = Optimist::options do
9
+ banner "AWS Live Inputlooper, helps in switching and looping the live inputs associated with Medialive channel"
10
+ opt :access_key_id, "AWS Key", :type => :string, :short => "k"
11
+ opt :secret_access_key, "AWS Secret", :type => :string, :short => "s"
12
+ opt :channel_id, "Channel Id", :type => :string, :short => "c", :required => true
13
+ opt :playlist, "Enter the list of files in comma separated fashion", :type => :string, :short => "p"
14
+ opt :loop_delay, " Enter the Delay to be induced for looping the inputs", :type => :int, :short => "d"
15
+ opt :verbose, "Enter true for verbose", :type => :string, :short => "v"
16
+ end
17
+ puts "AWS Live Inputlooper, helps in switching and looping the live inputs associated with Medialive channel"
18
+
19
+ def print_opts
20
+ puts ""
21
+ puts "Following options can be provided.."
22
+ puts "1. switch_and_loop_inputs"
23
+ puts "2. playlist_loop_alive"
24
+ puts "3. stop_playlist_loop"
25
+ puts "4. update_playlist"
26
+ puts "5. switch_playlist"
27
+ puts "6. pause_channel"
28
+ puts "7. Quit"
29
+ end
30
+
31
+ print_opts
32
+
33
+ @input_looper = Awslive::InputLooper.new(global_opts[:channel_id])
34
+ if !global_opts[:verbose].nil? && global_opts[:verbose] == "true"
35
+ @input_looper.set_log_flag(true)
36
+ else
37
+ @input_looper.set_log_flag(false)
38
+ end
39
+ while true
40
+ #cmd = ARGV.shift # get the subcommand
41
+ cmd = gets.chomp
42
+ cmd_opts = case cmd
43
+ when "switch_and_loop_inputs" # Switch and Loop Inputs
44
+ if global_opts[:playlist].nil?
45
+ puts "Please provide playlist details"
46
+ global_opts[:playlist] = gets.chomp
47
+ end
48
+ playlist = global_opts[:playlist].split(",")
49
+ puts "Switch and looping the channel #{global_opts[:channel_id]} with playlist #{playlist}"
50
+ delay = global_opts[:loop_delay].nil? ? 5 : global_opts[:loop_delay]
51
+ @input_looper.switch_and_loop_playlist(playlist, delay)
52
+ sleep 10
53
+ puts "Playlist Alive #{@input_looper.playlist_loop_alive}"
54
+ when "playlist_loop_alive"
55
+ puts @input_looper.playlist_loop_alive
56
+ when "stop_playlist_loop"
57
+ puts @input_looper.stop_playlist_loop
58
+ when "update_playlist"
59
+ puts "Enter New Playlist "
60
+ new_playist_str = gets.chomp
61
+ new_playlist = new_playist_str.split(",")
62
+ if @input_looper.playlist_loop_alive
63
+ @input_looper.update_playlist(new_playlist)
64
+ puts "Playlist updated!"
65
+ else
66
+ puts "Switch and Loop not active"
67
+ end
68
+ when "switch_playlist"
69
+ puts "Enter New Playlist "
70
+ new_playist_str = gets.chomp
71
+ new_playlist = new_playist_str.split(",")
72
+ delay = global_opts[:loop_delay].nil? ? 5 : global_opts[:loop_delay]
73
+ @input_looper.switch_playlist(new_playlist, delay )
74
+ when "pause_channel"
75
+ @input_looper.pause_channel
76
+ when "quit"
77
+ break
78
+ else
79
+ puts "Invalid command!!, try valid command"
80
+ end
81
+ end
82
+
83
+
@@ -0,0 +1,4 @@
1
+ module ActionType
2
+ INPUT_SWITCH = "Input Switch"
3
+ PAUSE = "pause"
4
+ end
@@ -0,0 +1,9 @@
1
+ module AwsliveExceptions
2
+
3
+ class InternalException < StandardError; end
4
+
5
+ class InvalidInputException < StandardError; end
6
+
7
+ class InvalidChannelStateException < StandardError; end
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+ module AwsliveLogging
2
+ @log_enabled = true
3
+ def set_log_flag(flag)
4
+ @log_enabled = flag
5
+ end
6
+ def log(text)
7
+ puts text if @log_enabled
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module StartType
2
+ FIXED = "fixed"
3
+ FOLLOW = "follow"
4
+ IMMEDIATE = "immediate"
5
+ end
@@ -0,0 +1 @@
1
+ require 'awslive-inputlooper/input_looper'
@@ -0,0 +1,216 @@
1
+ # Internal Libraries
2
+ require_relative '../awslive-common/start_type'
3
+ require_relative '../awslive-common/action_type'
4
+ require_relative '../awslive-scheduler/schedule_action'
5
+ require_relative '../awslive-common/all_exceptions'
6
+ require_relative '../awslive-common/logging'
7
+
8
+ # Thrid Party Library.
9
+ require 'aws-sdk-medialive'
10
+
11
+
12
+ module Awslive
13
+ class InputLooper
14
+ include StartType
15
+ include ActionType
16
+ include AwsliveExceptions
17
+ include AwsliveLogging
18
+
19
+ INITAL_INPUT_ACTION_NAME = "Initial Channel Input"
20
+
21
+ def initialize(channel_id, playlist = nil)
22
+ credentials = Aws::SharedCredentials.new
23
+ if credentials.set?
24
+ @medialiveclient = Aws::MediaLive::Client.new(:credentials => credentials)
25
+ else
26
+ @medialiveclient = Aws::MediaLive::Client.new
27
+ end
28
+ @scheduler = Awslive::ScheduleAction.new(@medialiveclient)
29
+ @channel_id = channel_id
30
+ @playlist = playlist
31
+ @loop_thread = nil
32
+ end
33
+
34
+ def switch_and_loop_playlist(playlist, sleep_time = nil)
35
+ @loop_thread = Thread.new {
36
+ @playlist = playlist
37
+ log ("Switch input Monitoring started!!")
38
+ switch_input(true)
39
+ # AWS recommends to have 5 sec delay beteen the switches.
40
+ sleep 5
41
+ sleep_time = 5 if sleep_time.nil? || sleep_time < 5
42
+ loop do
43
+ success = switch_input
44
+ break if !success
45
+ sleep sleep_time
46
+ end
47
+ log( "Switch input Monitoring Stopped!!")
48
+ }
49
+ end
50
+
51
+ def playlist_loop_alive
52
+ isalive = @loop_thread.nil? ? false : @loop_thread.alive?
53
+ isalive
54
+ end
55
+
56
+ def stop_playlist_loop
57
+ Thread.kill(@loop_thread) if playlist_loop_alive
58
+ true
59
+ end
60
+
61
+ def update_playlist(playlist)
62
+ @playlist = playlist
63
+ return true
64
+ end
65
+
66
+ def switch_playlist(playlist, sleep_time = nil)
67
+ if stop_playlist_loop
68
+ switch_and_loop_playlist(playlist, sleep_time)
69
+ end
70
+ return playlist_loop_alive
71
+ end
72
+
73
+ def switch_input(force_immed = nil)
74
+ # Fetching the channel information every time to know the state of the channel and input in pipeline.
75
+ channel_info = get_channel_info
76
+ channel_state = channel_info[:state]
77
+ # the switching loop will be active only when the channel is in "RUNNING" state.
78
+ if channel_state == "RUNNING"
79
+ # Identifying one static and one dyanmic input to enable the switch and loop inputs.
80
+ static_input, dynamic_input = get_valid_inputs(channel_info[:input_attachments])
81
+
82
+ if static_input.nil? || dynamic_input.nil?
83
+ log( "No Valid inputs for Switch and loop; please provision one static and one dynamic input in the Channel #{@channel_id}")
84
+ raise InvalidInputException.new("No Valid inputs; should be provisioned with one static and one dynamic Input")
85
+ end
86
+
87
+ current_input_name = get_current_input(channel_info)
88
+ current_input_action_name = get_current_action(channel_info)
89
+ sc_action = @scheduler.get_scheudle_action(@channel_id, current_input_action_name)
90
+ log( "Current input #{current_input_name} #{current_input_action_name}")
91
+ if force_immed || sc_action.nil? || is_schedule_empty?
92
+ log( "Schedule is empty or schedule does not exist; Hence creating one immediate action with static input")
93
+ data = {}
94
+ #data[:input_ref_name] = static_input[:input_attachment_name]
95
+ data[:input_ref_name] = dynamic_input[:input_attachment_name]
96
+ data[:url_path] = @playlist[0]
97
+ @scheduler.create(@channel_id, IMMEDIATE, INPUT_SWITCH, data)
98
+ return true
99
+ end
100
+
101
+ follow_schedule = @scheduler.get_follow_schedule(@channel_id, current_input_action_name)
102
+ current_url = @scheduler.get_action_url(@channel_id, current_input_action_name)
103
+ log( "current URL #{current_url} next URL #{follow_schedule}")
104
+ unless follow_schedule.nil?
105
+ follow_url = @scheduler.get_follow_action_url(@channel_id, current_input_action_name)
106
+ log("Follow URL #{follow_url}")
107
+ next_file = identify_next_input(current_url)
108
+ log( "Next URL #{next_file}")
109
+ if !follow_url[0].nil? && next_file != follow_url[0]
110
+ log( "Playlist seems to be changed, hence aligning.")
111
+ @scheduler.delete( @channel_id,[ "#{follow_schedule[:action_name]}"])
112
+ next_input_name = dynamic_input[:input_attachment_name]
113
+ log ("next input name #{next_input_name}")
114
+ data = {}
115
+ data[:follow_input] = current_input_action_name
116
+ data[:trigger_input] = next_input_name
117
+ data[:url_path] = next_file
118
+ @scheduler.create(@channel_id, FOLLOW, INPUT_SWITCH, data)
119
+ else
120
+ log( "No change in follow schedule!. not change in playlist")
121
+ return true
122
+ end
123
+ else
124
+ log("No follow Schedule!")
125
+ next_file = identify_next_input(current_url)
126
+ unless next_file.nil?
127
+ next_input_name = dynamic_input[:input_attachment_name]
128
+ log( "Next input Name #{next_input_name} #{next_file}")
129
+ data = {}
130
+ data[:follow_input] = current_input_action_name
131
+ data[:trigger_input] = next_input_name
132
+ data[:url_path] = next_file
133
+ @scheduler.create(@channel_id, FOLLOW, INPUT_SWITCH, data)
134
+ end
135
+ end
136
+ else
137
+ log("invalid channel state #{channel_state}")
138
+ raise InvalidChannelStateException.new("Channel state Should be RUNNING, instead of #{channel_state}")
139
+ end
140
+ end
141
+
142
+ def identify_next_input(file_url)
143
+ next_file = @playlist[0]
144
+ #puts " File Url #{file_url}"
145
+ if !file_url.nil? && !file_url[0].nil?
146
+ @playlist.each_with_index do | playlist_file, index |
147
+ #puts "next file identification #{playlist_file} #{file_url[0]} #{index}"
148
+ if playlist_file == file_url[0]
149
+ if index == (@playlist.length - 1)
150
+ next_file = @playlist[0]
151
+ else
152
+ next_file = @playlist[index + 1]
153
+ end
154
+ end
155
+ end
156
+ end
157
+ next_file
158
+ end
159
+
160
+ def is_schedule_empty?
161
+ schedule_info = @medialiveclient.describe_schedule({ :channel_id => "#{@channel_id}"})
162
+ schedule_actions = schedule_info[:schedule_actions]
163
+ schedule_actions.empty?
164
+ end
165
+
166
+ def get_valid_inputs(inputs)
167
+ static_input = nil
168
+ dynamic_input = nil
169
+
170
+ inputs.each do | input |
171
+ next if input[:input_settings][:source_end_behavior] != "CONTINUE"
172
+ input_info = @medialiveclient.describe_input({ :input_id => "#{input[:input_id]}" })
173
+ if input_info[:input_source_type] == "STATIC"
174
+ static_input = input
175
+ elsif input_info[:input_source_type] == "DYNAMIC"
176
+ dynamic_input = input
177
+ end
178
+ if !static_input.nil? && !dynamic_input.nil?
179
+ break
180
+ end
181
+ end
182
+ puts static_input
183
+ puts dynamic_input
184
+ return static_input, dynamic_input
185
+ end
186
+
187
+
188
+ def get_channel_info
189
+ @medialiveclient.describe_channel({ :channel_id => "#{@channel_id}" })
190
+ end
191
+
192
+ def get_current_input(channel_info = nil )
193
+ channel_info = get_channel_info if channel_info.nil?
194
+ current_input_name = channel_info[:pipeline_details][0][:active_input_attachment_name]
195
+ current_input_name
196
+ end
197
+
198
+ def get_current_action(channel_info = nil )
199
+ channel_info = get_channel_info if channel_info.nil?
200
+ current_action_name = channel_info[:pipeline_details][0][:active_input_switch_action_name]
201
+ current_action_name
202
+ end
203
+
204
+
205
+ def get_channel_class(channel_info = nil)
206
+ channel_info = get_channel_info if channel_info.nil?
207
+ channel_info[:channel_class]
208
+ end
209
+
210
+ def pause_channel
211
+ @scheduler.create(@channel_id, IMMEDIATE, PAUSE, get_channel_class)
212
+ end
213
+
214
+ end
215
+
216
+ end
@@ -0,0 +1,56 @@
1
+ module Awslive
2
+ class InputSwitchScheduleAction
3
+
4
+ FOLLOW_HASH = {
5
+ action_name: "f1",
6
+ schedule_action_start_settings: {
7
+ follow_mode_schedule_action_start_settings: {
8
+ reference_action_name: "imm",
9
+ follow_point: "END"
10
+ }
11
+ },
12
+ schedule_action_settings: {
13
+ input_switch_settings: {
14
+ input_attachment_name_reference: "input1",
15
+ url_path: []
16
+ }
17
+ }
18
+ }
19
+
20
+ IMMEDIATE_HASH = {
21
+ :action_name => "action_name",
22
+ :schedule_action_start_settings => {
23
+ :immediate_mode_schedule_action_start_settings => {}
24
+ },
25
+ :schedule_action_settings => {
26
+ :input_switch_settings => {
27
+ :input_attachment_name_reference => "input_name",
28
+ :url_path => []
29
+ }
30
+ }
31
+ }
32
+
33
+ def get_immediate_schedule_action( input_ref_name, urlpath = nil)
34
+ action_hash = IMMEDIATE_HASH.clone
35
+ action_hash[:action_name] = "#{get_action_id}"
36
+ action_hash[:schedule_action_settings][:input_switch_settings][:input_attachment_name_reference] = "#{input_ref_name}"
37
+ action_hash[:schedule_action_settings][:input_switch_settings][:url_path] = [ urlpath ] unless urlpath.nil?
38
+ action_hash
39
+ end
40
+
41
+ def get_follow_schedule_action(follow_input, trigger_input, urlpath = nil)
42
+ action_hash = FOLLOW_HASH.clone
43
+ action_hash[:action_name] = "#{get_action_id}"
44
+ puts "action hash #{action_hash}"
45
+ action_hash[:schedule_action_start_settings][:follow_mode_schedule_action_start_settings][:reference_action_name] = "#{follow_input}"
46
+ action_hash[:schedule_action_settings][:input_switch_settings][:input_attachment_name_reference] = "#{trigger_input}"
47
+ action_hash[:schedule_action_settings][:input_switch_settings][:url_path] = [ urlpath ] unless urlpath.nil?
48
+ action_hash
49
+ end
50
+
51
+ def get_action_id
52
+ Time.now.to_i
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,40 @@
1
+ module Awslive
2
+ class PauseScheduleAction
3
+
4
+ PAUSE_HASH = {
5
+ :action_name => "pause",
6
+ :schedule_action_start_settings => {
7
+ :fixed_mode_schedule_action_start_settings => {
8
+ :time => "2019-12-22T14:36:01.302Z"
9
+ }
10
+ },
11
+ :schedule_action_settings => {
12
+ :pause_state_settings => {
13
+ :pipelines => []
14
+ }
15
+ }
16
+ }
17
+
18
+ def get_pause_schedule_action(type)
19
+ action_hash = PAUSE_HASH.clone
20
+ action_hash["actionName"] = "#{get_action_id}"
21
+ exec_time = ( Time.now + 10 ).iso8601
22
+ action_hash["scheduleActionStartSettings"]["fixedModeScheduleActionStartSettings"]["time"] = "#{exec_time}"
23
+ pipelines = []
24
+ pipelines << {
25
+ pipeline_id: "PIPELINE_0"
26
+ }
27
+ if type == "STANDARD"
28
+ pipelines << {
29
+ pipeline_id: "PIPELINE_1"
30
+ }
31
+ end
32
+ action_hash["scheduleActionSettings"]["pauseStateSettings"]["pipelines"] = pipelines
33
+ action_hash
34
+ end
35
+
36
+ def get_action_id
37
+ Time.now.to_i
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,123 @@
1
+ require_relative '../awslive-common/action_type'
2
+ require_relative '../awslive-common/start_type'
3
+ require_relative 'input_switch_schedule_action'
4
+ require_relative 'pause_schedule_action'
5
+
6
+ require 'aws-sdk-medialive'
7
+
8
+ module Awslive
9
+ class ScheduleAction
10
+ include ActionType
11
+ include StartType
12
+
13
+ def initialize(mediaclient = nil)
14
+ if !mediaclient.nil?
15
+ @mediaclient = mediaclient
16
+ else
17
+ credentials = Aws::SharedCredentials.new
18
+ @mediaclient = Aws::MediaLive::Client.new(:credentials => credentials)
19
+ end
20
+ @input_switch_schedule_action = Awslive::InputSwitchScheduleAction.new
21
+ @pause_schedule_action = Awslive::PauseScheduleAction.new
22
+ end
23
+
24
+ def create_schedule(channel_id, scheduled_actions )
25
+ payload = {
26
+ channel_id: "#{channel_id}",
27
+ creates: {
28
+ schedule_actions: scheduled_actions
29
+ }
30
+ }
31
+ @mediaclient.batch_update_schedule( payload )
32
+ end
33
+
34
+ def delete(channel_id, action_names)
35
+ @mediaclient.batch_update_schedule( {
36
+ channel_id: "#{channel_id}",
37
+ deletes: {
38
+ action_names: action_names
39
+ }
40
+ } )
41
+
42
+ end
43
+
44
+ def get_follow_schedule(channel_id, action_name)
45
+ follow_schedule = nil
46
+ response = @mediaclient.describe_schedule({channel_id: "#{channel_id}", max_results: 100 } )
47
+ loop do
48
+ response[:schedule_actions].each do | schedule_action |
49
+ unless schedule_action[:schedule_action_start_settings][:follow_mode_schedule_action_start_settings].nil?
50
+ # This is follow action
51
+ if schedule_action[:schedule_action_start_settings][:follow_mode_schedule_action_start_settings][:reference_action_name] == action_name
52
+ follow_schedule = schedule_action
53
+ break
54
+ end
55
+ end
56
+ end
57
+ break if !follow_schedule.nil? || response[:next_token].nil?
58
+ response = @mediaclient.describe_schedule({channel_id: "#{channel_id}", max_results: 100, next_token: response[:next_token] } )
59
+ end
60
+ follow_schedule
61
+ end
62
+
63
+ def create(channel_id, start_type, action_type, data)
64
+ scheduled_action = []
65
+ if action_type == INPUT_SWITCH
66
+ if start_type == IMMEDIATE
67
+ scheduled_action << @input_switch_schedule_action.get_immediate_schedule_action(data[:input_ref_name], data[:url_path])
68
+ elsif start_type == FOLLOW
69
+ scheduled_action << @input_switch_schedule_action.get_follow_schedule_action(data[:follow_input], data[:trigger_input], data[:url_path])
70
+ end
71
+ elsif action_type == PAUSE
72
+ if start_type == FIXED
73
+ scheduled_action << @pause_scheduler.get_pause_schedule_action(data[:channel_class])
74
+ end
75
+ end
76
+ unless scheduled_action.empty?
77
+ create_response = create_schedule(channel_id, scheduled_action)
78
+ end
79
+ create_response
80
+ end
81
+
82
+ def get_scheudle_action(channel_id, action_name)
83
+ sc_action = nil
84
+ response = @mediaclient.describe_schedule({
85
+ channel_id: "#{channel_id}", max_results: 100
86
+ })
87
+ loop do
88
+ response[:schedule_actions].each do | schedule_action |
89
+ if schedule_action[:action_name] == action_name
90
+ sc_action = schedule_action
91
+ break
92
+ end
93
+ end
94
+ break if !sc_action.nil? || response[:next_token].nil?
95
+ response = @mediaclient.describe_schedule({channel_id: "#{channel_id}", max_results: 100, next_token: response[:next_token] } )
96
+ end
97
+ sc_action
98
+ end
99
+
100
+ def get_follow_action_url(channel_id, action_name)
101
+ url = nil
102
+ follow_schedule = get_follow_schedule(channel_id, action_name)
103
+ url = follow_schedule[:schedule_action_settings][:input_switch_settings][:url_path] unless follow_schedule.nil?
104
+ url
105
+ end
106
+
107
+ def get_action_url(channel_id, action_name)
108
+ url = nil
109
+ follow_schedule = get_scheudle_action(channel_id, action_name)
110
+ puts "Follow Schedule #{follow_schedule}"
111
+ url = follow_schedule[:schedule_action_settings][:input_switch_settings][:url_path] unless follow_schedule.nil?
112
+ url
113
+ end
114
+
115
+ def get_action_id
116
+ Time.now.to_i
117
+ end
118
+
119
+ def delete_all(channel_id)
120
+ @mediaclient.delete_schedule({ channel_id: channel_id })
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,8 @@
1
+ require 'awslive-inputlooper'
2
+
3
+ class AwsliveInputLooperTest
4
+ end
5
+
6
+ playlist = ["s3transition-lambda-poc/frozen_test1.mp4", "s3transition-lambda-poc/oceans.mp4", "s3transition-lambda-poc/big-bunny1.mp4", "s3transition-lambda-poc/sample1.mp4"]
7
+ looper = Awslive::InputLooper.new("2179374", playlist)
8
+ looper.switch_and_loop_playlist
@@ -0,0 +1,11 @@
1
+ require_relative './input-switch/put-switch/input_switch_schedule_action'
2
+
3
+ =begin
4
+ class ScheduleActionTest
5
+
6
+ end
7
+ =end
8
+ credentials = Aws::SharedCredentials.new
9
+ medialiveclient = Aws::MediaLive::Client.new(:credentials => credentials)
10
+ input_switch_action = InputSwitchScheduleAction.new(medialiveclient)
11
+ puts input_switch_action.get_immediate_schedule_action("test")
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: awslive-inputlooper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Maheshwaran G
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-01-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: aws-sdk-medialive
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.40'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.40'
55
+ - !ruby/object:Gem::Dependency
56
+ name: optimist
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: AWS live Input Looper gem helps in switching & looping live inputs in
70
+ AWS Medialive channel, enabling VOD playlist as live in a sequence / circular loop
71
+ fashion
72
+ email:
73
+ - pgmaheshwaran@gmail.com
74
+ executables:
75
+ - awslive-inputlooper
76
+ extensions: []
77
+ extra_rdoc_files: []
78
+ files:
79
+ - bin/awslive-inputlooper
80
+ - lib/awslive-common/action_type.rb
81
+ - lib/awslive-common/all_exceptions.rb
82
+ - lib/awslive-common/logging.rb
83
+ - lib/awslive-common/start_type.rb
84
+ - lib/awslive-inputlooper.rb
85
+ - lib/awslive-inputlooper/input_looper.rb
86
+ - lib/awslive-scheduler/input_switch_schedule_action.rb
87
+ - lib/awslive-scheduler/pause_schedule_action.rb
88
+ - lib/awslive-scheduler/schedule_action.rb
89
+ - lib/test/awslive_input_looper_test.rb
90
+ - lib/test/schedule_action_test.rb
91
+ homepage: https://github.com/ooyala/awslive-input-looper
92
+ licenses:
93
+ - MIT
94
+ metadata:
95
+ homepage_uri: https://github.com/ooyala/awslive-input-looper
96
+ source_code_uri: https://github.com/ooyala/awslive-input-looper
97
+ changelog_uri: https://github.com/ooyala/awslive-input-looper
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubygems_version: 3.1.2
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: AWS live Input Looper gem helps in switching & looping live inputs in AWS
117
+ Medialive channel, enabling VOD playlist as live in a sequence / circular loop fashion
118
+ test_files: []