awslive-inputlooper 0.1.9 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a11c3375ccc5456235263b78f407cf2d1c533775dacb8f8bb60a5cfadc2075a4
4
- data.tar.gz: e1f7cf9a62c6726352ae5900e0f1bb54176a688067855b932d9ac8d10d2d0ea7
3
+ metadata.gz: d9d5e1cccddf98cc55107733f14256f531af1aeff0bb6e50e2b183897dd69052
4
+ data.tar.gz: 6540207814106773f683346f7425d84170e7bf46e07c4875270f87c2bf6b991d
5
5
  SHA512:
6
- metadata.gz: ae17691c433f2e5ef37632dd0c0f4cab629b5fd2bf7574579138c6a0dd9846a9eee1012c8f9debf383b54da5ed698641b31023f94e740e27f222e0e43bb0a631
7
- data.tar.gz: a7c67fdaf217a8ba8be62c62a8b7419882ea9d53eb5c6b185bd4c4ea24a498f97c8b883412280b8ec916e710a7b23c799cfe50bce568dc753858378b6b94ef42
6
+ metadata.gz: 5357250243ae0a7b6c146e1351c604208b189f24ea9e9d07e317a1c504e4f0e4ddd227a9c89fea8b2f2e901c3abee2152bf0b84635c9cff05e8cec9c3e2c088b
7
+ data.tar.gz: fe1748e93bdb22ca0f27191ae0392445df6ce416c78176d1ad7755fbb0c521ce5f7498f6346bfc842e3e6f4c94486225de27c707148b4f4bbb78abe41dc4931f
@@ -1,5 +1,7 @@
1
1
  module ActionType
2
- INPUT_SWITCH = "Input Switch"
3
- PAUSE = "pause"
4
- UNPAUSE = "unpause"
2
+ INPUT_SWITCH = "input_switch"
3
+ PAUSE = "pause_state"
4
+ UNPAUSE = "unpause_state"
5
+ INPUT_PREPARE = "input_prepare"
6
+ SCTE35_SPLICE_INSERT = "scte_35_splice_insert"
5
7
  end
@@ -32,6 +32,7 @@ module Awslive
32
32
  @channel_id = channel_id
33
33
  @playlist = playlist
34
34
  @loop_thread = nil
35
+ set_log_flag(true)
35
36
  end
36
37
 
37
38
  def switch_and_loop_playlist(playlist, sleep_time = nil)
@@ -73,7 +74,7 @@ module Awslive
73
74
  return playlist_loop_alive
74
75
  end
75
76
 
76
- def switch_input(force_immed = nil, exclude_query_param = nil)
77
+ def switch_input(force_immed = nil, exclude_query_param = nil, loopback = nil)
77
78
  # Fetching the channel information every time to know the state of the channel and input in pipeline.
78
79
  channel_info = get_channel_info
79
80
  channel_state = channel_info[:state]
@@ -89,7 +90,7 @@ module Awslive
89
90
 
90
91
  current_input_name = get_current_input_name(channel_info)
91
92
  current_input_action_name = get_current_action(channel_info)
92
- sc_action = @scheduler.get_scheudle_action(@channel_id, current_input_action_name)
93
+ sc_action = @scheduler.get_schedule_action(@channel_id, current_input_action_name)
93
94
  log( "Current input #{current_input_name} #{current_input_action_name}")
94
95
  if force_immed || sc_action.nil? || is_schedule_empty?
95
96
  log( "Schedule is empty or schedule does not exist; Hence creating one immediate action with static input")
@@ -102,14 +103,20 @@ module Awslive
102
103
  end
103
104
 
104
105
  follow_schedule = @scheduler.get_follow_schedule(@channel_id, current_input_action_name)
106
+ log( "Follow Schedule => #{follow_schedule}")
105
107
  current_url = @scheduler.get_action_url(@channel_id, current_input_action_name)
106
- log( "current URL #{current_url} next URL #{follow_schedule}")
108
+ log("Current URL => #{current_url}")
109
+ next_file = identify_next_input(current_url, exclude_query_param, loopback )
110
+ log("Next URL => #{next_file}")
111
+ if next_file.nil? && follow_schedule.nil? && !loopback
112
+ log ("end of playlist and loopback not enabled!!")
113
+ return
114
+ end
115
+ log( "current URL #{current_url} next URL #{next_file}")
107
116
  unless follow_schedule.nil?
