#!/usr/bin/perl # Filename: myfilm # Author: David Ljung Madison <DaveSource.com> # See License: http://MarginalHacks.com/License/ # Description: Download iFilm/youtube movies given a film ID. # Converts youtube films from flash to .mov if ffmpeg is available. my $VERSION= '1.02'; # # Requires that ifilm/youtube's obfuscation doesn't change drastically. # # youtube: http://youtube.com/watch?v=[video_id] # video at: http://youtube.com/get_video.php?l=165&video_id=[video_id]&t=[??] # Need to find &t=[c0de] in HTML # # ifilm: http://www.ifilm.com/ifilmdetail/2667392 # -> http://secure.ifilm.com/qt/portal/2667392_300.mov?e=1159050000&h=6c97297693c58d818e86aba0819abf10 # Update: Don't know how to look this up with iFilm's new Flash player # # Also see: http://javimoya.com/blog/youtube_en.php ################################################## # CHANGELOG ################################################## # 2007/8/16 # ---------------- # Haxxed for the 770 by gogol. Somebody with # better perl skillz, please help # NOTE: The bookmark parsing REQUIRES that myfilm.pl is in your PATH # # 1.02 2006/05/13 # ---------------- # + Updated for new youtube obfuscation (&t=[c0de]) # # 1.01 2006/04/08 # ---------------- # + Released as myfilm # + Now handles youtube as well as iFilm # # 1.00 2005/12/08 # ---------------- # + Released as diFilm # ################################################## #use strict; ################################################## # Setup the variables ################################################## my $PROGNAME = $0; $PROGNAME =~ s|.*/||; my ($BASENAME,$PROGNAME) = ($0 =~ m|(.*)/(.+)|) ? ($1?$1:'/',$2) : ('.',$0); # This will probably change.. my $IFILM = "http://www.ifilm.com/player/mac.jsp?ifilmId="; my $YOUTUBE = "http://youtube.com/get_video.php?l=165&video_id="; # How to fetch web files - pick one # Actual Safari agent example: # Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/416.12 (KHTML, like Gecko) Safari/416.13 my $GET = "GET -H 'user-agent: Mozilla/5.0'"; my $LYNX = "links -source"; my $GET_URL = $LYNX; my $POST = "mov"; # For converting youtube to .mov my $FFMPEG = "ffmpeg"; #default save dir for youtube my $defdir = "/home/user/MyDocs/.videos"; #note no trailing slash ################################################## # Usage ################################################## sub fatal { foreach my $msg (@_) { print STDERR "[$PROGNAME] ERROR: $msg\n"; } exit(-1); } sub usage { foreach my $msg (@_) { print STDERR "ERROR: $msg\n"; } print STDERR <<USAGE; Usage:\t$PROGNAME [-d] <ifilm URL, youtube URL or ifilm id> Download an ifilm movie -o <file> Save to file -bw <56,200,300> Force a bandwidth other than your iFilm settings -d Set debug mode -bg Run ffmpeg in the background -z Scan /home/user/.bookmarks/MyBookmarks.xml for youtube video links. It will then download any that don't already exist in ~/MyDocs/.videos USAGE exit -1; } sub parse_args { my $opt = {}; while (my $arg=shift(@ARGV)) { if ($arg =~ /^-z$/) {$opt->{bmfile} = 1; next;} if ($arg =~ /^-h$/) { usage(); } if ($arg =~ /^-d$/) { $MAIN::DEBUG=1; next; } if ($arg =~ /^-bg$/) { $opt->{bg} = 1; next; } if ($arg =~ /^-bw$/) { $opt->{bw} = shift @ARGV; next; } if ($arg =~ /^-o$/) { $opt->{save} = shift @ARGV; next; } if ($arg =~ /^-/) { usage("Unknown option: $arg"); } if ($arg =~ m|^http://([^/]+)/.*?([^/]+)$|) { ($opt->{url}, $opt->{dom}, $opt->{film}) = ($arg, $1, $2); next; } if ($arg =~ /^[0-9]+$/) { ($opt->{arg}, $opt->{dom},$opt->{film}) = ("ifilm.com", $arg); next; } usage("Unknown film id. I need an iFilm or youtube URL"); } usage("No film URL specified.") unless $opt->{film} || $opt->{bmfile}; $opt; } sub debug { return unless $MAIN::DEBUG; foreach my $msg (@_) { print STDERR "[$PROGNAME] $msg\n"; } } ################################################## # Utils ################################################## sub title_embed { my ($opt, $url) = @_; debug("URL: $url"); my $open = "$GET_URL $url"; debug("GET: $open"); open(FILM,"$open |") || usage("Couldn't get URL: $url\nMake sure [$GET_URL] is installed"); # Find the film location my $dl; my $title; my $bw = $opt->{bw}; my $embed; my $and_t; while(<FILM>) { $dl = $1 if /var\s+dl\s*=\s*"?(-?\d+)"?/; $bw = $1 if !$bw && /var\s+bw\s*=\s*"?(\d+)"?/; $embed = $1 if /<embed.*(http:[^>"]+)/i; $title = $1 if /span class="title">([^<]+)/; $title = $1 if /<title>(.*)<\/title>/; $and_t = $1 if /video_id=.*&t=([^&"]+)/; } close(FILM); ($title,$embed,$dl,$bw,$and_t); } ################################################### #Bookmark parse ################################################### sub getbookmarks { my $BMARKS = "/home/user/.bookmarks/MyBookmarks.xml"; open BMARKS, "<$BMARKS" or die "Can't open bookmarks!: $!"; while (<BMARKS>) { chomp; if ($_ = m|(http://(?:www\.)?youtube\.com/watch\?v=[^"]+)|i){ push @youtube_vids, $1; } } print "Found ",($#youtube_vids + 1)," bookmarked videos:\n"; while ($ourcount < ($#youtube_vids+1) ) { print "$ourcount : $youtube_vids[$ourcount]\n"; @args = ("myfilm.pl", $youtube_vids[$ourcount]); $ourcount++; system(@args) == 0 or die "failed: $?\n"; } } ################################################## # iFilm ################################################## sub iFilm { my ($opt,$film) = @_; print STDERR "Fetching iFilm ID: $film\n"; # Read the ifilm HTML my $url = $IFILM.$film; my ($title,$smil,$dl,$bw) = title_embed($opt, $url); $title = $title || $film; usage("Couldn't find 'dl' key in URL [$url]") unless $dl; usage("Couldn't find 'bw' key in URL [$url]") unless $bw; usage("Couldn't find 'embed' tag in URL [$url]") unless $smil; $smil =~ s/'\s+\+\s+dl\s+\+\s+'/$dl/g; $smil =~ s/'\s+\+\s+bw\s+\+\s+'/$bw/g; $smil =~ s/"$//; debug("SMIL: $smil"); # Get the smil file my $open = "$GET_URL \Q$smil\E"; open(SMIL,"$open |") || usage("Couldn't get SMIL: $smil"); my $video; while (<SMIL>) { $video = $1 if /video src="(http[^"]+)"/; } usage("Couldn't find video source key in SMIL [$smil]") unless $video; close SMIL; debug("Found: $video"); $title =~ s/[:\s]+/_/g; my $save = $opt->{save} || "$title.$POST"; $save =~ s|/|_of_|g; print "Saving to: $save\n"; debug("$GET_URL \Q$video\E > \Q$save\E\n"); system("$GET_URL \Q$video\E > \Q$save\E"); } ################################################## # youtube ################################################## sub youtube { my ($opt, $film) = @_; print STDERR "Fetching youtube ID: $film\n"; # Get name my ($save,undef,undef,undef,$and_t) = title_embed($opt, $opt->{url}); fatal("No '&t=' code found for youtube [$opt->{url}]") unless $and_t; if ($opt->{save}) { $save = $opt->{save}; } else { fatal("No title found for youtube [$opt->{url}]") unless $save; $save =~ s/youtube( - )?(.+)/$2/ig; print STDERR "Found film '$save'\n"; $save =~ s/[:\s]+/_/g; } $save =~ s/(\.flv)?$/.flv/; $save =~ s|/|_of_|g; $save =~ s/[\*\?\'\"]//g; # Get rid of troublesome characters. # ffmpeg gets confused easily # Get video #print "TITLE; $title -> $save\n"; my $video = $YOUTUBE.$film."&t=$and_t"; debug("Video: $video"); $filename = join "/", $defdir, $save; print "$filename is filename\n"; if (-e $filename) { print "File $defdir/$save already exists, skipping.\n"; return; } print "Saving to: $defdir/$save\n"; system("$GET_URL \Q$video\E > $filename"); # Attempt convert to .mov #my $mov = $save; #$mov =~ s/\.flv$/.mov/; #print "Convert to: $mov\n"; #exec($FFMPEG,"-v",0,"-i",$save,$mov) unless fork; #if ($opt->{bg}) { # sleep 1; # To let the intial ffmpeg output go through.. #} else { # wait; } ################################################## # Main code ################################################## sub main { my $opt = parse_args(); if ($opt->{dom} =~ /youtube/i) { $opt->{film} = "watch?v=$opt->{film}" if $opt->{url} =~ s|www.youtube.com/v/|www.youtube.com/watch?v=|; usage("Couldn't find youtube video (URL must contain 'v=[video_id]')") unless $opt->{film} =~ /v=([a-z0-9_-]+)/i; return youtube($opt, $1); } if ($opt->{dom} =~ /ifilm/i) { usage("Couldn't find iFilm video (URL must contain a number/film id)") unless $opt->{film} =~ /([0-9]+)/; return iFilm($opt, $1); } if (defined $opt->{bmfile}) {&getbookmarks;} } main();