wco_models 3.1.0.313 → 3.1.0.314

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.txt +19 -4
  3. data/app/assets/stylesheets/wco/main.scss +4 -0
  4. data/app/assets/stylesheets/wco/newsvideos.scss +10 -2
  5. data/app/controllers/wco/api/leads_controller.rb +5 -2
  6. data/app/controllers/wco/api/newspartials_controller.rb +15 -4
  7. data/app/controllers/wco/api/newsproducer_controller.rb +26 -0
  8. data/app/controllers/wco/api/newsvideos_controller.rb +17 -3
  9. data/app/controllers/wco/api/tags_controller.rb +2 -0
  10. data/app/controllers/wco/api/videos_controller.rb +3 -3
  11. data/app/controllers/wco/api_controller.rb +9 -9
  12. data/app/controllers/wco/newsvideos_controller.rb +102 -1
  13. data/app/models/wco/newspartial.rb +7 -3
  14. data/app/models/wco/newsvideo.rb +93 -78
  15. data/app/models/wco/tag.rb +4 -0
  16. data/app/models/wco_email/context.rb +11 -0
  17. data/app/models/wco_email/email_filter_condition.rb +17 -1
  18. data/app/views/wco/api/newsproducer/README.txt +2 -0
  19. data/app/views/wco/{newsproducer → api/newsproducer}/_studio_1.js +111 -104
  20. data/app/views/wco/{newsproducer → api/newsproducer}/studio_1.html.erb +4 -3
  21. data/app/views/wco/api/newsvideos/show.jbuilder +13 -0
  22. data/app/views/wco/newspartials/_form.haml +4 -2
  23. data/app/views/wco/newspartials/_show_in_newsvideo.haml +3 -3
  24. data/app/views/wco/newsvideos/_form.haml +19 -6
  25. data/app/views/wco/newsvideos/edit.haml +2 -1
  26. data/app/views/wco/newsvideos/show.haml +9 -2
  27. data/config/initializers/08_integrations.rb +2 -0
  28. data/config/initializers/08_integrations.rb-example +2 -0
  29. data/config/routes.rb +12 -4
  30. metadata +9 -8
  31. data/app/controllers/wco/api/obfuscated_redirects_controller.rb +0 -26
  32. data/app/controllers/wco/newsproducer_controller.rb +0 -22
  33. /data/app/views/wco/{newsproducer → api/newsproducer}/canvas.html.erb +0 -0
  34. /data/app/views/wco/{newsproducer → api/newsproducer}/canvas_minimal.html.erb +0 -0
@@ -150,6 +150,17 @@ class WcoEmail::Context
150
150
  })
151
151
  end
152
152
 
153
+ def self.new_for message
154
+ self.new({
155
+ from_email: message.to&.downcase,
156
+ lead_id: message.lead_id,
157
+ subject: message.subject,
158
+ reply_to_message: message,
159
+ email_template_id: ET.find_by( slug: 'blank').id,
160
+ })
161
+ end
162
+
163
+
153
164
  end
154
165
  Ctx = WcoEmail::Context
155
166
 
@@ -47,6 +47,12 @@ class WcoEmail::EmailFilterCondition
47
47
 
48
48
  field :value
49
49
  validates :value, presence: true
50
+ before_validation :strip_value
51
+ def strip_value
52
+ self.value = value.strip
53
+ end
54
+
55
+ field :comment
50
56
 
51
57
 
52
58
  def apply lead:, message:
@@ -62,6 +68,16 @@ class WcoEmail::EmailFilterCondition
62
68
  end
63
69
  end
64
70
 
71
+ when WcoEmail::EmailFilterCondition::FIELD_LEADSET
72
+ if cond.operator == WcoEmail::EmailFilterCondition::OPERATOR__ID
73
+ test_leadset = Wco::Leadset.find( value ) rescue nil
74
+ if test_leadset
75
+ if lead.leadset == test_leadset
76
+ reason = "#{email_skip_filter ? 'skip_' : ''}condition leadset _id `#{value}`"
77
+ end
78
+ end
79
+ end
80
+
65
81
  when WcoEmail::EmailFilterCondition::FIELD_TAGGED
