| 1 |
<?php
|
| 2 |
|
| 3 |
/**
|
| 4 |
* Implementation of hook_menu, for admin content type selection form.
|
| 5 |
*/
|
| 6 |
function twistage_publish_menu($may_cache) {
|
| 7 |
$items = array();
|
| 8 |
|
| 9 |
$items[] = array(
|
| 10 |
'path' => 'admin/settings/twistage/publishing',
|
| 11 |
'title' => t('Publishing settings'),
|
| 12 |
'type' => MENU_CALLBACK,
|
| 13 |
'callback' => 'drupal_get_form',
|
| 14 |
'callback arguments' => array('twistage_publish_admin_form', arg(4)),
|
| 15 |
'access' => user_access('administer twistage'),
|
| 16 |
);
|
| 17 |
|
| 18 |
return $items;
|
| 19 |
}
|
| 20 |
|
| 21 |
/**
|
| 22 |
* Implementation of hook_form_alter, to add the video submission fieldset to the node form.
|
| 23 |
*/
|
| 24 |
function twistage_publish_form_alter($form_id, &$form) {
|
| 25 |
if (isset($form['type'])) {
|
| 26 |
$type = $form['type']['#value'];
|
| 27 |
} else {
|
| 28 |
return;
|
| 29 |
}
|
| 30 |
|
| 31 |
$avail_profiles = array();
|
| 32 |
$result = db_query("SELECT * FROM {twistage_profiles} WHERE 1");
|
| 33 |
while ($profile = db_fetch_object($result)) {
|
| 34 |
$types = unserialize($profile->publish_types);
|
| 35 |
if ($types[$type]) {
|
| 36 |
$avail_profiles[$profile->pid] = $profile->name;
|
| 37 |
}
|
| 38 |
}
|
| 39 |
|
| 40 |
if (!$avail_profiles) {
|
| 41 |
return;
|
| 42 |
}
|
| 43 |
|
| 44 |
drupal_add_js(drupal_get_path('module','twistage') . '/twistage_publish.js');
|
| 45 |
|
| 46 |
// Add elements for existing videos
|
| 47 |
$videos = twistage_publish_get_videos_by_nid($form['#node']->nid);
|
| 48 |
if ($videos) {
|
| 49 |
$form['twistage_edit'] = array(
|
| 50 |
'#type' => 'fieldset',
|
| 51 |
'#title' => t('Maintain videos'),
|
| 52 |
'#collapsible' => true,
|
| 53 |
'#tree' => true,
|
| 54 |
);
|
| 55 |
|
| 56 |
foreach($videos as $video) {
|
| 57 |
$form['twistage_edit'][$video->vid] = twistage_publish_form_element($avail_profiles, 0, $video);
|
| 58 |
}
|
| 59 |
}
|
| 60 |
|
| 61 |
// Allow now video uploads.
|
| 62 |
|
| 63 |
// The hidden value of twistage_sequence is manipulated by jQuery as the user adds videos on the fly.
|
| 64 |
// This is somewhat unorthodox, but we can "cheat" and look at the post vars to see how many internal forms API members of this array to create,
|
| 65 |
// thereby giving us access to them in hook_nodeapi later on.
|
| 66 |
$seq = $_POST['twistage_sequence'] ? $_POST['twistage_sequence'] : 0;
|
| 67 |
|
| 68 |
$form['twistage_sequence'] = array(
|
| 69 |
'#type' => 'hidden',
|
| 70 |
'#value' => $seq,
|
| 71 |
);
|
| 72 |
|
| 73 |
$form['twistage_upload'] = array(
|
| 74 |
'#tree' => true,
|
| 75 |
'#prefix' => '<div id="twistage-add-replicate">',
|
| 76 |
'#suffix' => '</div>',
|
| 77 |
);
|
| 78 |
|
| 79 |
for($i = 0; $i <= $seq; $i++) {
|
| 80 |
$elem = array(
|
| 81 |
'#type' => 'fieldset',
|
| 82 |
'#title' => t('Video Upload'),
|
| 83 |
'#collapsible' => true,
|
| 84 |
);
|
| 85 |
|
| 86 |
if ($i == 0) {
|
| 87 |
$elem['#attributes'] = array('class' => 'twistage-add-original');
|
| 88 |
}
|
| 89 |
|
| 90 |
$form['twistage_upload'][$i] = array_merge($elem, twistage_publish_form_element($avail_profiles, $seq));
|
| 91 |
}
|
| 92 |
|
| 93 |
|
| 94 |
}
|
| 95 |
|
| 96 |
/**
|
| 97 |
* Implementation of hook_nodeapi
|
| 98 |
*/
|
| 99 |
function twistage_publish_nodeapi(&$node, $op, $teaser, $page) {
|
| 100 |
switch($op) {
|
| 101 |
case 'load':
|
| 102 |
$result = db_query("SELECT * FROM {twistage_video_node} WHERE nid=%d", $node->nid);
|
| 103 |
$node->twistage_video = array();
|
| 104 |
while ($link = db_fetch_object($result)) {
|
| 105 |
$node->twistage_video[] = twistage_get_video($link->vid, $link->pid);
|
| 106 |
}
|
| 107 |
break;
|
| 108 |
|
| 109 |
case 'validate':
|
| 110 |
foreach ($node->twistage_edit as $vid => $edit) {
|
| 111 |
if (!$edit['twistage_title']) {
|
| 112 |
form_set_error('twistage_edit][' . $vid . '][twistage_title', t('Title is required'));
|
| 113 |
}
|
| 114 |
}
|
| 115 |
|
| 116 |
foreach ($node->twistage_upload as $seq => $upload) {
|
| 117 |
if (twistage_publish_upload_exists($seq) && !$upload['twistage_title']) {
|
| 118 |
form_set_error('twistage_upload][' . $seq . '][twistage_title', t('Title is required'));
|
| 119 |
}
|
| 120 |
}
|
| 121 |
break;
|
| 122 |
|
| 123 |
case 'insert':
|
| 124 |
case 'update':
|
| 125 |
//print_r($node); print_r($_FILES); die();
|
| 126 |
// The twistage_video property is set by hook_nodeapi on load only, so its our indicator of whether a video already exists.
|
| 127 |
// All the other properties are set only in the node form.
|
| 128 |
// This half of this if statement handles the case whereby a video exists, has not been overwritten, but some metadata may have been changed.
|
| 129 |
|
| 130 |
foreach ($node->twistage_edit as $vid => $edit) {
|
| 131 |
//if ($node->twistage_video && !twistage_publish_upload_exists()) {
|
| 132 |
$video = twistage_get_video($vid, $edit['twistage_pid']);
|
| 133 |
$query = '';
|
| 134 |
|
| 135 |
$availability = $edit['twistage_availability'] ? "available" : "hidden";
|
| 136 |
if ($availability != $video->availability) {
|
| 137 |
$query .= "&video[available_for_display]=" . $availability;
|
| 138 |
}
|
| 139 |
|
| 140 |
if ($edit['twistage_title'] != $video->title) {
|
| 141 |
$query .= "&video[title]=" . urlencode($edit['twistage_title']);
|
| 142 |
}
|
| 143 |
|
| 144 |
if ($edit['description'] != $video->description) {
|
| 145 |
$query .= "&video[description]=" . urlencode($edit['twistage_description']);
|
| 146 |
}
|
| 147 |
|
| 148 |
// An unfortunate workaround for the fact that trim() does not operate on arrays.
|
| 149 |
$in = explode(',', $edit['twistage_tags']);
|
| 150 |
$tags = array();
|
| 151 |
foreach ($in as $tag) {
|
| 152 |
$tags[] = trim($tag);
|
| 153 |
}
|
| 154 |
|
| 155 |
if ($tags != $video->tags) {
|
| 156 |
$send = array();
|
| 157 |
foreach ($tags as $tag) {
|
| 158 |
$send[] = urlencode($tag);
|
| 159 |
}
|
| 160 |
$query .= "&video[tag_list]=" . implode(',', $send);
|
| 161 |
}
|
| 162 |
|
| 163 |
// Video exists; check to see if we need to turn it off via the make avail. checkbox
|
| 164 |
if ($query) {
|
| 165 |
$profile = twistage_get_profile($video->pid);
|
| 166 |
$signature = _twistage_authenticate($profile->site_key, $profile->site_username);
|
| 167 |
$url = "http://service.twistage.com./videos/" . $video->vid . "?signature=" . urlencode($signature) . $query;
|
| 168 |
$f = tmpfile();
|
| 169 |
$ch = curl_init();
|
| 170 |
curl_setopt($ch, CURLOPT_URL, $url);
|
| 171 |
curl_setopt($ch, CURLOPT_PUT, true);
|
| 172 |
curl_setopt($ch, CURLOPT_INFILE, $f);
|
| 173 |
curl_setopt($ch, CURLOPT_INFILESIZE, 0);
|
| 174 |
curl_setopt($ch, CURLOPT_TIMEOUT, 900);
|
| 175 |
curl_setopt($ch, CURLOPT_CONNECTIONTIMEOUT, 30);
|
| 176 |
curl_setopt($ch, CURLOPT_FAILONERROR, false);
|
| 177 |
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
| 178 |
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
| 179 |
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
| 180 |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
| 181 |
$ret = curl_exec($ch);
|
| 182 |
fclose($f);
|
| 183 |
}
|
| 184 |
// This half of the if statement handles adding a new video to Twistage.
|
| 185 |
// It doesn't matter here if an old video exists -- the node-video association table will be updated in hook_twistage_api below
|
| 186 |
// after the video is done processing/transcoding. The old video will just remain stored on Twistage until an admin chooses to delete it.
|
| 187 |
}
|
| 188 |
// TODO: perform some cursory check on MIME types before forging ahead with the video
|
| 189 |
|
| 190 |
// This will be filled in the for loop.
|
| 191 |
$elements = array('add' => array('publish-profile' => 'development', 'list' => array()));
|
| 192 |
$proc = false;
|
| 193 |
|
| 194 |
foreach ($node->twistage_upload as $seq => $upload) {
|
| 195 |
// Break out if there's no upload.
|
| 196 |
if (!twistage_publish_upload_exists($seq)) {
|
| 197 |
continue;
|
| 198 |
}
|
| 199 |
$proc = true;
|
| 200 |
|
| 201 |
// First, move the uploaded file to a temp files directory, since Twistage must get the video over HTTP.
|
| 202 |
if (!is_dir(file_directory_path() . '/twistage_temp')) {
|
| 203 |
mkdir(file_directory_path() . '/twistage_temp');
|
| 204 |
}
|
| 205 |
$info = file_save_upload('twistage_upload._' . $seq, file_directory_path() . '/twistage_temp');
|
| 206 |
$url = url($info->filepath, NULL, NULL, TRUE);
|
| 207 |
|
| 208 |
$tags = explode(',', $upload['twistage_tags']);
|
| 209 |
$tags_arr = array();
|
| 210 |
foreach ($tags as $t) {
|
| 211 |
$tags_arr[] = array('key' => 'tag', 'value' => trim($t));
|
| 212 |
}
|
| 213 |
|
| 214 |
// Create an array to represent the XML we must submit to Twistage.
|
| 215 |
$elements['add']['list'][] = array(
|
| 216 |
'key' => 'entry',
|
| 217 |
'value' => array(
|
| 218 |
'src' => $url,
|
| 219 |
'title' => $upload['twistage_title'],
|
| 220 |
'description' => $upload['twistage_description'],
|
| 221 |
'tags' => $tags_arr,
|
| 222 |
'customdata' => array(
|
| 223 |
'nid' => $node->nid,
|
| 224 |
),
|
| 225 |
),
|
| 226 |
);
|
| 227 |
}
|
| 228 |
if ($proc) {
|
| 229 |
$profile = twistage_get_profile($upload['twistage_pid']);
|
| 230 |
$signature = _twistage_authenticate($profile->site_key, $profile->site_username);
|
| 231 |
$post = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" . format_xml_elements($elements);
|
| 232 |
$header = array("Content-type: text/xml");
|
| 233 |
$ch = curl_init();
|
| 234 |
curl_setopt($ch, CURLOPT_URL, "http://service.twistage.com/videos/create_many?signature=" . $signature);
|
| 235 |
curl_setopt($ch, CURLOPT_TIMEOUT, 900);
|
| 236 |
curl_setopt($ch, CURLOPT_CONNECTIONTIMEOUT, 30);
|
| 237 |
curl_setopt($ch, CURLOPT_FAILONERROR, false);
|
| 238 |
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
| 239 |
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
| 240 |
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
| 241 |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
| 242 |
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
| 243 |
curl_setopt($ch, CURLOPT_POST);
|
| 244 |
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
| 245 |
$ret = curl_exec($ch);
|
| 246 |
print_r($post);
|
| 247 |
print "ret: $ret\n";
|
| 248 |
curl_close($ch);
|
| 249 |
}
|
| 250 |
break;
|
| 251 |
|
| 252 |
case 'view':
|
| 253 |
// Make the video available in the node display.
|
| 254 |
$node->content['twistage_video'] = array('#value' => '', '#weight' => -1);
|
| 255 |
foreach($node->twistage_video as $video) {
|
| 256 |
$profile = twistage_get_profile($video->pid);
|
| 257 |
$preroll = twistage_get_preroll_video($video->pid);
|
| 258 |
// theme_twistage_video will return nothing if the video is still processing or has been marked unavailable.
|
| 259 |
// The default weight will place it just above the node body, but of course themes can override this and show the video code wherever they like.
|
| 260 |
$node->content['twistage_video']['#value'] .= theme('twistage_video', $video, $preroll, $profile->preroll_url, $profile->width, $profile->height, false);
|
| 261 |
}
|
| 262 |
break;
|
| 263 |
}
|
| 264 |
}
|
| 265 |
|
| 266 |
/**
|
| 267 |
* Implementation of hook_twistage_api (see twistage.module)
|
| 268 |
* Note that here we will get $video->nid in the event that it was passed down from Twistage.
|
| 269 |
* This indicates we've seeing the results of a one-click publish when we submitted the video back in hook_nodeapi.
|
| 270 |
*/
|
| 271 |
function twistage_publish_twistage_api($op, $video) {
|
| 272 |
// All we're interested in here is to see whether we need to maintain/delete node/video associations.
|
| 273 |
switch ($op) {
|
| 274 |
case 'update':
|
| 275 |
case 'create':
|
| 276 |
if ($video->nid) {
|
| 277 |
//db_query("DELETE FROM {twistage_video_node} WHERE nid=%d", $video->nid);
|
| 278 |
db_query("INSERT INTO {twistage_video_node} (nid, pid, vid) VALUES (%d, %d, '%s')", $video->nid, $video->pid, $video->vid);
|
| 279 |
}
|
| 280 |
break;
|
| 281 |
|
| 282 |
case 'delete':
|
| 283 |
db_query("DELETE FROM {twistage_video_node} WHERE vid='%s' AND pid=%d", $video->vid, $video->pid);
|
| 284 |
break;
|
| 285 |
}
|
| 286 |
}
|
| 287 |
|
| 288 |
function twistage_publish_admin_form($pid) {
|
| 289 |
$form = array();
|
| 290 |
|
| 291 |
$form['info'] = array(
|
| 292 |
'#value' => t('Select the content types which will allow uploading to this Twistage site.'),
|
| 293 |
);
|
| 294 |
|
| 295 |
|
| 296 |
$result = db_query("SELECT type,name FROM {node_type} WHERE 1");
|
| 297 |
$types = array();
|
| 298 |
while ($type = db_fetch_object($result)) {
|
| 299 |
$types[$type->type] = $type->name;
|
| 300 |
}
|
| 301 |
|
| 302 |
$profile = twistage_get_profile($pid);
|
| 303 |
$selected = unserialize($profile->publish_types);
|
| 304 |
|
| 305 |
$form['pid'] = array(
|
| 306 |
'#type' => 'hidden',
|
| 307 |
'#value' => $pid,
|
| 308 |
);
|
| 309 |
|
| 310 |
$form['types'] = array(
|
| 311 |
'#type' => 'checkboxes',
|
| 312 |
'#title' => t('Content types'),
|
| 313 |
'#options' => $types,
|
| 314 |
'#default_value' => $selected
|
| 315 |
);
|
| 316 |
|
| 317 |
return system_settings_form($form);
|
| 318 |
}
|
| 319 |
|
| 320 |
function twistage_publish_admin_form_submit($form_id, $form_values) {
|
| 321 |
$profile = twistage_get_profile($form_values['pid']);
|
| 322 |
db_query("UPDATE {twistage_profiles} SET publish_types='%s' WHERE pid=%d", serialize($form_values['types']), $form_values['pid']);
|
| 323 |
return 'admin/settings/twistage';
|
| 324 |
}
|
| 325 |
|
| 326 |
function twistage_publish_upload_exists($seq) {
|
| 327 |
if ($_FILES['files']['name']['twistage_upload_' . $seq]) {
|
| 328 |
return true;
|
| 329 |
} else {
|
| 330 |
return false;
|
| 331 |
}
|
| 332 |
}
|
| 333 |
|
| 334 |
function twistage_publish_get_video_by_nid($nid) {
|
| 335 |
$result = db_fetch_object(db_query("SELECT * FROM {twistage_video_node} WHERE nid=%d", $nid));
|
| 336 |
return twistage_get_video($result->vid, $result->pid);
|
| 337 |
}
|
| 338 |
|
| 339 |
function twistage_publish_get_videos_by_nid($nid) {
|
| 340 |
$result = db_query("SELECT * FROM {twistage_video_node} WHERE nid=%d", $nid);
|
| 341 |
$videos = array();
|
| 342 |
while ($video = db_fetch_object($result)) {
|
| 343 |
$videos[] = $video;
|
| 344 |
}
|
| 345 |
return $videos;
|
| 346 |
}
|
| 347 |
|
| 348 |
function twistage_publish_form_element($profiles, $seq = 0, $video = NULL) {
|
| 349 |
$form = array();
|
| 350 |
|
| 351 |
$form = array(
|
| 352 |
'#tree' => TRUE,
|
| 353 |
);
|
| 354 |
|
| 355 |
$form['notice'] = array(
|
| 356 |
'#value' => t('<p><b>Video note</b>: All video uploads and edits must be sent to Twistage and processed before taking effect locally. There will be a brief delay before changes are visible locally.'),
|
| 357 |
);
|
| 358 |
|
| 359 |
$avail = $video->availability == 'available' ? true : false;
|
| 360 |
$form['twistage_availability'] = array(
|
| 361 |
'#type' => 'checkbox',
|
| 362 |
'#title' => t('Make video available for viewing'),
|
| 363 |
'#default_value' => ($video) ? $avail : true,
|
| 364 |
);
|
| 365 |
|
| 366 |
$form['twistage_title'] = array(
|
| 367 |
'#type' => 'textfield',
|
| 368 |
'#title' => t('Video Title'),
|
| 369 |
'#default_value' => $video->title,
|
| 370 |
);
|
| 371 |
|
| 372 |
$form['twistage_tags'] = array(
|
| 373 |
'#type' => 'textfield',
|
| 374 |
'#title' => t('Video Tags'),
|
| 375 |
'#description' => t('Separate tags with commas'),
|
| 376 |
'#default_value' => implode(',', $video->tags),
|
| 377 |
);
|
| 378 |
|
| 379 |
$form['twistage_description'] = array(
|
| 380 |
'#type' => 'textarea',
|
| 381 |
'#title' => t('Video Description'),
|
| 382 |
'#default_value' => $video->description,
|
| 383 |
);
|
| 384 |
|
| 385 |
if (!$video) {
|
| 386 |
// These fields are only to be shown on nodes with no prior video uploaded; we don't want the user thinking they can change them later.
|
| 387 |
$form['twistage_pid'] = array(
|
| 388 |
'#type' => 'select',
|
| 389 |
'#title' => t('Profile'),
|
| 390 |
'#description' => t('Select the Twistage site profile to add this video to.'),
|
| 391 |
'#options' => $profiles,
|
| 392 |
);
|
| 393 |
|
| 394 |
$form['twistage_file_0'] = array(
|
| 395 |
'#type' => 'file',
|
| 396 |
'#title' => t('Select Video File'),
|
| 397 |
);
|
| 398 |
|
| 399 |
$form['more'] = array(
|
| 400 |
'#value' => '<a class="twistage-add-more">Add another video...</a>',
|
| 401 |
);
|
| 402 |
} else {
|
| 403 |
// Get current video name (also the nid of this node will be available, since existing video means existing node)
|
| 404 |
$existing = $video;
|
| 405 |
$existing_profile = twistage_get_profile($existing->pid);
|
| 406 |
$form['info'] = array(
|
| 407 |
'#value' => t('<p><b>Current video</b>: @title</p>', array('@title' => $existing->title)),
|
| 408 |
);
|
| 409 |
$form['info2'] = array(
|
| 410 |
'#value' => t('<p><b>Current profile</b>: @profile</p>', array('@profile' => $existing_profile->name)),
|
| 411 |
);
|
| 412 |
|
| 413 |
$form['twistage_vid'] = array(
|
| 414 |
'#type' => 'hidden',
|
| 415 |
'#value' => $video->vid,
|
| 416 |
);
|
| 417 |
|
| 418 |
/*$form['twistage_file_0'] = array(
|
| 419 |
'#type' => 'file',
|
| 420 |
'#title' => t('Upload a new video'),
|
| 421 |
'#description' => t('This will overwrite the old video. Leave this field blank to keep the old video as-is.'),
|
| 422 |
);*/
|
| 423 |
}
|
| 424 |
|
| 425 |
return $form;
|
| 426 |
}
|