awslive-inputlooper 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []