user profile page; account activation backend (without UI)
[living-lab-site.git] / application / models / videos_model.php
1 <?php
2
3 /**
4  * Class Videos_model models videos information from the DB
5  *
6  * @category    Model
7  * @author              Călin-Andrei Burloiu
8  */
9 class Videos_model extends CI_Model {
10         public $db = NULL;
11         
12         public function __construct()
13         {
14                 parent::__construct();
15                 
16                 if ($this->db === NULL)
17                 {
18                         $this->load->library('singleton_db');
19                         $this->db = $this->singleton_db->connect();
20                 }
21         }
22         
23         /**
24          * Retrieves a set of videos information which can be used for displaying
25          * that videos as a list with few details.
26          *
27          * @param               int $category_id        DB category ID; pass NULL for all
28          * categories
29          * @param               mixed $user                     an user_id (as int) or an username 
30          * (as string); pass NULL for all users
31          * @param               int $offset
32          * @param               int $count
33          * @param               string $ordering        control videos ording by these
34          * possibilities:
35          * <ul>
36          *   <li><strong>'hottest':</strong> newest most appreciated first. An
37          *   appreciated video is one which has a bigger
38          *   score = views + likes - dislikes.</li>
39          *   <li><strong>'newest':</strong> newest first.</li>
40          *   <li><strong>'alphabetically':</strong> sort alphabetically.</li>
41          * </ul>
42          * @return              array   a list of videos, each one being an assoc array with:
43          * <ul>
44          *   <li>id, name, title, duration, thumbs_count, default_thumb, views => from DB</li>
45          *   <li>shorted_title => ellipsized title</li>
46          *   <li>video_url => P2P-Tube video URl</li>
47          *   <li>TODO: user_id, user_name</li>
48          *   <li>thumbs => thumbnail images' URLs</li>
49          * </ul>
50          */
51         public function get_videos_summary($category_id, $user, $offset, $count,
52                 $ordering = 'hottest')
53         {
54                 $this->load->helper('text');
55                 
56                 // Ordering
57                 switch ($ordering)
58                 {
59                 case 'hottest':
60                         $order_statement = "ORDER BY date DESC, score DESC, RAND()";
61                         break;
62                 case 'newest':
63                         $order_statement = "ORDER BY date DESC";
64                         break;
65                 case 'alphabetically':
66                         $order_statement = "ORDER BY title";
67                         break;
68                         
69                 default:
70                         $order_statement = "";
71                 }
72                 
73                 // Category filtering
74                 if ($category_id === NULL)
75                         $cond_category = "1";
76                 else
77                 {
78                         $category_id = intval($category_id);
79                         $cond_category = "category_id = $category_id";
80                 }
81                 
82                 // User filtering
83                 if ($user === NULL)
84                         $cond_user = "1";
85                 else
86                 {
87                         if (is_int($user))
88                                 $cond_user = "v.user_id = $user";
89                         else if (is_string($user))
90                                 $cond_user = "u.username = '$user'";
91                 }
92                 
93                 $query = $this->db->query(
94                         "SELECT v.id, name, title, duration, user_id, u.username, views,
95                                 thumbs_count, default_thumb,
96                                 (views + likes - dislikes) AS score
97                         FROM `videos` v, `users` u
98                         WHERE v.user_id = u.id AND $cond_category AND $cond_user
99                         $order_statement
100                         LIMIT $offset, $count"); 
101                 
102                 if ($query->num_rows() > 0)
103                         $videos = $query->result_array();
104                 else
105                         return array();
106                 
107                 foreach ($videos as & $video)
108                 {
109                         // P2P-Tube Video URL
110                         $video['video_url'] = site_url(sprintf("watch/%d/%s",
111                                 $video['id'], $video['name']));
112                         
113                         // Thumbnails
114                         $video['thumbs'] = $this->get_thumbs($video['name'], 
115                                 $video['thumbs_count']);
116                                 
117                         // Ellipsized title
118                         //$video['shorted_title'] = ellipsize($video['title'], 45, 0.75);
119                         $video['shorted_title'] = character_limiter($video['title'], 50);
120                 }
121                 
122                 return $videos;
123         }
124         
125         /**
126          * Returns the number of videos from database from a specific category or
127          * user.
128          * NULL parameters count videos from all categories and / or all users.
129          * 
130          * @param int $category_id
131          * @param mixed $user   an user_id (as int) or an username (as string)
132          * @return int  number of videos or NULL if an error occured
133          */
134         public function get_videos_count($category_id = NULL, $user = NULL)
135         {
136                 if ($category_id === NULL)
137                         $cond_category = "1";
138                 else
139                         $cond_category = "category_id = $category_id";
140                 
141                 if ($user === NULL)
142                         $cond_user = "1";
143                 else
144                 {
145                         if (is_int($user))
146                                 $cond_user = "v.user_id = $user";
147                         else if(is_string($user))
148                                 $cond_user = "u.username = '$user'";
149                 }
150                 
151                 $query = $this->db->query(
152                         "SELECT COUNT(*) count
153                         FROM `videos` v, `users` u
154                         WHERE v.user_id = u.id AND $cond_category AND $cond_user");
155                 
156                 if ($query->num_rows() > 0)
157                         return $query->row()->count;
158                 
159                 // Error
160                 return NULL;
161         }
162         
163         /**
164          * Retrieves information about a video.
165          *
166          * If $name does not match with the video's `name` from the DB an error is
167          * marked in the key 'err'. If it's NULL it is ignored.
168          *
169          * @access              public
170          * @param               string $id      video's `id` column from `videos` DB table
171          * @param               string $name    video's `name` column from `videos` DB
172          * table. NULL means there is no name provided.
173          * @return              array   an associative list with information about a video
174          * with the following keys:
175          * <ul>
176          *   <li>all columns form DB with some exceptions that are overwritten or new</li>
177          *   <li>content is moved in assets</li>
178          *   <li>assets => list of associative lists where each one represents a</li>
179          * video asset having keys: "src", "res", "par" and "ext". Value of key
180          * "src" is the video torrent formated as
181          * {name}_{format}.{video_ext}.{default_torrent_ext}</li>
182          *   <li>user_name => TODO: user name from `users` table</li>
183          *   <li>category_title => a human-friendly category name</li>
184          *   <li>tags => associative list of "tag => score"</li>
185          *   <li>date => date and time when the video was created</li>
186          *   <li>thumbs => thumbnail images' URLs</li>
187          * </ul>
188          */
189         public function get_video($id, $name = NULL)
190         {
191                 $this->load->helper('video');
192                 
193                 $query = $this->db->query('SELECT * 
194                                                                 FROM `videos` 
195                                                                 WHERE id = ?', $id);
196                 $video = array();
197                 
198                 if ($query->num_rows() > 0)
199                 {
200                         $video = $query->row_array();
201                         if ($name !== NULL && $video['name'] != $name)
202                                 $video['err'] = 'INVALID_NAME';
203                 }
204                 else
205                 {
206                         $video['err'] = 'INVALID_ID';
207                         return $video;
208                 }
209                 
210                 // Convert JSON encoded string to arrays.
211                 $video['assets'] = json_decode($video['formats'], TRUE);
212                 unset($video['formats']);
213                 $video['tags'] = json_decode($video['tags'], TRUE);
214                 asort($video['tags']);
215                 $video['tags'] = array_reverse($video['tags'], TRUE);
216                 
217                 // Sort assets by their megapixels number.
218                 function access_function($a) { return $a['res']; }
219                 function assets_cmp($a, $b) 
220                         { return megapixels_cmp($a, $b, "access_function"); }
221                 usort($video['assets'], "assets_cmp");
222                 
223                 // Torrents
224                 $video['url'] = array();
225                 foreach ($video['assets'] as & $asset)
226                 {
227                         $def = substr($asset['res'], strpos($asset['res'], 'x') + 1) . 'p';
228                         $asset['src'] = site_url('data/torrents/'. $video['name'] . '_'
229                                 . $def . '.'. $asset['ext']
230                                 . '.'. $this->config->item('default_torrent_ext'));
231                 }
232                 
233                 // Category title
234                 $categories = $this->config->item('categories');
235                 $category_name = $categories[ intval($video['category_id']) ];
236                 $video['category_title'] = $category_name ?
237                         $this->lang->line("ui_categ_$category_name") : $category_name;
238                 
239                 // Thumbnails
240                 $video['thumbs'] = $this->get_thumbs($video['name'], $video['thumbs_count']);
241                 
242                 // TODO: user information
243                 $video['user_name'] = 'TODO';
244                 
245                 return $video;
246         }
247         
248         /**
249          * Increment a video parameter from DB: `views`, `likes` or `dislikes`.
250          * 
251          * @param int $id       DB video id
252          * @param string $param DB parameter column name.
253          * @return void
254          */
255         public function inc_video_var($id, $var)
256         {
257                 // TODO error report if query returns FALSE
258                 $this->db->query('UPDATE `videos` '
259                                                 . 'SET `'. $var. '`=`'. $var. '`+1 '
260                                                 . 'WHERE id='. $id); 
261         }
262         
263         public function get_thumbs($name, $count)
264         {
265                 $thumbs = array();
266                 
267                 for ($i=0; $i < $count; $i++)
268                         $thumbs[] = site_url(sprintf("data/thumbs/%s_t%02d.jpg", $name, $i));
269                 
270                 return $thumbs;
271         }
272
273         /**
274          * Searches videos in DB based on a search query string and returns an
275          * associative array of results.
276          * If count is zero the function only return the number of results.
277          * @param string $search_query
278          * @param int $offset
279          * @param int $count
280          * @param int $category_id      if NULL, all categories are searched
281          * @return array        an associative array with the same keys as that from
282          * get_videos_summary's result, but with two additional keys: 
283          * description and date.
284          */
285         public function search_videos($search_query, $offset = 0, $count = 0, 
286                                                                         $category_id = NULL)
287         {
288                 $search_query = trim($search_query);
289                 $search_query = str_replace("'", " ", $search_query);
290                 
291                 // Search word fragments.
292                 // sfc = search fragment condition
293                 $sfc = "( ";
294                 // sfr = serach fragment relevation
295                 $sfr = "( ";
296                 $sep = ' +-*<>()~"';
297                 $fragm = strtok($search_query, $sep);
298                 while ($fragm !== FALSE)
299                 {
300                         $sfc .= "(title LIKE '%$fragm%'
301                                         OR description LIKE '%$fragm%'
302                                         OR tags LIKE '%$fragm%') OR ";
303                         
304                         // Frament relevations are half of boolean relevations such
305                         // that they will appear at the end of the results.
306                         $sfr .= "0.25 * (title LIKE '%$fragm%')
307                                         + 0.1 * (description LIKE '%$fragm%')
308                                         + 0.15 * (tags LIKE '%$fragm%') + ";
309                         
310                         $fragm = strtok($sep);
311                 }
312                 $sfc = substr($sfc, 0, -4) . " )";
313                 $sfr = substr($sfr, 0, -3) . " )";
314                 
315                 if (! $this->is_advanced_search_query($search_query))
316                 {
317                         $search_cond = "MATCH (title, description, tags)
318                                         AGAINST ('$search_query') OR $sfc";
319                         $relevance = "( MATCH (title, description, tags)
320                                         AGAINST ('$search_query') + $sfr ) AS relevance";
321                 }
322                 // boolean mode
323                 else
324                 {
325                         $against = "AGAINST ('$search_query' IN BOOLEAN MODE)";
326                         $search_cond = "( MATCH (title, description, tags)
327                                         $against) OR $sfc";
328                         $relevance = "( 0.5 * (MATCH(title) $against)
329                                         + 0.3 * (MATCH(tags) $against)
330                                         + 0.2 * (MATCH(description) $against)
331                                         + $sfr) AS relevance";
332                 }
333                 
334                 if ($count === 0)
335                 {
336                         $selected_columns = "COUNT(*) count";
337                         $order = "";
338                         $limit = "";
339                 }
340                 else
341                 {
342                         // TODO select data, description if details are needed
343                         $selected_columns = "id, name, title, duration, user_id, views,
344                                         thumbs_count, default_thumb,
345                                         (views + likes - dislikes) AS score, 
346                                         $relevance";
347                         $order = "ORDER BY relevance DESC, score DESC";
348                         $limit = "LIMIT $offset, $count";
349                 }
350                 
351                 if ($category_id !== NULL)
352                         $category_cond = "category_id = '$category_id' AND ";
353                 else
354                         $category_cond = "";
355
356                 $str_query = "SELECT $selected_columns
357                         FROM `videos`
358                         WHERE  $category_cond ( $search_cond )
359                         $order
360                         $limit";
361 //              echo "<p>$str_query</p>";
362                 $query = $this->db->query($str_query);
363                 
364                 if ($query->num_rows() > 0)
365                 {
366                         if ($count === 0)
367                                 return $query->row()->count;
368                         else
369                                 $videos = $query->result_array();
370                 }
371                 else
372                         return NULL;
373                 
374                 $this->load->helper('text');
375                 
376                 foreach ($videos as & $video)
377                 {
378                         // P2P-Tube Video URL
379                         $video['video_url'] = site_url(sprintf("watch/%d/%s",
380                                 $video['id'], $video['name']));
381                         
382                         // Thumbnails
383                         $video['thumbs'] = $this->get_thumbs($video['name'], 
384                                 $video['thumbs_count']);
385                                 
386                         // Ellipsized title
387                         //$video['shorted_title'] = ellipsize($video['title'], 45, 0.75);
388                         $video['shorted_title'] = character_limiter($video['title'], 50);
389                         
390                         // TODO: user information
391                         $video['user_name'] = 'TODO';
392                 }
393                 
394                 return $videos;
395         }
396         
397         public function decode_search_query($search_query)
398         {
399                 $search_query = urldecode($search_query);
400                 
401                 $search_query = str_replace('_AST_', '*', $search_query);
402                 $search_query = str_replace('_AND_', '+', $search_query);
403                 $search_query = str_replace('_GT_', '>', $search_query);
404                 $search_query = str_replace('_LT_', '<', $search_query);
405                 $search_query = str_replace('_PO_', '(', $search_query);
406                 $search_query = str_replace('_PC_', ')', $search_query);
407                 $search_query = str_replace('_LOW_', '~', $search_query);
408                 $search_query = str_replace('_QUO_', '"', $search_query);
409                 
410                 return $search_query;
411         }
412         
413         public function encode_search_query($search_query)
414         {
415                 $search_query = str_replace('*', '_AST_', $search_query);
416                 $search_query = str_replace('+', '_AND_', $search_query);
417                 $search_query = str_replace('>', '_GT_', $search_query);
418                 $search_query = str_replace('<', '_LT_', $search_query);
419                 $search_query = str_replace('(', '_PO_', $search_query);
420                 $search_query = str_replace(')', '_PC_', $search_query);
421                 $search_query = str_replace('~', '_LOW_', $search_query);
422                 $search_query = str_replace('"', '_QUO_', $search_query);
423                 
424                 $search_query = urlencode($search_query);
425         
426                 return $search_query;
427         }
428         
429         /**
430          * Return TRUE if it contains any special caracter from an advanced search
431          * query.
432          * @param string $search_query
433          * @return boolean
434          */
435         public function is_advanced_search_query($search_query)
436         {
437                 return (preg_match('/\*|\+|\-|>|\<|\(|\)|~|"/', $search_query) == 0
438                         ? FALSE : TRUE);
439         }
440 }
441
442 /* End of file videos_model.php */
443 /* Location: ./application/models/videos_model.php */