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 +4 -4
- data/lib/awslive-common/action_type.rb +5 -3
- data/lib/awslive-inputlooper/input_looper.rb +71 -12
- data/lib/awslive-scheduler/ad_marker_scheduled_action.rb +53 -0
- data/lib/awslive-scheduler/input_prepare_schedule_action.rb +26 -0
- data/lib/awslive-scheduler/input_switch_schedule_action.rb +0 -1
- data/lib/awslive-scheduler/schedule_action.rb +83 -5
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9d5e1cccddf98cc55107733f14256f531af1aeff0bb6e50e2b183897dd69052
|
4
|
+
data.tar.gz: 6540207814106773f683346f7425d84170e7bf46e07c4875270f87c2bf6b991d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5357250243ae0a7b6c146e1351c604208b189f24ea9e9d07e317a1c504e4f0e4ddd227a9c89fea8b2f2e901c3abee2152bf0b84635c9cff05e8cec9c3e2c088b
|
7
|
+
data.tar.gz: fe1748e93bdb22ca0f27191ae0392445df6ce416c78176d1ad7755fbb0c521ce5f7498f6346bfc842e3e6f4c94486225de27c707148b4f4bbb78abe41dc4931f
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module ActionType
|
2
|
-
INPUT_SWITCH
|
3
|
-
PAUSE
|
4
|
-
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.
|
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(
|
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
|
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
|
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
|
-
|
153
|
-
|
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
|
-
|
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
|
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
|
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 =
|
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.
|
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-
|
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
|