rget 4.8.4 → 4.10.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 03b7d1828386cb0e82ac5a74e638df84d09261e127ed70ab6d3d0b5ab8ab0e27
4
- data.tar.gz: 20ac0f562a4247470d0f805a3b6916c142089bc46ff93dc70ea83bf6a850e057
3
+ metadata.gz: 002a0d55ff230dabdb3c046e67cf09a56f28aae9bbbb44c3bd7de3a4490cc770
4
+ data.tar.gz: 33f86195c750fb5cad0f133fe199fc8a94fe65f6a5bae2b0eb372eb7a34aed6f
5
5
  SHA512:
6
- metadata.gz: 1ac0660ba7e663e31410fc9c5efa10d7700ae39e44605bab3a7be9b1981708ed41ee7611f5cab987830766eef8bc3433da777dcf76a4c20b90cb30708e69e36d
7
- data.tar.gz: 04a08917dfbd660f2ba2e1be0df9d9ac8af7bd611d42795a6a278fcc9eedcd30d32cf36ab2f5e732e359eccdeda2b4aa29a5677aa1e885f61ae083b1543a6928
6
+ metadata.gz: f144e5b3623c29342f278b22de551b3e535f8ce1a699d6454116718a4653bc4425b49ce3f4e8062cc98ca08e4940e6ce77462456161a99144008e9c5a36a7972
7
+ data.tar.gz: cf9a018da02a9651e554cff2237bebbe744aff02073799b10f02806fd55079e051fc123f2c79802694efc030682126b52eb2f128041d553468a8cdc6564a0e0b
@@ -0,0 +1,14 @@
1
+ FROM ruby:2
2
+ ENV USER vscode
3
+ LABEL maintainer "@tdtds <t@tdtds.jp>"
4
+ RUN apt-get -y update && apt-get -y install ffmpeg && \
5
+ curl -sLo /usr/local/bin/youtube-dl http://www.yt-dl.org/downloads/latest/youtube-dl && \
6
+ chmod +x /usr/local/bin/youtube-dl && \
7
+ useradd -u 1000 -m $USER && chsh -s /bin/bash $USER
8
+ USER $USER
9
+ RUN bundle config set path vendor/bundle && \
10
+ bundle config set with development:test && \
11
+ echo 'git config --global --unset core.editor' >> /home/$USER/.bashrc && \
12
+ echo 'git config --global --unset core.sshCommand' >> /home/$USER/.bashrc && \
13
+ echo 'git ls-remote -q > /dev/null' >> /home/$USER/.bashrc
14
+ CMD [ "sleep", "infinity" ]
@@ -0,0 +1,30 @@
1
+ // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
2
+ // https://github.com/microsoft/vscode-dev-containers/tree/v0.122.1/containers/docker-from-docker-compose
3
+ // If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
4
+ {
5
+ "name": "rget",
6
+ "context": "..",
7
+ "dockerFile": "Dockerfile",
8
+
9
+ // Set *default* container specific settings.json values on container create.
10
+ "settings": {
11
+ "terminal.integrated.shell.linux": "/bin/bash"
12
+ },
13
+
14
+ // Add the IDs of extensions you want installed when the container is created.
15
+ "extensions": [
16
+ "rebornix.ruby"
17
+ ],
18
+
19
+ // Uncomment the next line if you want start specific services in your Docker Compose config.
20
+ // "runServices": [],
21
+
22
+ // Uncomment the next line if you want to keep your containers running after VS Code shuts down.
23
+ // "shutdownAction": "none",
24
+
25
+ // Use 'postCreateCommand' to run commands after the container is created.
26
+ // "postCreateCommand": "docker --version",
27
+
28
+ // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
29
+ // "remoteUser": "vscode"
30
+ }
@@ -5,7 +5,7 @@ before_install:
5
5
  - gem install bundler -v '> 1.5.0'
6
6
 
7
7
  rvm:
8
- - 2.5.0
8
+ - 2.7.2
9
9
 
10
10
  deploy:
11
11
  provider: rubygems
data/README.md CHANGED
@@ -5,9 +5,9 @@ Downloading newest radio programs on the web. Supported radio stations are:
5
5
  * hibiki
6
6
  * onsen
7
7
  * niconico
8
- * freshlive.tv
9
8
  * himalaya.fm
10
- * Abobi Store
9
+ * Asobi Store
10
+ * stand.fm
11
11
 
