dlpodget.defaults / dlpodget

#!/usr/bin/perl -w

package main;
use LWP::UserAgent;
use XML::Feed;
use Data::Dumper;
use Daybo::ConfReader;
use Getopt::Std;
use URI::Escape;
use strict;
use warnings;
use diagnostics;

my $Debug = 0;

sub FileFromURI($)
{
	my $Url = shift;
	return undef if ( !$Url );
	my @uri_parts = split('/', $Url);
	return $uri_parts[-1];
}

sub InitConfigDefaults($)
{
	my $Feeds = shift;
	my $confmain = $Feeds->{_main};
	die 'Assertion failure' unless $confmain;

	$confmain->{TMPDIR} = '/tmp' unless ( $confmain->{TMPDIR} );
	$confmain->{HOME} = $confmain->{TMPDIR} unless ( $confmain->{HOME} );
	$confmain->{localpfx} = $confmain->{HOME} unless ( $confmain->{localpfx} );

	my %defaults = (
		'enable' => 1,
		'noop'   => 0,
		'debug'  => 0
	);

	foreach my $opt ( keys(%defaults) ) {
		next if ( defined($confmain->{$opt}) && $confmain->{$opt} =~ m/\d$/ );
		$confmain->{$opt} = $defaults{$opt};
	}
}

sub InitFeedDefaults($$)
{
	my ( $Feeds, $Feed ) = @_;
	$Feed->{localpath} = $Feeds->{_main}->{localpfx} unless ( $Feed->{localpath} );
	$Feed->{rss} = '' unless ( $Feed->{rss} );
	foreach my $chk ( 'check', 'download', 'enable' ) {
		$Feed->{$chk} = 1 if ( !$Feed->{$chk} || $Feed->{$chk} !~ m/\^d$/ );
	}
}

sub ReadStream($$$)
{
	my @entries = ( );
	my ( $Feeds, $Url, $Name ) = @_;
	my $feed = XML::Feed->parse(URI->new($Url));
	if ( !$feed ) {
		printf(STDERR "Stream %s error: %s\n", $Name, $@);
		return @entries;
	}

	foreach my $entry ($feed->entries) {
		my $enclosure = $entry->{'entry'}->{'enclosure'};
		my $uriDecoded = uri_unescape($enclosure->{'url'});
		my $filename = FileFromURI($uriDecoded);
		push(@entries, {
			filename => $filename,
			uri      => $uriDecoded,
			title    => $entry->title,
			type     => $enclosure->{'type'},
			length   => $enclosure->{'length'}
		}) if ( $filename );
	}
	return @entries;
}

sub DownloadStream($$$)
{
	my ( $ua, $f, %get_params );
	my $local_length = 0;
	my ( $Feeds, $entry, $Name ) = @_;
	my $local_podcast = $Feeds->{$Name}->{localpath} . '/' . $entry->{filename};
	if ( -f $local_podcast ) {
		$local_length = (stat($local_podcast))[7];
		if ( !$entry->{length} || $local_length == $entry->{length} ) {
			printf(STDERR "%s already exists\n", $local_podcast);
			return;
		}
	}
	$ua = LWP::UserAgent->new( show_progress => 1 );
	unless ( $Feeds->{_main}->{noop} ) {
		if ( open($f, '>>:raw', $local_podcast) ) {
			binmode($f);
		} else {
			printf(STDERR "Failed -- %s\n", $!);
			return;
		}
	}
	%get_params = (
		'Range' => "bytes=$local_length-"
	) if ( $local_length );
	$ua->get(
		$entry->{uri},
		%get_params,
		':content_cb' => sub {
			my ( $chunk ) = @_;
			print $f $chunk unless ( $Feeds->{_main}->{noop} );
		}
	);
	close($f) if ( !$Feeds->{_main}->{noop} );
}

sub ProcessTags($$)
{
	my ( $Feeds, $V ) = @_;
	foreach my $c ( keys(%{ $Feeds->{_main} }) ) {
		my $ucc = '$' . uc($c);
		while ( my $idx = index($V, $ucc) > -1 ) {
			substr($V, $idx-1, length($ucc), $Feeds->{_main}->{$c});
		}
	}
	return $V;
}

sub main()
{
	my $conf;
	my @entries = ( );
	my @defKeys;
	my %feeds = ( );
	my %opts = ( );
	my $confSeen = 0;
	my ( $streamsEnabledCount, $streamsDefinedCount ) = ( 0, 0 );
	my @confFiles = (
		'dlpodget.rc',
		"$ENV{HOME}/.dlpodget.rc"
	);

	return 1 if ( !getopts('d', \%opts) );
	$Debug = 1 if ( $opts{'d'} );
	print(STDERR "Explicit debug mode enabled by -d\n") if ( $Debug );

	$conf = Daybo::ConfReader->new();
	foreach my $confFile ( @confFiles ) {
		next unless ( -f $confFile );
		if ( $conf->SetFn($confFile) ) {
			$conf->Reload();
			$confSeen++;
			last;
		}
	}
	$conf = undef if ( !$confSeen );

	if ( $conf && $conf->GetKeys(undef, \@defKeys) ) {
		if ( 'enable' ~~ @defKeys ) {
			if ( !$conf->GetDatum(undef, 'enable') ) {
				print(STDERR "Configuration disabled.\n");
				$conf = undef;
			}
		}
	}

	if ( $conf ) {
		my ( @sections, $secC );
		$secC = $conf->GetSections(\@sections);

		# First load the generation configuration information
		$feeds{_main} = { %ENV }; # Include environment variables.
		if ( scalar(@defKeys) ) {
			foreach my $mk ( @defKeys ) {
				$feeds{_main}->{$mk} = $conf->GetDatum(undef, $mk);
			}
			# Set debug flag via config if it existed.
			if ( $feeds{_main}->{debug} ) {
				$Debug = $feeds{_main}->{debug};
				printf(STDERR "Set Debug via config: %s\n", $Debug);
			}
		}

		InitConfigDefaults(\%feeds);
		for ( my $secI = 0; $secI < $secC; $secI++ ) {
			my @secKeys;
			my $keyC = $conf->GetKeys($sections[$secI], \@secKeys);
			foreach ( my $keyI = 0; $keyI < $keyC; $keyI++ ) {
				next if ( $sections[$secI] eq '_main' ); # Skip reserved section
				my $v = $conf->GetDatum($sections[$secI], $secKeys[$keyI]);
				$v = ProcessTags(\%feeds, $v);
				printf(
					STDERR
					'[%s] %s -> %s'."\n",
					$sections[$secI],
					$secKeys[$keyI],
					$v
				) if ( $Debug );
				$feeds{ $sections[$secI] }->{ $secKeys[$keyI] } = $v;
			}
		}
	}

	foreach my $feedName ( keys(%feeds) ) {
		my $feed = $feeds{$feedName};
		InitFeedDefaults(\%feeds, $feed);
		$streamsDefinedCount++ if ( $feed->{rss} );
		next if ( !$feed->{enable} );
		next if ( !$feed->{download} );
		@entries = ReadStream(\%feeds, $feed->{rss}, $feedName);
		foreach my $entry ( @entries ) {
			$streamsEnabledCount++;
			print STDERR 'Processing entry: ' . Dumper $entry if ( $Debug );
			DownloadStream(\%feeds, $entry, $feedName);
		}
	}
	unless ( $streamsDefinedCount ) {
		print "No valid streams defined.\n";
		return 1;
	}
	unless ( $streamsEnabledCount ) {
		print "No enabled streams.\n";
		return 0;
	}

	return 0;
}

exit(main());
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.