ripdiru 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -1
- data/bin/ripdiru +2 -153
- data/lib/ripdiru/version.rb +1 -1
- data/lib/ripdiru.rb +151 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -42,7 +42,7 @@ Recommended to install the following:
|
|
42
42
|
|
43
43
|
- [matchy2 (MACHIDA Hideki)](https://github.com/matchy2), for the shell script to rip Radiru\*Radiru https://gist.github.com/5310409.git
|
44
44
|
|
45
|
-
- [miyagawa (Tatsuhiko Miyagawa)](https://github.com/miyagawa/), for
|
45
|
+
- [miyagawa (Tatsuhiko Miyagawa)](https://github.com/miyagawa/), for [ripdiko](https://github.com/miyagawa/ripdiko), from which I shamelessly copy-pasted most of the code.
|
46
46
|
|
47
47
|
- [riocampos](https://github.com/riocampos/), for all the research published on the [blog](http://d.hatena.ne.jp/riocampos+tech/)
|
48
48
|
|
data/bin/ripdiru
CHANGED
@@ -1,154 +1,3 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
|
4
|
-
require 'nokogiri'
|
5
|
-
require 'uri'
|
6
|
-
require 'pathname'
|
7
|
-
require 'base64'
|
8
|
-
require 'open-uri'
|
9
|
-
require 'date'
|
10
|
-
require 'fileutils'
|
11
|
-
|
12
|
-
class DownloadTask
|
13
|
-
|
14
|
-
PLAYER_URL = "http://www3.nhk.or.jp/netradio/files/swf/rtmpe.swf"
|
15
|
-
TMPDIR = ENV['TMPDIR'] || '/tmp'
|
16
|
-
|
17
|
-
attr_accessor :station, :cache, :buffer, :outdir, :bitrate
|
18
|
-
|
19
|
-
def initialize(station = nil, duration = 1800, *args)
|
20
|
-
unless station
|
21
|
-
abort "Usage: ripdiru [station-id]"
|
22
|
-
end
|
23
|
-
@station = station
|
24
|
-
@channel = channel
|
25
|
-
@duration = duration
|
26
|
-
@cache = CacheDir.new(TMPDIR)
|
27
|
-
@buffer = ENV['RIPDIRU_BUFFER'] || 60
|
28
|
-
@outdir = ENV['RIPDIRU_OUTDIR'] || "#{ENV['HOME']}/Music/Radiru"
|
29
|
-
@bitrate = ENV['RIPDIRU_BITRATE'] || '48k'
|
30
|
-
end
|
31
|
-
|
32
|
-
def channel
|
33
|
-
case station
|
34
|
-
when "NHK1"
|
35
|
-
@rtmp="rtmpe://netradio-r1-flash.nhk.jp"
|
36
|
-
@playpath="NetRadio_R1_flash@63346"
|
37
|
-
@xmlpath="http://cgi4.nhk.or.jp/hensei/api/sche-nr.cgi?tz=all&ch=netr1"
|
38
|
-
when "NHK2"
|
39
|
-
@rtmp="rtmpe://netradio-r2-flash.nhk.jp"
|
40
|
-
@playpath="NetRadio_R2_flash@63342"
|
41
|
-
@xmlpath="http://cgi4.nhk.or.jp/hensei/api/sche-nr.cgi?tz=all&ch=netr2"
|
42
|
-
when "FM"
|
43
|
-
@rtmp="rtmpe://netradio-fm-flash.nhk.jp"
|
44
|
-
@playpath="NetRadio_FM_flash@63343"
|
45
|
-
@xmlpath="http://cgi4.nhk.or.jp/hensei/api/sche-nr.cgi?tz=all&ch=netfm"
|
46
|
-
else
|
47
|
-
puts "invalid channel"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def val(node, xpath)
|
52
|
-
node.xpath(".//#{xpath}").text
|
53
|
-
end
|
54
|
-
|
55
|
-
def parse_time(str)
|
56
|
-
DateTime.strptime("#{str}+0900", "%Y-%m-%d %H:%M:%S%Z").to_time
|
57
|
-
end
|
58
|
-
|
59
|
-
def now_playing(station)
|
60
|
-
today = Date.today
|
61
|
-
now = Time.now
|
62
|
-
doc = Nokogiri::XML(open(@xmlpath))
|
63
|
-
|
64
|
-
node = doc.xpath("//program").first
|
65
|
-
node.xpath(".//item").each do |item|
|
66
|
-
from, to = parse_time(val(item, "starttime")), parse_time(val(item, "endtime"))
|
67
|
-
start_time = now.to_i + buffer
|
68
|
-
if from.to_i <= start_time && start_time < to.to_i
|
69
|
-
return Program.new(
|
70
|
-
id: now.strftime("%Y%m%d%H%M%S") + "-#{station}",
|
71
|
-
station: station,
|
72
|
-
title: val(item, "title"),
|
73
|
-
from: from,
|
74
|
-
to: to,
|
75
|
-
duration: to.to_i - from.to_i,
|
76
|
-
info: val(item, "link"),
|
77
|
-
)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def run
|
83
|
-
program = now_playing(station)
|
84
|
-
|
85
|
-
duration = program.recording_duration + buffer
|
86
|
-
|
87
|
-
tempfile = "#{TMPDIR}/#{program.id}.mp3"
|
88
|
-
puts "Streaming #{program.title} ~ #{program.to.strftime("%H:%M")} (#{duration}s)"
|
89
|
-
puts "Ripping audio file to #{tempfile}"
|
90
|
-
|
91
|
-
command = %W(
|
92
|
-
rtmpdump --live --quiet
|
93
|
-
-r #{@rtmp}
|
94
|
-
--playpath #{@playpath}
|
95
|
-
--app "live"
|
96
|
-
-W #{PLAYER_URL}
|
97
|
-
--live --stop #{duration} -o - |
|
98
|
-
ffmpeg -y -i - -vn
|
99
|
-
-loglevel error
|
100
|
-
-metadata author="NHK"
|
101
|
-
-metadata artist="#{program.station}"
|
102
|
-
-metadata title="#{program.title} #{program.effective_date.strftime}"
|
103
|
-
-metadata album="#{program.title}"
|
104
|
-
-metadata genre=Radio
|
105
|
-
-metadata year="#{program.effective_date.year}"
|
106
|
-
-acodec libmp3lame -ar 44100 -ab #{bitrate} -ac 2
|
107
|
-
-id3v2_version 3
|
108
|
-
#{tempfile}
|
109
|
-
)
|
110
|
-
|
111
|
-
system command.join(" ")
|
112
|
-
|
113
|
-
FileUtils.mkpath(outdir)
|
114
|
-
File.rename tempfile, "#{outdir}/#{program.id}.mp3"
|
115
|
-
|
116
|
-
end
|
117
|
-
|
118
|
-
def abort(msg)
|
119
|
-
puts msg
|
120
|
-
exit 1
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
class Program
|
125
|
-
attr_accessor :id, :station, :title, :from, :to, :duration, :info
|
126
|
-
def initialize(args = {})
|
127
|
-
args.each do |k, v|
|
128
|
-
send "#{k}=", v
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def effective_date
|
133
|
-
time = from.hour < 5 ? from - 24 * 60 * 60 : from
|
134
|
-
Date.new(time.year, time.month, time.day)
|
135
|
-
end
|
136
|
-
|
137
|
-
def recording_duration
|
138
|
-
(to - Time.now).to_i
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
class CacheDir
|
143
|
-
attr_accessor :dir
|
144
|
-
def initialize(dir)
|
145
|
-
@dir = dir
|
146
|
-
@paths = {}
|
147
|
-
end
|
148
|
-
|
149
|
-
def [](name)
|
150
|
-
@paths[name] ||= Pathname.new(File.join(@dir, name))
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
DownloadTask.new(*ARGV).run
|
2
|
+
require "ripdiru"
|
3
|
+
Ripdiru::DownloadTask.new(*ARGV).run
|
data/lib/ripdiru/version.rb
CHANGED
data/lib/ripdiru.rb
CHANGED
@@ -1,5 +1,155 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
1
3
|
require "ripdiru/version"
|
4
|
+
require 'net/https'
|
5
|
+
require 'nokogiri'
|
6
|
+
require 'uri'
|
7
|
+
require 'pathname'
|
8
|
+
require 'base64'
|
9
|
+
require 'open-uri'
|
10
|
+
require 'date'
|
11
|
+
require 'fileutils'
|
2
12
|
|
3
13
|
module Ripdiru
|
4
|
-
|
14
|
+
class DownloadTask
|
15
|
+
|
16
|
+
PLAYER_URL = "http://www3.nhk.or.jp/netradio/files/swf/rtmpe.swf"
|
17
|
+
TMPDIR = ENV['TMPDIR'] || '/tmp'
|
18
|
+
|
19
|
+
attr_accessor :station, :cache, :buffer, :outdir, :bitrate
|
20
|
+
|
21
|
+
def initialize(station = nil, duration = 1800, *args)
|
22
|
+
unless station
|
23
|
+
abort "Usage: ripdiru [station-id]"
|
24
|
+
end
|
25
|
+
@station = station
|
26
|
+
@channel = channel
|
27
|
+
@duration = duration
|
28
|
+
@cache = CacheDir.new(TMPDIR)
|
29
|
+
@buffer = ENV['RIPDIRU_BUFFER'] || 60
|
30
|
+
@outdir = ENV['RIPDIRU_OUTDIR'] || "#{ENV['HOME']}/Music/Radiru"
|
31
|
+
@bitrate = ENV['RIPDIRU_BITRATE'] || '48k'
|
32
|
+
end
|
33
|
+
|
34
|
+
def channel
|
35
|
+
case station
|
36
|
+
when "NHK1"
|
37
|
+
@rtmp="rtmpe://netradio-r1-flash.nhk.jp"
|
38
|
+
@playpath="NetRadio_R1_flash@63346"
|
39
|
+
@xmlpath="http://cgi4.nhk.or.jp/hensei/api/sche-nr.cgi?tz=all&ch=netr1"
|
40
|
+
when "NHK2"
|
41
|
+
@rtmp="rtmpe://netradio-r2-flash.nhk.jp"
|
42
|
+
@playpath="NetRadio_R2_flash@63342"
|
43
|
+
@xmlpath="http://cgi4.nhk.or.jp/hensei/api/sche-nr.cgi?tz=all&ch=netr2"
|
44
|
+
when "FM"
|
45
|
+
@rtmp="rtmpe://netradio-fm-flash.nhk.jp"
|
46
|
+
@playpath="NetRadio_FM_flash@63343"
|
47
|
+
@xmlpath="http://cgi4.nhk.or.jp/hensei/api/sche-nr.cgi?tz=all&ch=netfm"
|
48
|
+
else
|
49
|
+
puts "invalid channel"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def val(node, xpath)
|
54
|
+
node.xpath(".//#{xpath}").text
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_time(str)
|
58
|
+
DateTime.strptime("#{str}+0900", "%Y-%m-%d %H:%M:%S%Z").to_time
|
59
|
+
end
|
60
|
+
|
61
|
+
def now_playing(station)
|
62
|
+
today = Date.today
|
63
|
+
now = Time.now
|
64
|
+
doc = Nokogiri::XML(open(@xmlpath))
|
65
|
+
|
66
|
+
node = doc.xpath("//program").first
|
67
|
+
node.xpath(".//item").each do |item|
|
68
|
+
from, to = parse_time(val(item, "starttime")), parse_time(val(item, "endtime"))
|
69
|
+
start_time = now.to_i + buffer
|
70
|
+
if from.to_i <= start_time && start_time < to.to_i
|
71
|
+
return Program.new(
|
72
|
+
id: now.strftime("%Y%m%d%H%M%S") + "-#{station}",
|
73
|
+
station: station,
|
74
|
+
title: val(item, "title"),
|
75
|
+
from: from,
|
76
|
+
to: to,
|
77
|
+
duration: to.to_i - from.to_i,
|
78
|
+
info: val(item, "link"),
|
79
|
+
)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def run
|
85
|
+
program = now_playing(station)
|
86
|
+
|
87
|
+
duration = program.recording_duration + buffer
|
88
|
+
|
89
|
+
tempfile = "#{TMPDIR}/#{program.id}.mp3"
|
90
|
+
puts "Streaming #{program.title} ~ #{program.to.strftime("%H:%M")} (#{duration}s)"
|
91
|
+
puts "Ripping audio file to #{tempfile}"
|
92
|
+
|
93
|
+
command = %W(
|
94
|
+
rtmpdump --live --quiet
|
95
|
+
-r #{@rtmp}
|
96
|
+
--playpath #{@playpath}
|
97
|
+
--app "live"
|
98
|
+
-W #{PLAYER_URL}
|
99
|
+
--live --stop #{duration} -o - |
|
100
|
+
ffmpeg -y -i - -vn
|
101
|
+
-loglevel error
|
102
|
+
-metadata author="NHK"
|
103
|
+
-metadata artist="#{program.station}"
|
104
|
+
-metadata title="#{program.title} #{program.effective_date.strftime}"
|
105
|
+
-metadata album="#{program.title}"
|
106
|
+
-metadata genre=Radio
|
107
|
+
-metadata year="#{program.effective_date.year}"
|
108
|
+
-acodec libmp3lame -ar 44100 -ab #{bitrate} -ac 2
|
109
|
+
-id3v2_version 3
|
110
|
+
#{tempfile}
|
111
|
+
)
|
112
|
+
|
113
|
+
system command.join(" ")
|
114
|
+
|
115
|
+
FileUtils.mkpath(outdir)
|
116
|
+
File.rename tempfile, "#{outdir}/#{program.id}.mp3"
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
def abort(msg)
|
121
|
+
puts msg
|
122
|
+
exit 1
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class Program
|
127
|
+
attr_accessor :id, :station, :title, :from, :to, :duration, :info
|
128
|
+
def initialize(args = {})
|
129
|
+
args.each do |k, v|
|
130
|
+
send "#{k}=", v
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def effective_date
|
135
|
+
time = from.hour < 5 ? from - 24 * 60 * 60 : from
|
136
|
+
Date.new(time.year, time.month, time.day)
|
137
|
+
end
|
138
|
+
|
139
|
+
def recording_duration
|
140
|
+
(to - Time.now).to_i
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class CacheDir
|
145
|
+
attr_accessor :dir
|
146
|
+
def initialize(dir)
|
147
|
+
@dir = dir
|
148
|
+
@paths = {}
|
149
|
+
end
|
150
|
+
|
151
|
+
def [](name)
|
152
|
+
@paths[name] ||= Pathname.new(File.join(@dir, name))
|
153
|
+
end
|
154
|
+
end
|
5
155
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ripdiru
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-10-
|
12
|
+
date: 2013-10-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|