wco_models 3.1.0.223 → 3.1.0.225

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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/wco/newsvideos.scss +58 -0
  3. data/app/controllers/wco/api/newsvideos_controller.rb +23 -0
  4. data/app/controllers/wco/newsoverlay_configs_controller.rb +11 -0
  5. data/app/controllers/wco/newsoverlays_controller.rb +62 -0
  6. data/app/controllers/wco/newspartials_controller.rb +8 -3
  7. data/app/controllers/wco/newsvideos_controller.rb +164 -20
  8. data/app/jobs/wco/newspartial_video_job.rb +15 -0
  9. data/app/jobs/wco/newsvideo_illustration_job.rb +33 -0
  10. data/app/models/wco/newsoverlay.rb +44 -0
  11. data/app/models/wco/newsoverlay_config.rb +13 -0
  12. data/app/models/wco/newspartial.rb +43 -2
  13. data/app/models/wco/newsvideo.rb +13 -1
  14. data/app/models/wco/video.rb +3 -1
  15. data/app/views/layouts/wco/application.haml +0 -1
  16. data/app/views/wco/_main_footer.haml +36 -33
  17. data/app/views/wco/_main_header.haml +6 -3
  18. data/app/views/wco/newsoverlay_configs/_form.haml +15 -0
  19. data/app/views/wco/newsoverlay_configs/new.haml +4 -0
  20. data/app/views/wco/newsoverlays/_form.haml +22 -0
  21. data/app/views/wco/newsoverlays/_show_in_newsvideo.haml +10 -0
  22. data/app/views/wco/newsoverlays/edit.haml +4 -0
  23. data/app/views/wco/newsoverlays/new.haml +4 -0
  24. data/app/views/wco/newspartials/_show_in_newsvideo.haml +24 -23
  25. data/app/views/wco/newsvideos/index.haml +1 -1
  26. data/app/views/wco/newsvideos/show.haml +19 -7
  27. data/app/views/wco/reports/_index.haml +12 -13
  28. data/app/views/wco/videos/_form.haml +3 -0
  29. data/app/views/wco/videos/_index.haml +2 -0
  30. data/app/views/wco/videos/index.haml +1 -2
  31. data/app/views/wco/videos/show.haml +1 -0
  32. data/config/routes.rb +7 -0
  33. data/lib/wco_models.rb +5 -0
  34. metadata +15 -2
  35. data/app/assets/stylesheets/wco/newsvideos_newspartials.scss +0 -31
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f69322c6f97753488603d03b7438b7855f404df3b30dfc195c9b67ab4d2bc9c
4
- data.tar.gz: e075c71ede3d49b95c7163f2224c58aee5879db95c226a215ad730c27331e68e
3
+ metadata.gz: 7ca7ade6153f9d370599a082e97ef9b625afc6d972467acb889f89eb464c79e6
4
+ data.tar.gz: 7292522eb303b9f5bcd906346d0e179652e454447051358de69d7156e265d40b
5
5
  SHA512:
6
- metadata.gz: 6a82bb730896e49d3ba7402d9fee427a08c89060784c4b2506517303aae8f7ecbbb2e2cee94dbd11c1caf4cb3df5c721c20bf40b628527ce309904d6c1cece5d
7
- data.tar.gz: 10849ffee5a49bfcbfae302eb76cbaace4913ae472a41f817a9ef570968999636102225a5c2728354dfd1e697b79696c9f6a7b964abe29818e18c0a13d246beb
6
+ metadata.gz: ac170c556fc3895669b8f583f1a0e2d27e2fb525875731d562743e7533abe410a5fc32de4fa36641607d32aa89594651e3c1b3b3edf513d36dd21c7e81c3dbc4
7
+ data.tar.gz: 3225baa3b6c77cab386e29b68ec49ba08f98217ff2c578399f4564fc09fe55960a46e00c562ebee5670d6cf5723c02612ed72e489a3be0fc87c5cc9b3d592e67
@@ -0,0 +1,58 @@
1
+
2
+ .NewsoverlayTimeline {
3
+ border: 5px solid green;
4
+ position: absolute;
5
+ left: 230px;
6
+ }
7
+
8
+ .NewspartialTimeline {
9
+ border: 1px solid blue;
10
+ position: relative;
11
+
12
+ margin-left: 50px;
13
+ width: 400px;
14
+
15
+ .full-text {
16
+ position: absolute;
17
+ left: 300px;
18
+
19
+ .header {
20
+ background: #efefef;
21
+ }
22
+
23
+ .flex-row > div {
24
+ margin-right: 1em;
25
+ }
26
+
27
+ .descr {
28
+ min-width: 300px;
29
+ }
30
+
31
+ }
32
+
33
+ .main {
34
+ width: 200px;
35
+ }
36
+
37
+
38
+ .timestamp {
39
+ position: absolute;
40
+ .word {
41
+ border: 1px solid cyan;
42
+ left: 100px;
43
+ position: absolute;
44
+ }
45
+ .wtime {
46
+ border: 1px solid yellow;
47
+ left: 20px;
48
+ position: absolute;
49
+ }
50
+ }
51
+
52
+ }
53
+
54
+
55
+ .NewsvideoTimeline {
56
+ border: 5px solid yellow;
57
+ position: absolute;
58
+ }
@@ -0,0 +1,23 @@
1
+
2
+
3
+ class Wco::Api::NewsvideosController < Wco::ApiController
4
+
5
+ skip_before_action :decode_jwt
6
+ skip_before_action :verify_authenticity_token
7
+ before_action :decode_simple_api_key
8
+
9
+ ##
10
+ ## the other one is used, not this one. Because I don't want to deal with api keys.
11
+ ##
12
+ def generate_illustration
13
+ @newsvideo = Wco::Newsvideo.unscoped.find params[:id]
14
+
15
+ Rails.env.production? ?
16
+ Wco::NewsvideoIllustrationJob.perform_async(@newsvideo.id.to_s, params[:image_url]) :
17
+ Wco::NewsvideoIllustrationJob.perform_sync( @newsvideo.id.to_s, params[:image_url])
18
+
19
+ render json: { status: :ok, message: 'scheduled the run on pc-ai' }
20
+ # redirect_to action: 'show', newsvideo_id: params[:id]
21
+ end
22
+
23
+ end
@@ -0,0 +1,11 @@
1
+
2
+
3
+ class Wco::NewsoverlayConfigsController < Wco::ApplicationController
4
+
5
+ def new
6
+ authorize! :create, Wco::NewsoverlayConfig
7
+ @newsoverlay_config = Wco::NewsoverlayConfig.new video_id: params[:video_id]
8
+ @newsvideos_list = Wco::Newsvideo.list
9
+ end
10
+
11
+ end
@@ -0,0 +1,62 @@
1
+
2
+
3
+ class Wco::NewsoverlaysController < Wco::ApplicationController
4
+
5
+ before_action :set_lists, only: [ :edit, :new ]
6
+
7
+ def create
8
+ @newsoverlay = Wco::Newsoverlay.new params[:newsoverlay].permit!
9
+ authorize! :create, @newsoverlay
10
+ if @newsoverlay.save
11
+ flash_notice 'Success'
12
+ else
13
+ flash_alert "No luck: #{@newsoverlay.errors.full_messages.join(',')}."
14
+ end
15
+ redirect_to controller: 'newsvideos', action: 'show', id: params[:newsoverlay][:newsvideo_id]
16
+ end
17
+
18
+ def destroy
19
+ @newsoverlay = Wco::Newsoverlay.find params[:id]
20
+ authorize! :destroy, @newsoverlay
21
+ flag = @newsoverlay.delete
22
+ if flag
23
+ flash[:notice] = "deleted newsoverlay"
24
+ else
25
+ flash[:alert] = "Cannot delete newsoverlay: #{@newsoverlay.errors.messages}"
26
+ end
27
+ redirect_to request.referrer
28
+ end
29
+
30
+ def edit
31
+ @newsoverlay = Wco::Newsoverlay.find params[:id]
32
+ authorize! :edit, @newsoverlay
33
+ end
34
+
35
+ def update
36
+ @newsoverlay = Wco::Newsoverlay.find params[:id]
37
+ authorize! :update, @newsoverlay
38
+
39
+ if @newsoverlay.update_attributes params[:newsoverlay].permit!
40
+ flash_notice 'Success'
41
+ else
42
+ flash_alert "No luck: #{@newsoverlay.errors.full_messages.join(',')}."
43
+ end
44
+ redirect_to controller: 'newsvideos', action: 'show', id: params[:newsoverlay][:newsvideo_id]
45
+ end
46
+
47
+ def new
48
+ authorize! :create, Wco::Newsoverlay
49
+ video = Wco::Video.find params[:video_id]
50
+ @newsoverlay = Wco::Newsoverlay.new video: video
51
+ end
52
+
53
+ ##
54
+ ## private
55
+ ##
56
+ private
57
+
58
+ def set_lists
59
+ @newsvideos_list = Wco::Newsvideo.list
60
+ end
61
+
62
+ end
@@ -25,7 +25,7 @@ class Wco::NewspartialsController < Wco::ApplicationController
25
25
  else