108
117
  follow_url = @scheduler.get_follow_action_url(@channel_id, current_input_action_name)
109
118
  log("Follow URL #{follow_url}")
110
- next_file = identify_next_input(current_url, exclude_query_param)
111
- log( "Next URL #{next_file}")
112
- if !follow_url[0].nil? && next_file != follow_url[0]
119
+ if !follow_url[0].nil? && next_file.split('?')[0] != follow_url[0].split('?')[0]
113
120
  log( "Playlist seems to be changed, hence aligning.")
114
121
  @scheduler.delete( @channel_id,[ "#{follow_schedule[:action_name]}"])
115
122
  next_input_name = dynamic_input[:input_attachment_name]
@@ -125,7 +132,7 @@ module Awslive
125
132
  end
126
133
  else
127
134
  log("No follow Schedule!")
128
- next_file = identify_next_input(current_url, exclude_query_param)
135
+ #next_file = identify_next_input(current_url, exclude_query_param)
129
136
  unless next_file.nil?
130
137
  next_input_name = dynamic_input[:input_attachment_name]
131
138
  log( "Next input Name #{next_input_name} #{next_file}")
@@ -142,21 +149,70 @@ module Awslive
142
149
  end
143
150
  end
144
151
 
145
- def identify_next_input(file_url, exclude_query_param)
152
+ def is_url_duplicated(url)
153
+ match_count = 0
154
+ is_duplicated = false
155
+ @playlist.each_with_index do | playlist_file, index |
156
+ playlist_file = playlist_file.split('?')[0]
157
+ if playlist_file == url.split('?')[0]
158
+ match_count = match_count + 1
159
+ end
160
+ if match_count >= 2
161
+ is_duplicated = true
162
+ break
163
+ end
164
+ end
165
+ is_duplicated
166
+ end
167
+
168
+ def get_order(url)
169
+ puts "URL => #{url}"
170
+ order = nil
171
+ if !url.nil?
172
+ uri = URI.parse(url) rescue nil
173
+ params = CGI.parse(uri.query) unless uri.nil?
174
+ if !params.nil?
175
+ order = params["order"].first rescue nil
176
+ end
177
+ end
178
+ order
179
+ end
180
+
181
+ def identify_next_input(file_url, exclude_query_param, loopback = true)
146
182
  next_file = @playlist[0]
147
183
  #puts " File Url #{file_url}"
148
184
  if !file_url.nil? && !file_url[0].nil?
185
+ is_duplicated = is_url_duplicated(file_url[0])
186
+ log( "URL Duplicate => #{is_duplicated}")
149
187
  @playlist.each_with_index do | playlist_file, index |
150
188
  #puts "next file identification #{playlist_file} #{file_url[0]} #{index}"
151
189
  if !exclude_query_param.nil?
152
- playlist_file = playlist_file.split('?')[0]
153
- file_url[0] = file_url[0].split('?')[0]
190
+ pfile = playlist_file.split('?')[0]
191
+ cfile = file_url[0].split('?')[0]
192
+ else
193
+ pfile = playlist_file
194
+ cfile = file_url[0]
154
195
  end
155
- if playlist_file == file_url[0]
196
+ log("pfile => #{pfile}")
197
+ log("cfile => #{cfile}")
198
+ if pfile == cfile
199
+ if is_duplicated
200
+ p_order = get_order(playlist_file)
201
+ c_order = get_order(file_url[0])
202
+ log("playlist Order #{p_order} : current order #{c_order}")
203
+ end
204
+ log("is Duplicated #{is_duplicated} porder #{p_order} corder #{c_order} ")
205
+ next if is_duplicated && !p_order.nil? && !c_order.nil? && p_order != c_order && index != (@playlist.length - 1)
206
+ #puts "passed Next #{index} and #{@playlist.length}"
156
207
  if index == (@playlist.length - 1)
208
+ if !loopback
209
+ next_file = nil
210
+ break
211
+ end
157
212
  next_file = @playlist[0]
