1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
|
<?php
/**
* @file
* Enable multiple file download in video module.
*
* @author Fabio Varesano <fvaresano at yahoo dot it>
* porting to Drupal 6
* @author Heshan Wanigasooriya <heshan at heidisoft.com><heshanmw@gmail.com>
* @todo
*/
/**
* Implementation of hook_help().
*/
function video_multidownload_help($path, $arg) {
switch ($path) {
case 'admin/modules#description':
return t('Enable multiple file download in video module.');
}
}
/**
* Implementation of hook_menu().
*
* @param $may_cache
* boolean indicating whether cacheable menu items should be returned
*
* @return
* array of menu information
*/
function video_multidownload_menu() {
$items = array();
/* TODO
Non menu code that was placed in hook_menu under the '!$may_cache' block
so that it could be run during initialization, should now be moved to hook_init.
Previously we called hook_init twice, once early in the bootstrap process, second
just after the bootstrap has finished. The first instance is now called boot
instead of init.
In Drupal 6, there are now two hooks that can be used by modules to execute code
at the beginning of a page request. hook_boot() replaces hook_boot() in Drupal 5
and runs on each page request, even for cached pages. hook_boot() now only runs
for non-cached pages and thus can be used for code that was previously placed in
hook_menu() with $may_cache = FALSE:
Dynamic menu items under a '!$may_cache' block can often be simplified
to remove references to arg(n) and use of '%<function-name>' to check
conditions. See http://drupal.org/node/103114.
The title and description arguments should not have strings wrapped in t(),
because translation of these happen in a later stage in the menu system.
*/
$may_cache=true;
if ($may_cache) {
$items['admin/content/video/multidownload'] = array(
'title' => 'Multidownload',
'description' => 'Administer video_multidownload module settings',
'page callback' => 'drupal_get_form',
'page arguments' => array('video_multidownload_settings_form'),
'access arguments' => array('administer site configuration'),
'type' => MENU_NORMAL_ITEM,
);
}
else {
if (arg(0) == 'node' && is_numeric(arg(1))) {
if ($node = node_load(arg(1)) and $node->type == 'video') {
if(isset($node->disable_multidownload) &&
!$node->disable_multidownload &&
($node->use_play_folder || $node->download_folder!='')
) {
$items['node/'.'%'.'/multidownload'] = array(
'title' => 'download other formats',
'page callback' => 'video_multidownload_download',
'access arguments' => array('access video'),
'weight' => 7,
'type' => MENU_LOCAL_TASK);
}
}
}
}
return $items;
}
/**
* Implementation of hook_perm().
*/
function video_multidownload_perm() {
return array('create multi-file downloads');
}
/**
* Implementation of hook_settings()
*/
function video_multidownload_settings_form() {
$form = array();
$options = array(1 => 'Yes', 0 => 'No');
$form['multifile'] = array('#type' => 'fieldset', '#title' => t('Multi-file download options'), '#description' => t('Allows a list of files to be shown on the download page. The list is usually gotten from a specified folder. This ability is useful for providing different sizes and video types for download.'));
$form['multifile']['video_multidownload'] = array(
'#type' => 'radios',
'#title' => t('Allow Multi-file Downloads'),
'#options' => $options,
'#default_value' => variable_get('video_multidownload', 0),
'#description' => t('This feature can be disabled separately for each node. If turned on make sure you set the permissions so users can use this feature.') . ' ' . l(t('access control'), 'admin/access'));
$form['multifile']['video_download_ext'] = array(
'#type' => 'textfield',
'#title' => t('File extensions to show'),
'#default_value' => variable_get('video_download_ext', 'mov,wmv,rm,flv,avi,divx,mpg,mpeg,mp4,zip'),
'#description' => t('The extensions of files to list from the multi-file download folder on the download page. Extensions should be comma seperated with no spaces, for example (mov,wmv,rm).'));
return system_settings_form($form);
}
/**
* Implementation of hook_form_alter()
* We use this to add multidownload fields to the video creation form.
*/
function video_multidownload_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'video_node_form' && isset($form['video']) && user_access('create multi-file downloads')) {
$node = $form['#node'];
$form['multi-file'] = array(
'#type' => 'fieldset',
'#title' => t('Multiple files in download tab'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => -18,
'#description' => t('These options allow you to have multiple files shown on the download page. This is useful for allowing users to download different file sizes and video formats. ') . l(t('More information.'), 'video/help', array('fragment' => 'multi-download'))
);
$form['multi-file']['disable_multidownload'] = array(
'#type' => 'checkbox',
'#title' => t('Disable multi-file downloads'),
'#default_value' => isset($node->disable_multidownload) ? $node->disable_multidownload : 1,
'#description' => t('Disables multi-file downloads for this video only.')
);
$form['multi-file']['download_folder'] = array(
'#type' => 'textfield',
'#title' => t('Multi-file download folder'),
'#default_value' => $node->download_folder,
'#maxlength' => 250,
'#description' => t('Enter the folder containing your videos. It must be relative from the drupal directory. If the absolute path is "C:\inetpub\drupal\videos\projectfolder\" or "/usr/htdocs/drupal/videos/projectfolder/" then enter something like "videos/projectfolder/".'));
$form['multi-file']['use_play_folder'] = array(
'#type' => 'checkbox',
'#title' => t('Show files in "play" folder'),
'#default_value' => $node->use_play_folder,
'#description' => t('Display videos in the same directory as the "play" video. If folder above is entered this will be in addition.'));
}
}
/**
* Implementation of hook_nodeapi()
*/
function video_multidownload_nodeapi(&$node, $op, $teaser) {
if($node->type == 'video') {
switch ($op) {
case 'validate':
//Validate multi-file download values.
if (user_access('create multi-file downloads')) { //Make sure the user has permission.
//Checks to make sure either multi-downloads are disabled, or a valid folder is given, or use_play_folder is checked.
if ($node->disable_multidownload == 0 and !is_dir(getcwd() . '/' . $node->download_folder) and $node->use_play_folder == 0) {
form_set_error('disable_multidownload', t("Please disable multi-file downloads if you are not going to use the feature."));
form_set_error('download_folder', t('Download directory does not exist. Make sure it has a trailing forward slash "/".'));
}
}
break;
}
}
}
function video_multidownload_download() {
if ($node = node_load(arg(1))) {
if (variable_get("video_multidownload", 0) == 0 or $node->disable_multidownload == 1) {
}
else if (arg(3) != '') { //If we are passed an encoded URL redirect to the downloader.
_video_multidownload_download_goto(arg(3), $node->vid, TRUE);
}
else { //Multiple file downloads is turned on.
$download_error = FALSE; //Initialize and clear the error flag.
$node->file_array = array(); //Initialize the final file array.
global $base_url;
$full_download_folder = getcwd() . '/' . $node->download_folder; //Get absolute path to folder.
//If the download folder is set and valid scan it for files.
if ($node->download_folder != '' and file_exists($full_download_folder)) {
$scan_download_folder = _video_multidownload_scandir($full_download_folder); //Get array of file names in the directory.
$scan_download_folder['local_dir'] = $full_download_folder; //For getting filesize.
$scan_download_folder['dir_stub'] = $node->download_folder; //To put in the URL.
$folder_array[] = $scan_download_folder;
}
//If option is set to use "play" folder and it exists, scan it for files.
$play_dir_stub = str_replace(basename($node->vidfile), "", $node->vidfile); //Remove the filename from the play file to get directory.
$play_dir = getcwd() . '/' . $play_dir_stub; //Get the local directory path where the file is kept.
if ($node->use_play_folder == 1 and file_exists($play_dir) and $play_dir_stub != '/') { //Make sure play stub won't allow scanning base drupal directory.
$scan_play_folder = _video_multidownload_scandir($play_dir);
$scan_play_folder['local_dir'] = $play_dir; //For getting filesize.
$scan_play_folder['dir_stub'] = $play_dir_stub; //To put in the URL.
$folder_array[] = $scan_play_folder;
}
if (count($folder_array) > 0) { //Make sure we have a folder to scan.
foreach ($folder_array as $dir_scan) { //Scan through one or both folders results.
foreach ($dir_scan as $file) { //Go through each file in the directory.
if (is_file($dir_scan['local_dir'] . "/" . $file)) { //Make sure it's a valid file.
//Checks the new file with the files already in the array to eliminate dupes.
$match = false;
foreach ($node->file_array as $file_array_file) {
if ($file_array_file['file'] == $file) { //If the file is already in the array.
$match = TRUE;
}
} //If we get here with $match still set FALSE we don't have a dupe.
$file_ext = substr($file, strrpos($file, '.') + 1); //Get the file extension.
$ext_array = explode(',', variable_get('video_download_ext', 'mov,wmv,avi'));
if (!$match and in_array($file_ext, $ext_array)) { //Only add file if it's not already in the array and it's extension shouldn't be hidden.
$file_array_size[] = filesize($dir_scan['local_dir'] . $file); //Create an array of the file sizes for sorting.
global $base_url;
$file_url = $base_url . '/' . $dir_scan['dir_stub'] . $file; //Generate absolute URL to video.
$file_url = str_replace(' ', '%20', $file_url); //Replace any spaces in filename.
$encoded_url = base64_encode($file_url); //Encode URL to base64 MIME value so it can be passed in URL.
$encoded_url = str_replace('/', '-', $encoded_url); //Replace "/" with "-" so it doesn't mess up the URL.
$node->file_array[] = array( 'file' => $file
, 'type' => $file_ext
, 'size' => filesize($dir_scan['local_dir'] . $file)
, 'encoded_url' => $encoded_url
);
}
} //Close the valid file check.
} //Close the directory scan.
} //Close scan location array.
if (count($node->file_array) > 0) { //Make sure atleast 1 file was found.
array_multisort($file_array_size, SORT_ASC, $node->file_array); //Sort based of file size.
}
else { //Else if no files were found in the directory.
$download_error = TRUE;
}
}
else { //Else if we have no valid folders to scan.
$download_error = TRUE;
}
//If there was no error send the files array to the theme function for display.
if($download_error == FALSE) {
print theme('video_multidownload_download', $node); //Print to the screen from the theme_video_download function.
}
else { //Else if there is an error download the play file.
_video_download_goto($node->vidfile, $node->vid);
}
} //Close multi-file downloads is turned on.
}
}
/**
* Outputs the HTML for the download page when multi-file download are turned on.
*
* @param $node
* object with node information
*
* @return
* string of content to display
*/
function theme_video_multidownload_download($node) {
$output = '';
//Replace some common file types with full name and links.
$find = array('mov', 'wmv', 'rm', 'avi', 'zip', 'divx', 'flv', 'ogg');
$replace = array('<a href="http://www.apple.com/quicktime" title="'. t('QuickTime Homepage') . '">' . t('Quicktime') . '</a>'
, '<a href="http://www.microsoft.com/windowsmedia" title="'. t('Windows Media Homepage') . '">' . t('Windows Media') . '</a>'
, '<a href="http://www.real.com" title="'. t('Real Media Homepage') . '">' . t('Real Media') . '</a>'
, '<a href="http://en.wikipedia.org/wiki/AVI" title="'. t('AVI Information at wikipedia.org') . '">' . t('AVI') . '</a>'
, '<a href="http://en.wikipedia.org/wiki/ZIP_file_format" title="'. t('ZIP Information at wikipedia.org') . '">' . t('ZIP') . '</a>'
, '<a href="http://www.divx.com" title="'. t('Divx Homepage') . '">' . t('DIVX') . '</a>'
, '<a href="http://www.macromedia.com/go/getflashplayer" title="'. t('Macromedia Flash Homepage') . '">' .t('Flash FLV') . '</a>'
, '<a href="http://www.theora.org/theorafaq.html" title="'. t('Ogg Theora FAQ at theora.org') . '">'.t('Ogg Theora FAQ') .'</a>, <a href="http://en.wikipedia.org/wiki/Wikipedia:Media_help_(Ogg)" title="'. t('Ogg Theora media help at Wikipedia') . '">' . t('Ogg Theora help') . '</a>'
);
$output .= '<br /><div class="videodownload">'; //Enclose all HTML in "videodownload" class.
foreach($node->file_array as $file) { //Goes through the array of video files and gets them ready for display.
$file_type = str_replace($find, $replace, $file['type']); //Match and replace common file types.
$link = l($file['file'], "node/$node->nid/multidownload/" . $file['encoded_url']); //Create link to download file.
$file_array_table[] = array($link, format_size($file['size']), $file_type); //Create table row.
}
$headers = array(t('File Link'), t('File Size'), t('File Type'));
$output .= theme_table($headers, $file_array_table); //Create the table of files.
$output .= '</div>'; //Close the "videodownload" class.
//Adds a breadcrumb back to view on the download page. This may not be needed but some better breadcrumbs are.
$breadcrumb = drupal_get_breadcrumb();
$breadcrumb[] = l(t('View'), "node/$node->nid");
drupal_set_breadcrumb($breadcrumb);
drupal_set_title(t('Downloading').' '. theme('placeholder', $node->title));
return theme("page", $output);
}
/**
* Scans a directory and returns an array of all the filenames in the directory.
* This function is only necessary to maintain PHP 4 support.
*
* @param $dir
* The directory. Can be an absolute path or relative from the current working directory.
*
* @return
* array of filenames.
*/
function _video_multidownload_scandir($dir) {
//Try a few different ways to open the directory.
if (is_dir($dir)) {
$dir_open = opendir($dir);
}
else if (is_dir($new_dir = getcwd() . $dir)) {
$dir_open = opendir($new_dir);
}
else if (is_dir($new_dir = getcwd() . '/' . $dir)) {
$dir_open = opendir($new_dir);
}
else { //If directory does not exist.
return FALSE;
}
if (!$dir_open) { //If opendir returned false then return false.
return FALSE;
}
//If it makes it this far $dir_open should be valid.
while (($dir_content = readdir($dir_open)) !== FALSE) {
$files[] = $dir_content;
}
return $files;
}
/**
* Forward user directly to the file for downloading
*
* @param $input_url
* string should be either a base64 encoded absolute URL, relative URL, or absolute URL.
*
* @param $vid
* integer node version ID of the node to have it's download counter updated.
*
* @param $base64_encoded
* boolean value determines whether the $input is base64 encoded.
*
* @return
* Nothing
*/
function _video_multidownload_download_goto($input_url, $vid, $base64_encoded) {
if (user_access('download video') && $base64_encoded) {
$encoded_url = str_replace('-', '/', $input_url); //Replace "-" to "/" for MIME base64.
$location = base64_decode($encoded_url);
if (variable_get('video_downloadcounter', 1)) {
db_query("UPDATE {video} SET download_counter = download_counter + 1 where vid = '%d'", $vid); //Increment download counter.
}
header("Location: $location"); //Redirect to the video files URL.
}
else { //If the user does not have access to download videos.
drupal_set_message(t('You do not have permission to download videos.'), 'error');
$node = node_load(array('vid' => $vid)); //Load a node with the $vid so we can get the nid.
drupal_goto("node/$node->nid"); //Use the nid we just loaded to go back to the node page.
}
}
/**
* Implementation of hook_theme().
*/
function video_multidownload_theme() {
return array(
'video_multidownload_download' => array(
'arguments' => array('node' => NULL),
),
);
}
|