26
26
  flash_alert 'No luck.'
27
27
  end
28
- redirect_to action: 'index'
28
+ redirect_to request.referrer
29
29
  end
30
30
 
31
31
  def edit
@@ -42,8 +42,13 @@ class Wco::NewspartialsController < Wco::ApplicationController
42
42
 
43
43
  def generate_video
44
44
  @newspartial = Wco::Newspartial.unscoped.find params[:id]
45
- authorize! :show, @newspartial
46
- @newspartial.generate_video
45
+ authorize! :edit, @newspartial
46
+
47
+ Rails.env.production? ?
48
+ Wco::NewspartialVideoJob.perform_async(params[:id]) :
49
+ Wco::NewspartialVideoJob.perform_sync( params[:id])
50
+
51
+ flash_notice 'Scheduled.'
47
52
  redirect_to controller: 'newsvideos', id: @newspartial.newsvideo_id, action: 'show'
48
53
  end
49
54
 
@@ -1,8 +1,10 @@
1
1
  require 'net/ssh'
2
+ require 'pragmatic_segmenter'
2
3
 
3
4
  class Wco::NewsvideosController < Wco::ApplicationController
4
5
 
5
6
  before_action :set_lists
7
+ skip_before_action :verify_authenticity_token, only: [ :generate_illustration ]
6
8
 
7
9
  def create
8
10
  params[:newsvideo][:tag_ids]&.delete ''
@@ -26,36 +28,131 @@ class Wco::NewsvideosController < Wco::ApplicationController
26
28
  authorize! :edit, @newsvideo
27
29
  end
28
30
 
29
- def generate_illustration
31
+ def generate
30
32
  @newsvideo = Wco::Newsvideo.unscoped.find params[:id]
31
33
  authorize! :edit, @newsvideo
32
34
 
33
- cmd = " cd /opt/projects/simple_ai_1/src/Stability ; \
34
- wget --user-agent='Mozilla/5.0' -O input.png #{params[:image_url]} ";
35
-
36
- cmd_1 = " . zenv_stability/bin/activate ; \
37
- rm -rf out ; \
38
- python scripts/minimal_run.py ";
39
35
 
