upload facility now works in single CIS mode; some simple command-line video moderati...
authorCălin-Andrei Burloiu <calin.burloiu@gmail.com>
Thu, 16 Feb 2012 17:49:51 +0000 (19:49 +0200)
committerCălin-Andrei Burloiu <calin.burloiu@gmail.com>
Thu, 16 Feb 2012 17:49:51 +0000 (19:49 +0200)
12 files changed:
application/config/p2p-tube.php
application/controllers/admin_cli.php
application/controllers/catalog.php
application/controllers/user.php
application/controllers/video.php
application/exceptions/Send_email_exception.php
application/language/english/video_lang.php
application/models/videos_model.php
cis/api/base.py
cis/cis.py
cis/config.py
cis/extract_summary_thumbs.py [new file with mode: 0755]

index 20ba114..96491f5 100644 (file)
@@ -90,7 +90,12 @@ $config['default_torrent_ext'] = 'tstream';
 | 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'
+);
 
 /*
 |--------------------------------------------------------------------------
@@ -156,3 +161,14 @@ $config['available_languages_list'] = array(
 |
 */
 $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
index 604c07f..f0ef13b 100644 (file)
@@ -19,7 +19,8 @@ class Admin_cli extends CI_Controller {
        }
        
        public function index()
-       {               
+       {
+               echo "P2P-Tube".PHP_EOL;
        }
        
        /**
@@ -39,6 +40,38 @@ class Admin_cli extends CI_Controller {
                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 */
index 31bdc51..d9aa933 100644 (file)
@@ -17,6 +17,18 @@ class Catalog extends CI_Controller {
 
        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
                // **
@@ -26,7 +38,8 @@ class Catalog extends CI_Controller {
                {
                        // 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;
@@ -78,6 +91,17 @@ class Catalog extends CI_Controller {
 
        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
                // **
@@ -88,7 +112,8 @@ class Catalog extends CI_Controller {
                $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;
 
@@ -98,7 +123,7 @@ class Catalog extends CI_Controller {
                                "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();
index fad3ddf..169d5d2 100644 (file)
@@ -26,7 +26,7 @@ class User extends CI_Controller {
        
        public function test($user_id = 1)
        {
-               echo extension_loaded('gd') ? 'gd' : 'nu';
+//             echo extension_loaded('gd') ? 'gd' : 'nu';
        }
        
        // DEBUG
@@ -179,6 +179,7 @@ class User extends CI_Controller {
                $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)));
@@ -348,6 +349,17 @@ class User extends CI_Controller {
        {
                // 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');
@@ -370,15 +382,16 @@ class User extends CI_Controller {
                // 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();
@@ -687,6 +700,7 @@ class User extends CI_Controller {
                        '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);
index 6a5c19e..283851d 100644 (file)
@@ -10,6 +10,7 @@
 class Video extends CI_Controller {
 
        protected $uploaded_file;
+       protected $av_info;
        
        public function __construct()
        {
@@ -23,12 +24,14 @@ class Video extends CI_Controller {
                //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);
        }
        
        /**
@@ -44,17 +47,67 @@ class Video extends CI_Controller {
                // **
                // ** 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'] . ' &ndash; '
@@ -161,7 +214,8 @@ class Video extends CI_Controller {
                                        $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).
@@ -176,6 +230,18 @@ class Video extends CI_Controller {
                }
        }
        
+       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.
index 17b3009..33856cd 100644 (file)
@@ -2,5 +2,4 @@
 
 class Send_email_exception extends Exception
 {
-       
 }
\ No newline at end of file
index 92b93df..77c0225 100644 (file)
@@ -23,7 +23,11 @@ $lang['video_category'] = 'Category';
 $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 */
index f927561..87b0d3b 100644 (file)
@@ -26,11 +26,12 @@ class Videos_model extends CI_Model {
         *
         * @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
@@ -39,7 +40,9 @@ class Videos_model extends CI_Model {
         *   <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>
@@ -49,27 +52,37 @@ class Videos_model extends CI_Model {
         * </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";
@@ -90,17 +103,31 @@ class Videos_model extends CI_Model {
                                $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();
                
@@ -128,36 +155,14 @@ class Videos_model extends CI_Model {
         * 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);
        }
        
        /**
@@ -191,9 +196,12 @@ class Videos_model extends CI_Model {
                $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)
@@ -204,8 +212,7 @@ class Videos_model extends CI_Model {
                }
                else
                {
-                       $video['err'] = 'INVALID_ID';
-                       return $video;
+                       return FALSE;
                }
                
                // Convert JSON encoded string to arrays.
@@ -260,10 +267,11 @@ class Videos_model extends CI_Model {
         * 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();
@@ -299,12 +307,69 @@ class Videos_model extends CI_Model {
                $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.
         * 
index 11c922a..9e4ea5e 100644 (file)
@@ -253,9 +253,9 @@ class BaseThumbExtractor:
         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
 
index 3ae47cf..d096a9e 100755 (executable)
@@ -151,11 +151,16 @@ class CIWorker(threading.Thread):
         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):
@@ -232,7 +237,7 @@ class CIWorker(threading.Thread):
             # * 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' \
@@ -246,6 +251,8 @@ class CIWorker(threading.Thread):
             # * JOB FINISHED
             Server.queue.task_done()
             Server.load -= job['weight']
+            logger.log_msg('#%s: finished' \
+                        % job['code'], logger.LOG_LEVEL_INFO)                     
 
 
 class Server:
index ec35ca0..adb5ed0 100644 (file)
@@ -33,8 +33,8 @@ WS_THUMBS_PATH = 'devel/data/thumbs'
 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 ===
diff --git a/cis/extract_summary_thumbs.py b/cis/extract_summary_thumbs.py
new file mode 100755 (executable)
index 0000000..f0a569c
--- /dev/null
@@ -0,0 +1,21 @@
+#!/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