12
12
  If you want to save files as MP3, needs `ffmpeg` command.
13
13
  To download niconico video, also needs latest `youtube-dl` command (you can get it from `https://yt-dl.org/`), then specify niconico user ID and password to `~/.netrc` as:
@@ -25,9 +25,10 @@ For customize radio programs, copy `rget.yaml` to `~/.rget` or current work dire
25
25
  * `~/.rget`
26
26
  * `<command path>/../rget.yaml` (for gem)
27
27
 
28
- ## Installation
28
+ ## Installation and Setup
29
29
  ```
30
30
  $ gem install rget
31
+ $ rget init > ~/.rget # or your local rget.yaml
31
32
  ```
32
33
 
33
34
  ## Usage
@@ -41,14 +42,14 @@ rget yaml http://example.com/radio >> ~/.rget
41
42
  # download and convert to mp3 THE iDOLM@STER Cinderella Girls Radio
42
43
  rget imas_cg
43
44
 
44
- # download takamori only (saving movie file as .MP4)
45
- rget takamori --no-mp3
45
+ # download suzakinishi only (saving movie file as .MP4)
46
+ rget suzakinishi --no-mp3
46
47
 
47
48
  # srore mp3 file to specified directory
48
- rget suzakinishi --path=/home/hoge/radio
49
+ rget matsui --path=/home/hoge/radio
49
50
 
50
51
  # store mp3 file to radio folder of Dropbox