40
- cmd_2 = " ffmpeg -framerate 7 -i out/frames/frame_%04d.png -c:v libx264 -pix_fmt yuv420p out/output.mp4 ; \
36
+ ## put together config
37
+ # cmd = "cd #{Rails.root.join('tmp')} ; mkdir -p #{@newsvideo.id} ; cd #{@newsvideo.id} ; rm -f videolist.txt audiolist.txt ; "
38
+ # @newsvideo.newspartials.each_with_index do |part, idx|
39
+ # cmd = "#{cmd} echo \"file 'newspartial_#{idx}.mp4' \" >> videolist.txt ; "
40
+ # cmd = "#{cmd} echo \"file 'newspartial_#{idx}.wav' \" >> audiolist.txt ; "
41
+ # cmd = "#{cmd} ffmpeg -i newspartial_#{idx}.webm newspartial_#{idx}.mp4 ; "
42
+ # end
43
+ # puts! cmd, 'cmd'
44
+ # out = `#{cmd}`
45
+ # puts! out, 'out'
46
+
47
+ ## get base files locally
48
+ # cmd = "cd #{Rails.root.join('tmp', @newsvideo.id)} ; "
49
+ # @newsvideo.newspartials.each_with_index do |part, idx|
50
+ # cmd = "#{cmd} wget -O newspartial_#{idx}.webm #{part.video.video.url} ; "
51
+ # cmd = "#{cmd} wget -O newspartial_#{idx}.wav #{part.audio.url} ; "
52
+ # end
53
+ # puts! cmd, 'cmd'
54
+ # out = `#{cmd}`
55
+ # puts! out, 'out'
56
+
57
+ ## get overlays
58
+ # cmd = "cd #{Rails.root.join('tmp', @newsvideo.id)} ; "
59
+ # @newsvideo.newsoverlays.each_with_index do |overlay, idx|
60
+ # cmd = "#{cmd} wget -O overlay_#{idx}.mp4 #{overlay.video.video.url} ; "
61
+ # end
62
+ # puts! cmd, 'cmd'
63
+ # out = `#{cmd}`
64
+ # puts! out, 'out'
65
+
66
+ ## video concat
67
+ # cmd = <<AOL
68
+ # cd #{Rails.root.join('tmp', @newsvideo.id)} ;
69
+ # rm -f video_concat.mp4 ;
70
+ # ffmpeg -f concat -safe 0 -i videolist.txt -c copy video_concat.mp4 ;
71
+ # AOL
72
+ # puts! cmd, 'cmd'
73
+ # out = `#{cmd}`
74
+ # puts! out, 'out'
75
+
76
+ ## audio concat
77
+ # audio_filenames = (0...@newsvideo.newspartials.length).map { |i| "newspartial_#{i}.wav" }.join("|")
78
+ # cmd = <<AOL
79
+ # cd #{Rails.root.join('tmp', @newsvideo.id)} ;
80
+ # rm -f audio_concat.wav ;
81
+ # ffmpeg -f concat -safe 0 -i audiolist.txt -c copy audio_concat.wav ;
82
+ # AOL
83
+ # puts! cmd, 'cmd'
84
+ # out = `#{cmd}`
85
+ # puts! out, 'out'
86
+
87
+ ## combine base
88
+ # cmd = <<AOL
89
+ # cd #{Rails.root.join('tmp', @newsvideo.id)} ;
90
+ # rm -f output.mp4 ;
91
+ # ffmpeg -i video_concat.mp4 -i audio_concat.wav -c:v copy -c:a aac combined_base.mp4 ;
92
+ # AOL
93
+ # puts! cmd, 'cmd'
94
+ # out = `#{cmd}`
95
+ # puts! out, 'out'
96
+
97
+ ## combine overlays
98
+ # nn = @newsvideo.newsoverlays.map { |ol| ol.start_at_ms }
99
+ # puts! nn, 'nn'
100
+ # ffmpeg_cmd = [ "ffmpeg -i combined_base.mp4 \\ " ]
101
+ # nn.each_with_index do |ms, idx|
102
+ # ffmpeg_cmd.push " -i overlay_#{idx}.mp4 \\ "
103
+ # end
104
+ # ffmpeg_cmd.push "-filter_complex \" \\ "
105
+ # #
106
+ # nn.each_with_index do |ms, idx|
107
+ # ffmpeg_cmd.push " [#{idx+1}:v]setpts=PTS-STARTPTS+#{ms.to_f/1000}/TB[v#{idx+1}]; \\ "
108
+ # end
109
+ # #
110
+ # curr_s = "0:v"
111
+ # n = nil
112
+ # nn.each_with_index do |ms, idx|
113
+ # n = idx+1
114
+ # ffmpeg_cmd.push " [#{curr_s}][v#{n}]overlay=0:0:eof_action=pass[tmp#{n}]; \\ "
115
+ # curr_s = "tmp#{n}"
116
+ # end
117
+ # ffmpeg_cmd.push " \" -map \"[#{curr_s}]\" -map 0:a? -c:v libx264 -c:a copy combined_fin.mp4 "
118
+ # ffmpeg_cmd = ffmpeg_cmd.join("\n")
119
+ # puts "+++ ffmpeg_cmd:"
120
+ # puts ffmpeg_cmd
121
+
122
+ # combine overlays 2
123
+ # cmd = <<AOL
124
+ # cd #{Rails.root.join('tmp', @newsvideo.id)} ;
125
+ # rm -f combined_fin.mp4 ;
126
+ # #{ffmpeg_cmd} ;
127
+ # AOL
128
+ # puts! cmd, 'cmd'
129
+ # out = `#{cmd}`
130
+ # puts! out, 'out'
131
+
132
+ ## upload the video.
133
+ @video = Wco::Video.new name: @newsvideo.title
134
+ video_path = Rails.root.join("tmp", @newsvideo.id, "combined_fin.mp4")
135
+ @video.video = File.open(video_path)
136
+ @video.save!
137
+
138
+ render json: { status: :ok }
139
+ end
41
140
 
42
- curl -v -X POST '#{WCO_ORIGIN_2}/wco/api/videos/?api_key=#{SIMPLE_API_KEY}&api_secret=#{SIMPLE_API_SECRET}' \
43
- -H 'Accept: application/json' \
44
- -F 'video=@out/output.mp4' \
45
- -F 'thumb=@out/frames/frame_0000.png' \
46
- -F 'name=#{@newsvideo.title}' \
47
- -D 'newsvideo_id=#{params[:id]}' ";
141
+ def generate_illustration
142
+ @newsvideo = Wco::Newsvideo.unscoped.find params[:id]
143
+ authorize! :edit, @newsvideo
48
144
 
49
- out = `ssh pc-ai " whoami ; pwd ; #{cmd} ; #{cmd_1} ; #{cmd_2} ; "`
50
- puts! out, 'out'
145
+ Rails.env.production? ?
146
+ Wco::NewsvideoIllustrationJob.perform_async(@newsvideo.id.to_s, params[:image_url]) :
147
+ Wco::NewsvideoIllustrationJob.perform_sync( @newsvideo.id.to_s, params[:image_url])
51
148
 
52
- render json: { status: :ok } ## _TODO: remove
149
+ render json: { status: :ok, message: 'scheduled the run on pc-ai' }
53
150
  # redirect_to action: 'show', newsvideo_id: params[:id]
54
151
  end
55
152
 
56
153
  def index
57
154
  authorize! :index, Wco::Newsvideo
58
- @newsvideos = Wco::Newsvideo.all
155
+ @newsvideos = Wco::Newsvideo.all.order_by( created_at: :desc )
59
156
  if params[:deleted]
60
157
  @newsvideos = Wco::Newsvideo.unscoped.where( :deleted_at.ne => nil )
61
158
  end
@@ -71,9 +168,31 @@ class Wco::NewsvideosController < Wco::ApplicationController
71
168
  @newsvideo = Wco::Newsvideo.unscoped.find params[:id]
72
169
  authorize! :show, @newsvideo
73
170
  @newspartials = Wco::Newspartial.where( newsvideo_id: @newsvideo.id.to_s).includes(:video)