158
213
  else
159
214
  next_file = @playlist[index + 1]
215
+ break
160
216
  end
161
217
  end
162
218
  end
@@ -305,5 +361,8 @@ module Awslive
305
361
  @scheduler.create(@channel_id, FIXED, UNPAUSE, { :channel_class => "#{get_channel_class}" })
306
362
  end
307
363
 
364
+ def delete_all_schedules
365
+ @scheduler.delete_all(@channel_id)
366
+ end
308
367
  end
309
- end
368
+ end
@@ -0,0 +1,53 @@
1
+ module Awslive
2
+ class AdMarkerScheduledAction
3
+ FOLLOW_HASH = {
4
+ action_name: "f1",
5
+ schedule_action_start_settings: {
6
+ follow_mode_schedule_action_start_settings: {
7
+ reference_action_name: "imm",
8
+ follow_point: "END"
9
+ }
10
+ },
11
+ schedule_action_settings: {
12
+ :scte_35_splice_insert_settings => {
13
+ :duration => 1,
14
+ :splice_event_id => 1
15
+ }
16
+ }
17
+ }
18
+
19
+ IMMEDIATE_HASH = {
20
+ :action_name => "action_name",
21
+ :schedule_action_start_settings => {
22
+ :immediate_mode_schedule_action_start_settings => {}
23
+ },
24
+ :schedule_action_settings => {
25
+ :scte_35_splice_insert_settings => {
26
+ :duration => 1,
27
+ :splice_event_id => 1
28
+ }
29
+ }
30
+ }
31
+
32
+ def get_immediate_schedule_action( ad_duration )
33
+ action_hash = IMMEDIATE_HASH.clone
34
+ action_hash[:action_name] = "#{get_action_id}-ad"
35
+ action_hash[:schedule_action_settings][:scte_35_splice_insert_settings][:duration] = ad_duration * 90000
36
+ action_hash[:schedule_action_settings][:scte_35_splice_insert_settings][:splice_event_id] = get_action_id
37
+ action_hash
38
+ end
39
+
40
+ def get_follow_schedule_action(follow_input, ad_duration)
41
+ action_hash = FOLLOW_HASH.clone
42
+ action_hash[:action_name] = "#{get_action_id}-ad"
43
+ action_hash[:schedule_action_start_settings][:follow_mode_schedule_action_start_settings][:reference_action_name] = "#{follow_input}"
44
+ action_hash[:schedule_action_settings][:scte_35_splice_insert_settings][:duration] = ad_duration * 90000
45
+ action_hash[:schedule_action_settings][:scte_35_splice_insert_settings][:splice_event_id] = get_action_id
46
+ action_hash
47
+ end
48
+
49
+ def get_action_id
50
+ Time.now.to_i
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,26 @@
1
+ module Awslive
2
+ class InputPrepareScheduleAction
3
+ IMMEDIATE_HASH = {
4
+ :action_name => "action_name",
5
+ :schedule_action_start_settings => {
6
+ :immediate_mode_schedule_action_start_settings => {}
7
+ },
8
+ :schedule_action_settings => {
9
+ :input_prepare_settings => {
10
+ :input_attachment_name_reference => "input_name"
11
+ }
12
+ }
13
+ }
14
+
15
+ def get_immediate_schedule_action( input_ref_name)
16
+ action_hash = IMMEDIATE_HASH.clone
17
+ action_hash[:action_name] = "#{get_action_id}"
18
+ action_hash[:schedule_action_settings][:input_prepare_settings][:input_attachment_name_reference] = "#{input_ref_name}"
19
+ action_hash
20
+ end
21
+
22
+ def get_action_id
23
+ Time.now.to_i
24
+ end
25
+ end
26
+ end
@@ -41,7 +41,6 @@ module Awslive
41
41
  def get_follow_schedule_action(follow_input, trigger_input, urlpath = nil)
42
42
  action_hash = FOLLOW_HASH.clone
43
43
  action_hash[:action_name] = "#{get_action_id}"
44
- puts "action hash #{action_hash}"
45
44
  action_hash[:schedule_action_start_settings][:follow_mode_schedule_action_start_settings][:reference_action_name] = "#{follow_input}"
