2007-02-24 09:01:43 +00:00
|
|
|
#!/usr/bin/env ruby
|
2006-02-14 20:50:57 +00:00
|
|
|
|
2006-02-14 20:53:13 +00:00
|
|
|
# $Id$
|
|
|
|
|
# $URL$
|
2006-02-14 20:50:57 +00:00
|
|
|
|
|
|
|
|
#
|
2007-07-17 20:33:52 +00:00
|
|
|
# Copyright (c) 2006-2007 Ward Wouts <ward@wouts.nl>
|
2006-02-14 20:50:57 +00:00
|
|
|
#
|
|
|
|
|
# Permission to use, copy, modify, and distribute this software for any
|
|
|
|
|
# purpose with or without fee is hereby granted, provided that the above
|
|
|
|
|
# copyright notice and this permission notice appear in all copies.
|
|
|
|
|
#
|
|
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
require 'net/http'
|
|
|
|
|
require 'uri'
|
|
|
|
|
require 'rexml/document'
|
2006-04-16 19:26:24 +00:00
|
|
|
require 'date'
|
2007-02-24 09:01:43 +00:00
|
|
|
require 'getoptlong'
|
2008-06-03 11:02:26 +00:00
|
|
|
require 'yaml'
|
2007-02-24 09:01:43 +00:00
|
|
|
|
2007-09-22 22:50:03 +00:00
|
|
|
@debug=false
|
|
|
|
|
|
2007-02-24 09:01:43 +00:00
|
|
|
def usage
|
|
|
|
|
puts <<EOT
|
|
|
|
|
Usage: #{$0.sub(/.*\//, "")} [options]
|
|
|
|
|
|
|
|
|
|
-c, --configfile <file> use configuration from <file> (default $HOME/.getdistortedrc)
|
|
|
|
|
-h, --help show this message
|
|
|
|
|
-l, --list list podcasts
|
|
|
|
|
-p, --podcast <podcast> only fetch <podcast>
|
2007-07-17 20:08:21 +00:00
|
|
|
-v, --verbose be more verbose
|
2007-09-22 22:50:03 +00:00
|
|
|
|
|
|
|
|
To use a proxy set the HTTP_PROXY environment variable, like such:
|
|
|
|
|
export HTTP_PROXY=http://<host>:<port>
|
2007-02-24 09:01:43 +00:00
|
|
|
EOT
|
|
|
|
|
exit
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def cmdline
|
|
|
|
|
options = Hash.new
|
|
|
|
|
begin
|
|
|
|
|
opts = GetoptLong.new(
|
|
|
|
|
[ "-c", "--configfile", GetoptLong::REQUIRED_ARGUMENT ],
|
|
|
|
|
[ "-h", "--help", GetoptLong::NO_ARGUMENT ],
|
|
|
|
|
[ "-l", "--list", GetoptLong::NO_ARGUMENT ],
|
2007-07-17 20:08:21 +00:00
|
|
|
[ "-p", "--podcast", GetoptLong::REQUIRED_ARGUMENT ],
|
|
|
|
|
[ "-v", "--verbose", GetoptLong::NO_ARGUMENT ]
|
2007-02-24 09:01:43 +00:00
|
|
|
)
|
|
|
|
|
opts.quiet=true
|
|
|
|
|
|
|
|
|
|
opts.each do |opt, arg|
|
|
|
|
|
options[opt] = arg
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
rescue
|
|
|
|
|
print "#{$!}\n"
|
|
|
|
|
usage
|
|
|
|
|
end
|
|
|
|
|
if options["-h"]
|
|
|
|
|
usage
|
|
|
|
|
end
|
2007-07-17 20:08:21 +00:00
|
|
|
if options["-v"]
|
|
|
|
|
@verbose = true
|
|
|
|
|
end
|
2007-02-24 09:01:43 +00:00
|
|
|
return options
|
|
|
|
|
end
|
|
|
|
|
|
2007-07-17 20:08:21 +00:00
|
|
|
def verbose(msg)
|
|
|
|
|
if @verbose
|
|
|
|
|
puts msg
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2007-02-24 09:01:43 +00:00
|
|
|
def readconfig(configfile=nil)
|
|
|
|
|
configfile = configfile.nil? ? "#{ENV['HOME']}/.getdistortedrc" : configfile
|
|
|
|
|
load configfile
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def listpodcasts
|
|
|
|
|
for podcast in @podcasts.keys.sort
|
|
|
|
|
puts podcast
|
|
|
|
|
end
|
|
|
|
|
exit
|
|
|
|
|
end
|
2006-02-14 20:50:57 +00:00
|
|
|
|
|
|
|
|
def fetch(uri_str, limit = 10)
|
|
|
|
|
# You should choose better exception.
|
|
|
|
|
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
|
|
|
|
|
|
2007-07-17 20:08:21 +00:00
|
|
|
verbose("Fetching #{uri_str}\n\n")
|
|
|
|
|
|
2007-02-24 14:57:47 +00:00
|
|
|
host = URI.parse(uri_str).host
|
|
|
|
|
path = URI.parse(uri_str).path
|
|
|
|
|
query = URI.parse(uri_str).query
|
|
|
|
|
|
2007-07-17 20:08:21 +00:00
|
|
|
proxy_host = nil
|
|
|
|
|
proxy_port = nil
|
|
|
|
|
proxy_user = nil
|
|
|
|
|
proxy_pass = nil
|
|
|
|
|
|
|
|
|
|
if ENV['HTTP_PROXY']
|
2007-09-22 22:50:03 +00:00
|
|
|
begin
|
2007-07-17 20:08:21 +00:00
|
|
|
uri = URI.parse(ENV['HTTP_PROXY'])
|
|
|
|
|
proxy_host = uri.host
|
|
|
|
|
proxy_port = uri.port
|
|
|
|
|
proxy_user, proxy_pass = uri.userinfo.split(/:/) if uri.userinfo
|
2007-09-22 22:50:03 +00:00
|
|
|
rescue
|
|
|
|
|
puts $!
|
|
|
|
|
end
|
2007-07-17 20:08:21 +00:00
|
|
|
end
|
2007-09-22 22:50:03 +00:00
|
|
|
if @debug
|
|
|
|
|
p "Host: #{host}"
|
|
|
|
|
p "Path: #{path}"
|
|
|
|
|
p "Query: #{query}"
|
|
|
|
|
|
|
|
|
|
p "proxy_host #{proxy_host}"
|
|
|
|
|
p "proxy_port #{proxy_port}"
|
|
|
|
|
p "proxy_user #{proxy_user}"
|
|
|
|
|
p "proxy_pass #{proxy_pass}"
|
|
|
|
|
end
|
2007-07-17 20:08:21 +00:00
|
|
|
|
|
|
|
|
Net::HTTP::Proxy(proxy_host, proxy_port,
|
|
|
|
|
proxy_user, proxy_pass).start(host) {|http|
|
|
|
|
|
if query
|
|
|
|
|
req = Net::HTTP::Get.new("#{path}?#{query}")
|
|
|
|
|
else
|
|
|
|
|
req = Net::HTTP::Get.new("#{path}")
|
|
|
|
|
end
|
2007-09-22 22:50:03 +00:00
|
|
|
if ! @user.nil? && ! @pass.nil?
|
|
|
|
|
req.basic_auth @user, @pass
|
|
|
|
|
end
|
2007-02-24 14:57:47 +00:00
|
|
|
response = http.request(req)
|
|
|
|
|
case response
|
|
|
|
|
when Net::HTTPSuccess then response
|
2007-07-17 20:08:21 +00:00
|
|
|
when Net::HTTPRedirection then
|
|
|
|
|
verbose("Redirecting to #{response['location']}")
|
|
|
|
|
fetch(response['location'], limit - 1)
|
2007-02-24 14:57:47 +00:00
|
|
|
when Net::HTTPNotFound then puts "404 Not Found #{uri_str}"; response.error!
|
|
|
|
|
when Net::HTTPUnauthorized then puts "401 Authorization Required #{uri_str}"; response.error!
|
|
|
|
|
else
|
2007-09-22 22:50:03 +00:00
|
|
|
puts response.message
|
2007-02-24 14:57:47 +00:00
|
|
|
response.error!
|
|
|
|
|
end
|
|
|
|
|
}
|
2006-02-14 20:50:57 +00:00
|
|
|
end
|
|
|
|
|
|
2006-02-14 21:13:55 +00:00
|
|
|
def deleteold(podcast)
|
|
|
|
|
Dir.open(@podcasts[podcast]["savedir"]).each {|entry|
|
|
|
|
|
if File.file?("#{@podcasts[podcast]["savedir"]}/#{entry}") &&
|
|
|
|
|
! @filelist[entry]
|
2006-02-17 13:36:07 +00:00
|
|
|
puts " deleting #{entry}"
|
2006-02-14 21:13:55 +00:00
|
|
|
File.unlink("#{@podcasts[podcast]["savedir"]}/#{entry}")
|
|
|
|
|
end
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
2006-04-16 19:26:24 +00:00
|
|
|
def getenclosure(podcast, item)
|
2006-10-29 20:01:51 +00:00
|
|
|
enclosure = nil
|
|
|
|
|
item.each_element{|x|
|
|
|
|
|
if x.name == "enclosure"
|
|
|
|
|
enclosure = x
|
|
|
|
|
end
|
|
|
|
|
}
|
2006-04-16 19:26:24 +00:00
|
|
|
pubdate = item.get_elements("pubDate")[0]
|
|
|
|
|
date = nil
|
|
|
|
|
if ! pubdate.nil?
|
|
|
|
|
date = Date.parse(pubdate.text).strftime("%Y%m%d")
|
|
|
|
|
end
|
|
|
|
|
if ! enclosure.nil? && ! enclosure.attribute("url").nil?
|
2007-09-22 17:01:10 +00:00
|
|
|
cast = enclosure.attribute("url").value.to_s.dup
|
2006-02-14 21:27:42 +00:00
|
|
|
filename = cast.dup
|
|
|
|
|
filename.sub!(/^.*\//, "")
|
|
|
|
|
if @podcasts[podcast]["rename"]
|
2008-06-03 11:02:26 +00:00
|
|
|
renames = Array.new
|
|
|
|
|
@podcasts[podcast]["rename"].collect{|x| renames.push(x.dup)}
|
|
|
|
|
while renames.length > 0
|
|
|
|
|
pattern = renames.shift
|
|
|
|
|
replacement = renames.shift
|
|
|
|
|
if replacement.match(/%%DATE%%/)
|
|
|
|
|
replacement.gsub!(/%%DATE%%/, date)
|
|
|
|
|
end
|
|
|
|
|
filename.gsub!(pattern, replacement)
|
2006-04-16 19:26:24 +00:00
|
|
|
end
|
2006-02-14 21:27:42 +00:00
|
|
|
end
|
|
|
|
|
@filelist[filename] = true
|
|
|
|
|
if ! File.exists?("#{@podcasts[podcast]["savedir"]}/#{filename}")
|
2006-02-17 13:36:07 +00:00
|
|
|
puts " getting #{@podcasts[podcast]["savedir"]}/#{filename}"
|
2006-03-15 12:00:53 +00:00
|
|
|
begin
|
|
|
|
|
response = fetch(cast)
|
|
|
|
|
File.open("#{@podcasts[podcast]["savedir"]}/#{filename}", "w"){|f|
|
|
|
|
|
f.print(response.body)
|
|
|
|
|
}
|
|
|
|
|
if @podcasts[podcast]["linkdir"]
|
|
|
|
|
File.symlink("#{@podcasts[podcast]["savedir"]}/#{filename}", "#{@podcasts[podcast]["linkdir"]}/#{filename}")
|
|
|
|
|
end
|
2006-03-15 12:20:03 +00:00
|
|
|
return "#{@podcasts[podcast]["savedir"]}/#{filename}"
|
2006-07-04 11:55:23 +00:00
|
|
|
rescue Timeout::Error, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT, Net::HTTPFatalError
|
|
|
|
|
puts " error #{$!} fetching, skipping"
|
2007-09-22 22:50:03 +00:00
|
|
|
rescue
|
2008-06-03 11:02:26 +00:00
|
|
|
puts "WTF: #{$!}"
|
2006-02-18 11:08:33 +00:00
|
|
|
end
|
2006-03-15 12:20:03 +00:00
|
|
|
else
|
|
|
|
|
return "#{@podcasts[podcast]["savedir"]}/#{filename}"
|
2006-02-14 21:27:42 +00:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2007-02-24 09:01:43 +00:00
|
|
|
def getcasts(podcast=nil)
|
|
|
|
|
worklist = Array.new
|
|
|
|
|
if podcast.nil?
|
|
|
|
|
worklist = @podcasts.keys.sort
|
|
|
|
|
else
|
|
|
|
|
worklist.push podcast
|
|
|
|
|
end
|
|
|
|
|
for podcast in worklist
|
|
|
|
|
files = Array.new
|
|
|
|
|
puts podcast
|
|
|
|
|
begin
|
2007-02-24 14:57:47 +00:00
|
|
|
@user = @podcasts[podcast]["username"].nil? ? nil : @podcasts[podcast]["username"]
|
|
|
|
|
@pass = @podcasts[podcast]["password"].nil? ? nil : @podcasts[podcast]["password"]
|
2007-02-24 09:01:43 +00:00
|
|
|
res = fetch(@podcasts[podcast]["rss"])
|
|
|
|
|
@filelist = {}
|
2007-02-24 14:57:47 +00:00
|
|
|
|
2007-02-24 09:01:43 +00:00
|
|
|
# body.gsub!(/#{13.chr}#{10.chr}/, "#{10.chr}")
|
|
|
|
|
xmldoc = REXML::Document.new(res.body)
|
|
|
|
|
xmldoc.elements.each("rss/channel") {|item|
|
|
|
|
|
item.each_element{|x|
|
|
|
|
|
if x.name == "item"
|
2007-07-17 20:08:21 +00:00
|
|
|
verbose("Item found:\n#{x}\n\n")
|
2007-02-24 09:01:43 +00:00
|
|
|
files.push getenclosure(podcast, x)
|
|
|
|
|
end
|
2006-08-10 11:23:08 +00:00
|
|
|
}
|
|
|
|
|
}
|
2007-02-24 09:01:43 +00:00
|
|
|
if @podcasts[podcast]["delete"]
|
|
|
|
|
deleteold(podcast)
|
|
|
|
|
end
|
|
|
|
|
if @podcasts[podcast]["m3u"]
|
|
|
|
|
File.open(@podcasts[podcast]["m3u"], "w"){|f|
|
|
|
|
|
files.each{|file|
|
|
|
|
|
f.puts file
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
rescue
|
|
|
|
|
rescue Timeout::Error, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT, Net::HTTPFatalError
|
|
|
|
|
puts " error #{$!} fetching, skipping"
|
2006-08-10 11:23:08 +00:00
|
|
|
end
|
2006-03-15 12:20:03 +00:00
|
|
|
end
|
2006-02-14 20:50:57 +00:00
|
|
|
end
|
2007-02-24 09:01:43 +00:00
|
|
|
|
2007-07-17 20:08:21 +00:00
|
|
|
@verbose = false
|
2007-02-24 09:01:43 +00:00
|
|
|
options = cmdline
|
|
|
|
|
readconfig
|
|
|
|
|
options["-l"].nil? || listpodcasts
|
|
|
|
|
if options["-p"].nil?
|
|
|
|
|
getcasts
|
|
|
|
|
else
|
|
|
|
|
getcasts(options["-p"])
|
|
|
|
|
end
|