171
+ @newsoverlays = @newsvideo.newsoverlays
172
+ @skip_footer = true
173
+ end
174
+
175
+ def split
176
+ @newsvideo = Wco::Newsvideo.unscoped.find params[:id]
177
+ authorize! :edit, @newsvideo
178
+
179
+ if Wco::Newspartial.where( newsvideo: @newsvideo).length > 0
180
+ # Wco::Newspartial.where( newsvideo: @newsvideo).each { |n| n.delete }
181
+ flash_alert 'newspartials already exist for this newsvideo - cannot split.'
182
+ redirect_to request.referrer
183
+ return
184
+ end
185
+
186
+ sentences = PragmaticSegmenter::Segmenter.new(text: @newsvideo.body).segment
187
+ phrases = sentences_to_phrases(sentences)
188
+ # puts! phrases, 'phrases'
189
+ phrases.each do |phrase|
190
+ newspartial = Wco::Newspartial.new body: phrase, newsvideo: @newsvideo
191
+ newspartial.save!
192
+ end
74
193
 
75
- # @config = JSON.parse( @newsvideo.config_json )
76
- # @duration_ms = @config['vtimes'].last.to_i + @config['vdurations'].last.to_i
194
+ flash_notice 'All done.'
195
+ redirect_to request.referrer
77
196
  end
78
197
 
79
198
 
@@ -95,6 +214,31 @@ class Wco::NewsvideosController < Wco::ApplicationController
95
214
  ##
96
215
  private
97
216
 
217
+ def sentences_to_phrases sentences
218
+ max_words = 50
219
+ phrases = []
220
+ current_phrase = []
221
+
222
+ current_word_count = 0
223
+
224
+ sentences.each do |sentence|
225
+ words_in_sentence = sentence.split.size
226
+
227
+ # If adding this sentence exceeds the limit, start a new phrase
228
+ if current_word_count + words_in_sentence > max_words
229
+ phrases << current_phrase.join(" ")
230
+ current_phrase = []
231
+ current_word_count = 0
232
+ end
233
+
234
+ current_phrase << sentence
235
+ current_word_count += words_in_sentence
236
+ end
237
+
238
+ # Add the last phrase if any
239
+ phrases << current_phrase.join(" ") unless current_phrase.empty?
240
+ end
241
+
98
242
  def set_lists
99
243
  @tags_list = Wco::Tag.list
100
244
  end
@@ -0,0 +1,15 @@
1
+
2
+ require 'sidekiq'
3
+ require 'net/ssh'
4
+
5
+ class Wco::NewspartialVideoJob
6
+ include Sidekiq::Job
7
+ sidekiq_options queue: 'default'
8
+
9
+ def perform id
10
+ puts! id, 'Newspartial video job...'
11
+ @newspartial = Wco::Newspartial.find id
12
+ @newspartial.generate_video
13
+ end
14
+
15
+ end
@@ -0,0 +1,33 @@
1
+
2
+ require 'sidekiq'
3
+ require 'net/ssh'
4
+
5
+ class Wco::NewsvideoIllustrationJob
6
+ include Sidekiq::Job
7
+ sidekiq_options queue: 'default'
8
+
9
+ def perform id, image_url
10
+ puts! [ id, image_url ], 'NewsvideoIllustrationJob#perform...'
11
+ @newsvideo = Wco::Newsvideo.unscoped.find id
12
+
13
+ cmd = " cd /opt/projects/simple_ai_1/src/Stability ; \
14
+ wget --user-agent='Mozilla/5.0' -O input.png #{image_url} ";
15
+
16
+ cmd_1 = " . zenv_stability/bin/activate ; \
17
+ rm -rf out ; \
18
+ python scripts/minimal_run_cont.py ";
19
+
20
+ cmd_2 = " ffmpeg -framerate 7 -i out/frames/frame_%04d.png -c:v libx264 -pix_fmt yuv420p out/output.mp4 ; \
21
+
22
+ curl -v -X POST '#{WCO_ORIGIN_2}/wco/api/videos/?api_key=#{SIMPLE_API_KEY}&api_secret=#{SIMPLE_API_SECRET}' \
23
+ -H 'Accept: application/json' \
24
+ -F 'video=@out/output.mp4' \
25
+ -F 'thumb=@out/frames/frame_0000.png' \
26
+ -F 'name=#{@newsvideo.title}' \
27
+ -F 'newsvideo_id=#{id}' ";
28
+
29
+ out = `ssh pc-ai " whoami ; pwd ; #{cmd} ; #{cmd_1} ; #{cmd_2} ; "`
30
+ puts! out, 'out'
31
+ end
32
+
33
+ end
@@ -0,0 +1,44 @@
1
+
2
+ ##
3
+ ## it has start and duration.
4
+ ##
5
+
6
+ =begin
7
+
8
+ ffmpeg \
9
+ -i combined.mp4 \
10
+ -i overlay_1.mp4 \
11
+ -i overlay_2.mp4 \
12
+ -filter_complex \
13
+ "[1:v]setpts=PTS-STARTPTS+1.55/TB[v1];
14
+ [2:v]setpts=PTS-STARTPTS+5.55/TB[v2];
15
+ [0:v][v1]overlay=0:0:eof_action=pass[tmp];
16
+ [tmp][v2]overlay=0:0:eof_action=pass[vout]" \
17
+ -map "[vout]" \
18
+ -map 0:a? \
19
+ -c:v libx264 \
20
+ -c:a copy \
21
+ combined_2.mp4
22
+
23
+ =end
24
+
25
+ class Wco::Newsoverlay
26
+ include Mongoid::Document
27
+ include Mongoid::Timestamps
28
+ include Mongoid::Paranoia
29
+ include Wco::Utils
30
+ store_in collection: 'wco_newsoverlays'
31
+
32
+ PAGE_PARAM_NAME = 'newsoverlays_page'
33
+
34
+ belongs_to :video
35
+ belongs_to :newsoverlay_config, optional: true
36
+ belongs_to :newsvideo
37
+
38
+ field :start_at_ms, type: :integer, default: 0
39
+ field :duration_ms, type: :integer, default: 0
40
+
41
+ delegate :duration_ms, to: :video
42
+ delegate :name, to: :video
43
+
44
+ end
@@ -0,0 +1,13 @@
1
+
2
+ class Wco::NewsoverlayConfig
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ include Wco::Utils
6
+ store_in collection: 'wco_newsoverlay_configs'
7
+
8
+ PAGE_PARAM_NAME = 'newsoverlayconfigs_page'
9
+
10
+ belongs_to :video
11
+ belongs_to :newsvideo
12
+
13
+ end
@@ -1,8 +1,11 @@
1
1
 
2
+ require 'mongoid_paperclip'
3
+
2
4
  class Wco::Newspartial
