awslive-inputlooper 0.1.9 → 0.2.6

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.
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