anstaendig 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +7 -0
- data/bin/anstaendig +114 -0
- data/lib/anstaendig/abstractagent.rb +48 -0
- data/lib/anstaendig/agents/3sat.rb +31 -0
- data/lib/anstaendig/agents/ard.rb +49 -0
- data/lib/anstaendig/agents/arte.rb +49 -0
- data/lib/anstaendig/agents/zdf.rb +47 -0
- data/lib/anstaendig.rb +11 -0
- metadata +74 -0
data/README.rdoc
ADDED
data/bin/anstaendig
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Script to download videos from various streaming sites.
|
4
|
+
#
|
5
|
+
# Author:: henning mueller (mailto:henning@orgizm.net)
|
6
|
+
# Copyright:: Copyright (c) 2010 henning mueller
|
7
|
+
# License:: Beerware
|
8
|
+
|
9
|
+
require( 'uri' )
|
10
|
+
require( 'getoptlong' )
|
11
|
+
|
12
|
+
# Add source lib directory to include paths for require to work if anstaendig
|
13
|
+
# not installed as a gem.
|
14
|
+
$:.unshift( File.dirname( __FILE__ ) + '/../lib' )
|
15
|
+
require( 'anstaendig' )
|
16
|
+
include( Anstaendig )
|
17
|
+
|
18
|
+
# Shows a summary of the command line options.
|
19
|
+
def usageMessage
|
20
|
+
$stderr << "#{File.basename( $0 )} [options] <url>
|
21
|
+
Download videos from video streaming sites.
|
22
|
+
|
23
|
+
-h This help.
|
24
|
+
-l List available agents.
|
25
|
+
-m Keep mess (do not clean up on Interrupt).
|
26
|
+
-o name File to save the video to.
|
27
|
+
-q quality Quality of the video.
|
28
|
+
-r Recode to Theora/Vorbis.
|
29
|
+
-s Only show stream URL.
|
30
|
+
|
31
|
+
"
|
32
|
+
exit( 1 )
|
33
|
+
end
|
34
|
+
|
35
|
+
# Prints available download agents.
|
36
|
+
def listAgents
|
37
|
+
puts( AGENTS.keys.sort )
|
38
|
+
exit( 0 )
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns a new filename, if the desired one is taken.
|
42
|
+
def nextFilename( filename )
|
43
|
+
if( File.exists?( filename ) )
|
44
|
+
new = filename.insert( filename.index( /\./, -5 ), '.new' )
|
45
|
+
nextFilename( new )
|
46
|
+
else
|
47
|
+
return( filename )
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
options = GetoptLong.new(
|
52
|
+
[ '-h', GetoptLong::NO_ARGUMENT ],
|
53
|
+
[ '-l', GetoptLong::NO_ARGUMENT ],
|
54
|
+
[ '-m', GetoptLong::NO_ARGUMENT ],
|
55
|
+
[ '-o', GetoptLong::REQUIRED_ARGUMENT ],
|
56
|
+
[ '-q', GetoptLong::REQUIRED_ARGUMENT ],
|
57
|
+
[ '-r', GetoptLong::NO_ARGUMENT ],
|
58
|
+
[ '-s', GetoptLong::NO_ARGUMENT ]
|
59
|
+
)
|
60
|
+
|
61
|
+
saveAs = ""
|
62
|
+
quality = :default
|
63
|
+
cleanUp = true
|
64
|
+
recodeOGG, showStreamURL = false
|
65
|
+
|
66
|
+
options.each do |option, argument|
|
67
|
+
case( option )
|
68
|
+
when '-h'
|
69
|
+
usageMessage
|
70
|
+
when '-l'
|
71
|
+
listAgents
|
72
|
+
when '-m'
|
73
|
+
cleanUp = false
|
74
|
+
when '-o'
|
75
|
+
saveAs = argument
|
76
|
+
when '-q'
|
77
|
+
quality = argument.to_sym
|
78
|
+
when '-r'
|
79
|
+
recodeOGG = true
|
80
|
+
when '-s'
|
81
|
+
showStreamURL = true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
begin
|
86
|
+
uri = URI.parse( ARGV[0] )
|
87
|
+
rescue URI::InvalidURIError
|
88
|
+
usageMessage
|
89
|
+
end
|
90
|
+
|
91
|
+
agent = AGENTS[ uri.host ].new( uri, quality )
|
92
|
+
|
93
|
+
if( showStreamURL )
|
94
|
+
puts( agent.url )
|
95
|
+
exit( 0 )
|
96
|
+
end
|
97
|
+
|
98
|
+
if( saveAs.empty? )
|
99
|
+
agent.filename = nextFilename( agent.filename )
|
100
|
+
else
|
101
|
+
agent.filename = saveAs
|
102
|
+
end
|
103
|
+
|
104
|
+
begin
|
105
|
+
agent.run
|
106
|
+
rescue Interrupt
|
107
|
+
if( cleanUp and File.exists?( agent.filename ) )
|
108
|
+
File.unlink( agent.filename )
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
if( recodeOGG )
|
113
|
+
agent.recode
|
114
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Anstaendig
|
2
|
+
AGENTS = Hash.new
|
3
|
+
|
4
|
+
# This interface describes download agents.
|
5
|
+
class AbstractAgent
|
6
|
+
attr_accessor :filename, :url
|
7
|
+
|
8
|
+
# Exception should be thrown, if an non-existent quality is demanded
|
9
|
+
# by the user.
|
10
|
+
class NoSuchQualityException
|
11
|
+
end
|
12
|
+
|
13
|
+
# If an agent does not set @filename, it would be the current time
|
14
|
+
# and date.
|
15
|
+
def initialize( url, quality = :high )
|
16
|
+
@filename = Time.now.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
# Calls the ripping process after substitution of certain characters
|
20
|
+
# in the filename generated by the agent.
|
21
|
+
def run
|
22
|
+
[ '/', '"', "'" ].each do |char|
|
23
|
+
@filename.gsub!( char, '' )
|
24
|
+
end
|
25
|
+
|
26
|
+
rip
|
27
|
+
end
|
28
|
+
|
29
|
+
# Contains the subshell command to rip the video stream. mplayer by
|
30
|
+
# default. Meant to be overloaded by the agent if necessary.
|
31
|
+
def rip
|
32
|
+
`mplayer -user-agent "#{userAgent}" -dumpstream -dumpfile "#{@filename}" "#{@url}"`
|
33
|
+
end
|
34
|
+
|
35
|
+
# Contains the subshell command to recode the video to a Vorbis/Theora
|
36
|
+
# encoded video in an OGG container. Meant to be overloaded by the
|
37
|
+
# agent if necessary.
|
38
|
+
def recode
|
39
|
+
`ffmpeg -i "#{@filename}" -acodec libvorbis -vcodec libtheora "#{@filename}.ogg"`
|
40
|
+
end
|
41
|
+
|
42
|
+
# Return the user agent which is sent on stream retrieval. Meant to be
|
43
|
+
# overloaded by the agent if necessary.
|
44
|
+
def userAgent
|
45
|
+
"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.2) Gecko/20100323 Namoroka/3.6.2"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Anstaendig
|
2
|
+
# Agent for anstaendig to download videos from the 3sat media center.
|
3
|
+
#
|
4
|
+
# Author:: henning mueller (mailto:henning@orgizm.net)
|
5
|
+
# Copyright:: Copyright (c) 2010 henning mueller
|
6
|
+
# License:: Beerware
|
7
|
+
|
8
|
+
# 3sat agent class inherits from agent interface.
|
9
|
+
class DreiSatAgent < AbstractAgent
|
10
|
+
AGENTS[ 'www.3sat.de' ] = self
|
11
|
+
|
12
|
+
def initialize( uri, quality )
|
13
|
+
require( 'nokogiri' )
|
14
|
+
require( 'open-uri' )
|
15
|
+
require( 'iconv' )
|
16
|
+
|
17
|
+
uri.query += '&mode=play'
|
18
|
+
|
19
|
+
doc = Nokogiri::HTML( open( uri.to_s ) )
|
20
|
+
|
21
|
+
title = doc.xpath( '//title' ).inner_html
|
22
|
+
title = title.gsub!( '3sat.Mediathek - Video: ', '' ) + '.wmv'
|
23
|
+
|
24
|
+
asx = doc.xpath( '//embed[@id="Player2"]' ).attr( 'data' )
|
25
|
+
asx = Nokogiri::HTML( open( asx ) )
|
26
|
+
|
27
|
+
@filename = Iconv.conv( 'utf8', 'latin1', title )
|
28
|
+
@url = asx.xpath( '//ref' ).attr( 'href' )
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Anstaendig
|
2
|
+
# Agent for anstaendig to download videos from the ARD media center.
|
3
|
+
#
|
4
|
+
# Author:: henning mueller (mailto:henning@orgizm.net)
|
5
|
+
# Copyright:: Copyright (c) 2010 henning mueller
|
6
|
+
# License:: Beerware
|
7
|
+
|
8
|
+
# ARD agent class inherits from agent interface.
|
9
|
+
class ArdAgent < AbstractAgent
|
10
|
+
AGENTS[ 'www.ardmediathek.de' ] = self
|
11
|
+
|
12
|
+
def initialize( uri, quality )
|
13
|
+
require( 'nokogiri' )
|
14
|
+
require( 'open-uri' )
|
15
|
+
|
16
|
+
doc = Nokogiri::HTML( open( uri.to_s ) )
|
17
|
+
raw = doc.content.split( "\r\n" ).grep( /rtmp/ )
|
18
|
+
|
19
|
+
@url = case( quality )
|
20
|
+
when :high, :default
|
21
|
+
conjure( raw.last )
|
22
|
+
when :medium
|
23
|
+
begin
|
24
|
+
conjure( raw[1] )
|
25
|
+
rescue( NoMethodError )
|
26
|
+
raise( NoSuchQualityException )
|
27
|
+
end
|
28
|
+
when :low
|
29
|
+
conjure( raw.first )
|
30
|
+
else
|
31
|
+
raise( NoSuchQualityException )
|
32
|
+
end
|
33
|
+
|
34
|
+
title = doc.xpath( '//title' ).inner_text
|
35
|
+
title = title.gsub( 'ARD Mediathek: ', '' )
|
36
|
+
n = title.index( /\ -\ [A-Za-z]*,/ ) - 1
|
37
|
+
|
38
|
+
@filename = title[0..n] + '.flv'
|
39
|
+
end
|
40
|
+
|
41
|
+
def conjure( string )
|
42
|
+
a = string.index( '"' ) + 1
|
43
|
+
b = string.index( '", "' ) - 1
|
44
|
+
c = string.index( '")' ) - 1
|
45
|
+
|
46
|
+
string.slice( a..b ) + string.slice( b+5..c )
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Anstaendig
|
2
|
+
# Agent for anstaendig to download videos from the arte media center.
|
3
|
+
#
|
4
|
+
# Author:: henning mueller (mailto:henning@orgizm.net)
|
5
|
+
# Copyright:: Copyright (c) 2010 henning mueller
|
6
|
+
# License:: Beerware
|
7
|
+
|
8
|
+
#
|
9
|
+
# TODO
|
10
|
+
# This extracts the correct filename and url, but the stream ripping dies
|
11
|
+
# somehow after a few minutes.
|
12
|
+
#
|
13
|
+
|
14
|
+
# arte agent class inherits from agent interface.
|
15
|
+
class ArteAgent < AbstractAgent
|
16
|
+
AGENTS[ 'videos.arte.tv' ] = self
|
17
|
+
|
18
|
+
def initialize( uri, quality )
|
19
|
+
require( 'nokogiri' )
|
20
|
+
require( 'open-uri' )
|
21
|
+
|
22
|
+
lang = ENV['LANG'].slice(0..1)
|
23
|
+
|
24
|
+
doc = open( uri.to_s ).readlines
|
25
|
+
|
26
|
+
doc = Nokogiri::XML( open(
|
27
|
+
doc.grep( /vars_player\.videorefFileUrl/ )
|
28
|
+
.first.match( /(http.*xml)/ )[1]
|
29
|
+
))
|
30
|
+
|
31
|
+
doc.xpath( '//videos/video' ).each do |item|
|
32
|
+
if( item.attr( 'lang' ) == lang )
|
33
|
+
doc = Nokogiri::XML( open( item.attr( 'ref' ) ) )
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
@filename = doc.xpath( '//name' ).first.text + '.wmv'
|
38
|
+
|
39
|
+
case( quality )
|
40
|
+
when :hd, :high, :default
|
41
|
+
@url = doc.xpath( '//urls/url[@quality="hd"]' ).text
|
42
|
+
when :sd, :medium, :low
|
43
|
+
@url = doc.xpath( '//urls/url[@quality="sd"]' ).text
|
44
|
+
else
|
45
|
+
raise( NoSuchQualityException )
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Anstaendig
|
2
|
+
# Agent for anstaendig to download videos from the ZDF media center.
|
3
|
+
#
|
4
|
+
# Author:: henning mueller (mailto:henning@orgizm.net)
|
5
|
+
# Copyright:: Copyright (c) 2010 henning mueller
|
6
|
+
# License:: Beerware
|
7
|
+
|
8
|
+
# ZDF agent class inherits from agent interface.
|
9
|
+
class ZdfAgent < AbstractAgent
|
10
|
+
AGENTS[ 'www.zdf.de' ] = self
|
11
|
+
|
12
|
+
def initialize( uri, quality )
|
13
|
+
require( 'nokogiri' )
|
14
|
+
require( 'open-uri' )
|
15
|
+
|
16
|
+
uri = uri.to_s
|
17
|
+
|
18
|
+
if( uri =~ /hauptnavigation\/startseite\/#/ )
|
19
|
+
uri.gsub!( 'hauptnavigation/startseite/#/', '' )
|
20
|
+
end
|
21
|
+
|
22
|
+
doc = Nokogiri::HTML( open( uri ) )
|
23
|
+
|
24
|
+
quality = case( quality )
|
25
|
+
when :high, :default
|
26
|
+
'/veryhigh/'
|
27
|
+
when :medium, :low
|
28
|
+
'/300/'
|
29
|
+
else
|
30
|
+
raise( NoSuchQualityException )
|
31
|
+
end
|
32
|
+
|
33
|
+
doc.xpath( '//a[@class="play"]' ).each do |temp|
|
34
|
+
temp = temp.attribute( 'href' ).to_s
|
35
|
+
if( temp.include?( quality ) and temp.include?( '.asx' ) )
|
36
|
+
uri = temp
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
@filename = doc.xpath( '//h1[@class="beitragHeadline"]' ).inner_text + '.wmv'
|
41
|
+
|
42
|
+
doc = Nokogiri::HTML( open( uri ) )
|
43
|
+
# @url = doc.xpath( '//ref' ).attr( 'href' )
|
44
|
+
@url = doc.to_s.match( /(mms.*wmv)/ )[0]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/anstaendig.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
$:.unshift( File.dirname( __FILE__ ) )
|
2
|
+
|
3
|
+
# The Anstaendig module includes an abstract agent class and all agents
|
4
|
+
# implementing this.
|
5
|
+
module Anstaendig
|
6
|
+
VERSION = '0.1.0'
|
7
|
+
end
|
8
|
+
|
9
|
+
Dir.glob( $:.first + '/**/*.rb' ).sort.each do |file|
|
10
|
+
require( file )
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: anstaendig
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- henning mueller
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-05-31 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: anstaendig is a extendable script to rip movie clips from TV station media center sites.
|
23
|
+
email: henning@orgizm.net
|
24
|
+
executables:
|
25
|
+
- anstaendig
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- bin/anstaendig
|
32
|
+
- lib/anstaendig.rb
|
33
|
+
- lib/anstaendig/agents/zdf.rb
|
34
|
+
- lib/anstaendig/agents/ard.rb
|
35
|
+
- lib/anstaendig/agents/3sat.rb
|
36
|
+
- lib/anstaendig/agents/arte.rb
|
37
|
+
- lib/anstaendig/abstractagent.rb
|
38
|
+
- README.rdoc
|
39
|
+
has_rdoc: true
|
40
|
+
homepage:
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
hash: 3
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 3
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.3.7
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Rip clips from TV station media center sites.
|
73
|
+
test_files: []
|
74
|
+
|