3
5
  include Mongoid::Document
4
- include Mongoid::Timestamps
6
+ include Mongoid::Paperclip
5
7
  include Mongoid::Paranoia
8
+ include Mongoid::Timestamps
6
9
  include Wco::Utils
7
10
  store_in collection: 'wco_newspartials'
8
11
 
@@ -19,6 +22,35 @@ class Wco::Newspartial
19
22
  belongs_to :newsvideo
20
23
  has_one :video
21
24
 
25
+ has_mongoid_attached_file :audio,
26
+ :storage => :s3,
27
+ :s3_credentials => ::S3_CREDENTIALS,
28
+ :path => "newspartials/:id/audio/:filename",
29
+ :s3_protocol => 'https',
30
+ # :s3_permissions => 'public-read',
31
+ :validate_media_type => false,
32
+ s3_region: ::S3_CREDENTIALS[:region]
33
+ validates_attachment_content_type :audio, content_type: [ /\Aaudio\/.*\z/, ]
34
+
35
+ # has_mongoid_attached_file :video,
36
+ # :storage => :s3,
37
+ # :s3_credentials => ::S3_CREDENTIALS,
38
+ # :path => "newspartials/:id/video/:filename",
39
+ # :s3_protocol => 'https',
40
+ # :validate_media_type => false,
41
+ # s3_region: ::S3_CREDENTIALS[:region]
42
+ # validates_attachment_content_type :video, content_type: [ /\Avideo\/.*\Z/, ]
43
+
44
+ # has_mongoid_attached_file :thumb,
45
+ # :storage => :s3,
46
+ # :s3_credentials => ::S3_CREDENTIALS,
47
+ # :path => "newspartials/:id/thumb/:filename",
48
+ # :s3_protocol => 'https',
49
+ # :validate_media_type => false,
50
+ # s3_region: ::S3_CREDENTIALS[:region]
51
+ # validates_attachment_content_type :thumb, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif", 'application/octet-stream' ]
52
+
53
+
22
54
  def config
23
55
  @config ||= JSON.parse self[:config_json]
24
56
  end
@@ -42,9 +74,18 @@ class Wco::Newspartial
42
74
  puts! out, 'out'
43
75
 
44
76
  self[:config_json] = out
45
-
46
77
  tmp = JSON.parse( out )
78
+
79
+ decoded_audio = Base64.decode64( tmp['audio'] )
80
+ temp_file = Tempfile.new(['speech', '.wav'])
81
+ temp_file.binmode
82
+ temp_file.write(decoded_audio)
83
+ temp_file.rewind
84
+ self.audio = temp_file
85
+ temp_file.close
86
+ temp_file.unlink
47
87
  tmp.delete('audio')
88
+
48
89
  self[:speech_json] = tmp.to_json
49
90
 
50
91
  self.save
@@ -24,6 +24,7 @@ class Wco::Newsvideo
24
24
 
25
25
  field :body
26
26
  field :config_json, type: :string
27
+ field :duration_ms, type: :integer
27
28
 
28
29
  field :x, :type => Float
29
30
  field :y, :type => Float
@@ -34,8 +35,19 @@ class Wco::Newsvideo
34
35
 
35
36
  belongs_to :author, class_name: 'Wco::Profile'
36
37
 
37
- has_and_belongs_to_many :tags
38
38
  has_many :newspartials
39
+ def newspartials
40
+ Wco::Newspartial.where( newsvideo_id: self.id )
41
+ end
42
+
43
+ has_many :newsoverlay_configs
44
+ has_and_belongs_to_many :tags
39
45
  has_many :videos
40
46
 
47
+
48
+ has_many :newsoverlays
49
+ def newsoverlays
50
+ Wco::Newsoverlay.where( newsvideo_id: self.id )
51
+ end
52
+
41
53
  end
@@ -3,9 +3,9 @@ require 'mongoid_paperclip'
3
3
 
4
4
  class Wco::Video
5
5
  include Mongoid::Document
6
- include Mongoid::Timestamps
7
6
  include Mongoid::Paperclip
8
7
  include Mongoid::Paranoia
8
+ include Mongoid::Timestamps
9
9
  include Wco::Utils
10
10
  store_in collection: 'videos'
11
11
 
@@ -31,6 +31,8 @@ class Wco::Video
31
31
  validates_uniqueness_of :youtube_id, allow_blank: true, case_sensitive: false
32
32
  before_save { youtube_id.present? || youtube_id = nil }
33
33
 
34
+ field :duration_ms, type: :integer
35
+
34
36
  # belongs_to :user_profile, :class_name => 'Ish::UserProfile', :inverse_of => :videos
35
37
  # has_and_belongs_to_many :shared_profiles, :class_name => 'Ish::UserProfile', :inverse_of => :shared_videos
36
38
 
@@ -36,7 +36,6 @@
36
36
  %hr
37
37
 
38
38
  = yield
39
- %hr
40
39
  = render '/wco/main_footer'
41
40
  = render '/wco/analytics' if Rails.env.production?
42
41
 
@@ -1,35 +1,38 @@
1
1
 
2
- #Config{ data: { jwt_token: @jwt_token } }
3
- :javascript
4
- localStorage.setItem('jwt_token', $("#Config").data('jwt-token') )
5
-
6
- .application--main-footer.main-footer
7
- .maxwidth
8
-
9
- %i.fa.fa-compress.collapse-expand#mainFooter
10
- Account & Session
11
- .a
12
- .row
13
- .col-sm-4
14
- %ul
15
- %li
16
- <b>Email:</b> #{@current_profile.email}
17
- = button_to 'Logout', main_app.destroy_user_session_path, :method => :delete, data: { confirm: 'Are you sure?' }
18
- %li= link_to 'sidekiq', '/sidekiq', target: :_blank
19
- %li= link_to 'Iron Warbler', '/iron_warbler'
20
-
21
-
22
- .col-sm-4
23
- %ul
24
- %li ~__^ &nbsp; &nbsp; v#{@version}
25
- %li
26
- = pp_date Time.now
27
- = pp_time Time.now
28
-
29
- .col-sm-4
30
- = render '/wco/profiles/form_extra', profile: @current_profile
31
- = link_to 'RTEditor', wco.application_tinymce_path, target: :_blank
32
- = render 'wco/application/debug' if !Rails.env.production?
33
-
34
- .c
2
+ - if !@skip_footer
3
+ %hr
4
+
5
+ #Config{ data: { jwt_token: @jwt_token } }
6
+ :javascript
7
+ localStorage.setItem('jwt_token', $("#Config").data('jwt-token') )
8
+
9
+ .application--main-footer.main-footer
10
+ .maxwidth
11
+
12
+ %i.fa.fa-compress.collapse-expand#mainFooter
13
+ Account & Session
14
+ .a
15
+ .row
16
+ .col-sm-4
17
+ %ul
18
+ %li
19
+ <b>Email:</b> #{@current_profile.email}
20
+ = button_to 'Logout', main_app.destroy_user_session_path, :method => :delete, data: { confirm: 'Are you sure?' }
21
+ %li= link_to 'sidekiq', '/sidekiq', target: :_blank
22
+ %li= link_to 'Iron Warbler', '/iron_warbler'
23
+
24
+
25
+ .col-sm-4
26
+ %ul
27
+ %li ~__^ &nbsp; &nbsp; v#{@version}
28
+ %li
29
+ = pp_date Time.now
30
+ = pp_time Time.now
31
+
32
+ .col-sm-4
33
+ = render '/wco/profiles/form_extra', profile: @current_profile
34
+ = link_to 'RTEditor', wco.application_tinymce_path, target: :_blank
35
+ = render 'wco/application/debug' if !Rails.env.production?
36
+
37
+ .c
35
38
 
