| IDs must be numeric and must preferably start from 1.
|
*/
-$config['categories'] = array(1 => 'movies', 2 => 'tech-talks', 3 => 'events', 4 => 'karaoke');
+$config['categories'] = array(
+ 1 => 'movies',
+ 2 => 'tech-talks',
+ 3 => 'events',
+ 4 => 'karaoke'
+);
/*
|--------------------------------------------------------------------------
|
*/
$config['noreply_email'] = 'no-reply@p2p-next.cs.pub.ro';
+
+/*
+|--------------------------------------------------------------------------
+| Require Moderation
+|--------------------------------------------------------------------------
+|
+| Set whether or not a new uploaded video must be aproved by an
+| administrator.
+|
+*/
+$config['require_moderation'] = TRUE;
\ No newline at end of file
}
public function index()
- {
+ {
+ echo "P2P-Tube".PHP_EOL;
}
/**
else
echo "No users were deleted.".PHP_EOL;
}
+
+ public function print_unactivated_videos()
+ {
+ $this->load->model('videos_model');
+
+ $videos = $this->videos_model->get_unactivated_videos();
+
+ if ($videos)
+ {
+ foreach($videos as $video)
+ {
+ echo $video['video_id']. ' '
+ . site_url("watch/". $video['video_id']
+ . "/". $video['name']). PHP_EOL;
+ }
+ }
+ }
+
+ public function activate_video($video_id = NULL)
+ {
+ $this->load->model('videos_model');
+ $video_id = intval($video_id);
+
+ if ($video_id == 0)
+ {
+ echo 'usage: admin_cli activate_video $video_id'.PHP_EOL;
+ return;
+ }
+
+ if (!$this->videos_model->activate_video(intval($video_id)))
+ echo 'error: an error occured while activating the video'.PHP_EOL;
+ }
}
/* End of file admin_cli.php */
public function index()
{
+ $user_id = $this->session->userdata('user_id');
+ if ($user_id)
+ {
+ if (intval($user_id) & USER_ROLE_ADMIN)
+ $allow_unactivated = TRUE;
+ else
+ $allow_unactivated = FALSE;
+ }
+ else
+ $allow_unactivated = FALSE;
+
+
// **
// ** LOADING MODEL
// **
{
// Videos
$vs_data['videos'] = $this->videos_model->get_videos_summary(
- $id, NULL, 0, $this->config->item('videos_per_row'));
+ $id, NULL, 0, $this->config->item('videos_per_row'),
+ $allow_unactivated);
// Category
$vs_data['category_name'] = $name;
public function category($category_name, $ordering = 'hottest', $offset = 0)
{
+ $user_id = $this->session->userdata('user_id');
+ if ($user_id)
+ {
+ if (intval($user_id) & USER_ROLE_ADMIN)
+ $allow_unactivated = TRUE;
+ else
+ $allow_unactivated = FALSE;
+ }
+ else
+ $allow_unactivated = FALSE;
+
// **
// ** LOADING MODEL
// **
$this->load->model('videos_model');
$vs_data['videos'] = $this->videos_model->get_videos_summary(
$category_data['category_id'], NULL, intval($offset),
- $this->config->item('videos_per_page'), $ordering);
+ $this->config->item('videos_per_page'), $ordering,
+ $allow_unactivated);
$vs_data['ordering'] = $ordering;
"catalog/category/$category_name/$ordering/");
$pg_config['uri_segment'] = 5;
$pg_config['total_rows'] = $this->videos_model->get_videos_count(
- $category_data['category_id']);
+ $category_data['category_id'], NULL, $allow_unactivated);
$pg_config['per_page'] = $this->config->item('videos_per_page');
$this->pagination->initialize($pg_config);
$vs_data['pagination'] = $this->pagination->create_links();
public function test($user_id = 1)
{
- echo extension_loaded('gd') ? 'gd' : 'nu';
+// echo extension_loaded('gd') ? 'gd' : 'nu';
}
// DEBUG
$this->session->unset_userdata('user_id');
$this->session->unset_userdata('username');
$this->session->unset_userdata('auth_src');
+ $this->session->unset_userdata('roles');
$this->session->unset_userdata('time_zone');
header('Location: '. site_url(urldecode_segments($redirect)));
{
// TODO handle user not found
+ $user_id = $this->session->userdata('user_id');
+ if ($user_id)
+ {
+ if (intval($user_id) & USER_ROLE_ADMIN)
+ $allow_unactivated = TRUE;
+ else
+ $allow_unactivated = FALSE;
+ }
+ else
+ $allow_unactivated = FALSE;
+
$this->load->config('localization');
$this->load->helper('date');
$this->lang->load('date');
// User's videos
$this->load->model('videos_model');
$vs_data['videos'] = $this->videos_model->get_videos_summary(
- NULL, $username, intval($videos_offset),
- $this->config->item('videos_per_page'));
+ NULL, $username, intval($videos_offset),
+ $this->config->item('videos_per_page'), 'hottest',
+ $allow_unactivated);
// Pagination
$this->load->library('pagination');
$pg_config['base_url'] = site_url("user/profile/$username/");
$pg_config['uri_segment'] = 4;
$pg_config['total_rows'] = $this->videos_model->get_videos_count(
- NULL, $username);
+ NULL, $username, $allow_unactivated);
$pg_config['per_page'] = $this->config->item('videos_per_page');
$this->pagination->initialize($pg_config);
$vs_data['pagination'] = $this->pagination->create_links();
'user_id'=> $user['id'],
'username'=> $user['username'],
'auth_src'=> $user['auth_src'],
+ 'roles'=> $user['roles'],
'time_zone'=> $user['time_zone']
));
$this->import = (isset($user['import']) ? $user['import'] : FALSE);
class Video extends CI_Controller {
protected $uploaded_file;
+ protected $av_info;
public function __construct()
{
//phpinfo();
}
- public function test($fn)
+ public function test()
{
- $fn = "data/upload/$fn";
- $this->load->helper('video');
+ $this->load->model('videos_model');
+
+ $videos = $this->videos_model->get_videos_summary(1, NULL, 0, 10,
+ 'alphabetically', TRUE);
- var_dump(get_av_info($fn));
+ var_dump($videos);
}
/**
// **
// ** LOADING MODEL
// **
- // Retrieve video information.
$this->load->model('videos_model');
- $this->videos_model->inc_views($id);
+
+ $data['user_id'] = $this->session->userdata('user_id');
+ if ($data['user_id'] === FALSE)
+ $data['user_id'] = '';
+ else
+ $data['user_id'] = intval($data['user_id']);
+ $user_roles = intval($this->session->userdata('roles'));
+// echo USER_ROLE_ADMIN . ' / ';
+// var_dump($user_roles);
+// var_dump($user_roles | USER_ROLE_ADMIN);
+// die();
+
+ // Retrieve video information.
$data['video'] = $this->videos_model->get_video($id, $name);
+ if ($data['video'] === FALSE)
+ {
+ $this->load->helper('message');
+ show_error_msg_page($this,
+ $this->lang->line('video_msg_no_video'));
+ return;
+ }
+
+ // Video is being processed by CIS.
+ if ($data['video']['activation_code']
+ && !$data['video']['content_ingested'])
+ {
+ $this->load->helper('message');
+ show_error_msg_page($this,
+ $this->lang->line('video_msg_video_not_ready'));
+ return;
+ }
+
+ // Unlogged in user can't see unactivated videos.
+ if (empty($data['user_id']))
+ $allow_unactivated = FALSE;
+ else
+ {
+ if (($user_roles & USER_ROLE_ADMIN) == 0
+ && $data['user_id'] != $data['video']['user_id'])
+ $allow_unactivated = FALSE;
+ else
+ $allow_unactivated = TRUE;
+ }
+
+ // Video is not activated; can be seen by owner and admin.
+ if ($data['video']['activation_code'] && !$allow_unactivated)
+ {
+ $this->load->helper('message');
+ show_error_msg_page($this,
+ $this->lang->line('video_msg_video_unactivated'));
+ return;
+ }
+
$categories = $this->config->item('categories');
$data['video']['category_name'] =
$categories[ $data['video']['category_id'] ];
$data['plugin_type'] = ($plugin === NULL ? 'auto' : $plugin);
- $data['user_id'] = $this->session->userdata('user_id');
- if ($data['user_id'] === FALSE)
- $data['user_id'] = '';
+
+ // Increment the number of views for the video.
+ $this->videos_model->inc_views($id);
// Display page.
$params = array( 'title' => $data['video']['title'] . ' – '
$this->input->post('video-description'),
$this->input->post('video-tags'),
$this->av_info['duration'],
- $prepared_formats['db_formats'], $category_id, $user_id);
+ $prepared_formats['db_formats'], $category_id, $user_id,
+ $this->uploaded_file);
// Send a content ingestion request to
// CIS (Content Ingestion Server).
}
}
+ public function cis_completion($activation_code)
+ {
+ $this->load->model('videos_model');
+
+ if ($this->config->item('require_moderation'))
+ $this->videos_model->set_content_ingested($activation_code);
+ else
+ $this->videos_model->activate_video($activation_code);
+
+// log_message('info', "cis_completion $activation_code");
+ }
+
/**
* Increments (dis)likes count for video with the specified id and returns to
* the client as plain text the number if likes.
class Send_email_exception extends Exception
{
-
}
\ No newline at end of file
$lang['video_tags'] = 'Tags';
$lang['video_tags_hint'] = 'comma separated tags';
$lang['video_submit_upload'] = 'Upload';
+
$lang['video_msg_video_uploaded'] = 'Your video has been uploaded and is now being processed.';
+$lang['video_msg_no_video'] = 'This video does not exist.';
+$lang['video_msg_video_not_ready'] = 'This video is being processed and is not available yet.';
+$lang['video_msg_video_unactivated'] = 'This video requires moderation and must be approved by an administrator.';
/* End of file video_lang.php */
*
* @param int $category_id DB category ID; pass NULL for all
* categories
- * @param mixed $user an user_id (as int) or an username
+ * @param mixed $user an user_id (as int) or an username
* (as string); pass NULL for all users
- * @param int $offset
- * @param int $count
- * @param string $ordering control videos ording by these
+ * @param int $offset
+ * @param int $count number of videos to retrieve; if set to TRUE this
+ * method will retrieve the number of videos that satisfy condition
+ * @param string $ordering control videos ording by these
* possibilities:
* <ul>
* <li><strong>'hottest':</strong> newest most appreciated first. An
* <li><strong>'newest':</strong> newest first.</li>
* <li><strong>'alphabetically':</strong> sort alphabetically.</li>
* </ul>
- * @return array a list of videos, each one being an assoc array with:
+ * @param bool $unactivated whether to retrieve or not ingested unactivated
+ * videos; typically only administrators should see this kind of assets
+ * @return array a list of videos, each one being an assoc array with:
* <ul>
* <li>id, name, title, duration, thumbs_count, default_thumb, views => from DB</li>
* <li>shorted_title => ellipsized title</li>
* </ul>
*/
public function get_videos_summary($category_id, $user, $offset, $count,
- $ordering = 'hottest')
+ $ordering = 'hottest', $unactivated = FALSE)
{
$this->load->helper('text');
- // Ordering
- switch ($ordering)
+ $order_statement = "";
+ if ($count !== TRUE)
{
- case 'hottest':
- $order_statement = "ORDER BY date DESC, score DESC, RAND()";
- break;
- case 'newest':
- $order_statement = "ORDER BY date DESC";
- break;
- case 'alphabetically':
- $order_statement = "ORDER BY title";
- break;
-
- default:
- $order_statement = "";
+ // Ordering
+ switch ($ordering)
+ {
+ case 'hottest':
+ $order_statement = "ORDER BY date DESC, score DESC, RAND()";
+ break;
+ case 'newest':
+ $order_statement = "ORDER BY date DESC";
+ break;
+ case 'alphabetically':
+ $order_statement = "ORDER BY title";
+ break;
+
+ default:
+ $order_statement = "";
+ }
}
+ // Show unactivated videos.
+ $cond_unactivated = ($unactivated
+ ? '(a.activation_code IS NULL OR a.activation_code IS NOT NULL
+ AND a.content_ingested = 1)'
+ : 'a.activation_code IS NULL');
+
// Category filtering
if ($category_id === NULL)
$cond_category = "1";
$cond_user = "u.username = '$user'";
}
- $query = $this->db->query(
- "SELECT v.id, name, title, duration, user_id, u.username, views,
+ if ($count === TRUE)
+ $fields = "COUNT(*) count";
+ else
+ $fields = "v.id, name, title, duration, user_id, u.username, views,
thumbs_count, default_thumb,
- (views + likes - dislikes) AS score
- FROM `videos` v, `users` u
+ (views + likes - dislikes) AS score,
+ a.activation_code, a.content_ingested";
+
+ $query = $this->db->query(
+ "SELECT $fields
+ FROM `videos` v
+ LEFT JOIN `videos_unactivated` a ON (id = a.video_id),
+ `users` u
WHERE v.user_id = u.id AND $cond_category AND $cond_user
+ AND $cond_unactivated
$order_statement
LIMIT $offset, $count");
if ($query->num_rows() > 0)
+ {
+ if ($count === TRUE)
+ return $query->row()->count;
+
$videos = $query->result_array();
+ }
else
return array();
* NULL parameters count videos from all categories and / or all users.
*
* @param int $category_id
- * @param mixed $user an user_id (as int) or an username (as string)
- * @return int number of videos or FALSE if an error occured
+ * @param mixed $user an user_id (as int) or an username (as string)
+ * @return int number of videos or FALSE if an error occured
*/
- public function get_videos_count($category_id = NULL, $user = NULL)
+ public function get_videos_count($category_id = NULL, $user = NULL,
+ $unactivated = FALSE)
{
- if ($category_id === NULL)
- $cond_category = "1";
- else
- $cond_category = "category_id = $category_id";
-
- if ($user === NULL)
- $cond_user = "1";
- else
- {
- if (is_int($user))
- $cond_user = "v.user_id = $user";
- else if(is_string($user))
- $cond_user = "u.username = '$user'";
- }
-
- $query = $this->db->query(
- "SELECT COUNT(*) count
- FROM `videos` v, `users` u
- WHERE v.user_id = u.id AND $cond_category AND $cond_user");
-
- if ($query->num_rows() > 0)
- return $query->row()->count;
-
- // Error
- return FALSE;
+ return $this->get_videos_summary($category_id, $user, 0, TRUE, NULL,
+ $unactivated);
}
/**
$this->load->helper('video');
$this->load->helper('text');
- $query = $this->db->query("SELECT v.*, u.username
- FROM `videos` v, `users` u
- WHERE v.user_id = u.id AND v.id = $id");
+ $query = $this->db->query("SELECT v.*, u.username,
+ a.activation_code, a.content_ingested
+ FROM `videos` v
+ LEFT JOIN `videos_unactivated` a ON (v.id = a.video_id),
+ `users` u
+ WHERE v.user_id = u.id AND v.id = $id");
$video = array();
if ($query->num_rows() > 0)
}
else
{
- $video['err'] = 'INVALID_ID';
- return $video;
+ return FALSE;
}
// Convert JSON encoded string to arrays.
* column from `videos` table
* @param int $category_id
* @param int $user_id
+ * @param string $uploaded_file the raw video file uploaded by the user
* @return mixed returns an activation code on success or FALSE otherwise
*/
public function add_video($name, $title, $description, $tags, $duration,
- $formats, $category_id, $user_id)
+ $formats, $category_id, $user_id, $uploaded_file)
{
// Tags.
$json_tags = array();
$activation_code = Videos_model::gen_activation_code();
$query = $this->db->query("INSERT INTO `videos_unactivated`
- (video_id, activation_code)
- VALUES ($video_id, '$activation_code')");
+ (video_id, activation_code, uploaded_file)
+ VALUES ($video_id, '$activation_code', '$uploaded_file')");
return $activation_code;
}
+ public function set_content_ingested($activation_code)
+ {
+ return $this->db->query("UPDATE `videos_unactivated`
+ SET content_ingested = 1
+ WHERE activation_code = '$activation_code'");
+ }
+
+ /**
+ * Activates a video by deleting its entry from `videos_unactivated`.
+ *
+ * @param mixed $code_or_id use type string for activation_code or type
+ * int for video_id
+ * @return boolean TRUE on success, FALSE otherwise
+ */
+ public function activate_video($code_or_id)
+ {
+ if (is_string($code_or_id))
+ $query = $this->db->query("SELECT uploaded_file from `videos_unactivated`
+ WHERE activation_code = '$code_or_id'");
+ else if (is_int($code_or_id))
+ $query = $this->db->query("SELECT uploaded_file from `videos_unactivated`
+ WHERE video_id = '$code_or_id'");
+ else
+ return FALSE;
+
+ if ($query->num_rows() > 0)
+ $uploaded_file = $query->row()->uploaded_file;
+ else
+ return FALSE;
+
+ if (is_string($code_or_id))
+ $query = $this->db->query("DELETE FROM `videos_unactivated`
+ WHERE activation_code = '$code_or_id'");
+ else if (is_int($code_or_id))
+ $query = $this->db->query("DELETE FROM `videos_unactivated`
+ WHERE video_id = '$code_or_id'");
+ else
+ return FALSE;
+
+ if (!$query)
+ return $query;
+
+ return unlink("data/upload/$uploaded_file");
+ }
+
+ public function get_unactivated_videos()
+ {
+ $query = $this->db->query("SELECT a.video_id, v.name, a.content_ingested
+ FROM `videos_unactivated` a, `videos` v
+ WHERE a.video_id = v.id AND a.content_ingested = 1");
+
+ if ($query->num_rows() > 0)
+ return $query->result_array();
+ else
+ return FALSE;
+ }
+
/**
* Retrieves comments for a video.
*
output_file_name = os.path.join(self.dest_path, self.name) \
+ '_t' + ("%02d" % index) + '.jpg'
- if os.path.exists(output_file_name):
- raise cis_exceptions.FileAlreadyExistsException( \
- 'file "%s" already exists' % output_file_name)
+ #if os.path.exists(output_file_name):
+ #raise cis_exceptions.FileAlreadyExistsException( \
+ #'file "%s" already exists' % output_file_name)
return output_file_name
for f in files:
os.unlink(os.path.join(path, f))
- def notify_completion(self):
+ def notify_completion(self, code):
logger.log_msg('#%s: notifying web server about the job completion...'\
% self.job_id)
- f = urllib.urlopen(config.WS_COMPLETION)
+ if config.WS_COMPLETION[len(config.WS_COMPLETION) - 1] == '/':
+ url = config.WS_COMPLETION + code
+ else:
+ url = config.WS_COMPLETION + '/' + code
+
+ f = urllib.urlopen(url)
f.read()
def run(self):
# * NOTIFY WEB SERVER ABOUT CONTENT INGESTION COMPLETION
# TODO in the future web server should also be notified about errors
try:
- self.notify_completion()
+ self.notify_completion(job['code'])
except Exception as e:
logger.log_msg(
'#%s: error while notifying web server about the job completion: %s' \
# * JOB FINISHED
Server.queue.task_done()
Server.load -= job['weight']
+ logger.log_msg('#%s: finished' \
+ % job['code'], logger.LOG_LEVEL_INFO)
class Server:
BT_TRACKER = 'http://p2p-next-10.grid.pub.ro:6969/announce'
# Web server's URL for content ingestion completion. P2P-Tube uses
# http://<site>/video/cis_completion .
-WS_COMPLETION = 'http://p2p-next-03.grid.pub.ro:8081/cis_completion'
-#WS_COMPLETION = 'http://koala.cs.pub.ro/video/cis_completion'
+#WS_COMPLETION = 'http://p2p-next-03.grid.pub.ro:8081/cis_completion'
+WS_COMPLETION = 'http://p2p-next.cs.pub.ro/devel/video/cis_completion'
# === CIS PATHS ===
--- /dev/null
+#!/usr/bin/env python
+
+import sys
+
+from api import ffmpeg
+
+if len(sys.argv) != 4:
+ sys.stderr.write('usage: ' + sys.argv[0] + ' input_video_file dest_path thumbs_count\n')
+ exit(1)
+
+if __name__ == '__main__':
+ fn = sys.argv[1]
+ thumbs_count = int(sys.argv[3])
+
+ video_name = fn[0:fn.rindex('_')]
+ video_name = video_name[video_name.rindex('/')+1:]
+
+ fte = ffmpeg.FFmpegThumbExtractor(input_file = fn, name = video_name)
+ fte.dest_path = sys.argv[2]
+
+ fte.extract_summary_thumbs(thumbs_count)
\ No newline at end of file