66
82
  ## cond.operator should eql OPERATOR__ID but I don't check b/c if its slug, it should work also.
67
83
  tag = Wco::Tag.find( cond.value ) rescue nil
@@ -98,7 +114,7 @@ class WcoEmail::EmailFilterCondition
98
114
  "<EF#{email_skip_filter ? 'Skip' : ''}Condition #{field} #{operator} `#{value}` />"
99
115
  end
100
116
  def to_s_full indent: 0
101
- "#{" " * indent }<EF#{email_skip_filter ? 'Skip' : ''}Condition #{field} #{operator} `#{value}` />\n"
117
+ "#{" " * indent }<EF#{email_skip_filter ? 'Skip' : ''}Condition #{field} #{operator} `#{value}` #{comment} />\n"
102
118
  end
103
119
 
104
120
 
@@ -0,0 +1,2 @@
1
+
2
+ studio_1 is that chick on gray background
@@ -3,23 +3,23 @@
3
3
  **/
4
4
  const logg = (a, b="", c=null) => {
5
5
  if ('undefined' === typeof window) { return }
6
- c = "string" === typeof c ? c : b.replace(/\W/g, "");
6
+ c = "string" === typeof c ? c : b.replace(/\W/g, '')
7
7
  if (c.length > 0) {
8
- window[c] = a;
8
+ window[c] = a
9
9
  }
10
- console.log(`+++ ${b}:`, a); // eslint-disable-line no-console
11
- };
10
+ console.log(`+++ ${b}:`, a) // eslint-disable-line no-console
11
+ }
12
12
 
13
13
  let avatar_url = 'https://cdn.jsdelivr.net/gh/wasya-co/ishlib3js@0.0.3/public/vendor/models/avatars/brunette.glb'
14
14
 
15
- import * as THREE from 'three';
15
+ import * as THREE from 'three'
16
16
 
17
- import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
18
- import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
17
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
18
+ import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
19
19
 
20
- import { TalkingHead } from "talkinghead";
20
+ import { TalkingHead } from "talkinghead"
21
21
 
22
- const params = new URLSearchParams(window.location.search);
22
+ const params = new URLSearchParams(window.location.search)
23
23
 
24
24
  let config = {
25
25
  sampleRate: 8000,
@@ -29,22 +29,23 @@ let config = {
29
29
  lipsyncLang: "en",
30
30
  waitForAudioChunks: false,
31
31
  enableMetrics: false,
32
- };
33
- let width = 640;
34
- let height = 480;
35
- const FPS = 24;
32
+ }
33
+ let width = 50
34
+ let height = 50
35
+ let slug = '<ccapture>'
36
+ const FPS = 24
36
37
 
37
- let frame = 0;
38
+ let frame = 0
38
39
  const api_key = params.get('api_key')
39
40
  const api_secret = params.get('api_secret')
40
41
  const wco_origin = params.get('wco_origin')
41
42
  const newspartial_id = params.get('newspartial_id')
42
43
  let totalFrames
43
44
 
44
- let camera, controls, head, renderer, scene;
45
- let faceTarget = new THREE.Vector3();
46
- let chunkedInput = null;
47
- var capturer = new CCapture( { format: 'webm', framerate: FPS } );
45
+ let camera, controls, head, renderer, scene
46
+ let faceTarget = new THREE.Vector3()
47
+ let chunkedInput = null
48
+ var capturer = new CCapture( { format: 'webm', framerate: FPS } )
48
49
 