46
45
  action_hash[:schedule_action_settings][:input_switch_settings][:input_attachment_name_reference] = "#{trigger_input}"
47
46
  action_hash[:schedule_action_settings][:input_switch_settings][:url_path] = [ urlpath ] unless urlpath.nil?
@@ -2,6 +2,10 @@ require_relative '../awslive-common/action_type'
2
2
  require_relative '../awslive-common/start_type'
3
3
  require_relative 'input_switch_schedule_action'
4
4
  require_relative 'pause_schedule_action'
5
+ require_relative 'ad_marker_scheduled_action'
6
+ require_relative 'input_prepare_schedule_action'
7
+ require 'uri'
8
+ require 'cgi'
5
9
 
6
10
  require 'aws-sdk-medialive'
7
11
 
@@ -19,6 +23,8 @@ module Awslive
19
23
  end
20
24
  @input_switch_schedule_action = Awslive::InputSwitchScheduleAction.new
21
25
  @pause_schedule_action = Awslive::PauseScheduleAction.new
26
+ @ad_marker_schedule_action = Awslive::AdMarkerScheduledAction.new
27
+ @input_prepare_schedule_action = Awslive::InputPrepareScheduleAction.new
22
28
  end
23
29
 
24
30
  def create_schedule(channel_id, scheduled_actions )
@@ -42,6 +48,7 @@ module Awslive
42
48
  end
43
49
 
44
50
  def get_follow_schedule(channel_id, action_name)
51
+ puts "Follow for action Name : #{action_name}"
45
52
  follow_schedule = nil
46
53
  response = @mediaclient.describe_schedule({channel_id: "#{channel_id}", max_results: 100 } )
47
54
  loop do
@@ -49,6 +56,11 @@ module Awslive
49
56
  unless schedule_action[:schedule_action_start_settings][:follow_mode_schedule_action_start_settings].nil?
50
57
  # This is follow action
51
58
  if schedule_action[:schedule_action_start_settings][:follow_mode_schedule_action_start_settings][:reference_action_name] == action_name
59
+ # Identifying only the input switch follow action for right follow up! as it provides SCTE35 follow up as well.
60
+ puts "Scheduled Action #{schedule_action}"
61
+ if schedule_action[:schedule_action_settings][:input_switch_settings].nil?
62
+ next
63
+ end
52
64
  follow_schedule = schedule_action
53
65
  break
54
66
  end
@@ -60,13 +72,39 @@ module Awslive
60
72
  follow_schedule
61
73
  end
62
74
 
75
+ def get_type_duration(url)
76
+ type = nil
77
+ duration = nil
78
+ if !url.nil?
79
+ uri = URI.parse(url) rescue nil
80
+ params = CGI.parse(uri.query) unless uri.nil?
81
+ if !params.nil?
82
+ type = params["type"].first rescue nil
83
+ duration = params["duration"].first rescue nil
84
+ end
85
+ end
86
+ return type, duration
87
+ end
88
+
63
89
  def create(channel_id, start_type, action_type, data)
64
90
  scheduled_action = []
91
+ ad_scheduled_action = []
92
+ create_response = []
93
+
65
94
  if action_type == INPUT_SWITCH
66
95
  if start_type == IMMEDIATE
67
96
  scheduled_action << @input_switch_schedule_action.get_immediate_schedule_action(data[:input_ref_name], data[:url_path])
97
+ type, duration = get_type_duration(data[:url_path])
98
+ if !type.nil? && !duration.nil? && type == "ad_marker"
99
+ ad_scheduled_action << @ad_marker_schedule_action.get_immediate_schedule_action(duration)
100
+ end
68
101
  elsif start_type == FOLLOW
69
102
  scheduled_action << @input_switch_schedule_action.get_follow_schedule_action(data[:follow_input], data[:trigger_input], data[:url_path])
103
+ type, duration = get_type_duration(data[:url_path])
104
+ if !type.nil? && !duration.nil? && type == "ad_marker"
105
+ puts "ad marker provisioned for duration => #{duration}"
106
+ ad_scheduled_action << @ad_marker_schedule_action.get_follow_schedule_action(data[:follow_input], duration.to_i)
107
+ end
70
108
  end