@@ -29,18 +29,21 @@
29
29
  %ul
30
30
  %li= render '/wco/leadsets/header'
31
31
  %li= render '/wco/leads/header'
32
- %li= render '/wco/office_action_templates/header'
33
- %li= render '/wco/office_actions/header'
34
32
  %li= render '/wco/profiles/header'
35
33
 
36
34
  %ul
35
+ %li= render '/wco/office_action_templates/header'
36
+ %li= render '/wco/office_actions/header'
37
37
  %li= render '/wco/sites/header'
38
- %li= render '/wco/headlines/header'
39
38
  %li= render '/wco/publishers/header'
39
+
40
+ %ul
41
+ -# %li= render '/wco/headlines/header'
40
42
  %li= render '/wco/galleries/header_mini'
41
43
  %li= render '/wco/newsvideos/header_mini'
42
44
  %li= render '/wco/reports/header'
43
45
  %li= render '/wco/videos/header'
44
46
 
45
47
 
48
+
46
49
  .c
@@ -0,0 +1,15 @@
1
+
2
+ = form_for newsoverlay_config do |f|
3
+ .actions
4
+ = f.submit 'Submit'
5
+
6
+ .field
7
+ %label Newsvideo
8
+ = f.select :newsvideo_id, options_for_select(@newsvideos_list, selected: newsoverlay_config.newsvideo_id), {}, class: :select2
9
+
10
+ .field
11
+ %label Video
12
+ = f.text_field :video_id, value: newsoverlay_config[:video_id] || params[:video_id]
13
+
14
+ .actions
15
+ = f.submit 'Submit'
@@ -0,0 +1,4 @@
1
+
2
+ .maxwidth
3
+ %h5.text-center New newsoverlay_config
4
+ = render 'form', newsoverlay_config: @newsoverlay_config
@@ -0,0 +1,22 @@
1
+
2
+ = form_for newsoverlay do |f|
3
+ .actions
4
+ = f.submit 'Submit'
5
+
6
+ .field
7
+ %label Newsvideo
8
+ = f.select :newsvideo_id, options_for_select(@newsvideos_list, selected: newsoverlay.newsvideo_id), {}, class: :select2
9
+
10
+ .field.d-flex.flex-column
11
+ %label Video
12
+ = f.text_field :video_id, value: newsoverlay[:video_id] || params[:video_id], disabled: true
13
+ .flex-row
14
+ .thumb= image_tag( newsoverlay.video.thumb.url( :thumb ), :alt => '' )
15
+ .a Duration: #{newsoverlay.video.duration_ms}ms
16
+
17
+ .field
18
+ %label Start at ms
19
+ = f.text_field :start_at_ms, value: newsoverlay.start_at_ms
20
+
21
+ .actions
22
+ = f.submit 'Submit'
@@ -0,0 +1,10 @@
1
+
2
+ .NewsoverlayTimeline{ style: "top: #{newsoverlay.start_at_ms*HEIGHT_MS}px; height: #{newsoverlay.duration_ms*HEIGHT_MS}px;"}
3
+ .d-flex
4
+ = newsoverlay.name
5
+ = link_to '[~]', edit_newsoverlay_path(newsoverlay)
6
+ = button_to 'x', newsoverlay_path(newsoverlay), method: :delete, data: { confirm: 'Are you sure?' }
7
+
8
+ %img{ src: newsoverlay.video.thumb.url(:thumb) }
9
+ .a start_at: #{newsoverlay.start_at_ms}ms
10
+ .a Duration: #{newsoverlay.duration_ms}ms
@@ -0,0 +1,4 @@
1
+
2
+ .maxwidth
3
+ %h5.text-center Edit newsoverlay
4
+ = render 'form', newsoverlay: @newsoverlay
@@ -0,0 +1,4 @@
1
+
2
+ .maxwidth
3
+ %h5.text-center New newsoverlay
4
+ = render 'form', newsoverlay: @newsoverlay
@@ -1,31 +1,32 @@
1
1
 
2
- - height_ms = 100.0/1000
3
-
4
- .newspartials--show-in-newsvideo
5
-
6
- .a
7
- = link_to '[~]', edit_newspartial_path(newspartial)
8
- Newspartial `#{link_to newspartial.title, newspartial_path(newspartial)}`
9
- %span{ class: 'gray' } #{newspartial.id}
10
- = link_to '[api]', api_newspartial_config_path(newspartial, format: :json, api_key: SIMPLE_API_KEY, api_secret: SIMPLE_API_SECRET ), target: :_blank
11
-
12
-
13
- .Timeline{ style: "height: #{newspartial.duration_ms*height_ms}px; min-height: 100px;" }
2
+ .NewspartialTimeline{ style: "height: #{newspartial.duration_ms*HEIGHT_MS}px; min-height: 100px;" }
14
3
  .main
15
4
  - newspartial.config['wtimes']&.each_with_index do |wtime, idx|
16
5
 
17
- %div.ts{ style: "top: #{wtime.to_f*height_ms}px"}
6
+ %div.timestamp{ style: "top: #{wtime.to_f*HEIGHT_MS}px"}
18
7
  .wtime= wtime
19
8
  .word= newspartial.config['words'][idx]
20
9
 
21
10
  .full-text
