View difference between Paste ID: QV2eZzrP and acY61cn5
SHOW: | | - or go back to the newest paste.
1
#!/usr/bin/env perl
2
#
3
# MPlayer wrapper to select and play random video file(s) 
4
# 
5
6
# TODO: incorporate history-cleanse ?
7
8
use strict;
9
use warnings;
10
11
use File::Find;
12
use File::stat;
13
14
#-------------------------------------------------------------------------------------------------------#
15
## BEGIN CONFIGURABLE OPTIONS : 
16
#-------------------------------------------------------------------------------------------------------#
17
my $version="3.3";		# Current Version.
18
19
# Configure your video 'collection' locations here. This is probably the only thing you need to change. 
20
our @Collections=(
21
	"/Volumes/ENCRYPTED",
22
	#"/mnt/pr0n",
23
);
24
25
# Specify Alternate image viewer, it will take one argument - related filename(s) 
26
our $image_viewer="";
27
28
# Otherwise the defaults:
29
our $def_image_viewer_osx="open";
30
our $def_image_viewer_linux="eog";
31
32
# Autoplay the files, or give a y/n prompt? 1 = auto, 0 = prompt
33
our $autoplay="0";
34
35
# Path to mplayer, and any default options you want to pass along
36
our $mplayer="mplayer";
37
our $mplayer_opts="";
38
#our $mplayer_opts="-display :0";
39
40
# Supported file types mplayer can handle - if it's not in this list, it won't be played, even though mplayer probably supports it
41
our @Supported_videos=("mpg","mpeg","avi","wmv","asf","mov","mp4","mkv","m4v","rmvb","flv");
42
43
# Cover images - some filetypes that may exist in your collection that mplayer should ignore / will not play
44
our @Supported_images=(".jpg",".png",".gif",".bmp");
45-
# Volume Suppression. use Negative integer to decrease mplayer's volume.
45+
46-
our $volume_suppression="-25"; 
46+
# Default audio volume; be careful :p
47-
our $volume_mods="";
47+
our $volume_level="-volume 05";
48-
#our $volume_mods="-af volume=$volume_suppression:0";
48+
49
# Set some default behavior switches; alter for desired behavior
50
our $file_info_banner="1"; 	# Display info about the selected file ?
51-
my $version="3.1";		# Current Version.
51+
52
our $verbose="0";		# Verbose by default ?
53
our $very_verbose="0";		# Even more info ?
54
our $fullscreen="0";		# Fullscreen mplayer ?
55
our $sort_order="0";		# Sort by mtime (1), vs alphabetical (0)?
56
our $cover="0";			# Open related images ?
57
our $vol_muted="0";		# Start muted (volume 0) ?		
58
our $nosound="0";		# Nosound (unrecoverable stream) ?		
59
our $search="0";		# Jump to search prompt ?
60
our $test_exists="0";		# Simple test for existance of file
61
our $listing="0";		# List files by default ?
62
our $list_everything="0";	# List videos, images, and unrelated files ?
63
our $list_full_paths="0";	# Display full paths for files ?
64
our $mplayer_output="0";	# Attach to mplayer output ?
65
our $search_char_min="2";	# Minimum search characters ?
66
our $specific_result="0";	# Selected file number to play ?
67
our $debug = "0";		# Debug info by default ?
68
our $pretend="0";		# No Exec ?
69
our $auto_sort="1";		# 1 implies -o with -t
70
our $fork_bomb_protect="1";	# Prevent fork bombing the system with mplayer calls
71
our $do_exec="0";		# Probably never need to change this.
72
our $search_char="0";		# Probably never need to change this.
73
our $custom_dir="0";		# Probably never need to change this.
74
our $total_videos="0";		# Probably never need to change this.
75
our $total_images="0";		# Probably never need to change this.
76
our $total_rejected="0";	# Probably never need to change this.
77
our $search_term="";		# Probably never need to change this.
78
our $search_input;		# Probably never need to change this.
79
our $search_request;		# Probably never need to change this.
80
our $limit_recent="0";		# Probably never need to change this.
81
our $limit_time="0";		# Probably never need to change this.
82
our $old_or_new;		# Probably never need to change this.
83
our $repeat="0";		# Repeat / Range
84
our $default_repeat="5";	# Default repeat range
85
our $repeat_range="0";
86
our $range_request;
87
our $repetition;
88
our $mplayer_max="10";		# Maximum amount of mplayer windows before limiting spawn
89
our $video_width="0";
90
our $video_height="0";
91
our $target_x="0";
92
our $target_y="0";
93
our $screen_res_x="0";
94
our $screen_res_y="0";
95
our $resolution="";
96
our $mplayer_opts_geo="";
97
our $kill_players="0";
98
our $kill_signal="hup";
99
our $user_ok="";
100
our $null_term="0";
101
our $exclude_term="";
102
our $timejump="0";		# start player(s) playing +x seconds into video file
103
our $jumptime="30";		# Default jumptime
104
105
# Define highlight color codes
106
my $color_bold = "\033[0;1m";
107
my $color_white = "\033[0m";
108
my $color_black = "\033[1;30m";
109
my $color_red = "\033[1;31m";
110
my $color_green = "\033[1;32m";
111
my $color_blue = "\033[1;34m";
112
my $color_yellow = "\033[1;33m";
113
my $color_cyan = "\033[1;36m";
114
my $color_purple = "\033[1;35m";
115
my $color_dark_blue = "\033[0;34m";
116
my $color_dark_red = "\033[0;31m";
117
my $color_dark_green = "\033[0;32m";
118
my $color_dark_yellow = "\033[0;33m";
119
my $color_dark_cyan = "\033[0;36m";
120
my $color_dark_purple = "\033[0;35m";
121
my $color_dark_black = "\033[0;30m"; 
122
123
# Set which color to actually use for various 'tags'
124
our $colortag_name = $color_red;
125
our $colortag_search = $color_cyan;
126
our $colortag_number = $color_dark_yellow;
127
our $colortag_mtime = $color_dark_blue;
128
our $colortag_default = $color_white;
129
our $colortag_online = $color_bold;
130
our $colortag_offline = $color_bold;
131
our $colortag_warning = $color_bold;
132
our $colortag_error = $color_bold;
133
our $colortag_pretend = $color_dark_purple;
134
our $colortag_exec = $color_bold;
135
our $colortag_vidlabel = $color_bold;
136
our $colortag_abort = $color_yellow;
137
our $colortag_category = $color_blue;
138
our $colortag_imgname = $color_purple;
139
our $colortag_selection = $color_dark_red;
140
141
# Text used for the static variable tags;
142
our $online_label = "AVAILABLE";
143
our $offline_label = "UNAVAILABLE";
144
our $warning_label = "WARNING";
145
our $error_label = "ERROR";
146
our $pretend_label = "PRETEND";
147
our $exists_label = "FOUND";
148
our $exec_label = "EXEC";
149
our $abort_label = "ABORT";
150
our $yes_label = "y";
151
our $no_label = "n";
152
our $category_label = "CATEGORY";
153
our $vid_label = "VID FILE";
154
155
# Initial self awareness for this script
156
my @ScriptPath=split(/\//,$0);
157
our $script_name=$ScriptPath[$#ScriptPath];
158
159
# Required commands used by this script
160
our @Required=("$mplayer","grep");
161
162
#-------------------------------------------------------------------------------------------------------#
163
&Init; ## END CONFIGURABLE OPTIONS : YOU SHOULDN'T NEED TO EDIT ANYTHING BELOW THIS POINT 
164
#-------------------------------------------------------------------------------------------------------#
165
166
sub GlobalVars {
167
168
	if ($debug == 1) {
169
		print qq| <Enter Sub> GlobalVars\n|;
170
	}
171
172
	our $mplayer = $main::mplayer;
173-
	our $volume_suppression = $main::volume_suppression;
173+
174-
	our $volume_mods = $main::volume_mods;
174+
	our $volume_level = $main::volume_level;
175
	our $image_viewer = $main::image_viewer;
176
	our $version = $main::version;
177
	our @Collections = @main::Collections;
178
	our @Videos = @main::Videos;
179
	our @Images = @main::Images;
180
	our @Rejected = @main::Rejected;
181
	our @Supported_videos = @main::Supported_videos;
182
	our @Supported_images = @main::Supported_images;
183
	our @AlreadyPicked=@main::AlreadyPicked;
184
}
185
186
sub Init {
187
188
	# Set & Get some initial requirements
189
	&GlobalVars;
190
191
	print qq|\n|;
192
193
	if (@ARGV) {
194
		&CheckArgs;
195
	}
196
	
197
	if ($debug == 1) {
198
		print qq| <Enter Sub> Init\n|;
199
	}
200
201
	# swap out colors
202
	if ($use_colors == 1) {
203
		$online_label = $colortag_online . "$online_label" . $colortag_default;
204
		$offline_label = $colortag_offline . "$offline_label" . $colortag_default;
205
		$warning_label = $colortag_error . "$warning_label" . $colortag_default;
206
		$error_label = $colortag_error . "$error_label" . $colortag_default;
207
		$pretend_label = $colortag_pretend . "$pretend_label" . $colortag_default;
208
		$exists_label = $colortag_pretend . "$exists_label" . $colortag_default;
209
		$exec_label = $colortag_exec . "$exec_label" . $colortag_default;
210
		$abort_label = $colortag_abort . "$abort_label" . $colortag_default;
211
		$yes_label = $color_bold . "$yes_label" . $colortag_default; 
212
		$no_label = $color_bold . "$no_label" . $colortag_default;
213
		$vid_label = $colortag_vidlabel . $vid_label . $colortag_default;
214
		$script_name = $color_bold . $script_name . $colortag_default;
215
		#$category_label = $colortag_category . "$category_label" . $colortag_default;
216
	}
217
	
218
	if ($autoplay == 1) {
219
		our $do_exec = 1;
220
	}
221
222
	# Check some command dependancies 
223
	&DepCheck;
224
	
225
	# If one of the args is a directory, play file from requested dir
226
	if ($custom_dir == 1) {
227
		our $dir=$main::user_dir;
228
		
229
		my $dirlabel = $color_bold . "USING DIR" . $colortag_default;
230
		print qq| [$dirlabel]: $dir\n\n|;
231
		
232
		if ($search == 1) {
233
			&Search;
234
		}
235
		else {
236
			#Draw random file from user dir (will inherit dir)
237
			&BeginFlow;
238
		}
239
	}
240
	else {
241
		# Default Program flow; Play random file from collections
242
		&BeginFlow;
243
	}	
244
}
245
246
sub CheckArgs {
247
248
	# Process arguments before action
249
250
	if ($debug == 1) {
251
		print qq| <Enter Sub> CheckArgs\n|;
252
	}
253
254
	my $args=0;
255
	my $pass_opt_check=0;
256
	my $next;
257
	
258
	foreach my $arg (@ARGV) {	
259
		
260
		if ($arg =~/^\-q$/) {
261
			$vol_muted = 1;
262
		}
263
		elsif ($arg =~/^\-qq$/) {
264
			$nosound = 1;
265
		}
266
		elsif ($arg =~/^\-i$/) {
267
			our $cover = 1;
268
		}
269
		elsif ($arg =~/^\-h$|^-{1,2}help$/) {
270
			&Usage;
271
		}
272
		elsif ($arg =~/^\-v$/) {
273
			our $verbose = 1;
274
		}
275
		elsif ($arg =~/^-vv$/) {
276
			our $verbose = 1;
277
			our $very_verbose = 1;
278
		}
279
		elsif ($arg =~/^-{1,2}debug$/) {
280
			our $debug = 1;
281
		}
282
		elsif ($arg =~/^\-a$/) {
283
			our $autoplay = 1;
284
			our $do_exec = 1;
285
		}
286
		elsif ($arg =~/^\-l$/) {
287
			our $listing = 1;
288
		}
289
		elsif ($arg =~/^\-z$/) {
290
			our $list_everything = 1;
291
			our $listing = 1;
292
		}
293
		elsif ($arg =~/^\-c$/) {
294
			
295
			if ($use_colors == 1) {
296
				our $use_colors = 0;
297
			}
298
			else {
299
				our $use_colors = 1;
300
			}
301
		}
302
		elsif ($arg =~/^\-o$/) {
303
			
304
			if ($sort_order == 1) {
305
				our $sort_order = 0;
306
			}
307
			else {
308
				our $sort_order = 1;
309
			}
310
		}
311
		elsif ($arg =~/^\-k$/) {
312
			our $kill_players = 1;
313
			
314
			chomp(my $mplayer_pid=`pidof mplayer`);
315
			
316
			if ($mplayer_pid) {
317
				system("kill -s $kill_signal $mplayer_pid");
318
			}
319
		}
320
		elsif ($arg =~/^\-p$/) {
321
			our $pretend = 1;
322
		}
323
		elsif ($arg =~ /^\-fs$/) {
324
			our $fullscreen = 1;
325
		}
326
		elsif ($arg =~ /^\-m$/) {
327
			our $mplayer_output = 1;
328
		}
329
		elsif ($arg =~/^\-t$/) {
330
			
331
			# Limit results by time logic;
332
333
			our $limit_recent = 1;
334
			
335
			if ($auto_sort == 1) {
336
				our $sort_order = 1;
337
			}
338
339
			my $next=$ARGV[$args+1];
340
			
341
			unless ($next) { 
342
				print qq|[$error_label]: With -t, You must specify a time period.\n\n|;
343
				sleep 1;
344
				&Usage;
345
			}		
346
					
347
			unless ($next=~/^-(\w+)/) {
348
				$limit_time = $next;
349
			}
350
			
351
			if ($limit_time=~/^(\+?)(\d+)(\w?)$/) {
352
				
353
				$pass_opt_check=1;
354
				
355
				our $old_or_new = $1;
356
				my $number = $2;
357
				my $amount = $3;
358
				
359
				if ($amount) {
360
					if ($amount eq 'd') {
361
						if ($old_or_new) {
362
							$number = $number - 1;	
363
						}
364
						$limit_time = $number * 1;
365
					}
366
					elsif ($amount eq 'w') {
367
						$limit_time = $number * 7;
368
					}
369
					elsif ($amount eq 'm') {
370
						$limit_time = $number * 31;
371
					}
372
					elsif ($amount eq 'y') {
373
						$limit_time = $number * 365;
374
					}
375
					else {
376
						print qq|Recent Limit: $limit_time - "$amount" is not a valid time period... must be either d,w,m,y\n|; 
377
						exit;
378
					}
379
				}
380
			}
381
		}
382
		elsif (($arg =~ /^\-s$/) || ($arg=~ /^-e$/)) {
383
384
			# grab search term 
385
			
386
			if ($arg =~/^\-s$/) {
387
				our $search = 1;
388
			}
389
			elsif ($arg =~/^\-e$/) {
390
				our $search = 1;
391
				our $listing = 1;
392
				our $test_exists = 1;
393
			}
394
			
395
			my $next=$ARGV[$args+1];
396
397
			if ($next) { 
398
				
399
				unless ($next=~/^-(\w+)/) {
400
					$search_term = $next;
401
				} 
402
				if ($search_term=~/^((\w+)|(\*)|(\.))/g) {
403
					$pass_opt_check=1;
404
				}
405
			}
406
			else {
407
				$search_term = "";
408
			}
409
		}
410
		elsif ($arg =~ /^\-x$/) {
411
412
			our $null_term = 1;
413
			
414
			my $next=$ARGV[$args+1];
415
416
			if ($next) { 	
417
				unless ($next=~/^-(\w+)/) {
418
					$exclude_term = $next;
419
				} 
420
				if ($exclude_term=~/^((\w+)|(\*)|(\.))/g) {
421
					$pass_opt_check=1;
422
				}
423
			}
424
			else {
425
				$exclude_term = "";
426
			}
427
		}
428
		elsif ($arg =~ /^\-n$/) {
429
430
			our $specific_result = 1;
431
432
			my $wrong_number="[$error_label]: With -n, You must specify the number of a search result to play.\n";
433
			my $next = $ARGV[$args+1];
434
435
			if ($next) {
436
				
437
				unless ($next=~/^(\d+)$/) {
438
					print qq|$wrong_number\n|;
439
					sleep 1;
440
					&Usage;
441
				}
442
				else {
443
					$search_request = $next;
444
				}
445
				if ($search_request=~/^(\d+)/) {
446
					$pass_opt_check=1;
447
				}
448
			}
449
			else {
450
				print qq|$wrong_number\n|;
451
				sleep 1;
452
				&Usage;
453
			}
454
		}	
455
		elsif ($arg =~ /^\-r$/) {
456
457
			our $repeat = 1;			
458
			$repeat_range = "$default_repeat";
459
			
460
			my $next=$ARGV[$args+1];
461
462
			if ($next) { 
463
				
464
				# unless next var is another option, assign it as a var
465
				unless ($next=~/^-(\w+)/) {
466
					
467
					unless (-d $next) {
468
						$repeat_range = $next;
469
					}
470
				}
471
				
472
				if ($repeat_range=~/^((\d+)|all)$/g) {
473
					
474
					my $range_limit=$mplayer_max + $default_repeat;
475
					
476
					if (($repeat_range=~/^\d+/) && ($repeat_range > $range_limit)) {
477
						
478
						unless ($fork_bomb_protect == 1) {
479
						
480
							&PromptUser("WARNING: $repeat_range is over $range_limit processes. Continue?");
481
						}
482
					}
483
					
484
					$pass_opt_check=1;
485
				}
486
			}
487
488
			$range_request = $repeat_range;
489
		}
490
		elsif ($arg =~/^\-j$/) {
491
			our $timejump = 1;
492
			
493
			my $next=$ARGV[$args+1];
494
			
495
			if ($next) {
496
				if ($next=~/^(\d+)$/) {
497
					our $jumptime = $1;
498
					$pass_opt_check=1;
499
				}
500
			}
501
			else {
502
				#$jumptime = $jumptime;
503
			}
504
		}
505
		elsif ((-d "$arg")||(-l "$arg")) {
506
			our $custom_dir = 1;
507
			our $user_dir=$arg;
508
			$user_dir=~s/\/$//;
509
		}
510
		else {
511
			# if an option has been validated, don't complain
512
			unless ($pass_opt_check == 1) {
513
				
514
				print qq|[$error_label]: Unknown Argument: "$arg"\n\n|;
515
				
516
				sleep 1;
517
				
518
				&Usage;
519
				exit;
520
			}
521
			$pass_opt_check=0;
522
		}
523
		$args++;
524
	}
525
	return;
526
}
527
528
sub BeginFlow {
529
	
530
	# Silence errors of subcommands, unless ... 
531
532
	unless (($very_verbose == 1) || ($debug == 1)) {
533
		open(STDERR, ">/dev/null") or die "Can't redirect stderr: $!";
534
	}
535
	
536
	if ($debug == 1) {
537
		print qq| <Enter Sub> BeginFlow\n|;
538
	}
539
	
540
	&CheckStorage;		
541
	&GetSysInfo;
542
	
543
	if (($search == 1) || ($test_exists == 1)) {
544
		&Search;
545
	}
546
	else {
547
		&SelectFile;
548
	}
549
550
	print qq|OOPS! You should not be here.\n|;
551
552
	exit;
553
}
554
555
sub GetSysInfo {
556
557
	# Alter commands per OS; 
558
	my $this_os="$^O";
559
	
560
	# MAC OSX
561
	if ($this_os =~/^(darwin)$/i) {
562
		
563
		# grab default for image viewer
564
		unless ($image_viewer) {
565
			$image_viewer = $def_image_viewer_osx;
566
		}
567
		
568
		# If repeating, and resolution hasn't been grabbed yet... we need it to determine window layouts
569
		if ($repeat == 1) {
570
			
571
			unless ($resolution) {
572
573
				my $getrez_cmd="system_profiler SPDisplaysDataType | grep Resolution";
574
				chomp($resolution=`$getrez_cmd`);
575
				
576
				$resolution=~s/^\s+//g;
577
				$resolution=~s/Resolution: //g;
578
				
579
				# Pull x & Y variables from result
580
				($screen_res_x,$screen_res_y)=split(/\ x\ /,$resolution);
581
			}
582
		}
583
	}
584
	elsif ($this_os =~/^(linux)$/i) {
585
		
586
		# grab default for image viewer
587
		unless ($image_viewer) {
588
			$image_viewer = $def_image_viewer_linux;
589
		}
590
		
591
		# Same process as above..
592
		if ($repeat == 1) {
593
			unless($resolution) {
594
				
595
				my $getrez_cmd="xdpyinfo | grep dimensions | awk '{print \$2}' | awk -Fx '{print \$1, \$2}'";
596
				chomp($resolution=`$getrez_cmd`);
597
				
598
				# Pull x & Y variables from result	
599
				($screen_res_x,$screen_res_y)=split(/\ /,$resolution);
600
			}
601
		}
602
	}
603
	else {
604
		print qq|Unsupported OS: some things may not work as expected.\n|;
605
	}
606
607
	if ($debug == 1) { print qq| Screen Resolution: "$resolution"\n|; };
608
}
609
610
sub CheckStorage {
611
	
612
	# Consider multiple sources, check for availability
613
614
	if ($debug == 1) {
615
		print qq| <Enter Sub> CheckStorage\n|;
616
	}
617
	
618
	our @Available;
619
	our @Unavailable;
620
621
	my $count;
622
623
	# Check storage for availability	
624
	foreach my $csellection (@Collections) {
625
		$count++;
626
		chomp $csellection;
627
		
628
		if (-d "$csellection") {
629
			push(@Available,$csellection);
630
		}
631
		else {
632
			push(@Unavailable,$csellection);
633
		}
634
	}
635
	
636
	# if no collections available, print error -- unless user specified a directory to use	
637
	my $X;
638
	my $Y;
639
	my $storage_info="";
640
	
641
	unless ($#Available == -1) {
642
643
		if ($very_verbose == 1) {
644
645
			$storage_info .= qq| [COLLECTIONS]:\n\n|;
646
647
			foreach my $avail (@Available) {
648
				$storage_info .= qq|  [$online_label]: $avail\n|;
649
			}
650
			foreach my $unavail (@Unavailable) {
651
				$storage_info .= qq|  [$offline_label]: $unavail\n|;
652
			}
653
			print qq|$storage_info\n|;
654
		}
655
		else {
656
			$Y=0;
657
658
			foreach my $unavail (@Unavailable) {
659
				
660
				if ($verbose == 1) {
661
					
662
					print qq|[$warning_label]: $unavail is currently unavailable.\n\n|; 
663
					
664
					if ($Y == $#Unavailable) {
665
						print qq|  Consider editing the \@Collections array.\n\n|;
666
					}
667
				}
668
				$Y++;
669
			}
670
			unless ($#Unavailable < 0) {
671
				#print qq|\n|;
672
			}
673
		}
674
	}
675
	else {
676
		unless ($custom_dir == 1) {
677
678
			# Display this message if no available collections
679
680
			$storage_info .= qq|[$error_label]: No collections currently available?\n\n|;
681
682
			$X=0;
683
684
			foreach my $unavail (@Unavailable) {
685
				$X++;
686
				$storage_info .= qq|[$offline_label]: $unavail\n|;
687
			}
688
689
			$storage_info .= qq|\n You may need to edit the list of \@Collections in this script,\n|;
690
			$storage_info .= qq| or otherwise specify a directory to select a file from:\n|;
691
			$storage_info .= qq|\n $script_name ~/path/to/videos\n|;
692
693
			print qq|$storage_info\n|;
694
695
			exit;
696
		}
697
	}
698
	return;
699
}
700
701
sub DepCheck {
702
703
	# Ensure required commands exist
704
705
	if ($debug == 1) {
706
		print qq| <Enter Sub> DepCheck\n|;
707
	}
708
	
709
	foreach my $command (@Required) {	
710
		
711
		chomp(my $which=`which $command`);		
712
		
713
		unless (-e "$which") {
714
		
715
			print qq|[$error_label]: "$command" command not found!\n\n|;
716
			
717
			if ($command =~/mplayer$/) {
718
				print qq|This script is just a wrapper for command line mplayer.\n|;
719
				print qq|Please ensure mplayer is compiled & installed properly.\n|;
720
				print qq|http://www.mplayerhq.hu/design7/dload.html\n\n|;
721
			}
722
723
			exit;
724
		}
725
	}
726
}
727
728
sub BuildLists {
729
730
	# Filter unsupported file types and build list of available files. 
731
732
	if ($debug == 1) {
733
		print qq| <Enter Sub> BuildLists\n|;
734
	}
735
	
736
	our $location;
737
	my $Y=0;
738
739
	my $mtime;
740
	my %mtime;
741
	my $supported_videos;
742
	my $supported_images;
743
	my @AllFiles;
744
	my @FileList;
745
		
746
	# Build List from a collection directory, or user-specified path
747
	if ($custom_dir == 1) {
748
		$location = &PrepPath("$main::user_dir");
749
		@main::Available = $main::user_dir;
750
	}
751
	else {
752
		
753
		$location="";
754
		
755
		foreach my $item (@main::Available) {
756
		
757
			chomp $item;
758
			
759
			$location .= &PrepPath("$item");
760
761
			if ($#main::Available > 0) {
762
				$location = $location . " ";
763
			}
764
		}
765
	}
766
	
767
	if ($debug == 1) { print qq| <FIND AND SORT FILES>\n|; }
768
	
769
	# FILE FIND: IF sorting by oder, find files in all available paths & sort by mtime (-l -o)
770
	if ($sort_order == 1 && $limit_recent == 0) {
771
		
772
		find(sub {$mtime{$File::Find::name} = -M _ if -f;}, @main::Available);
773
		@AllFiles = sort {$mtime{$b} <=> $mtime{$a}} keys %mtime;
774
		
775
	}
776
	# FILE FIND: (-l -o -t [x]): selective population of the $mtime{} hash for sorting, based on mtime vs $limit_time 
777
	elsif ($sort_order == 1 && $limit_recent == 1) {
778
		
779
		unless ($repetition) {
780
		
781
			unless ($old_or_new eq '+') {
782
				$old_or_new = "-";
783
			}
784
			$limit_time = $old_or_new . $limit_time;
785
		}
786
		
787
		# File::Find in action;
788
		find(
789
			sub { 	
790
				if ($old_or_new eq '+') {
791
		
792
					if (-f && -M >= $limit_time) {
793
						$mtime{$File::Find::name} = -M _;
794
					}
795
				}
796
				elsif ($old_or_new eq '-') {
797
		
798
					$limit_time=~s/\-//;
799
		
800
					if (-f && $limit_time >= -M) {
801
						$mtime{$File::Find::name} = -M _;
802
					}
803
				}	
804
			}, @main::Available);
805
806
		@AllFiles = sort { $mtime{$b} <=> $mtime{$a} } keys %mtime;	
807
		
808
	}
809
	# FIND FILE: Limit file list to time period (-l -t [x])
810
	elsif ($sort_order == 0 && $limit_recent == 1) {
811
		
812
		# THIS CONDITION IS UNREACHABLE IF $sort_order =1 is defined under -t option -- or $auto_sort = 1|;
813
		#@AllFiles=`find $location -type f -mtime $limit_time`;
814
		
815
		unless ($repetition) {
816
		
817
			unless ($old_or_new eq '+') {
818
				$old_or_new = "-";
819
			}
820
			$limit_time = $old_or_new . $limit_time;
821
		}
822
		
823
		find(
824
			sub { 	
825
				if ($old_or_new eq '+') {
826
					if (-f && -M >= $limit_time) {
827
						push(@AllFiles, $File::Find::name); ### FIX THIS SHIT CONDITIONAL
828
					}
829
				}
830
				elsif ($old_or_new eq '-') {
831
	
832
					$limit_time=~s/\-//;
833
	
834
					if (-f && $limit_time >= -M) {
835
						push(@AllFiles, $File::Find::name);
836
					}
837
				}	
838
			}, @main::Available);
839
							
840
	}
841
	# IF NOT sorting, no need for mtime check (just -l), slight speedup
842
	else {
843
		#@AllFiles=`find $location -type f`;
844
		find(sub { push(@AllFiles, $File::Find::name) if -f }, @main::Available);
845
	}
846
	
847
	# SEARCH FILTER: Now we'll use a secondary list for parsed search results
848
	if ($search == 1) {
849
					
850
		my @search_words=split(/\,/,$search_term);
851
		
852
		foreach my $search_word (@search_words) {
853
854
			$search_word=~s/\,\ /\,/g;
855
			$search_word=~s/\./\(\\W+\)/g;
856
			#$search_word=~s/\./\(\(\\W+\)|\(\\S+\)\)/g;
857
			
858
			# Must-have for simple search
859
			$search_word=~s/\ /\./g;
860
			#$search_word=~s/\ /\(\\W+\)/g;
861
			
862
			# Expand search if wildcard, else this will not split and var is still useable
863
	
864
			my @sub_words=(split(/\*/,"$search_word"));
865
866
			# Now, actually populate @FileList if file matches search terms
867
			foreach my $sub_word (@sub_words) {
868
				
869
				$sub_word=~s/^\.//g;
870
871
				foreach my $item (@AllFiles) {
872
					chomp $item;
873
					
874
					# .. unless it matches an -x exclusion_term, put it in the list
875
					unless (($null_term == 1 )&& ($exclude_term ne "") && ($item=~/$exclude_term/ig)) {
876
						
877
						if ($item=~/$search_word/ig) {			
878
							push(@FileList,$item);
879
						}
880
					
881
						if ($item=~/$sub_word/ig) {
882
							push(@FileList,$item);
883
						}
884
					}
885
				}
886
			}
887
		}
888
	}
889
	else {
890
		# If not searching, use the complete list
891
		@FileList = @AllFiles;
892
	}
893
	
894
	# Determine Supported file types by creating a filter
895
896
	$Y=0;
897
898
	foreach my $type (@Supported_videos) {
899
900
		$supported_videos .= "\.$type\$";
901
902
		unless ($Y == $#Supported_videos) {
903
			$supported_videos .= "|";
904
		}
905
		$Y++;
906
	}
907
908
	# Same style filter image types
909
910
	$Y=0;
911
912
	foreach my $type (@Supported_images) {
913
914
		$supported_images .= "\.$type\$";
915
916
		unless ($Y == $#Supported_images) {
917
			$supported_images .= "|";
918
		}
919
		$Y++;
920
	}
921
922
	# Isolate specific file types into arrays for later access
923
924
	foreach my $item (@FileList) {
925
926
		chomp $item;
927
928
		if ($item =~/$supported_videos/i) {
929
			push (@main::Videos,$item);
930
			our $total_videos++;
931
		}
932
		elsif ($item=~/$supported_images/i) {
933
			push (@main::Images,$item);
934
			our $total_images++;
935
		}
936
		else {
937
			# Store all other files as rejected
938
			push (@main::Rejected,$item);
939
			our $total_rejected++;
940
		}
941
	}
942
	
943
	# Strip out duplicates. 
944
	my %unique;
945
 
946
   	undef %unique;
947
    	@unique{@main::Videos} = ();
948
949
    	my @Videos = keys %unique;
950
	
951
	unless ($sort_order == 1) {
952
		#NOTE: Don't sort this list, it should already be sorted
953
		@main::Videos=sort(@Videos); 
954
	}
955
	else {
956
		# Strip duplicates;
957
		@main::Videos = grep(!$unique{$_}++, @main::Videos);	    
958
	}
959
	
960
    	undef %unique;
961
 	@unique{@main::Images} = ();
962
963
	my @Images = keys %unique;
964
965
	@main::Images = sort(@Images);
966
967
	undef %unique;
968
	@unique{@main::Rejected} = ();
969
	
970
	my @Rejected = keys %unique;
971
	@main::Rejected =  sort(@Rejected);
972
	
973
	my $zero;
974
975
	if ($total_videos == 0) {
976
		if ($use_colors == 1) {
977
			$zero = $color_red . "0" . $colortag_default;
978
		}
979
		else {
980
			$zero = "0";
981
		}
982
		
983
		if ($search == 1 && $limit_recent == 0) {
984
			print qq|[$error_label]: $zero results found for "$main::search_input" in: $location\n\n|;
985
		}
986
		elsif ($search == 1 && $limit_recent == 1) {
987
	
988
			my $result_text="";
989
	
990
			if ($limit_time =~/^\-/) {
991
				$result_text = "results NEWER than $limit_time days";
992
			}
993
			elsif ($limit_time =~/^\+/) {
994
				$result_text = "results OLDER than $limit_time days";
995
			}
996
	
997
			print qq|[$error_label]: $zero $result_text found for "$main::search_input" in: $location\n\n|;
998
		}
999
		else {
1000
			print qq|[$error_label:] $zero results found in: $location\n\n|;
1001
		}	
1002
		exit;
1003
	}
1004
1005
	return;
1006
}
1007
1008
sub Search {
1009
1010
	if ($debug == 1) {
1011
		print qq| <Enter Sub> Search: \"$main::search_term\"\n|;
1012
	}
1013
	
1014
	# Gather Search input if not specified on the command line
1015
	unless ($main::search_term) {
1016
1017
		print qq|[SEARCH]: |;
1018
1019
		chomp($search_input=<STDIN>);
1020
1021
		print qq|\n|;
1022
1023
	}
1024
	else {
1025
		unless (-d "$main::search_term") {
1026
			$search_input=$main::search_term;
1027
		}
1028
		else {
1029
			if ($debug == 1) {
1030
				print qq|<DEBUG>Search $main::search_term is a dir.\n|;
1031
			}
1032
1033
			$main::search_term = "";
1034
1035
			print qq|[SEARCH]: |;
1036
1037
			chomp($search_input=<STDIN>);
1038
1039
			print qq|\n|;
1040
		}
1041
	}
1042
	
1043
	my $search_char=length($search_input);
1044
	
1045
	# if empty search input, default to random selection, else format a regex based on input
1046
	if ($search_char == 0) {
1047
		
1048
		print qq|[NOTICE]: No Search terms specified, selecting random file...\n\n|;
1049
1050
		$main::search = 0;
1051
1052
		&SelectFile;
1053
		exit;
1054
	}
1055
	elsif ($search_char < $main::search_char_min ) {
1056
		print qq|[$error_label]: $search_input is too short ($search_char of $main::search_char_min min).\n\n|;
1057
		exit;	
1058
	}
1059
	else {
1060
		# Now that input is validated, Search
1061
		$search_term="$search_input";
1062
1063
		&SelectFile;
1064
		exit;
1065
	}
1066
}
1067
1068
sub SelectFile {
1069
1070
	if ($debug == 1) {
1071
		print qq| <Enter Sub> SelectFile\n|;
1072
	}
1073
1074
	# Only build the list once
1075
	unless ($repetition) {
1076
		&BuildLists;	
1077
	}
1078
1079
	my $count;
1080
	my $display_name;
1081
	my $selected;
1082
	my $selected_movie_raw_path;
1083
	my $unique_videos=$#main::Videos+1;
1084
	
1085
	
1086
	# If the range is 'all', play in order (avoid dupes) by dropping to 1st request, and jumping back to top of &SelectFile for full increment
1087
	if (($repeat == 1) && ($range_request =~/^all$/)) {
1088
		
1089
		$specific_result = 1;
1090
		$search_request = 1;
1091
		
1092
		$range_request = $total_videos;
1093
		$repeat_range = $range_request;
1094
		
1095
		# Reset counter		
1096
		$total_videos = "";
1097
		
1098
		# Start over;		
1099
		&SelectFile;
1100
	}
1101
	
1102
	# If a user specifies the file from a list, we already know it's number. Else draw randomly. 
1103
	if ($specific_result == 1) {
1104
	
1105
		my $result_summary;
1106
		my $req_orig = $search_request;
1107
	
1108
	 	$selected = $search_request;
1109
		
1110
		# Alter user request to align with array
1111
		unless ($search_request == 0) {
1112
			$search_request = ($search_request - 1);
1113
		}
1114
			
1115
		if ($search_request > $#main::Videos) {
1116
			
1117
			if ($total_videos == 1) {
1118
				$result_summary = qq|only 1 result for "$search_term" ... |;
1119
			}
1120
			else {
1121
				$result_summary = qq|only $unique_videos Videos found |;
1122
				if ($search == 1) {
1123
					$result_summary .= qq|for "$search_term" |;
1124
				}
1125
				$result_summary .= qq |...|;
1126
			}
1127
			
1128
			print qq|[$error_label]: $req_orig is out of bounds, $result_summary\n\n|;
1129
			exit;
1130
		}
1131
		chomp($selected_movie_raw_path=$main::Videos[$search_request]);
1132
	}
1133
	else {
1134
		# THE WHEEL OF FATE SPINS!
1135
		my $rand=int rand ($#main::Videos+1); 
1136
		$selected = $rand;
1137
		
1138
		chomp($selected_movie_raw_path=$main::Videos[$rand]);
1139
		
1140
		unless ($selected == 0) {
1141
			$selected = ($selected + 1);
1142
		}
1143
		
1144
		# ..but try to avoid dupes
1145
		if ($repeat == 1) {
1146
			
1147
			foreach my $past_select (@main::AlreadyPicked) {
1148
				
1149
				# If this selection has been drawn before...
1150
				if ($past_select == $selected) {
1151
					
1152
					if ($debug == 1) {
1153
						print qq| PICKED $selected but ALREADY PLAYED $#main::AlreadyPicked $#main::Videos\n|;
1154
					}
1155
					
1156
					# exit if we've gone through the full list, else roll again
1157
					if ($#main::AlreadyPicked >= $#main::Videos) {
1158
						exit;
1159
					}
1160
					else {
1161
						&SelectFile;
1162
					}
1163
				}
1164
			}
1165
			
1166
			# Keep track of drawn numbers
1167
			push (@main::AlreadyPicked,$selected);
1168
		}
1169
	}
1170
1171
	if (($selected)&&($debug == 1)) {
1172
		print qq| <SELECTED:> "$selected"\n|;
1173
		print qq| <FILENAME: $selected_movie_raw_path\n|;
1174
	}
1175
1176
	# Mangle the path to seperate the $file_name from the raw $file_folder_path
1177
	my $playable_path=&PrepPath("$selected_movie_raw_path");	
1178
	my $file_folder_path=$selected_movie_raw_path;
1179
	
1180
	foreach my $item (@main::Available) {
1181
		$file_folder_path=~s/^$item//g;
1182
	}
1183
	
1184
	# Extract file name from path and determine generic name of file (without extension)
1185
		
1186
	my $file_path=$file_folder_path;
1187
	my @folders=split(/\//,$file_folder_path);
1188
	
1189
	our $file_name = $folders[$#folders];
1190
		
1191
	# if $file_name contains invalid characters it gets treated as a nested regex, escape, then replace
1192
	$file_name =~s/\?/\\\?/g;
1193
	$file_name =~s/\[/\\\[/g;
1194
	$file_name =~s/\]/\\\]/g;
1195
	
1196
	$file_path=~s/$file_name//g;
1197
	
1198
	$file_name =~s/\\\?/\?/g;
1199
	$file_name =~s/\\\[/\[/g;
1200
	$file_name =~s/\\\]/\]/g;
1201
1202
	# Strip extension for a generic name to find images with
1203
	our $generic_name = $file_name;
1204
	$generic_name =~s/\.(\w{3})$//i;
1205
	
1206
	# Ok, NOW PRINT list if -l 
1207
	if ($listing == 1) {	
1208
	
1209
		if ($total_videos > 0) {
1210
			print qq| [VIDEO FILES]:|;
1211
	
1212
			if ($search == 1) { 
1213
				$total_videos = $unique_videos;
1214
				print qq| $total_videos results for "$search_input" ... \n\n|; 
1215
			}
1216
			elsif ($limit_recent == 1) {
1217
			
1218
				my $result_text="";
1219
1220
				if ($limit_time =~/^\-/) {
1221
					$result_text = "results NEWER than $limit_time days";
1222
				}
1223
				elsif ($limit_time =~/^\+/) {
1224
					$result_text = "results OLDER than $limit_time days";
1225
				}
1226
		
1227
				print qq| $total_videos $result_text\n\n|;
1228
			}
1229
			else {
1230
				print qq| $total_videos videos available.\n\n|;
1231
			}
1232
			
1233
			$count=0;
1234
			
1235
			# Loop through and print list
1236
			foreach my $item (@main::Videos) {
1237
			
1238
				$count++;
1239
				$display_name=$item;
1240
					
1241
				# Strip source name from file to help categorize
1242
				unless ($list_full_paths == 1) {
1243
					foreach my $avail (@main::Available) {
1244
						$display_name=~s/^$avail\///g;
1245
					}
1246
				}
1247
			
1248
				# Colorize search-term hits
1249
				if (($search == 1) && ($use_colors == 1)) {
1250
			
1251
					my $search_word;
1252
					
1253
					# Split seperated terms
1254
					my @search_breakdown2=split(/\,/,$search_term);
1255
			
1256
					foreach my $seperate_term (@search_breakdown2) {
1257
					
1258
						#$search_term=~s/\,\ /\,/g;
1259
						my @search_breakdown=split(/\ |\,|\.|\*/,$search_term);
1260
					
1261
						# Break the search phrase down into individual words for matching results
1262
						foreach my $search_word (@search_breakdown) {		
1263
			
1264
							my @matches = $display_name =~/($search_word)/ig;
1265
			
1266
							foreach my $match (@matches) {
1267
							
1268
								my $highlighted=$colortag_search . "$match" . $colortag_default;
1269
								$display_name=~s/$match/$highlighted/g;
1270
							} 
1271
						}
1272
					}
1273
				}
1274
				
1275
				# Include mtime info ? 
1276
				my $mtime="";
1277
				
1278
				if (($verbose == 1) || ($limit_recent == 1) || ($sort_order == 1)) {
1279
1280
					$mtime = scalar localtime stat("$item")->mtime;
1281
					
1282
					# format only useful data
1283
					$mtime =~s/\ \ /\ /g;
1284
					(my $day,my $month,my $date,my $time,my $year)=split(/\ /,$mtime);
1285
					$mtime = "$year $month $date";
1286
					$mtime = " ($mtime)";
1287
1288
					if ($use_colors == 1) {
1289
						$mtime = $colortag_mtime . $mtime . $colortag_default;
1290
					}
1291
				}
1292
				my $number;
1293
				if ($use_colors == 1) {
1294
					$number = $colortag_number . $count . $colortag_default;
1295
				}
1296
				else {
1297
					$number = $count;
1298
				}
1299
				# Finally display list item
1300
				print qq|  [$number]:$mtime $display_name \n|;
1301
				
1302
			}
1303
			print qq|\n|;
1304
		}
1305
		$count=0;
1306
	}
1307
		
1308
	if ($list_everything == 1) {
1309
1310
		print qq| [IMAGES]:\n\n|;
1311
1312
		foreach my $item (@main::Images) {
1313
			$count++;
1314
			print qq|  [$count]: $item\n|;
1315
		}
1316
1317
		print qq|\n|;
1318
		$count=0;
1319
1320
		print qq| [OTHER FILES]:\n\n|;
1321
1322
		foreach my $item (@main::Rejected) {
1323
			$count++;
1324
			print qq|  [$count]: $item\n|;
1325
		}
1326
1327
		print qq|\n|;
1328
		$count=0;
1329
1330
		print qq| [VIDEOS]: $total_videos\n|;
1331
		print qq| [IMAGES]: $total_images\n|; 
1332
		print qq| [OTHER]: $total_rejected\n|;
1333
1334
		print qq|\n|; 
1335
		exit;
1336
	}
1337
	
1338
	if ($test_exists == 1) {
1339
1340
		$pretend = 1;
1341
1342
		if ($total_videos > 1) {
1343
			print qq| [$exists_label] $total_videos matches for "$search_term".\n\n|;
1344
		}
1345
		elsif ($total_videos == 1) {
1346
			print qq| [$exists_label] File "$file_name" matches.\n\n|;
1347
		}
1348
		exit;		
1349
	}
1350
	
1351
	# If repeating, report itteration
1352
	if ($repeat == 1) {
1353
					
1354
		#keep track of repetitions (after earlier reset) 
1355
		$repetition++;
1356
1357
		# If we've opened too many windows, bind to terminal to prevent fork bombing the system
1358
		if ($fork_bomb_protect == 1) {
1359
			
1360
			if ($repetition > $mplayer_max) {
1361
				
1362
				$target_x = 0;
1363
				$target_y = 0;
1364
				$mplayer_output = 1;
1365
			}
1366
		}
1367
		
1368
		# Turn off listing for repititions 
1369
		$listing = 0;
1370
		
1371
		#if user requests 4, but there's only 3 vids, drop range to match total_videos 
1372
		if ($range_request >= $total_videos) {
1373
			$range_request = $total_videos;
1374
		}
1375
		
1376
		print qq| [INSTANCE]: $repetition of $range_request\n|;
1377
	}
1378
	
1379
	# Determine selection # of total
1380
	if ($selected == 0) {
1381
		$selected = 1;
1382
	}
1383
	
1384
	my $file_info="";
1385
	my $selected_label = $selected;
1386
	
1387
	if ($use_colors == 1) {
1388
		$selected_label = $colortag_selection . $selected_label . $colortag_default;
1389
	}
1390
1391
	$file_info .= qq| [SELECTED]: File \# $selected_label of $unique_videos\n|;
1392
	
1393
	# Display some useful info about the file if verbose
1394
	if ($#Collections >= 1) {		
1395
1396
		foreach my $item (@main::Available) {
1397
1398
			if ($selected_movie_raw_path=~/^$item/) {
1399
1400
				my $csellection = $item;
1401
1402
				if ($use_colors == 1) {
1403
					#$csellection .= $colortag_category . $csellection . $colortag_default;
1404
				}
1405
				$file_info .= qq| [SOURCE]: $csellection\n|;
1406
			}
1407
		}
1408
	}			
1409
	# Unless custom dir, list some path info as 'category' - it's up to you to organize your files though
1410
	unless (($custom_dir == 1) || ($#folders == 1)) {		
1411
1412
		$file_info .= qq| [$category_label]: |;
1413
1414
		if ($use_colors == 1) {
1415
			$file_info .= $colortag_category;
1416
		}
1417
		
1418
		for (my $i=0; $i < $#folders; $i++) {	
1419
			
1420
			unless ($folders[$i] =~"^\/") {
1421
1422
				$file_info .= qq|$folders[$i]|;		
1423
1424
				unless ($i == 0) {
1425
					$file_info .= qq|/ |;
1426
				}
1427
			}
1428
		}
1429
		if ($use_colors == 1) {
1430
			$file_info .= $colortag_default;
1431
		}
1432
		$file_info .= qq|\n|;	    
1433
	}
1434
	
1435
	if ($verbose == 1) {
1436
1437
		# Additional date
1438
		my $mtime = scalar localtime stat("$selected_movie_raw_path")->mtime;
1439
1440
		# format only useful data
1441
		$mtime =~s/\ \ /\ /g;
1442
		(my $day,my $month,my $date,my $time,my $year)=split(/\ /,$mtime);
1443
		$mtime = "$month $date $year";
1444
	
1445
		if ($use_colors == 1) {
1446
			$mtime = $colortag_mtime . $mtime . $colortag_default;
1447
		}
1448
		$file_info .= qq| [VID DATE]: $mtime\n|;
1449
	}
1450
	
1451
	# Color label for filename?
1452
	my $filename_label = $file_name;
1453
	my $orig_total = $total_videos;
1454
1455
	if ($use_colors == 1) {
1456
		$filename_label = $colortag_name . $file_name . $colortag_default;
1457
		$total_videos = $color_red . $total_videos . $colortag_default;
1458
	}
1459
	else {
1460
		# Bold if no color
1461
		$filename_label = $color_bold . $file_name . $colortag_default;
1462
		$total_videos = $color_bold . $total_videos . $colortag_default;
1463
	} 
1464
1465
	$file_info .= qq| [$vid_label]: $filename_label\n\n|;
1466
	
1467
	# Finally print the $file_info we've formatted 
1468
	if (($file_info_banner == 1) || ($verbose == 1)) {
1469
1470
		unless (($#ARGV == 0)&&($listing == 1)) {
1471
			print qq|$file_info|;
1472
		}
1473
		else {
1474
			# Exit after -l is given
1475
			print qq| $total_videos videos in your collection.\n\n|;
1476
			exit;
1477
		}
1478
	}
1479
	
1480
	$total_videos = $orig_total;
1481
		
1482
	# Handle repitition requests
1483
	if ($repeat == 1) {
1484
		
1485
		# Determine geometries for multiple window layouts, unless remaining attached
1486
		unless ($mplayer_output == 1) {
1487
		
1488
			my $last_vid_x = $target_x;
1489
			my $last_vid_y = $target_y;
1490
		
1491
			# Only move across if user has played previous file, or autoplay
1492
			unless ($user_ok eq "n") {
1493
				$target_x=$target_x + $video_width;
1494
			}
1495
			
1496
			#$target_y= $target_y + $video_height;
1497
		
1498
			# Get video resolution
1499
			my $mplayer_info_cmd="mplayer -vo null -ao null -frames 0 -identify $playable_path 2>/dev/null | grep ^ID_VIDEO";
1500
			my @vid_info=`$mplayer_info_cmd`;
1501
			
1502
			foreach my $info_line (@vid_info) {
1503
1504
				chomp $info_line;
1505
1506
				if ($info_line =~/^ID_VIDEO_WIDTH=/) {
1507
					$video_width=$info_line;
1508
					$video_width=~s/^ID_VIDEO_WIDTH=//;
1509
				}
1510
				if ($info_line =~/^ID_VIDEO_HEIGHT=/) {
1511
					$video_height=$info_line;
1512
					$video_height=~s/^ID_VIDEO_HEIGHT=//;
1513
				}
1514
			};
1515
		
1516
			# Determine next geometry, and if breaching far edge, drop down to new row.
1517
			my $next_x = $target_x + $video_width;
1518
			my $next_y = $target_y + $video_height;
1519
			
1520
			if ($next_x >= $screen_res_x) {
1521
				$target_x = 0;
1522
				$target_y= $target_y + $video_height;
1523
			}
1524
			
1525
			if ($next_y >= $screen_res_y) {
1526
				#$target_y = 0;
1527
			}
1528
		
1529
			if ($debug == 1) {
1530
				print qq| vidX: $video_width : $target_x of $screen_res_x : $next_x ($resolution)\n|;
1531
				print qq| vidY: $video_height : $target_y of $screen_res_y : $next_y ($resolution)\n|;
1532
			}
1533
			
1534
			# Set next windows' mplayer geometry 
1535
			$mplayer_opts_geo = " -geometry $target_x:$target_y";
1536
			
1537
		}
1538
		
1539
		# Return to center if we've stacked too many
1540
		if ($repetition > $mplayer_max) {
1541
			$mplayer_opts_geo = "";
1542
		}
1543
		
1544
		## IF -n $search_request, array needs alignment elsewhere (-1), so to increment the range to +1, we must actually +2 
1545
		if ($search_request) {
1546
			$search_request = $search_request +2;
1547
		}
1548
		# If the file #1 is requested, var was = 0, so previous test fails, so we need to bump to 2 to equal back to 0 to allow file +1 
1549
		else {
1550
			$search_request = 2;
1551
		}
1552
		
1553
		# if repeat range has more cycles,
1554
		if ($repeat_range > 1) {
1555
1556
			# remove a cycle from requested repetitions,
1557
			$repeat_range--;
1558
			
1559
			# and unless this is the last cycle, spin another video
1560
			unless ($repetition >= $total_videos) {
1561
				#sleep 1;
1562
				&PlayFile("$playable_path");
1563
				&SelectFile;
1564
			}	
1565
		}	
1566
	}
1567
	
1568
	# Under regular operation, finally open file;
1569
	&PlayFile("$playable_path");
1570
	
1571
	if (($verbose == 1) || ($debug == 1)) {
1572
		&GetStats;
1573
	}	
1574
	exit;
1575
}
1576
1577
sub PlayFile {
1578-
	if ($nosound == 1) {
1578+
1579
	chomp(my $play_file="$_[0]");
1580
	
1581
	if ($debug == 1) {
1582-
		$cmd .= " $volume_mods";
1582+
1583
	}	
1584
	
1585
	# Form the actual mplayer command
1586
	my $cmd = "$mplayer $mplayer_opts -title \"$main::file_name\"";
1587
	my $silent_output="1>/dev/null 2>&1";
1588
	
1589
	# Append mplayer options before command is formed
1590
	if ($mplayer_opts_geo) {
1591
		$cmd .= " $mplayer_opts_geo";
1592
	}
1593
	if ($timejump == 1) {
1594
		$cmd .=" -ss $jumptime";
1595
	}
1596
	if ($fullscreen == 1)  {
1597
		$cmd .=" -fs";
1598
	}
1599
	if ($vol_muted == 1) {
1600
		$cmd .=" -volume 00";
1601
	}
1602
	elsif ($nosound == 1) {
1603
		$cmd .=" -nosound";
1604
	}
1605
	else {
1606
		$cmd .= " $volume_level";
1607
	}
1608
1609
	# Feed file to command
1610
	$cmd = $cmd . " $play_file";
1611
	
1612
	# Unless attaching, silence output
1613
	unless ($mplayer_output == 1) {
1614
		$cmd="$cmd $silent_output";		
1615
	}
1616
	
1617
	# Added Ability to open an image, even if -p
1618
	if ($cover == 1 && $pretend == 1) {
1619
1620
		&GetRelatedImages;
1621
1622
		if ($#main::Related_images >= 1) {
1623
1624
			&PromptUser("Open image only?");
1625
1626
			foreach my $item (@main::Related_images) {
1627
				
1628
				# Possible to be called and return nothing, so only act on tangible items
1629
				unless ($item =~/^$/) {
1630
					&OpenImage("$item");
1631
				}
1632
			}
1633
		}
1634
	}
1635
1636
	unless ($pretend == 1) {
1637
1638
		# Build a List
1639
		if ($cover == 1) {
1640
			&GetRelatedImages;
1641
		}
1642
		
1643
		unless ($do_exec == 1) {
1644
1645
			# SAFETY; confirmation prompt before playing the video;
1646
			print qq|[$warning_label]: Always wise to double-check before exec ... ('-a' to override)\n\n|;
1647
1648
			&PromptUser("Play file?");
1649
		}
1650
		
1651
		# Now that a user will have confirmed, open all related images
1652
		if ($cover == 1) {
1653
			if ($do_exec == 1) {
1654
				foreach my $item (@main::Related_images) {
1655
					
1656
					# Possible to be called and return nothing, so only act on tangible items
1657
					unless ($item =~/^$/) {
1658
						&OpenImage("$item");
1659
					}
1660
				}
1661
			}
1662
		}
1663
1664
		# NOW we can finally launch mplayer 
1665
		unless ($mplayer_output == 1) {		
1666
			
1667
			if ($do_exec == 1) {	
1668
					
1669
				system("$cmd \&");
1670
				
1671
				# Unless auto = 1, reset so it prompts again
1672
				unless ($autoplay == 1) {
1673
					$do_exec = 0;
1674
				}
1675
			}
1676
		}
1677
		else {
1678
			print qq|Mplayer output:\n--\n|;
1679
			system("$cmd");
1680
		}
1681
	}
1682
	else {
1683
		print qq| [$pretend_label]: no exec ...\n\n|;
1684
		unless ($repeat == 1) {
1685
			exit;
1686
		}
1687
	}	
1688
	if ($very_verbose == 1) {
1689
		print qq|\n [$exec_label]: $cmd\n\n|;
1690
	}
1691
	return;
1692
}
1693
1694
sub GetRelatedImages {
1695
1696
	# Find Associated Images;
1697
	
1698
	if ($debug == 1) {
1699
		print qq| <Enter Sub> GetRelatedImages for "$main::generic_name" in $main::location\n|;
1700
	}
1701
	
1702
	# Reset;
1703
	our @Related_images="";
1704
	our $path_to_image;
1705
1706
	my $image;
1707
	my $image_file="";
1708
	my $images_found="";
1709
	my $generic_name=$main::generic_name;
1710
	
1711
	# strip non-word characters into regex, strip "part X" for multi-part video labels
1712
	$generic_name =~s/part((\s+)*)(\d+)/\.\*/ig;
1713
	$generic_name =~s/(\W+)/\.\*/g;
1714
	
1715
	# Go through all images we found and find matches for the selected video, set them aside
1716
	foreach my $item (@main::Images) {
1717
1718
		chomp $item;
1719
1720
		if ($item=~/$generic_name/g) {
1721
			push (@Related_images,$item);
1722
			
1723
		}
1724
	}
1725
1726
	# If we have some related image results, make use of them - but don't pass to OpenImage yet
1727
	unless ($#Related_images == -1) {
1728
		my $X;
1729
		foreach my $image (@Related_images) {
1730
			$X++;
1731
			chomp $image;
1732
1733
			my @image_path=split(/\//,$image);
1734
			$image_file=$image_path[$#image_path];
1735
			
1736
			unless ($image =~/^$/) {
1737
				
1738
				if ($use_colors == 1) {
1739
					$image_file = $colortag_imgname . $image_file . $colortag_default;
1740
				}
1741
				print qq| [IMAGE]: $image_file\n|;
1742
				
1743
				# Format image file list correct, by adding space if it's the last one
1744
				if ($#Related_images < $X) {
1745
					print qq|\n|;
1746
				}
1747
			}
1748
		}	
1749
		
1750
	}
1751
	else {
1752
		print qq| [NOTICE]: No images found for "$generic_name"\n\n|;
1753
	}
1754
	return;
1755
}
1756
	
1757
sub OpenImage {
1758
1759
	# Open Associated Image(s)
1760
1761
	chomp(my $imagepath=$_[0]);
1762
	$imagepath=&PrepPath("$imagepath");
1763
1764
	my $image_command = "$image_viewer $imagepath 1>/dev/null 2>&1";
1765
	
1766
	my @image_path=split(/\//,$imagepath);
1767
	my $image_name=$image_path[$#image_path];
1768
	
1769
	if ($debug == 1) {
1770
		print qq| <OpenImageExec>: "$image_command"\n\n|;
1771
	}
1772
	
1773
	unless (($main::user_ok eq 'n') || ($imagepath =~/^$/)) {
1774
		system("$image_command \&");
1775
	}
1776
1777
	return;
1778
}
1779
1780
sub PromptUser {
1781
1782
	# Unless otherwise stated, prompt before blatantly opening a video.
1783
	
1784
	if ($debug == 1) {
1785
		print qq| <PromptUser:>\n|;
1786
	}
1787
1788
	my $prompt_msg = "$_[0]";
1789
	 
1790
	unless ($autoplay == 1) {
1791
1792
		print qq|$prompt_msg [$yes_label/$no_label|;
1793
		if ($repeat == 1) {
1794
			print $color_bold . qq|/q| . $colortag_default;
1795
		} 
1796
		print qq|] ($yes_label)|;
1797
		
1798
		chomp($main::user_ok=<STDIN>);
1799
1800
		if ($user_ok =~/^y$/i) {
1801
			$do_exec = 1;
1802
			#return;
1803
		}
1804
		elsif ($user_ok eq "") {
1805
			$do_exec = 1;
1806
			#return;
1807
		}
1808
		elsif ($user_ok =~/^n$/i) {
1809
			print qq|\n [$abort_label]: Not Launching.\n\n|;
1810
			#exit;
1811
		}
1812
		elsif ($user_ok =~/^q$|^quit$|^exit$/) {
1813
			print qq|\n [$abort_label]: Aborted.\n\n|;
1814
			exit;
1815
		}
1816
		else {
1817
			&PromptUser("$prompt_msg");
1818
		}
1819
		
1820
		print qq|\n|;
1821
	}
1822
}
1823
1824
sub PrepPath {
1825
1826
	# Sanitize path for command executions
1827
1828
	if ($debug == 1) {
1829
		print qq| <PrepPath:> "$_[0]"\n|;
1830
	}
1831
	
1832
	my $esc_path;
1833
	chomp($esc_path=$_[0]);
1834
	
1835
	$esc_path=~s/\ /\\\ /g;
1836
	$esc_path=~s/\&/\\&/g;
1837
	$esc_path=~s/\[/\\[/g;
1838
	$esc_path=~s/\]/\\]/g;
1839
	$esc_path=~s/\(/\\(/g;
1840
	$esc_path=~s/\)/\\)/g;
1841
	$esc_path=~s/\'/\\'/g;	
1842
	$esc_path=~s/\!/\\!/g;
1843
	$esc_path=~s/\;/\\;/g;
1844
	return $esc_path;
1845
}
1846
1847
sub GetStats {
1848
1849
	# Time this scripts execution time
1850
	
1851
	if (($verbose == 1)||($debug == 1)) { 	
1852
	
1853
		my $time = time - $^T;
1854
		my $decimal=$time/60;
1855
		my $minutes;
1856
		my $fraction;
1857
		my $time_report;
1858
		($minutes,$fraction)=split(/\./,$decimal);
1859
1860
		# Square off time into minutes, subtract from overall time to get additional seconds
1861
		my $min_seconds=($minutes*60);
1862
		my $seconds=($time-$min_seconds);
1863
1864
		# If over an hour, break down into additional minutes
1865
		if ($minutes >= 60) {
1866
			my $decimal2 = $minutes/60;
1867
			my $hours;
1868
			($hours,$fraction)=split(/\./,$decimal2);
1869
1870
			my $hour_minutes=($hours*60);
1871
			my $extramins=($minutes - $hour_minutes);
1872
1873
			$time_report = qq|$hours hours $extramins minutes $seconds seconds.\n|;
1874-
	print qq|   -q\t\tNo Volume. Play Muted.\n|;
1874+
1875
		elsif ($minutes >= 1) {
1876
			$time_report = qq|$minutes minutes $seconds seconds.\n|;
1877
		}
1878
		else {
1879
			$time_report = qq|$seconds seconds.\n|;
1880
		}
1881
		print qq|$script_name runtime: $time_report|;
1882
	}	
1883
}
1884
1885
sub Usage {
1886
	
1887
	if ($debug == 1) {
1888
		print qq| <Enter Sub> Usage\n|;
1889
	}
1890
	
1891
	if ($use_colors == 1) {
1892
		$script_name = $color_bold . $script_name . $colortag_default;
1893
	}
1894
	
1895
	print qq| $script_name [options] [dir]\n (v.$version)\n\n|;
1896
	print qq|   -h\t\tThis Help. \n|;
1897
	print qq|   -p\t\tPretend Only. No execution.\n|;
1898
	print qq|   -q\t\tStart with volume = 0.0\n|;
1899
	print qq|   -qq\t\tMute completely, no sound loaded.\n|;
1900
	print qq|   -a\t\tAutoplay. Bypass confirmation prompt.\n|;
1901
	print qq|   -l\t\tList available videos.\n|;
1902
	print qq|   -o\t\tSort listing by file modification times.\n|;
1903
	print qq|   -n [#]\tPlay Nth numbered result. (As numbered by the "-l" option)\n|;
1904
	print qq|   -e [TERM]\tQuick check against collection and exit. Shorter than '-s -p'\n|;
1905
	print qq|   -s [TERM]\tSearch files using keywords.\n\t\t ("." = wildcard, "," = expanded search terms)\n|;
1906
	print qq|   -x [TERM]\tExclude a term from search results.\n|;
1907
	print qq|   -t [#x]\tOnly list files newer than [Xx]. +X for 'older than' X.\n\t\t x = (d/w/m/y). Ex: 5d / 2w / 1m / 1y\n|;
1908
	print qq|   -r [#][all]\tRepeat selection process X amount of times. default: $default_repeat\n\t\t Will increment to n+X if starting point specified with -n\n|;
1909
	print qq|   -j [x]\tJump player to start X seconds in to file.\n|;
1910
	print qq|   -i\t\tOpen any images related to selection, if found.\n|;
1911
	print qq|   -fs\t\tFull Screen.\n|;
1912
	print qq|   -m\t\tAttach MPlayer output, do not fork to background.\n|;
1913
	print qq|   -k\t\tKill any existing mplayer instances before starting new ones.\n|;
1914
	print qq|   -c\t\tToggle \$use_colors on/off.\n|;
1915
	print qq|   -v\t\tVerbose information about the selected file. (file date)\n|;
1916
	print qq|   -vv\t\tVery verbose: even more info.\n|; 
1917
	print qq|   --debug\tInclude script execution debug info.\n|;
1918
	#print qq|   -z\t\tList Every file parsed from storage locations\n|;
1919
	
1920
	print qq|\n\n Example Usages:\n\n|;
1921
	
1922
	print qq|  Play a random file from the locations set in \@Collections array:\n|;
1923
	print qq|  (\@Collections = "@Collections")\n|;
1924
	print qq|\t$script_name\n\n|;
1925
1926
	print qq|  List files and play a random file from another directory:\n|;
1927
	print qq|\t$script_name -l ~/Downloads\n\n|;
1928
1929
	print qq|  Order listing by mtime, select 3rd video from list:\n|;
1930
	print qq|\t$script_name -l -o -n 3\n\n|;
1931
1932
	print qq|  Open multiple videos, no prompt. If not given, \$default_repeat = $default_repeat:\n|;
1933
	print qq|\t$script_name -r 3 -a\n\n|;
1934
1935
	print qq|  List and play $default_repeat videos from the past month, muted, kill any already running:\n|;
1936
	print qq|\t$script_name -q -l -t 1m -r -k\n\n|;
1937
1938
	print qq|  Starting at first vid, sequential play all videos that match search term:\n|;
1939
	print qq|\t$script_name -l -o -s "star wars" -n 1 -r all\n\n|;
1940
	
1941
	print qq|\n|;
1942
	
1943
	exit;
1944
}