71
109
  elsif action_type == PAUSE
72
110
  if start_type == FIXED
@@ -76,14 +114,26 @@ module Awslive
76
114
  if start_type == FIXED
77
115
  scheduled_action << @pause_schedule_action.get_unpause_schedule_action
78
116
  end
117
+ elsif action_type == INPUT_PREPARE
118
+ if start_type == IMMEDIATE
119
+ scheduled_action << @input_prepare_schedule_action.get_immediate_schedule_action(data[:input_ref_name])
120
+ end
79
121
  end
122
+
123
+
124
+
80
125
  unless scheduled_action.empty?
81
- create_response = create_schedule(channel_id, scheduled_action)
126
+ create_response << create_schedule(channel_id, scheduled_action)
127
+ unless ad_scheduled_action.empty?
128
+ puts "Ad Schedule Action #{ad_scheduled_action}"
129
+ create_response << create_schedule(channel_id, ad_scheduled_action) rescue nil
130
+ end
82
131
  end
132
+
83
133
  create_response
84
134
  end
85
135
 
86
- def get_scheudle_action(channel_id, action_name)
136
+ def get_schedule_action(channel_id, action_name)
87
137
  sc_action = nil
88
138
  response = @mediaclient.describe_schedule({
89
139
  channel_id: "#{channel_id}", max_results: 100
@@ -101,6 +151,35 @@ module Awslive
101
151
  sc_action
102
152
  end
103
153
 
154
+ def get_schedule_action_type(schedule_action)
155
+ action_type = nil
156
+ schedule_action[:schedule_action_settings].each_pair do | key, value |
157
+ if !value.nil?
158
+ action_type = key.to_s.sub!("_settings","")
159
+ break
160
+ end
161
+ end
162
+ action_type
163
+ end
164
+
165
+ def get_schedule_actions_by_type(channel_id, action_type)
166
+ sc_actions = []
167
+ response = @mediaclient.describe_schedule({
168
+ channel_id: "#{channel_id}", max_results: 100
169
+ })
170
+ loop do
171
+ response[:schedule_actions].each do | schedule_action |
172
+ current_action_type = get_schedule_action_type(schedule_action)
173
+ if current_action_type == action_type
174
+ sc_actions << schedule_action
175
+ end
176
+ end
177
+ break if response[:next_token].nil?
178
+ response = @mediaclient.describe_schedule({channel_id: "#{channel_id}", max_results: 100, next_token: response[:next_token] } )
179
+ end
180
+ sc_actions
181
+ end
182
+
104
183
  def get_follow_action_url(channel_id, action_name)
105
184
  url = nil
106
185
  follow_schedule = get_follow_schedule(channel_id, action_name)
@@ -110,8 +189,7 @@ module Awslive
110
189
 
111
190
  def get_action_url(channel_id, action_name)
112
191
  url = nil
113
- follow_schedule = get_scheudle_action(channel_id, action_name)
114
- puts "Follow Schedule #{follow_schedule}"
192
+ follow_schedule = get_schedule_action(channel_id, action_name)
115
193
  url = follow_schedule[:schedule_action_settings][:input_switch_settings][:url_path] unless follow_schedule.nil?
116
194
  url
117
195
  end
@@ -124,4 +202,4 @@ module Awslive
124
202
  @mediaclient.delete_schedule({ channel_id: channel_id })
125
203
  end
126
204
  end
127
- end
205
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: awslive-inputlooper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maheshwaran G
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-24 00:00:00.000000000 Z
11
+ date: 2020-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -83,6 +83,8 @@ files:
83
83
  - lib/awslive-common/start_type.rb
84
84
  - lib/awslive-inputlooper.rb
85
85
  - lib/awslive-inputlooper/input_looper.rb
86
+ - lib/awslive-scheduler/ad_marker_scheduled_action.rb
87
+ - lib/awslive-scheduler/input_prepare_schedule_action.rb
86
88
  - lib/awslive-scheduler/input_switch_schedule_action.rb
87
89
  - lib/awslive-scheduler/pause_schedule_action.rb
88
90
  - lib/awslive-scheduler/schedule_action.rb