22
- = newspartial.body
23
- .d-inline-block= button_to 'Generate visemes', newspartial_generate_speech_path(newspartial)
24
- .d-inline-block= button_to 'Generate video', newspartial_generate_video_path(newspartial)
25
-
26
- .a= newspartial.config_json[0...100]
27
- .a= newspartial.speech_json[0...100]
28
- .a
29
- Video:
30
- - if newspartial.video
31
- = image_tag newspartial.video.thumb.url(:thumb), class: 'thumb'
11
+ .header
12
+ Newspartial
13
+ = link_to '[~]', edit_newspartial_path(newspartial)
14
+ .d-inline-block= button_to 'x', newspartial_path(newspartial), method: :delete, :data => { :confirm => 'Are you sure?' }
15
+ %span{ class: 'gray' } #{newspartial.id}
16
+ = link_to '[api]', api_newspartial_config_path(newspartial, format: :json, api_key: SIMPLE_API_KEY, api_secret: SIMPLE_API_SECRET ), target: :_blank
17
+
18
+ .flex-row
19
+ .a Duration: `#{newspartial.duration_ms}`ms
20
+ .descr= newspartial.body
21
+ .d-flex.flex-column
22
+ = button_to 'Generate video', newspartial_generate_video_path(newspartial)
23
+ Video:
24
+ - if newspartial.video
25
+ = image_tag newspartial.video.thumb.url(:thumb), class: 'thumb'
26
+ .d-flex.flex-column
27
+ = button_to 'Generate speech', newspartial_generate_speech_path(newspartial)
28
+ Audio:
29
+ - if newspartial.audio.present?
30
+ %audio{ controls: true }
31
+ %source{ src: newspartial.audio, type: "audio/wav" }
32
+ Your browser does not support the audio element.
@@ -1,5 +1,5 @@
1
1
 
2
- .newsvideos-index
2
+ .newsvideos-index.maxwidth
3
3
  %h5.text-center Newsvideos
4
4
  %ul
5
5
  - @newsvideos.each do |nv|
@@ -1,10 +1,22 @@
1
1
 
2
2
  .newsvideos-show.maxwidth
3
- %h5.text-center Newsvideo `#{@newsvideo.title}` #{link_to '[~]', edit_newsvideo_path(@newsvideo)}
3
+ %h5.text-center
4
+ Newsvideo `#{@newsvideo.title}`
5
+ #{link_to '[~]', edit_newsvideo_path(@newsvideo)}
6
+ .d-inline-block= button_to 'split', split_newsvideo_path(@newsvideo), :data => { :confirm => 'Are you sure?' }
7
+ = link_to '[+ newspartial]', new_newspartial_path(newsvideo_id: @newsvideo.id)
8
+ = link_to '[search illustration]', pexels_search_path(newsvideo_id: @newsvideo.id), target: :_blank
9
+ .d-inline-block= button_to 'generate', generate_newsvideo_path(@newsvideo), :data => { :confirm => 'Are you sure?' }
10
+
4
11
  .descr= @newsvideo.body
5
- %hr
6
- .text-center
7
- Newspartials #{link_to '[+]', new_newspartial_path(newsvideo_id: @newsvideo.id) }
8
- = link_to '[+ illustration]', pexels_search_path(newsvideo_id: @newsvideo.id), target: :_blank
9
- - @newspartials.each do |newspartial|
10
- = render 'wco/newspartials/show_in_newsvideo', newspartial: newspartial
12
+ %br
13
+ %br
14
+
15
+ .NewsvideoTimeline
16
+ - @newspartials.each do |newspartial|
17
+ = render 'wco/newspartials/show_in_newsvideo', newspartial: newspartial
18
+
19
+ - @newsoverlays.each do |newsoverlay|
20
+ = render 'wco/newsoverlays/show_in_newsvideo', newsoverlay: newsoverlay
21
+
22
+ .c
@@ -3,18 +3,17 @@
3
3
 
4
4
  .reports--index
5
5
  = paginate reports, :param_name => :reports_page, :views_prefix => 'wco'
6
- %ul
7
- - reports.each do |ttt|
8
- %li.Card
6
+ - reports.each do |ttt|
7
+ .Card
8
+ .flex-row
9
+ = button_to '[x]', report_path(ttt), method: :delete, data: { confirm: 'Are you sure?' }
10
+ = link_to '[~]', edit_report_path(ttt)
11
+ .a
12
+ = link_to ttt.title, report_path(ttt)
13
+ %br
14
+ `#{ttt.slug}`
15
+ .gray.mini= ttt.id
16
+ - if !config[:skip_tags]
9
17
  .flex-row
10
- = button_to '[x]', report_path(ttt), method: :delete, data: { confirm: 'Are you sure?' }
11
- = link_to '[~]', edit_report_path(ttt)
12
- .a
13
- = link_to ttt.title, report_path(ttt)
14
- %br
15
- `#{ttt.slug}`
16
- .gray.mini= ttt.id
17
- - if !config[:skip_tags]
18
- .flex-row
19
- = render '/wco/tags/list_chips', tags: ttt.tags
18
+ = render '/wco/tags/list_chips', tags: ttt.tags
20
19
  = paginate reports, :param_name => :reports_page, :views_prefix => 'wco'
@@ -29,6 +29,9 @@
29
29
  .col-md-6
30
30
  %label descr
31
31
  = f.text_area :descr, class: :tinymce
32
+ .field
33
+ %label duration_ms
34
+ = f.text_field :duration_ms
32
35
 
33
36
 
34
37
  .action
@@ -12,6 +12,8 @@
12
12
  = link_to video.name, video_path( video )
13
13
  .d-flex
14
14
  = link_to '[~]', edit_video_path( video )
15
+ = link_to '[overlay]', new_newsoverlay_path( video_id: video.id.to_s )
16
+ = link_to '[overlay-multi]', new_newsoverlay_config_path( video_id: video.id.to_s )
15
17
  = button_to '[x]', video_path( video ), :method => :delete, :data => { :confirm => 'Are you sure?' }
16
18
  = render 'meta', item: video
17
19
 
@@ -2,10 +2,9 @@
2
2
  .videos-index.container-fluid
3
3
  .d-flex
4
4
  = link_to "Videos (#{@videos.count})", videos_path
5
-
6
5
  .inline-search
7
6
  = form_tag videos_path, method: :get do
8
7
  = text_field_tag :q
9
-
10
8
  = link_to '[+]', new_video_path
9
+
11
10
  = render '/wco/videos/index', videos: @videos
@@ -24,3 +24,4 @@
24
24
  Download File:&nbsp;#{link_to video.video_file_name, video.video.url}
25
25
  %ul