49
50
  async function init() {
50
51
  if (newspartial_id) {
@@ -55,20 +56,23 @@ async function init() {
55
56
  if (typeof chunkedInput === 'string') {
56
57
  chunkedInput = JSON.parse(chunkedInput)
57
58
  }
58
- logg(chunkedInput, 'chunkedInput')
59
+ // logg(chunkedInput, 'chunkedInput')
59
60
  const last = chunkedInput.wtimes.length-1
60
61
  const duration_ms = chunkedInput.wtimes[last] + chunkedInput.wdurations[last]
61
62
  logg(duration_ms, 'duration_ms')
62
- totalFrames = duration_ms/1000*FPS;
63
+ totalFrames = duration_ms/1000*FPS
64
+ width = chunkedInput.w_px
65
+ height = chunkedInput.h_px
66
+ slug = chunkedInput.slug
63
67
  } catch (error) {
64
- console.log(error);
65
- chunkedInput = null;
66
- totalFrames = undefined;
68
+ console.log(error)
69
+ chunkedInput = null
70
+ totalFrames = undefined
67
71
  }
68
72
  }
69
73
 
70
- scene = new THREE.Scene();
71
- scene.background = new THREE.Color(0xd3d3d3);
74
+ scene = new THREE.Scene()
75
+ scene.background = new THREE.Color(0xd3d3d3)
72
76
 
73
77
  /* fov — Camera frustum vertical field of view.
74
78
  * aspect — Camera frustum aspect ratio.
@@ -79,28 +83,28 @@ async function init() {
79
83
  camera.position.set( 0, 2, 8 )
80
84
  camera.lookAt( 0, 0, 0 )
81
85
 
82
- const ambientLight = new THREE.AmbientLight( 0xffffff );
83
- scene.add( ambientLight );
86
+ const ambientLight = new THREE.AmbientLight( 0xffffff )
87
+ scene.add( ambientLight )
84
88
 
85
- const grid = new THREE.GridHelper(10, 10, 0x888888, 0xbbbbbb);
86
- grid.position.y = 0;
87
- scene.add(grid);
89
+ const grid = new THREE.GridHelper(10, 10, 0x888888, 0xbbbbbb)
90
+ grid.position.y = 0
91
+ scene.add(grid)
88
92
 
89
- const nodeAvatar = document.getElementById('avatar');
93
+ const nodeAvatar = document.getElementById('avatar')
90
94
  head = new TalkingHead( nodeAvatar, {
91
95
  avatarOnly: true,
92
96
  avatarOnlyScene: scene,
93
97
  avatarOnlyCamera: camera,
94
98
 
95
99
  lipsyncModules: ["en"],
96
- });
97
- logg(head, 'head')
100
+ })
101
+ // logg(head, 'head')
98
102
 
99
103
 
100
104
 
101
- const nodeLoading = document.getElementById('loading');
105
+ const nodeLoading = document.getElementById('loading')
102
106
  try {
103
- nodeLoading.textContent = "Loading...";
107
+ nodeLoading.textContent = "Loading..."
104
108
  await head.showAvatar( {
105
109
  url: avatar_url,
106
110
  body: 'F',
@@ -108,41 +112,41 @@ async function init() {
108
112
  lipsyncLang: 'en'
109
113
  }, (ev) => {
110
114
  if ( ev.lengthComputable ) {
111
- let val = Math.min(100,Math.round(ev.loaded/ev.total * 100 ));
112
- nodeLoading.textContent = "Loading " + val + "%";
115
+ let val = Math.min(100,Math.round(ev.loaded/ev.total * 100 ))
116
+ nodeLoading.textContent = "Loading " + val + "%"
113
117
  }
114
- });
115
- nodeLoading.style.display = 'none';
118
+ })
119
+ nodeLoading.style.display = 'none'
116
120
 
117
- head.armature.position.set(0, 0, 0);
118
- head.armature.rotation.set(0, 0, 0);
119
- scene.add(head.armature);
121
+ head.armature.position.set(0, 0, 0)
122
+ head.armature.rotation.set(0, 0, 0)
123
+ scene.add(head.armature)
120
124
 
121
125
  // Put feet at the origin
122
- head.armature.updateMatrixWorld(true);
123
- const leftToe = new THREE.Vector3();
124
- const rightToe = new THREE.Vector3();
125
- head.objectLeftToeBase.getWorldPosition(leftToe);
126
- head.objectRightToeBase.getWorldPosition(rightToe);
126
+ head.armature.updateMatrixWorld(true)
127
+ const leftToe = new THREE.Vector3()
128
+ const rightToe = new THREE.Vector3()
129
+ head.objectLeftToeBase.getWorldPosition(leftToe)
130
+ head.objectRightToeBase.getWorldPosition(rightToe)
127
131
  head.armature.position.set(
128
132
  -(leftToe.x + rightToe.x) / 2,
129
133
  -Math.min(leftToe.y, rightToe.y),
130
134
  -(leftToe.z + rightToe.z) / 2
131
- );
132
- head.armature.updateMatrixWorld(true);
135
+ )
136
+ head.armature.updateMatrixWorld(true)
133
137
 
134
138
  // Camera at head level, pointed at the face
135
- const leftEye = new THREE.Vector3();
136
- const rightEye = new THREE.Vector3();
137
- head.objectLeftEye.getWorldPosition(leftEye);
138
- head.objectRightEye.getWorldPosition(rightEye);
139
- faceTarget.copy(leftEye).add(rightEye).multiplyScalar(0.5);
140
-
141
- const camPos = new THREE.Vector3(0, 0, 2);
142
- camPos.applyQuaternion(head.armature.quaternion);
143
- camPos.add(faceTarget);
144
- camera.position.copy(camPos);
145
- camera.lookAt(faceTarget);
139
+ const leftEye = new THREE.Vector3()
140
+ const rightEye = new THREE.Vector3()
141
+ head.objectLeftEye.getWorldPosition(leftEye)
142
+ head.objectRightEye.getWorldPosition(rightEye)
143
+ faceTarget.copy(leftEye).add(rightEye).multiplyScalar(0.5)
144
+
145
+ const camPos = new THREE.Vector3(0, 0, 2)
146
+ camPos.applyQuaternion(head.armature.quaternion)
147
+ camPos.add(faceTarget)
148
+ camera.position.copy(camPos)
149
+ camera.lookAt(faceTarget)
146
150
 
147
151
  await head.streamStart({
148
152
  sampleRate: config.sampleRate,
@@ -155,8 +159,8 @@ async function init() {
155
159
  })
156
160
 
157
161
  } catch (error) {
158
- console.log(error);
159
- nodeLoading.textContent = error.toString();
162
+ console.log(error)
163
+ nodeLoading.textContent = error.toString()
160
164
  }
161
165
 
162
166
 
@@ -165,41 +169,41 @@ async function init() {
165
169
  renderer = new THREE.WebGLRenderer( {
166
170
  alpha: false,
167
171
  antialias: true,
168
- } );
169
- renderer.setClearColor(0xd3d3d3, 1);
170
- renderer.setPixelRatio( 1 ); // window.devicePixelRatio );
171
- renderer.setSize( width, height );
172
- renderer.toneMapping = THREE.ACESFilmicToneMapping;
173
- renderer.toneMappingExposure = 1;
174
- renderer.outputColorSpace = THREE.SRGBColorSpace;
175
- document.getElementById('rotatingC').appendChild( renderer.domElement );
172
+ } )
173
+ renderer.setClearColor(0xd3d3d3, 1)
174
+ renderer.setPixelRatio( 1 ); // window.devicePixelRatio )
175
+ renderer.setSize( width, height )
176
+ renderer.toneMapping = THREE.ACESFilmicToneMapping
177
+ renderer.toneMappingExposure = 1
178
+ renderer.outputColorSpace = THREE.SRGBColorSpace
179
+ document.getElementById('rotatingC').appendChild( renderer.domElement )
176
180
 
177
181
  //
178
182
 
179
- controls = new OrbitControls( camera, renderer.domElement );
180
- controls.enableDamping = true;
181
- controls.enableRotate = true;
182
- controls.enablePan = true;
183
- controls.enableZoom = true;
184
- controls.minDistance = 0.5;
185
- controls.maxDistance = 100;
186
- controls.target.copy(faceTarget);
187
- controls.autoRotate = false;
188
- controls.update();
183
+ controls = new OrbitControls( camera, renderer.domElement )
184
+ controls.enableDamping = true
185
+ controls.enableRotate = true
186
+ controls.enablePan = true
187
+ controls.enableZoom = true
188
+ controls.minDistance = 0.5
189
+ controls.maxDistance = 100
190
+ controls.target.copy(faceTarget)
191
+ controls.autoRotate = false
192
+ controls.update()
189
193
 
190
194
  //
191
195
 
192
- window.addEventListener( 'resize', onWindowResize );
196
+ window.addEventListener( 'resize', onWindowResize )
193
197
 
194
198
 
195
199
  // Keep rendering so OrbitControls drag/damping stay live
196
- renderer.setAnimationLoop(animate);
200
+ renderer.setAnimationLoop(animate)
197
201
 
198
202
  // Start capture/audio only after the renderer exists
199
203
  if (newspartial_id && chunkedInput) {
200
- capturer.start();
204
+ capturer.start()
201
205
  logg('capturer.start')
202
- head.streamAudio(chunkedInput);
206
+ head.streamAudio(chunkedInput)
203
207
  }
204
208
  }
205
209
 
@@ -212,29 +216,29 @@ document.addEventListener('DOMContentLoaded', async function(e) {
212
216
  })
213
217
 
214
218
  function onWindowResize() {
215
- camera.aspect = width / height;
216
- camera.updateProjectionMatrix();
217
- renderer.setSize( width, height );
218
- render();
219
+ camera.aspect = width / height
220
+ camera.updateProjectionMatrix()
221
+ renderer.setSize( width, height )
222
+ render()
219
223
  }
220
224
 
221
225
  function render() {
222
- renderer.render( scene, camera );
226
+ renderer.render( scene, camera )
223
227
  }
224
228
 
225
229
  function animate() {
226
- const t = frame / FPS;
227
- if (head) head.animate(1000/FPS);
228
- controls.update();
229
- renderer.render( scene, camera );
230
+ const t = frame / FPS
231
+ if (head) head.animate(1000/FPS)
232
+ controls.update()
233
+ renderer.render( scene, camera )
230
234
 
231
235
  if (totalFrames) {
232
- capturer.capture( renderer.domElement );
233
- frame++;
236
+ capturer.capture( renderer.domElement )
237
+ frame++
234
238
  if (frame >= totalFrames) {
235
239
  totalFrames = false
236
- renderer.setAnimationLoop(null);
237
- capturer.stop();
240
+ renderer.setAnimationLoop(null)
241
+ capturer.stop()
238
242
  logg('capturer.stop')
239
243
 
240
244
  if (newspartial_id) {
@@ -242,9 +246,9 @@ function animate() {
242
246
  logg(blob, 'blob')
243
247
  renderer.domElement.toBlob((thumb) => {
244
248
  logg(thumb, 'thumb')
245
- const form = new FormData();
249
+ const form = new FormData()
246
250
  form.append('video', blob, 'lips.webm')
247
- form.append('name', '<ccapturejs>')
251
+ form.append('name', slug)
248
252
  form.append('thumb', thumb)
249
253
  form.append('newspartial_id', newspartial_id)
250
254
 
@@ -254,26 +258,29 @@ function animate() {
254
258
  // 'Content-Type': 'video/webm',
255
259
  },
256
260
  body: form,
261
+ }).then(() => {
262
+ document.getElementById('status').textContent = 'finished'
263
+ document.body.style.backgroundColor = 'gray'
257
264
  })
258
265
  })
259
- });
266
+ })
260
267
  }
261
268
  // Resume interactive orbit after capture
262
- renderer.setAnimationLoop(animate);
269
+ renderer.setAnimationLoop(animate)
263
270
  }
264
271
  }
265
272
  }
266
273
 
267
274
 
268
275
  // Speak when clicked
269
- const nodeSpeak = document.getElementById('speak');
276
+ const nodeSpeak = document.getElementById('speak')
270
277
  nodeSpeak.addEventListener('click', function () {
271
278
  try {
272
279
 
273
280
  } catch (error) {
274
- console.log(error);
281
+ console.log(error)
275
282
  }
276
- });
283
+ })
277
284
 
278
285
 
279
286
  console.log('+++ loaded wco_models :: newsproducer :: studio_1.js')
@@ -13,12 +13,13 @@
13
13
  }
14
14
  </script>
15
15
 
16
- <h1 class='center text-center'>{{ label }}</h1>
16
+ Status:<span id='status'>pending</span>
17
+
17
18
  <button id='speak'>Speak</button>
18
19
  <div id='avatar'></div>
19
20
  <div id='loading'>Loading...</div>
20
- <div id="rotatingC" class="r2" style="width: 640px;
21
- height: 480px;
21
+ <div id="rotatingC" class="r2" style="width: 50px;
22
+ height: 50px;
22
23
  border: 1px solid red;
23
24
  text-align: center; " >
24
25
  </div>
@@ -0,0 +1,13 @@
1
+
2
+ json.id @newsvideo.id.to_s
3
+ json.generate_url api_newsvideo_generate_url(@newsvideo, { api_key: Wco::Setting.get('WASYACO_SIMPLE_API_KEY'),
4
+ api_secret: Wco::Setting.get('WASYACO_SIMPLE_API_SECRET') })
5
+ json.newspartials @newsvideo.newspartials.each do |newspartial|
6
+ json.generate_speech_url api_newspartial_generate_speech_url({ id: newspartial.id.to_s,
7
+ api_key: Wco::Setting.get('WASYACO_SIMPLE_API_KEY'),
8
+ api_secret: Wco::Setting.get('WASYACO_SIMPLE_API_SECRET'), })
9
+ json.generate_video_url api_newsproducer_studio_1_url({ newspartial_id: newspartial.id.to_s,
10
+ wco_origin: request.base_url,
11
+ api_key: Wco::Setting.get('WASYACO_SIMPLE_API_KEY'),
12
+ api_secret: Wco::Setting.get('WASYACO_SIMPLE_API_SECRET'), })
13
+ end
@@ -5,8 +5,10 @@
5
5
  = f.submit
6
6
 
7
7
  .field.flex-row
8
- %label Title
9
- = f.text_field :title, class: 'w-100'
8
+ -# %label Title
9
+ -# = f.text_field :title, class: 'w-100'
10
+ %label slug
11
+ = f.text_field :slug, class: 'w-100'
10
12
 
11
13
  .field
12
14
  %label Body
@@ -14,10 +14,10 @@
14
14
 
15
15
  .full-text
16
16
  .header.collapse-expand{ id: newspartial.id.to_s }
17
- Newspartial
17
+ newspartial::#{newspartial.slug}
18
18
  = link_to '[~]', edit_newspartial_path(newspartial)
19
19
  %span{ class: 'gray' } #{newspartial.id}
20
- = link_to '[api]', api_newspartial_config_path(newspartial, format: :json, api_key: Wco::Setting.get('WASYACO_SIMPLE_API_KEY'), api_secret: Wco::Setting.get('WASYACO_SIMPLE_API_SECRET') ), target: :_blank
20
+ = link_to '[config.json]', api_newspartial_config_path(newspartial, format: :json, api_key: Wco::Setting.get('WASYACO_SIMPLE_API_KEY'), api_secret: Wco::Setting.get('WASYACO_SIMPLE_API_SECRET') ), target: :_blank
21
21
 
22
22
  .full-textC
23
23
  .flex-row
@@ -29,7 +29,7 @@
29
29
  -# = button_to 'Generate video', newspartial_generate_video_path(newspartial), :data => { :confirm => 'Are you sure?' }
30
30
  -# .small.gray ISHLIB3JS_ROOT
31
31
 
32
- = link_to 'Generate video 2', newsproducer_studio_1_path({ newspartial_id: newspartial.id.to_s, wco_origin: request.base_url, api_key: Wco::Setting.get('WASYACO_SIMPLE_API_KEY'), api_secret: Wco::Setting.get('WASYACO_SIMPLE_API_SECRET') }), class: 'btn btn-primary', data: { confirm: 'Are you sure?' }
32
+ = link_to 'Generate video 2', api_newsproducer_studio_1_path({ newspartial_id: newspartial.id.to_s, wco_origin: request.base_url, api_key: Wco::Setting.get('WASYACO_SIMPLE_API_KEY'), api_secret: Wco::Setting.get('WASYACO_SIMPLE_API_SECRET') }), target: :_blank, class: 'btn btn-primary', data: { confirm: 'Are you sure?' }
33
33
 
34
34
  Video:
35
35
  - if newspartial.video
@@ -12,12 +12,21 @@
12
12
  = f.text_field :slug, class: 'w-100'
13
13
 
14
14
  .row
15
- .field
16
- %label w_px
17
- = f.text_field :w_px
18
- .field
19
- %label h_px
20
- = f.text_field :h_px
15
+ .a
16
+ .field
17
+ %label w_px
18
+ = f.text_field :w_px
19
+ .a
20
+ .field
21
+ %label h_px
22
+ = f.text_field :h_px
23
+ .descr
24
+ %ul
25
+ %li 1280x720 16:9
26
+ %li 1024x768 4:3
27
+ %li 854x480 16:9
28
+ %li 640x360 16:9
29
+ %li 640x480 4:3
21
30
 
22
31
  .field
23
32
  %label Body
@@ -28,5 +37,9 @@
28
37
  -# = render '/wco/tags/index', tags: newsvideo.tags
29
38
  = f.select :tag_ids, options_for_select(@tags_list, selected: newsvideo.tag_ids), {}, { multiple: true, class: 'select2' }
30
39
 
40
+ .field
41
+ %label next_overlay_ms
42
+ = f.text_field :next_overlay_ms
43
+
31
44
  .actions
32
45
  = f.submit
@@ -1,2 +1,3 @@
1
1
 
2
- = render 'form', newsvideo: @newsvideo
2
+ .newsvideos-new.maxwidth
3
+ = render 'form', newsvideo: @newsvideo
@@ -4,17 +4,24 @@
4
4
  Newsvideo `#{@newsvideo.title}`
5
5
  #{link_to '[~]', edit_newsvideo_path(@newsvideo)}
6
6
 
7
+ = link_to '_[config.json]', api_newsvideo_path(@newsvideo.id, { api_key: Wco::Setting.get('WASYACO_SIMPLE_API_KEY'), api_secret: Wco::Setting.get('WASYACO_SIMPLE_API_SECRET') }), target: :_blank
7
8
  = 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
+ = link_to '_[search illustration]', pexels_search_path(newsvideo_id: @newsvideo.id), target: :_blank
9
10
 
10
11
 
11
12
  %ul.actions
13
+ %li #{@newsvideo.w_px} x #{@newsvideo.h_px}
12
14
  %li
13
15
  .d-inline-block= button_to 'split', split_newsvideo_path(@newsvideo), :data => { :confirm => 'Are you sure?' }
14
16
  .small.gray
15
17
  Uses sentences_to_phrases to reasonably create Wco::Newspartial's
16
18
  %li
17
- .d-inline-block= button_to 'generate', generate_newsvideo_path(@newsvideo), :data => { :confirm => 'Are you sure?' }
19
+ .d-inline-block= button_to 'generate all audio', newsvideo_generate_all_audio_path(@newsvideo), :data => { :confirm => 'Are you sure?' }
20
+ %li
21
+ .d-inline-block= button_to 'generate (obsolete)', generate_newsvideo_path(@newsvideo), :data => { :confirm => 'Are you sure?' }
22
+ %li
23
+ .d-inline-block= button_to 'generate video & output', newsvideo_generate_all_video_path(@newsvideo), :data => { :confirm => 'Are you sure?' }
24
+
18
25
 
19
26
  %i.fa.fa-compress.collapse-expand{ id: @newsvideo.id.to_s } Descr
20
27
  .descr= raw @newsvideo.body.gsub(/(\r?\n){2}/, "<br /><br />")
@@ -7,3 +7,5 @@ Stripe.api_version = '2020-08-27'
7
7
 
8
8
  PI_DRUP_PROD_USERNAME ||= 'test-1@piousbox.com'
9
9
  PI_DRUP_PROD_PASSWD ||= 'KSUisl321,'
10
+
11
+ PUPPETEER_ROOT = '/Users/piousbox/projects/node/puppeteer_example'
@@ -4,3 +4,5 @@ STRIPE_SK = ''
4
4
 
5
5
  Stripe.api_key = ::STRIPE_SK
6
6
  Stripe.api_version = '2020-08-27'
7
+
8
+ PUPPETEER_ROOT = '/Users/piousbox/projects/node/puppeteer_example'
data/config/routes.rb CHANGED
@@ -15,9 +15,17 @@ Wco::Engine.routes.draw do
15
15
 
16
16
  post 'reports', to: 'reports#create'
17
17
  patch 'reports/:id/add-config', to: 'reports#add_config'
18
- get 'newspartials/:id/config', to: 'newspartials#show_config', as: :newspartial_config
18
+ get 'newspartials/:id/config', to: 'newspartials#show_config', as: :newspartial_config
19
+ match 'newspartials/:id/generate-speech', to: 'newspartials#generate_speech', as: :newspartial_generate_speech, via: [ :get, :post ]
20
+
21
+ get 'newsproducer/canvas', to: 'newsproducer#canvas'
22
+ get 'newsproducer/canvas_minimal', to: 'newsproducer#canvas_minimal'
23
+ get 'newsproducer/studio_1', to: 'newsproducer#studio_1'
24
+
19
25
 
20
26
  match 'newsvideos/:id/generate-illustration', to: 'newsvideos#generate_illustration', as: :newsvideo_generate_illustration, via: [ :get, :post ]
27
+ match 'newsvideos/:id/generate-video', to: 'newsvideos#generate', as: :newsvideo_generate, via: [ :get, :post ]
28
+ get 'newsvideos/:id', to: 'newsvideos#show', as: :newsvideo, defaults: { format: :json }
21
29
 
22
30
  get 'tags', to: 'tags#index'
23
31
 
@@ -69,13 +77,13 @@ Wco::Engine.routes.draw do
69
77
  resources :newspartials
70
78
 
71
79
 
72
- get 'newsproducer/canvas', to: 'newsproducer#canvas'
73
- get 'newsproducer/canvas_minimal', to: 'newsproducer#canvas_minimal'
74
- get 'newsproducer/studio_1', to: 'newsproducer#studio_1'
75
80
 
76
81
  match 'newsvideos/:id/generate-illustration', to: 'newsvideos#generate_illustration', as: :newsvideo_generate_illustration, via: [ :get, :post ]
82
+ match 'newsvideos/:id/generate-all-audio', to: 'newsvideos#generate_all_audio', as: :newsvideo_generate_all_audio, via: [ :get, :post ]
83
+ match 'newsvideos/:id/generate-all-video', to: 'newsvideos#generate_all_video', as: :newsvideo_generate_all_video, via: [ :get, :post ]
77
84
  post 'newsvideos/:id/generate', to: 'newsvideos#generate', as: :generate_newsvideo
78
85
  post 'newsvideos/:id/split', to: 'newsvideos#split', as: :split_newsvideo
86
+ post 'newsvideos/:id/add-image-as-overlay', to: 'newsvideos#add_image_as_overlay'
79
87
  resources :newsvideos
80
88
 
81
89
  resources :obfuscated_redirects