quran-audio 0.3.1 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd6892ac4ea40e4ceedcf5596e92bb06bcd578db055b16acf793cec19dca277f
4
- data.tar.gz: 942914a841bd747cbcd11fd8af1666aef716d48996789438acac8b5cbdd08cb9
3
+ metadata.gz: 709a79351be5539a80a26a13ac39b41336b6a084cc14e56d476e5cd203090ab6
4
+ data.tar.gz: 7a0e5403541389a206d28f98bf53756a33ef672ad2bbc7162378efd59080642e
5
5
  SHA512:
6
- metadata.gz: b732e4378bf21f7d7341f68db747e2fae0dcee83ad7d0b5235b602ab3a7439daa6f1311b0d1a0f7a6a19ca2537fff21280d58ee9d5c881c7ae11f5aabd94628a
7
- data.tar.gz: 77b4d19899be0bc4041a4d087fcad940a5e624f64559fe0ae024009378f1b7cb5d4579eb6446038f31bd4e41cadf7388101ff15deab3f0eb1cee42d74f8406a7
6
+ metadata.gz: 655fda01723b31bd0d125f886a1b4695d6f16f8ae6bc5b3fac69c12019954c059f1a0fad0987e4d417e689d818400696a11dfa4431002cbcf4d9151f3c41640e
7
+ data.tar.gz: ede8a0dee97e2c33ddb78314bf4004ab8e785cf6b761cb7b9aea2c1ce03e30d7bbc88b7c0dfc0eeca96c5ac23b013f767b062f415eb3d2ed6608da600fd76554
data/README.md CHANGED
@@ -19,15 +19,14 @@ An example path:
19
19
  * **~/.local/share/quran-audio/mp3/yassin/** <br>
20
20
  Contains recitations by Sahl Yassin
21
21
 
22
- ## Usage
22
+ ## Install
23
23
 
24
- # Clone
25
- git clone https://github.com/ReflectsLight/quran-audio
26
- cd quran-audio
24
+ quran-audio is available via rubygems.org:
27
25
 
28
- # Install
29
- gem install quran-audio
30
- quran-audio --help
26
+ user@localhost$ gem install quran-audio
27
+ user@localhost$ quran-audio --help
28
+ user@localhost$ quran-audio ls --help
29
+ user@localhost$ quran-audio pull --help
31
30
 
32
31
  ## Thanks
33
32
 
data/bin/quran-audio CHANGED
@@ -1,17 +1,28 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- libexec = File.realpath File.join(__dir__, "..", "libexec", "quran-audio")
5
- case ARGV[0]
6
- when "pull"
7
- Process.spawn File.join(libexec, "pull"), *ARGV[1..]
4
+ def wait
8
5
  Process.wait
9
- when "ls"
10
- Process.spawn File.join(libexec, "ls"), *ARGV[1..]
11
- Process.wait
12
- else
13
- warn "Usage: quran-audio [COMMAND] [OPTIONS]\n\n" \
14
- "Commands:\n" \
15
- " pull Pull MP3 files from everyayah.com\n" \
16
- " ls List reciters\n" \
6
+ rescue Interrupt
7
+ retry
8
+ end
9
+
10
+ def main(argv)
11
+ libexec = File.realpath File.join(__dir__, "..", "libexec", "quran-audio")
12
+ case argv[0]
13
+ when "pull"
14
+ Process.spawn File.join(libexec, "pull"), *ARGV[1..]
15
+ Process.wait
16
+ when "ls"
17
+ Process.spawn File.join(libexec, "ls"), *ARGV[1..]
18
+ Process.wait
19
+ else
20
+ warn "Usage: quran-audio [COMMAND] [OPTIONS]\n\n" \
21
+ "Commands:\n" \
22
+ " pull Pull MP3 files from everyayah.com\n" \
23
+ " ls List reciters\n" \
24
+ end
25
+ rescue Interrupt
26
+ wait
17
27
  end
28
+ main(ARGV)
@@ -3,19 +3,19 @@
3
3
  module Quran::Audio
4
4
  class Command::Ls < Command
5
5
  set_banner usage: "quran-audio ls [OPTIONS]",
6
- description: "List reciters"
6
+ description: "List recitations"
7
7
 
8
8
  def run
9
- authors = Ryo.from_json(path: File.join(dir.datadir, "authors.json"))
10
- template = File.binread(File.join(dir.datadir, "erb", "author.txt.erb"))
11
- render(authors, template)
9
+ recitations = Ryo.from_json(path: File.join(dir.datadir, "recitations.json"))
10
+ template = File.binread(File.join(dir.datadir, "erb", "recitation.erb"))
11
+ render(recitations, template)
12
12
  end
13
13
 
14
14
  private
15
15
 
16
- def render(authors, template)
17
- puts Ryo.each(authors).map { |switch, author|
18
- ERB.new(template).result_with_hash({switch:, author: Ryo(author)})
16
+ def render(recitations, template)
17
+ puts Ryo.each(recitations).map { |switch, recitation|
18
+ ERB.new(template).result_with_hash({switch:, recitation: Ryo(recitation)})
19
19
  }.join("\n")
20
20
  end
21
21
  end
@@ -4,44 +4,47 @@ module Quran::Audio
4
4
  class Command::Pull < Command
5
5
  set_banner usage: "quran-audio pull [OPTIONS]",
6
6
  description: "Pull MP3 files from everyayah.com"
7
- set_option "-a AUTHOR", "--author AUTHOR", "An author's name"
7
+ set_option "-r RECITATION", "--recitation RECITATION", "A recitation's name", default: "alafasy"
8
8
  set_option "-b BITRATE", "--bitrate BITRATE", "MP3 bitrate"
9
- set_option "-s NUMBERS", "--surahs NUMBERS", "Comma-separated list of surah IDs", as: Array
10
- set_option "-d SECONDS", "--delay", "Delay between requests, in seconds", as: Float
11
- set_default author: "alafasy", surahs: (1..114).to_a, delay: 0.5
12
-
13
- attr_reader :http
9
+ set_option "-s NUMBERS", "--surahs NUMBERS", "Comma-separated list of surah IDs", as: Array, default: (1..114)
10
+ set_option "-d SECONDS", "--delay", "Delay between requests, in seconds", as: Float, default: 0.5
14
11
 
15
12
  def initialize(...)
16
13
  super
17
14
  @http = Net::HTTP.new("everyayah.com", 443).tap { _1.use_ssl = true }
18
- @surah_length = Ryo.from_json(path: File.join(dir.datadir, "surah_length.json"))
19
15
  end
20
16
 
21
17
  def run
18
+ summary(recitations[recitation])
19
+ start(surahs)
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :http
25
+
26
+ def start(surahs)
22
27
  surahs.each do |surah|
23
- 1.upto(surah_length(surah)) do |ayah|
24
- mp3 = MP3.new(author:, surah:, ayah:, bitrate:)
25
- pull(mp3, options.delay) unless File.exist?(mp3.local_path)
26
- percent = sprintf("%.2f", (ayah / surah_length(surah).to_f) * 100)
28
+ 1.upto(sizeof[surah]) do |ayah|
29
+ mp3 = MP3.new(recitation:, surah:, ayah:, bitrate:)
30
+ pull(mp3, delay) unless File.exist?(mp3.local_path)
31
+ percent = sprintf("%.2f", (ayah / sizeof[surah].to_f) * 100)
27
32
  line.rewind.print "Surah #{surah} [#{percent}%]"
28
33
  end
29
34
  line.end
30
35
  end
31
36
  end
32
37
 
33
- private
34
-
35
38
  def pull(mp3, delay, interrupt: false)
36
39
  res = http.get(mp3.remote_path)
37
40
  write(mp3, res, interrupt:)
38
41
  sleep(delay)
39
42
  rescue Interrupt
40
- line.end.rewind.print("Wait for a graceful exit").end
43
+ line.end.rewind.print("SIGINT: exiting cleanly, please wait").end
41
44
  pull(mp3, delay, interrupt: true)
42
45
  rescue SocketError, SystemCallError, Net::OpenTimeout => e
43
46
  line.end.rewind.print("#{e.class}: retry")
44
- interrupt ? throw(:interrupt, true) : pull(mp3, delay)
47
+ interrupt ? abort! : pull(mp3, delay)
45
48
  end
46
49
 
47
50
  def write(mp3, res, interrupt:)
@@ -49,14 +52,31 @@ module Quran::Audio
49
52
  when Net::HTTPOK
50
53
  mkdir_p File.dirname(mp3.local_path)
51
54
  File.binwrite(mp3.local_path, res.body)
52
- throw(:interrupt, true) if interrupt
55
+ abort! if interrupt
53
56
  else
54
- puts "error #{res.body}"
57
+ line.end.print("error: unexpected response (#{res.class})")
58
+ abort!
55
59
  end
56
60
  end
57
61
 
58
- def surah_length(surah)
59
- @surah_length[surah.to_s]
62
+ def summary(r)
63
+ line
64
+ .rewind
65
+ .print("Recitation".ljust(12), r.name).end
66
+ .print("Directory".ljust(12), format(r.destdir, sharedir: dir.sharedir))
67
+ .end.end
68
+ end
69
+
70
+ def sizeof
71
+ @sizeof ||= Ryo.from_json(path: File.join(dir.datadir, "sizeof.json"))
72
+ end
73
+
74
+ def recitations
75
+ @recitations ||= Ryo.from_json(path: File.join(dir.datadir, "recitations.json"))
76
+ end
77
+
78
+ def abort!
79
+ throw(:abort, 1)
60
80
  end
61
81
  end
62
82
  end
@@ -1,23 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Quran::Audio
4
- class MP3 < Struct.new(:author, :surah, :ayah, :bitrate, keyword_init: true)
5
- def initialize(author:, **kw)
6
- super(author: authors[author], **kw)
4
+ ##
5
+ # {Quran::Audio::MP3 Quran::Audio::MP3} provides
6
+ # an abstract interface around an MP3 file, and
7
+ # within the context of the quran-audio project.
8
+ class MP3 < Struct.new(:recitation, :surah, :ayah, :bitrate, keyword_init: true)
9
+ def initialize(recitation:, **kw)
10
+ super(recitation: recitations[recitation], **kw)
7
11
  end
8
12
 
13
+ ##
14
+ # @return [String]
15
+ # Returns the bitrate of an MP3 file
9
16
  def bitrate
10
- super || author.default_bitrate
17
+ super || recitation.default_bitrate
11
18
  end
12
19
 
20
+ ##
21
+ # @return [String]
22
+ # Returns the path to an MP3 file on a remote HTTP server
13
23
  def remote_path
14
24
  filename = [surah.to_s.rjust(3, "0"), ayah.to_s.rjust(3, "0"), ".mp3"].join
15
- File.join format(author.remote_path, bitrate:), filename
25
+ File.join format(recitation.path, bitrate:), filename
16
26
  end
17
27
 
28
+ ##
29
+ # @return [String]
30
+ # Returns the path to an MP3 file on disk
18
31
  def local_path
19
32
  File.join(
20
- format(author.dest_dir, sharedir:),
33
+ format(recitation.destdir, sharedir:),
21
34
  surah.to_s,
22
35
  "#{ayah}.mp3"
23
36
  )
@@ -25,8 +38,8 @@ module Quran::Audio
25
38
 
26
39
  private
27
40
 
28
- def authors
29
- @authors ||= Ryo.from_json(path: File.join(datadir, "authors.json"))
41
+ def recitations
42
+ @recitations ||= Ryo.from_json(path: File.join(datadir, "recitations.json"))
30
43
  end
31
44
 
32
45
  def sharedir
@@ -7,5 +7,8 @@ def main(argv)
7
7
  .new(argv)
8
8
  .run
9
9
  end
10
- interrupt = catch(:interrupt) { main(ARGV) }
11
- exit(1) if interrupt
10
+ excode = catch(:abort) {
11
+ main(ARGV)
12
+ 0
13
+ }
14
+ exit excode
@@ -1 +1 @@
1
- v0.3.1
1
+ v0.3.3
@@ -0,0 +1,4 @@
1
+ <%= Paint[recitation.name, :bold] %>
2
+ From <%= recitation.origin %>
3
+ Bitrates <%= recitation.available_bitrates.join(", ") %> (default = <%= recitation.default_bitrate %>)
4
+ CLI --recitation <%= switch %>
@@ -0,0 +1,26 @@
1
+ {
2
+ "alafasy": {
3
+ "name": "Mishari bin Rashed Alafasy",
4
+ "origin": "Kuwait",
5
+ "available_bitrates": [128, 64],
6
+ "default_bitrate": 128,
7
+ "path": "/data/Alafasy_%{bitrate}kbps/",
8
+ "destdir": "%{sharedir}/mp3/alafasy/"
9
+ },
10
+ "alajmi": {
11
+ "name": "Ahmad bin Ali Al-Ajmi",
12
+ "origin": "Saudi Arabia",
13
+ "available_bitrates": [128],
14
+ "default_bitrate": 128,
15
+ "path": "/data/ahmed_ibn_ali_al_ajamy_%{bitrate}kbps/",
16
+ "destdir": "%{sharedir}/mp3/alajmi/"
17
+ },
18
+ "yassin": {
19
+ "name": "Sahl Yassin",
20
+ "origin": "Saudi Arabia",
21
+ "available_bitrates": [128],
22
+ "default_bitrate": 128,
23
+ "path": "/data/Sahl_Yassin_%{bitrate}kbps/",
24
+ "destdir": "%{sharedir}/mp3/yassin/"
25
+ }
26
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quran-audio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - '0x1eef'
@@ -113,12 +113,12 @@ files:
113
113
  - libexec/quran-audio/ls
114
114
  - libexec/quran-audio/pull
115
115
  - share/quran-audio/VERSION
116
- - share/quran-audio/data/authors.json
117
- - share/quran-audio/data/erb/author.txt.erb
118
- - share/quran-audio/data/surah_length.json
116
+ - share/quran-audio/data/erb/recitation.erb
117
+ - share/quran-audio/data/recitations.json
118
+ - share/quran-audio/data/sizeof.json
119
119
  homepage: https://github.com/ReflectsLight/quran-audio#readme
120
120
  licenses:
121
- - BSD0L
121
+ - GPL-3.0-or-later
122
122
  metadata: {}
123
123
  post_install_message:
124
124
  rdoc_options: []
@@ -1,26 +0,0 @@
1
- {
2
- "alafasy": {
3
- "name": "Mishari bin Rashed Alafasy",
4
- "nationality": "Kuwait",
5
- "available_bitrates": [128, 64],
6
- "default_bitrate": 128,
7
- "remote_path": "/data/Alafasy_%{bitrate}kbps/",
8
- "dest_dir": "%{sharedir}/mp3/alafasy/"
9
- },
10
- "alajmi": {
11
- "name": "Ahmad bin Ali Al-Ajmi",
12
- "nationality": "Saudi Arabia",
13
- "available_bitrates": [128],
14
- "default_bitrate": 128,
15
- "remote_path": "/data/ahmed_ibn_ali_al_ajamy_%{bitrate}kbps/",
16
- "dest_dir": "%{sharedir}/mp3/alajmi/"
17
- },
18
- "yassin": {
19
- "name": "Sahl Yassin",
20
- "nationality": "Saudi Arabia",
21
- "available_bitrates": [128],
22
- "default_bitrate": 128,
23
- "remote_path": "/data/Sahl_Yassin_%{bitrate}kbps/",
24
- "dest_dir": "%{sharedir}/mp3/yassin/"
25
- }
26
- }
@@ -1,4 +0,0 @@
1
- <%= Paint[author.name, :bold] %>
2
- From <%= author.nationality %>
3
- Bitrates <%= author.available_bitrates.join(", ") %> (default = <%= author.default_bitrate %>)
4
- CLI --author <%= switch %>