26
26
  %li newspartial_id: #{video.newspartial_id}
27
+ %li newsvideo_id: #{video.newsvideo_id}
data/config/routes.rb CHANGED
@@ -12,6 +12,8 @@ Wco::Engine.routes.draw do
12
12
  patch 'reports/:id/add-config', to: 'reports#add_config'
13
13
  get 'newspartials/:id/config', to: 'newspartials#show_config', as: :newspartial_config
14
14
 
15
+ match 'newsvideos/:id/generate-illustration', to: 'newsvideos#generate_illustration', as: :newsvideo_generate_illustration, via: [ :get, :post ]
16
+
15
17
  get 'tags', to: 'tags#index'
16
18
 
17
19
  post 'videos', to: 'videos#create'
@@ -47,11 +49,16 @@ Wco::Engine.routes.draw do
47
49
  delete 'logs/bulkop', to: 'logs#bulkop', as: :logs_bulkop
48
50
  resources :logs
49
51
 
52
+ resources :newsoverlay_configs
53
+ resources :newsoverlays
54
+
50
55
  match 'newspartials/:id/generate-speech', to: 'newspartials#generate_speech', as: :newspartial_generate_speech, via: [ :get, :post ]
51
56
  match 'newspartials/:id/generate-video', to: 'newspartials#generate_video', as: :newspartial_generate_video, via: [ :get, :post ]
52
57
  resources :newspartials
53
58
 
54
59
  match 'newsvideos/:id/generate-illustration', to: 'newsvideos#generate_illustration', as: :newsvideo_generate_illustration, via: [ :get, :post ]
60
+ post 'newsvideos/:id/generate', to: 'newsvideos#generate', as: :generate_newsvideo
61
+ post 'newsvideos/:id/split', to: 'newsvideos#split', as: :split_newsvideo
55
62
  resources :newsvideos
56
63
 
57
64
  resources :obfuscated_redirects
data/lib/wco_models.rb CHANGED
@@ -65,3 +65,8 @@ class Wco::HTTParty
65
65
  end
66
66
 
67
67
  ActiveSupport.escape_html_entities_in_json = true
68
+
69
+
70
+ HEIGHT_SEC = 100.0
71
+ HEIGHT_MS = HEIGHT_SEC/1000
72
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wco_models
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0.223
4
+ version: 3.1.0.225
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Pudeyev
@@ -422,7 +422,7 @@ files:
422
422
  - app/assets/stylesheets/wco/galleries.scss
423
423
  - app/assets/stylesheets/wco/leads_leadsets.scss
424
424
  - app/assets/stylesheets/wco/main.scss
425
- - app/assets/stylesheets/wco/newsvideos_newspartials.scss
425
+ - app/assets/stylesheets/wco/newsvideos.scss
426
426
  - app/assets/stylesheets/wco/office_action_templates.scss
427
427
  - app/assets/stylesheets/wco/pagination.scss
428
428
  - app/assets/stylesheets/wco/photos.scss
@@ -430,6 +430,7 @@ files:
430
430
  - app/assets/stylesheets/wco/videos.scss
431
431
  - app/controllers/wco/api/leads_controller.rb
432
432
  - app/controllers/wco/api/newspartials_controller.rb
433
+ - app/controllers/wco/api/newsvideos_controller.rb
433
434
  - app/controllers/wco/api/obfuscated_redirects_controller.rb
434
435
  - app/controllers/wco/api/tags_controller.rb
435
436
  - app/controllers/wco/api/videos_controller.rb
@@ -441,6 +442,8 @@ files:
441
442
  - app/controllers/wco/leads_controller.rb
442
443
  - app/controllers/wco/leadsets_controller.rb
443
444
  - app/controllers/wco/logs_controller.rb
445
+ - app/controllers/wco/newsoverlay_configs_controller.rb
446
+ - app/controllers/wco/newsoverlays_controller.rb
444
447
  - app/controllers/wco/newspartials_controller.rb
445
448
  - app/controllers/wco/newsvideos_controller.rb
446
449
  - app/controllers/wco/obfuscated_redirects_controller.rb
@@ -459,6 +462,8 @@ files:
459
462
  - app/controllers/wco/unsubscribes_controller.rb
460
463
  - app/controllers/wco/videos_controller.rb
461
464
  - app/helpers/wco/application_helper.rb
465
+ - app/jobs/wco/newspartial_video_job.rb
466
+ - app/jobs/wco/newsvideo_illustration_job.rb
462
467
  - app/jobs/wco_hosting/certbot_job.rb
463
468
  - app/mailers/wco_email/application_mailer.rb
464
469
  - app/models/ability.rb
@@ -486,6 +491,8 @@ files:
486
491
  - app/models/wco/leadset_appliance_tmpl.rb
487
492
  - app/models/wco/log.rb
488
493
  - app/models/wco/newsitem.rb
494
+ - app/models/wco/newsoverlay.rb
495
+ - app/models/wco/newsoverlay_config.rb
489
496
  - app/models/wco/newspartial.rb
490
497
  - app/models/wco/newsvideo.rb
491
498
  - app/models/wco/obfuscated_redirect.rb
@@ -600,6 +607,12 @@ files:
600
607
  - app/views/wco/logs/_index.haml
601
608
  - app/views/wco/logs/edit.haml
602
609
  - app/views/wco/logs/new.haml
610
+ - app/views/wco/newsoverlay_configs/_form.haml
611
+ - app/views/wco/newsoverlay_configs/new.haml
612
+ - app/views/wco/newsoverlays/_form.haml
613
+ - app/views/wco/newsoverlays/_show_in_newsvideo.haml
614
+ - app/views/wco/newsoverlays/edit.haml
615
+ - app/views/wco/newsoverlays/new.haml
603
616
  - app/views/wco/newspartials/_form.haml
604
617
  - app/views/wco/newspartials/_show_in_newsvideo.haml
605
618
  - app/views/wco/newspartials/index.haml-trash
@@ -1,31 +0,0 @@
1
-
2
- .Timeline {
3
- border: 1px solid blue;
4
- position: relative;
5
-
6
- .full-text {
7
- position: absolute;
8
- left: 300px;
9
- }
10
-
11
- .main {
12
- width: 200px;
13
- }
14
-
15
-
16
- .ts { /* timestamp */
17
- position: absolute;
18
- .word {
19
- border: 1px solid cyan;
20
- left: 100px;
21
- position: absolute;
22
- }
23
- .wtime {
24
- border: 1px solid yellow;
25
- left: 20px;
26
- position: absolute;
27
- }
28
- }
29
-
30
- }
31
-