51
- rget matsui --path=dropbpx://radio
52
+ rget shiny_radio --path=dropbpx://radio
52
53
  ```
53
54
 
54
55
  ### add\_mp3info command
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ require "open3"
3
+
4
+ if ARGV.size != 2
5
+ $stderr.puts "HLS downloader wrapping ffmpeg"
6
+ $stderr.puts "hls-dl <playlist.m3u8> <output(.mp4,mp3,...)>"
7
+ exit 1
8
+ end
9
+
10
+ ffmpeg = %Q[ffmpeg -loglevel error -protocol_whitelist file,http,https,tcp,tls,crypto -n -i "#{ARGV[0]}" #{ARGV[1]}]
11
+ result = Open3.capture3(ffmpeg)
12
+ unless result[2].to_i == 0
13
+ p result
14
+ File.delete(ARGV[1]) if File.exist?(ARGV[1])
15
+ $stderr.puts result[1]
16
+ exit(1)
17
+ end
18
+ exit(0)
@@ -10,9 +10,9 @@ class AsobiStore < WebRadio
10
10
 
11
11
  def download
12
12
  player = find_player(@url)
13
- html = Nokogiri(open("https:#{player}").read)
13
+ html = Nokogiri(URI.open("https:#{player}").read)
14
14
  src_m3u8 = html.css('source').first.attr('src')
15
- m3u8 = "#{File.dirname(src_m3u8)}/#{open(src_m3u8).read.match(/^[^#].*/)[0]}"
15
+ m3u8 = "#{File.dirname(src_m3u8)}/#{URI.open(src_m3u8).read.match(/^[^#].*/)[0]}"
16
16
 
17
17
  serial = html.title.scan(/#(\d+)/).flatten.first.to_i
18
18
  @cover = "https:#{html.css('audio,video').first.attr('poster')}" unless @cover
@@ -24,7 +24,7 @@ class AsobiStore < WebRadio
24
24
  agent.get(m3u8)
25
25
  body = agent.page.body
26
26
  rescue ArgumentError
27
- body = open(m3u8, &:read)
27
+ body = URI.open(m3u8, &:read)
28
28
  end
29
29
  tses = body.scan(/.*\.ts.*/)
30
30
  key_url = body.scan(/URI="(.*)"/).flatten.first
@@ -52,10 +52,10 @@ class AsobiStore < WebRadio
52
52
 
53
53
  private
54
54
  def find_player(url)
55
- programs = Nokogiri(open(url).read)
55
+ programs = Nokogiri(URI.open(url).read)
56
56
  programs.css('.list-main-product a.wrap').each do |program|
57
57
  begin
58
- return Nokogiri(open("https://asobistore.jp#{program.attr('href')}").read).css('iframe').last.attr('src')
58
+ return Nokogiri(URI.open("https://asobistore.jp#{program.attr('href')}").read).css('iframe').last.attr('src')
59
59
  rescue # access denied because only access by premium members
60
60
  next
61
61
  end
@@ -10,7 +10,7 @@ class FreshLive < WebRadio
10
10
  archive = URI(File.join(@url + '/programs/archive'))
11
11
  end
12
12
 
13
- each_programs(Nokogiri(open(archive).read)) do |meta|
13
+ each_programs(Nokogiri(URI.open(archive).read)) do |meta|
14
14
  begin
15
15
  serial = meta['data']['title'].scan(/\d+$/).first.to_i
16
16
  src = "#{@label}##{'%02d' % serial}.ts"
@@ -24,7 +24,7 @@ class FreshLive < WebRadio
24
24
  print "getting #{src}..."
25
25
  ts_list(meta['data']['archiveStreamUrl']).each_with_index do |u, i|
26
26
  print '.' if i % 50 == 0
27
- w.write(open(u, 'rb').read)
27
+ w.write(URI.open(u, 'rb').read)
28
28
  end
29
29
  end
30
30
  end
@@ -62,7 +62,7 @@ class FreshLive < WebRadio
62
62
  }
63
63
  else
64
64
  tag = Pathname(u.path).basename.to_s
65
- meta = JSON.parse(Nokogiri(open(@url, &:read)).css('script').first)
65
+ meta = JSON.parse(Nokogiri(URI.open(@url, &:read)).css('script').first)
66
66
  return {
67
67
  tag => {
68
68
  'desc' => meta['name'],
@@ -78,13 +78,13 @@ private
78
78
  x = "//section[descendant::h1[contains(text(),'アーカイブ')]]//*[contains(@class,'ProgramTitle')]/a/@href"
79
79
  html.xpath(x).each do |href|
80
80
  id = Pathname(href.value).basename.to_s
81
- yield JSON.parse(open("https://freshlive.tv/proxy/Programs;id=#{id}", &:read))
81
+ yield JSON.parse(URI.open("https://freshlive.tv/proxy/Programs;id=#{id}", &:read))
82
82
  end
83
83
  end
84
84
 
85
85
  def ts_list(rate_m3u8)
86
- ts_m3u8 = open(rate_m3u8).read.each_line.grep_v(/^#/)[1].chomp
87
- open(URI(rate_m3u8) + ts_m3u8).read.each_line.grep_v(/^#/).map{|u|URI(rate_m3u8) + u.chomp}
86
+ ts_m3u8 = URI.open(rate_m3u8).read.each_line.grep_v(/^#/)[1].chomp
87
+ URI.open(URI(rate_m3u8) + ts_m3u8).read.each_line.grep_v(/^#/).map{|u|URI(rate_m3u8) + u.chomp}
88
88
  end
89
89
 
90
90
  def to_mp3(src)
@@ -57,7 +57,9 @@ private
57
57
  playlist_url = video_info[:playlist_url]
58
58
  m3u8_url = URI(agent.get(playlist_url).body.scan(/http.*/).flatten.first)
59
59
 
60
- m3u8 = agent.get(m3u8_url).body.split("EXT-X-KEY").last
60
+ # choice the max size element from multi-part m3u8 file
61
+ m3u8 = agent.get(m3u8_url).body.split("EXT-X-KEY").sort{|m,n|m.size <=> n.size}.last
62
+
61
63
  key_url = m3u8.scan(/URI="(.*)"/).flatten.first
62
64
 
63
65
  tses = m3u8.scan(/^.*ts_.*\.ts/)
@@ -8,7 +8,7 @@ class Himalaya < WebRadio
8
8
  end
9
9
 
10
10
  def download
11
- html = open(@url).read
11
+ html = URI.open(@url).read
12
12
  json_str = html.scan(/__NEXT_DATA__ = (.*)/).flatten.first
13
13
  json = JSON.parse(json_str)
14
14
  tracks = json['props']['seo']['albumData']['data']['tracks']['list']
@@ -22,7 +22,7 @@ class Himalaya < WebRadio
22
22
  mp3_file = "#{@label}##{serial}.mp3"
23
23
  mp3nize(m4a_file, mp3_file) do
24
24
  open(m4a_file, 'wb:ASCII-8BIT') do |m4a|
25
- m4a.write(open(m4a_url).read)
25
+ m4a.write(URI.open(m4a_url).read)
26
26
  end
27
27
  end
28
28
  end
@@ -0,0 +1,19 @@
1
+ require 'webradio'
2
+ require 'open3'
3
+
4
+ class HLS < WebRadio
5
+ private
6
+ def hls_download(name, serial, m3u_meta)
7
+ mp4_file = "#{name}##{serial}.mp4"
8
+ mp3_file = "#{name}##{serial}.mp3"
9
+ m3u = URI.open(m3u_meta, &:read).scan(/^[^#].*/).first
10
+ m3u = Pathname(m3u_meta).dirname.join(m3u) if Pathname(m3u).relative?
11
+ mp3nize(mp4_file, mp3_file) do
12
+ result = Open3.capture3(%Q[ffmpeg -loglevel error -protocol_whitelist file,http,https,tcp,tls,crypto -i "#{m3u}" "#{mp4_file}"])
13
+ unless result[2].to_i == 0
14
+ raise WebRadio::DownloadError.new("failed download the radio program (#{@label}).")
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -39,7 +39,7 @@ class Nicovideo < WebRadio
39
39
  _, err, status = Open3.capture3("youtube-dl -f mp4 -o #{@file} --netrc #{video.url}")
40
40
  break if status == 0
41
41
  next if err =~ /403: Forbidden/
42
- raise ForbiddenError.new("Could not access to #{video.url}") if err =~ /TypeError/
42
+ raise ForbiddenError.new("Could not access to #{video.url}") if err =~ /TypeError|AssertionError/
43
43
  raise DownloadError.new(err)
44
44
  end
45
45
  end
@@ -74,11 +74,11 @@ private
74
74
  video_url = nil
75
75
  begin
76
76
  begin
77
- rss = RSS::Parser.parse(open(list_url).read)
77
+ rss = RSS::Parser.parse(URI.open(list_url).read)
78
78
  item = rss.items[offset]
79
79
  video_url = item.link
80
80
  rescue RSS::NotWellFormedError
81
- html = open(list_url, &:read)
81
+ html = URI.open(list_url, &:read)
82
82
  url = html.scan(%r|/watch/[\w]+|)[offset]
83
83
  raise WebRadio::DownloadError.new('video not found in this pege') unless url
84
84
  video_url = "http://www.nicovideo.jp#{url}"
@@ -93,7 +93,7 @@ private
93
93
  end
94
94
 
95
95
  def thumbinfo(video, elem = nil)
96
- xml = open("http://ext.nicovideo.jp/api/getthumbinfo/#{video.id}").read
96
+ xml = URI.open("http://ext.nicovideo.jp/api/getthumbinfo/#{video.id}").read
97
97
  if elem
98
98
  return xml.scan(%r|<#{elem}>(.*)</#{elem}>|m).flatten.first
99
99
  else
@@ -1,22 +1,26 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'webradio'
3
+ require 'hls'
4
4
  require 'nokogiri'
5
+ require 'json'
5
6
 
6
- class Onsen < WebRadio
7
+ class Onsen < HLS
7
8
  def initialize(params, options)
8
9
  super
9
- @cover = "//*[@id='newProgramWrap']//img[1]/@src" unless @cover
10
+ @cover = "//*[@class='newest-content--left']//img[1]/@src" unless @cover
10
11
  end
11
12
 
12
13
  def download
13
- onsen_download(@label, @url.scan(%r|/([^/]*)/$|).flatten.first)
14
+ html = URI.open(@url, &:read)
15
+ serial = Nokogiri(html).css('.play-video-info td')[0].text.scan(/\d+/)[0].to_i
16
+ m3u8 = JSON.parse(html.scan(%r|streaming_url:("https:.*?.m3u8")|).flatten.sort.last)
17
+ hls_download(@label, serial, m3u8)
14
18
  end
15
19
 
16
20
  def dump
17
21
  tag = Pathname(@url).basename.to_s.gsub(%r|[-/]|, '_')
18
- html = Nokogiri(open(@url, &:read))
19
- title = html.css('#outLineWrap h1').text
22
+ html = Nokogiri(URI.open(@url, &:read))
23
+ title = html.css('h3')[0].text
20
24
  return {
21
25
  tag => {
22
26
  'desc' => title,
@@ -25,24 +29,4 @@ class Onsen < WebRadio
25
29
  }
26
30
  }
27
31
  end
28
-
29
- private
30
- def onsen_download(name, program_id)
31
- html = Nokogiri(open('http://onsen.ag/', 'User-Agent' => 'iPhone', &:read))
32
- begin
33
- serial = html.css("##{program_id}").text.scan(/#(\d+)/).flatten.first
34
- mp3_url = html.css('form[target=_self]').select {|form|
35
- form.attr('action') =~ %r|/#{program_id}\w+\.mp[34]|
36
- }.first.attr('action')
37
- rescue NoMethodError
38
- raise NotFoundError.new("no radio program in #{program_id}.")
39
- end
40
- src_file = "#{name}##{serial}#{mp3_url.scan(/\.mp[34]$/).first}"
41
- mp3_file = "#{name}##{serial}.mp3"
42
- mp3nize(src_file, mp3_file, false) do
43
- open(src_file, 'wb:ASCII-8BIT') do |mp3|
44
- mp3.write open(mp3_url, 'rb:ASCII-8BIT', &:read)
45
- end
46
- end
47
- end
48
32
  end
@@ -29,7 +29,7 @@ class Podcast
29
29
  end
30
30
  print "getting #{serial}..."
31
31
  open(file, 'wb:ASCII-8BIT') do |o|
32
- o.write(open(episode.enclosure.url, 'rb:ASCII-8BIT', &:read))
32
+ o.write(URI.open(episode.enclosure.url, 'rb:ASCII-8BIT', &:read))
33
33
  end
34
34
  puts "done."
35
35
  end
@@ -0,0 +1,62 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+ require 'mechanize'
4
+ require 'json'
5
+
6
+ class StandFm < WebRadio
7
+ def initialize(params, options)
8
+ super
9
+ @offset = 0
10
+ end
11
+
12
+ def download
13
+ uri = URI(@url)
14
+ html = Nokogiri(uri.open.read)
15
+ episode = uri + html.css('#root a[href^="/episodes/"]').map{|e|e.attr('href')}.uniq[@offset]
16
+
17
+ html = episode.open.read
18
+ json = JSON.parse(html.scan(%r[<script>window.__SERVER_STATE__=(.*)</script>]).flatten[0])
19
+ m4a = json['topics'].find{|k,v|v['episodeId'] == File.basename(episode.path)}.last['downloadUrl']
20
+
21
+ doc = Nokogiri(html)
22
+ serial = doc.title.scan(/#(\d+)/).flatten.first.to_i
23
+ @cover = doc.css('meta[property="og:image"]').attr('content').text unless @cover
24
+ m4a_file = "#{@label}##{serial}.m4a"
25
+ mp3_file = "#{@label}##{serial}.mp3"
26
+
27
+ mp3nize(m4a_file, mp3_file) do
28
+ open(m4a_file, 'wb:ASCII-8BIT') do |w|
29
+ w.write(URI(m4a).open.read)
30
+ end
31
+ end
32
+ end
33
+
34
+ def dump
35
+ uri = URI(@url)
36
+ tag = File.basename(uri.path)
37
+ html = Nokogiri(uri.open.read)
38
+ label, = html.css('title').text.split(/ \| /)
39
+ cover = html.css('meta[property="og:image"]').attr('content').text
40
+ return {
41
+ tag => {
42
+ 'desc' => label,
43
+ 'url' => @url,
44
+ 'label' => label,
45
+ 'cover' => cover
46
+ }
47
+ }
48
+ end
49
+
50
+ private
51
+ def find_player(url)
52
+ programs = Nokogiri(URI.open(url).read)
53
+ programs.css('.list-main-product a.wrap').each do |program|
54
+ begin
55
+ return Nokogiri(URI.open("https://asobistore.jp#{program.attr('href')}").read).css('iframe').last.attr('src')
56
+ rescue # access denied because only access by premium members
57
+ next
58
+ end
59
+ end
60
+ raise StandardError.new('movie not found.')
61
+ end
62
+ end
@@ -14,7 +14,7 @@ class WebRadio
14
14
  when %r[^https?://hibiki-radio\.jp/]
15
15
  require 'hibiki'
16
16
  Hibiki.new(params, options)
17
- when %r[^http://(www\.)?onsen\.ag/program/]
17
+ when %r[^https?://(www\.)?onsen\.ag/program/]
18
18
  require 'onsen'
19
19
  Onsen.new(params, options)
20
20
  when %r[nicovideo\.jp]
@@ -29,6 +29,9 @@ class WebRadio
29
29
  when %r[^https://asobistore\.jp/]
30
30
  require 'asobistore'
31
31
  AsobiStore.new(params, options)
32
+ when %r[^https://stand\.fm/channels/]
33
+ require 'standfm'
34
+ StandFm.new(params, options)
32
35
  else
33
36
  raise UnsupportError, "unsupported url: #{params['url']}"
34
37
  end
@@ -132,13 +135,13 @@ private
132
135
  end
133
136
 
134
137
  def cover_image_as_url
135
- open(@cover, 'rb', &:read)
138
+ URI.open(@cover, 'rb', &:read)
136
139
  end
137
140
 
138
141
  def cover_image_as_xpath
139
- html = Nokogiri(open(@url, &:read))
142
+ html = Nokogiri(URI.open(@url, &:read))
140
143
  image_url = (URI(@url) + (html.xpath(@cover)[0].text)).to_s
141
- open(image_url, 'r:ASCII-8BIT', &:read)
144
+ URI.open(image_url, 'r:ASCII-8BIT', &:read)
142
145
  end
143
146
 
144
147
  def exist?(dst)
@@ -4,10 +4,10 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "rget"
7
- spec.version = "4.8.4"
8
- spec.authors = ["TADA Tadashi"]
7
+ spec.version = "4.10.0"
8
+ spec.authors = ["Tada, Tadashi"]
9
9
  spec.email = ["t@tdtds.jp"]
10
- spec.description = %q{Downloading newest radio programs on the web. Supported radio stations are hibiki, onsen, niconico, freshlive, himalaya and asobi store.}
10
+ spec.description = %q{Downloading newest radio programs on the web. Supported radio stations are hibiki, onsen, niconico, himalaya, asobi store and stand.fm.}
11
11
  spec.summary = %q{Downloading newest radio programs on the web.}
12
12
  spec.homepage = "https://github.com/wasamas/rget"
13
13
  spec.license = "GPL"
data/rget.yaml CHANGED
@@ -1,5 +1,5 @@
1
1
  options:
2
- mp3nize: ffmpeg -i '$1' -vn -acodec copy '$2' || ffmpeg -i '$1' -vn -y -ab 64k '$2'
2
+ mp3nize: ffmpeg -i '$1' -vn -acodec copy '$2' || ffmpeg -i '$1' -vn -y -ab 128k '$2'
3
3
  programs:
4
4
  imas_cg:
5
5
  desc: デレラジ☆
@@ -15,44 +15,15 @@ programs:
15
15
  url: http://ch.nicovideo.jp/search/%E6%B4%B2%E5%B4%8E%E8%A5%BF?channel_id=ch2589908&mode=s&sort=f&order=d&type=video
16
16
  label: 洲崎西
17
17
  cover: https://pbs.twimg.com/profile_images/836214019849506818/kXSasy1Y.jpg
18
- takamori:
19
- desc: 高森重戦舎 (声優バラエティ専門「声フレ」チャンネル内)
20
- url: https://freshlive.tv/seifre
21
- label: 高森重戦舎
22
- bahamut:
23
- desc: ラジオ神撃のバハムート
24
- url: http://hibiki-radio.jp/description/bahamut
25
- label: バハムート
26
- ssc:
27
- desc: 春佳・彩花のSSちゃんねる
28
- url: http://ch.nicovideo.jp/search/SS%E3%81%A1%E3%82%83%E3%82%93%E3%81%AD%E3%82%8B?channel_id=ch2589908&mode=s&sort=f&order=d&type=video
29
- label: 春佳・彩花のSSちゃんねる
30
- remake:
31
- desc: りめいく!
32
- url: http://ch.nicovideo.jp/search/%E3%82%8A%E3%82%81%E3%81%84%E3%81%8F?channel_id=ch2589908&mode=s&sort=f&order=d&type=video
33
- label: りめいく!
34
- adlib:
35
- desc: あどりぶ
36
- url: http://ch.nicovideo.jp/search/%E3%81%82%E3%81%A9%E3%82%8A%E3%81%B6?channel_id=ch2589908&mode=s&sort=f&order=d&type=video
37
- label: あどりぶ
38
- trysail:
39
- desc: TrySailのTRYangle harmony
40
- url: http://ch.nicovideo.jp/search/TrySail?channel_id=ch2585696&mode=s&sort=f&order=d&type=video
41
- label: トラハモ
42
- banpresto:
43
- desc: アイドルマスターWebラジオ~バンプレストスペシャル~
44
- url: http://ch.nicovideo.jp/search/IDOLM@STER?channel_id=ch346&mode=s&sort=f&order=d&type=video
45
- label: バンプレスト
46
- rebuild:
47
- desc: Rebuild.fm
48
- url: http://feeds.rebuild.fm/rebuildfm
49
- label: rebuildfm
50
- podcast: true
51
- taneharu:
52
- desc: ラジオ「たねさんはるさんとはなそ。(意志)」
53
- url: http://m.himalaya.fm/jp/podcast/190452
54
- label: たねさんはるさんとはなそ。(意志)
55
18
  shiny_radio:
56
19
  desc: ラジオ「アイドルマスター シャイニーカラーズ はばたきラジオステーション」
57
20
  url: https://asobistore.jp/special/List?ip_seq%5B%5D=1&ip_seq%5B%5D=14&tag_seq%5B%5D=1
58
21
  label: シャニラジ
22
+ luminesan:
23
+ desc: ル美子さん
24
+ url: https://ch.nicovideo.jp/luminesan/video?rss=2.0
25
+ label: ル美子さん
26
+ ranacha:
27
+ desc: らなちゃのひとりごと
28
+ url: https://stand.fm/channels/5f7d9011f04555115d2170ef
29
+ label: らなちゃのひとりごと
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rget
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.8.4
4
+ version: 4.10.0
5
5
  platform: ruby
6
6
  authors:
7
- - TADA Tadashi
7
+ - Tada, Tadashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-04 00:00:00.000000000 Z
11
+ date: 2020-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -151,16 +151,18 @@ dependencies:
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  description: Downloading newest radio programs on the web. Supported radio stations
154
- are hibiki, onsen, niconico, freshlive, himalaya and asobi store.
154
+ are hibiki, onsen, niconico, himalaya, asobi store and stand.fm.
155
155
  email:
156
156
  - t@tdtds.jp
157
157
  executables:
158
158
  - add_mp3info
159
+ - hls-dl
159
160
  - rget
160
- - ulizadl
161
161
  extensions: []
162
162
  extra_rdoc_files: []
163
163
  files:
164
+ - ".devcontainer/Dockerfile"
165
+ - ".devcontainer/devcontainer.json"
164
166
  - ".gitignore"
165
167
  - ".travis.yml"
166
168
  - Gemfile
@@ -168,17 +170,18 @@ files:
168
170
  - README.md
169
171
  - Rakefile
170
172
  - bin/add_mp3info
173
+ - bin/hls-dl
171
174
  - bin/rget
172
- - bin/ulizadl
173
175
  - lib/asobistore.rb
174
176
  - lib/dropbox.rb
175
177
  - lib/freshlive.rb
176
178
  - lib/hibiki.rb
177
179
  - lib/himalaya.rb
180
+ - lib/hls.rb
178
181
  - lib/nicovideo.rb
179
182
  - lib/onsen.rb
180
183
  - lib/podcast.rb
181
- - lib/uliza.rb
184
+ - lib/standfm.rb
182
185
  - lib/webradio.rb
183
186
  - rget.gemspec
184
187
  - rget.yaml
@@ -201,8 +204,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
201
204
  - !ruby/object:Gem::Version
202
205
  version: '0'
203
206
  requirements: []
204
- rubyforge_project:
205
- rubygems_version: 2.7.7
207
+ rubygems_version: 3.0.8
206
208
  signing_key:
207
209
  specification_version: 4
208
210
  summary: Downloading newest radio programs on the web.
@@ -1,103 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require "uri"
3
- require "mechanize"
4
- require 'open-uri'
5
- require 'thread'
6
-
7
- if ARGV.size != 2
8
- $stderr.puts "download TS file decoded by Uliza style video streaming"
9
- $stderr.puts "ulizadl <playlist.m3u8> <output(.ts)>"
10
- exit 1
11
- end
12
-
13
- m3u8 = ARGV.shift
14
- ts_file = "#{ARGV.shift}.ts"
15
- ts_file = nil if File.basename(ts_file) == "-.ts"
16
-
17
- begin
18
- agent = Mechanize.new
19
- agent.user_agent_alias = 'Windows Chrome'
20
- agent.verify_mode = OpenSSL::SSL::VERIFY_NONE
21
- agent.get(m3u8)
22
- body = agent.page.body
23
- rescue ArgumentError
24
- body = open(m3u8, &:read)
25
- end
26
- tses = body.scan(/.*\.ts.*/)
27
- key_url = body.scan(/URI="(.*)"/).flatten.first
28
-
29
- if key_url
30
- key = agent.get_file(key_url)
31
- decoder = OpenSSL::Cipher.new('aes-128-cbc')
32
- decoder.key = key
33
- decoder.decrypt
34
- else
35
- decoder = ''
36
- def decoder.update(s); return s; end
37
- def decoder.final(); return ''; end
38
- end
39
-
40
- q = Queue.new
41
- tses.each_with_index{|ts_url, block_no| q.push([ts_url, block_no])}
42
- q.close
43
- results = [nil] * q.size
44
-
45
- msgs = Queue.new
46
- stats = [0] * 3
47
- stats.size.times do |thread_no|
48
- Thread.start(thread_no) do |thread_no|
49
- while (ts_url, block_no = q.pop)
50
- begin
51
- sleep(rand(0.1) * 3)
52
- results[block_no] = agent.get_file(ts_url)
53
- stats[thread_no] = block_no
54
- rescue Mechanize::ResponseCodeError => e
55
- case e.response_code
56
- when "403" # Forbidden
57
- msgs.push "T#{thread_no}: 403 Forbidden"
58
- retry
59
- when "429" # TooManyRequests
60
- msgs.push "T#{thread_no}: 429 TooManyRequests"
61
- retry
62
- else
63
- msgs.push "T#{thread_no}: #{e}"
64
- retry # TODO: catch other status code
65
- end
66
- rescue
67
- msgs.push "T#{thread_no}: #{e.class} #{e}"
68
- break
69
- end
70
- end
71
- end
72
- end
73
-
74
- def print_status(block, tses, stats, msgs)
75
- $stderr.puts msgs.pop while !msgs.empty?
76
- $stderr.print "#{block+1}/#{tses.size} saved --"
77
- stats.each_with_index{|block_no, thread_no| $stderr.print " T#{thread_no+1}:#{block_no+1}"}
78
- $stderr.print "\r"
79
- end
80
-
81
- def save(fd, results, tses, stats, msgs, decoder)
82
- results.each_with_index do |data, i|
83
- print_status(i, tses, stats, msgs)
84
- loop do
85
- if data
86
- fd.write(decoder.update(data))
87
- results[i] = nil # be saved data want to GC
88
- break
89
- else
90
- sleep(1.0) # wait for complete of chunk download finished
91
- data = results[i]
92
- end
93
- end
94
- end
95
- fd.write(decoder.final)
96
- puts
97
- end
98
-
99
- if ts_file
100
- open(ts_file, 'wb:ASCII-8BIT'){|f|save(f, results, tses, stats, msgs, decoder)}
101
- else
102
- save($stdout, results, tses, stats, msgs, decoder)
103
- end
@@ -1,37 +0,0 @@
1
- require 'webradio'
2
-
3
- class Uliza < WebRadio
4
- private
5
- def uliza_download(name, html, serial_pattern, m3u_pattern)
6
- serial = html.scan(serial_pattern).flatten.sort{|a,b| a.to_i <=> b.to_i}.last
7
- @m4a_file = "#{name}##{serial}.m4a"
8
- @mp3_file = @m4a_file.sub(/\.m4a$/, '.mp3')
9
- mp3nize(@m4a_file, @mp3_file) do
10
- m3u_meta2 = html.scan(m3u_pattern).flatten.sort.last
11
- unless m3u_meta2
12
- raise WebRadio::DownloadError.new("recent radio program not found.")
13
- end
14
- m3u_meta1 = open(m3u_meta2, &:read)
15
- m3u = m3u_meta1.scan(/^[^#].*/).first
16
- save_m4a(URI(m3u), @m4a_file)
17
- end
18
- end
19
-
20
- def get_m4a(uri_playlist)
21
- open(uri_playlist).each_line do |l|
22
- next if /^#/ =~ l
23
- l.chomp!
24
- print "."
25
- yield open(uri_playlist + l, 'r:ASCII-8BIT', &:read)
26
- end
27
- end
28
-
29
- def save_m4a(uri_playlist, m4a_file)
30
- open(m4a_file, 'wb:ASCII-8BIT') do |m4a|
31
- get_m4a(uri_playlist) do |part|
32
- m4a.write part
33
- end
34
- end
35
- end
36
- end
37
-