The great rewrite
The project's directory structure has been changed to be similar to how FreeBSD organizes its filesystem. The english, portuguese, and farsi translations are now sourced from https://quran.com. The original Arabic is still sourced from searchtruth.com. Files have been removed, and / or replaced. The SQL-related files have been removed, with the intention to separate them into a new project in the future (quran-sql). The lessons learnt from the development of quran-audio were an inspiration for this change.
This commit is contained in:
parent
1dfe6ead25
commit
2d9a22ea8f
488 changed files with 273 additions and 157834 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
*.db
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ inherit_gem:
|
|||
standard: config/base.yml
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 3.1
|
||||
TargetRubyVersion: 3.2
|
||||
|
||||
##
|
||||
# Enabled cops
|
||||
|
@ -24,3 +24,5 @@ Layout/ArgumentAlignment:
|
|||
Enabled: false
|
||||
Style/LambdaCall:
|
||||
Enabled: false
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: false
|
||||
|
|
1
Gemfile
1
Gemfile
|
@ -5,3 +5,4 @@ gem "paint", "~> 2.2"
|
|||
gem "json", "~> 2.6"
|
||||
gem "standard", "~> 1.12"
|
||||
gem "io-line.rb", "~> 0.1", github: "0x1eef/io-line.rb", tag: "v0.1.0"
|
||||
gem "ryo.rb", "~> 0.3", github: "0x1eef/ryo.rb", tag: "v0.3.0"
|
||||
|
|
|
@ -6,6 +6,13 @@ GIT
|
|||
io-line.rb (0.1.0)
|
||||
io-console (~> 0.5)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/0x1eef/ryo.rb.git
|
||||
revision: 1fc0e7a2187d8020aadfb71b6b066dbc3af2fc2e
|
||||
tag: v0.3.0
|
||||
specs:
|
||||
ryo.rb (0.3.0)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
|
@ -55,6 +62,7 @@ DEPENDENCIES
|
|||
json (~> 2.6)
|
||||
nokogiri (~> 1.13)
|
||||
paint (~> 2.2)
|
||||
ryo.rb (~> 0.3)!
|
||||
standard (~> 1.12)
|
||||
|
||||
BUNDLED WITH
|
||||
|
|
15
README.md
15
README.md
|
@ -51,15 +51,16 @@ The [bin/](bin/) directory contains scripts that generate the contents of the
|
|||
* [bin/sql/create-sql-seed-file](bin/sql/create-sql-seed-file) <br>
|
||||
This script creates [src/sql/seed.sql](src/sql/seed.sql).
|
||||
|
||||
## Credit
|
||||
## Thanks
|
||||
|
||||
Thanks to the following websites:
|
||||
First and foremost, Alhamdulillah.
|
||||
|
||||
* https://searchtruth.com - for the original Arabic.
|
||||
* https://quran.com - for the English translation.
|
||||
* https://al-quran.cc - for the Farsi, and Portuguese translations.
|
||||
I'd also like to extend thanks to the following websites for providing
|
||||
the content that quran-pull downloads:
|
||||
|
||||
* https://searchtruth.com for the original Arabic.
|
||||
* https://quran.com for the English, Portuguese, and Farsi translations.
|
||||
|
||||
## License
|
||||
|
||||
This software is released into the Public Domain.
|
||||
|
||||
Public domain.
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
##
|
||||
# This script requests each verse, from each chapter
|
||||
# in The Qur'an in a language that is determined by
|
||||
# its first two arguments. For example:
|
||||
#
|
||||
# * ./al-quran pt portuguese
|
||||
# * ./al-quran fa farsi
|
||||
# * etc..
|
||||
|
||||
##
|
||||
# Set process title - primarily for the "ps" command
|
||||
Process.setproctitle("quran-pull (al-quran) (#{ARGV[1]})")
|
||||
|
||||
##
|
||||
# Dependencies
|
||||
require "bundler/setup"
|
||||
require "net/http"
|
||||
require "nokogiri"
|
||||
require "json"
|
||||
require "paint"
|
||||
require "fileutils"
|
||||
require "io/line"
|
||||
|
||||
##
|
||||
# Configuration variables
|
||||
base_uri = "al-quran.cc"
|
||||
path = "/quran-translation/#{ARGV[1]}/%{chapter}/%{verse}.html"
|
||||
dest = File.join("src", "json", ARGV[0], "%{chapter}.json")
|
||||
delay = 0.5
|
||||
|
||||
##
|
||||
# Chapter names
|
||||
names = JSON.parse(
|
||||
File.read(
|
||||
File.join("bindata", "al-quran.cc", "chapter-names.json")
|
||||
)
|
||||
)
|
||||
|
||||
##
|
||||
# Map chapters to their verse count.
|
||||
vmap_path = File.join("bindata", "chapters-length.json")
|
||||
vmap = JSON.parse(File.read(vmap_path))
|
||||
|
||||
##
|
||||
# Share a single Net::HTTP instance.
|
||||
http = Net::HTTP.new(base_uri, 443)
|
||||
http.use_ssl = true
|
||||
|
||||
##
|
||||
# Utils
|
||||
line = IO::Line.new($stdout)
|
||||
find_content = ->(res) do
|
||||
doc = Nokogiri::HTML(res.body)
|
||||
doc.css(".ayah .translate").text
|
||||
end
|
||||
|
||||
1.upto(114) do |chapter|
|
||||
line.rewind.print("Download chapter #{chapter}:").end
|
||||
rows = []
|
||||
vcount = vmap[chapter.to_s]
|
||||
1.upto(vcount) do |verse|
|
||||
res = http.request_get(format(path, chapter: names[chapter - 1], verse:))
|
||||
if Net::HTTPOK === res
|
||||
rows.push([verse, find_content.(res)])
|
||||
line.rewind.print("#{verse} of #{vcount} verses downloaded. ")
|
||||
else
|
||||
line.end.print(Paint["ABORT", :red, :bold])
|
||||
.end.print("Bad response: ", res.class)
|
||||
.end
|
||||
exit(1)
|
||||
end
|
||||
sleep(delay)
|
||||
end
|
||||
FileUtils.mkdir_p(File.dirname(dest))
|
||||
File.binwrite(format(dest, chapter:), JSON.pretty_generate(rows))
|
||||
line.end.print(Paint["Done.", :bold])
|
||||
.end.end
|
||||
end
|
|
@ -1,67 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
##
|
||||
# This script requests each verse, in each chapter
|
||||
# of The Qur'an - in the Arabic language. The content
|
||||
# is requested from the https://searchtruth.com website.
|
||||
#
|
||||
# Each chapter is then saved in a JSON file, for example:
|
||||
# "src/json/ar/1.json", "src/json/ar/2.json", etc.
|
||||
|
||||
##
|
||||
# Set process name - primarily for the "ps" command
|
||||
Process.setproctitle("quran-pull (pull-arabic)")
|
||||
|
||||
##
|
||||
# Dependencies
|
||||
require "bundler/setup"
|
||||
require "net/http"
|
||||
require "nokogiri"
|
||||
require "json"
|
||||
require "paint"
|
||||
require "io/line"
|
||||
|
||||
##
|
||||
# Configuration variables.
|
||||
base_uri = "www.searchtruth.com"
|
||||
dest = File.join("src", "json", "ar", "%{chapter}.json")
|
||||
delay = 1.5
|
||||
|
||||
##
|
||||
# Share a single Net::HTTP instance.
|
||||
http = Net::HTTP.new(base_uri, 443)
|
||||
http.use_ssl = true
|
||||
|
||||
##
|
||||
# Utils
|
||||
line = IO::Line.new($stdout)
|
||||
find_content = ->(res) do
|
||||
html = Nokogiri::HTML(res.body)
|
||||
html.css("table[dir='rtl'] tr td div:last-child").map do
|
||||
_1.text.strip
|
||||
end
|
||||
end
|
||||
|
||||
1.upto(114) do |chapter|
|
||||
rows = []
|
||||
res = http.request_get("/chapter_display.php?chapter=#{chapter}&translator=7")
|
||||
if Net::HTTPOK === res
|
||||
rows.concat(find_content.(res).map.with_index(1) { [_2, _1] })
|
||||
File.write(format(dest, chapter:), JSON.pretty_generate(rows))
|
||||
else
|
||||
line.end.print(Paint["ABORT", :red, :bold])
|
||||
.end.print("Bad response: ", res.class)
|
||||
.end
|
||||
exit(1)
|
||||
end
|
||||
line.rewind.print("#{chapter} of 114 chapters saved. ")
|
||||
sleep(delay)
|
||||
end
|
||||
line.end.print(Paint["Done.", :bold]).end
|
||||
|
||||
##
|
||||
# Spawn bin/json/insert-chapter-metadata
|
||||
Process.wait Process.spawn(
|
||||
"./bin/json/insert-chapter-metadata", "ar"
|
||||
)
|
|
@ -1,76 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
##
|
||||
# This script requests each verse, in each chapter
|
||||
# of The Qur'an - in the English language. The content
|
||||
# is requested from the https://quran.com website.
|
||||
#
|
||||
# Each chapter is then saved to a JSON file - for example:
|
||||
# "src/json/en/1.json", "src/json/en/2.json", etc.
|
||||
|
||||
##
|
||||
# Set process name - primarily for the "ps" command
|
||||
Process.setproctitle("quran-pull (pull-english)")
|
||||
|
||||
##
|
||||
# Dependencies
|
||||
require "bundler/setup"
|
||||
require "net/http"
|
||||
require "nokogiri"
|
||||
require "json"
|
||||
require "paint"
|
||||
require "io/line"
|
||||
|
||||
##
|
||||
# Configuration variables.
|
||||
base_uri = "quran.com"
|
||||
dest = File.join("src", "json", "en", "%{chapter}.json")
|
||||
delay = 1.5
|
||||
|
||||
##
|
||||
# Map chapters to their verse count.
|
||||
vmap_path = File.join("bindata", "chapters-length.json")
|
||||
vmap = JSON.parse(File.read(vmap_path))
|
||||
|
||||
##
|
||||
# Share a single Net::HTTP instance.
|
||||
http = Net::HTTP.new(base_uri, 443)
|
||||
http.use_ssl = true
|
||||
|
||||
##
|
||||
# Utils
|
||||
line = IO::Line.new($stdout)
|
||||
find_content = ->(res) do
|
||||
html = Nokogiri::HTML(res.body)
|
||||
el = html.css("div[class^='TranslationText']").last
|
||||
el.text.gsub(/[0-9]/, "")
|
||||
end
|
||||
|
||||
1.upto(114) do |chapter|
|
||||
rows = []
|
||||
vcount = vmap[chapter.to_s]
|
||||
line.rewind.print("Download chapter #{chapter}:").end
|
||||
1.upto(vcount) do |verse|
|
||||
res = http.request_get("/#{chapter}/#{verse}")
|
||||
if Net::HTTPOK === res
|
||||
rows.push([verse, find_content.(res)])
|
||||
line.rewind.print("#{verse} of #{vcount} verses downloaded. ")
|
||||
else
|
||||
line.end.print(Paint["ABORT", :red, :bold])
|
||||
.end.print("Bad response: ", res.class)
|
||||
.end
|
||||
exit(1)
|
||||
end
|
||||
sleep(delay)
|
||||
end
|
||||
File.write(format(dest, chapter:), JSON.pretty_generate(rows))
|
||||
line.end.print(Paint["Done.", :bold])
|
||||
.end.end
|
||||
end
|
||||
|
||||
##
|
||||
# Spawn bin/json/insert-chapter-metadata
|
||||
Process.wait Process.spawn(
|
||||
"./bin/json/insert-chapter-metadata", "en"
|
||||
)
|
|
@ -1,26 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
##
|
||||
# This script requests each verse, in each chapter
|
||||
# of The Qur'an - in the Farsi language. The content
|
||||
# is requested from the https://al-quran.cc website.
|
||||
#
|
||||
# Each chapter is then saved in a JSON file, for example:
|
||||
# "src/json/fa/1.json", "src/json/fa/2.json", etc.
|
||||
|
||||
##
|
||||
# Set process name - primarily for the "ps" command.
|
||||
Process.setproctitle("quran-pull (pull-farsi)")
|
||||
|
||||
##
|
||||
# Spawn bin/json/private/al-quran
|
||||
Process.wait Process.spawn(
|
||||
"./bin/json/private/al-quran", "fa", "farsi"
|
||||
)
|
||||
|
||||
##
|
||||
# Spawn bin/json/insert-chapter-metadata
|
||||
Process.wait Process.spawn(
|
||||
"./bin/json/insert-chapter-metadata", "fa"
|
||||
)
|
|
@ -1,26 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
##
|
||||
# This script requests each verse, in each chapter
|
||||
# of The Qur'an - in the Portuguese language. The content
|
||||
# is requested from the https://al-quran.cc website.
|
||||
#
|
||||
# Each chapter is then saved in a JSON file, for example:
|
||||
# "src/json/pt/1/.json", "src/json/pt/2.json", etc.
|
||||
|
||||
##
|
||||
# Set process title - primarily for the "ps" command.
|
||||
Process.setproctitle("quran-pull (pull-portuguese)")
|
||||
|
||||
##
|
||||
# Spawn bin/json/private/al-quran
|
||||
Process.wait Process.spawn(
|
||||
"./bin/json/private/al-quran", "pt", "portuguese"
|
||||
)
|
||||
|
||||
##
|
||||
# Spawn bin/json/insert-chapter-metadata
|
||||
Process.wait Process.spawn(
|
||||
"./bin/json/insert-chapter-metadata", "pt"
|
||||
)
|
35
bin/quran-pull
Normal file
35
bin/quran-pull
Normal file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
##
|
||||
# Utils
|
||||
def spawn(libexec_dir, exec, *args)
|
||||
Process.spawn File.join(libexec_dir, exec), *args
|
||||
end
|
||||
|
||||
def wait(pid)
|
||||
Process.wait(pid)
|
||||
rescue Interrupt
|
||||
retry
|
||||
end
|
||||
|
||||
##
|
||||
# main
|
||||
def main(argv)
|
||||
root_dir = File.realpath(File.join(__dir__, ".."))
|
||||
lib_dir = File.join(root_dir, "lib", "quran-pull")
|
||||
libexec_dir = File.join(root_dir, "libexec", "quran-pull")
|
||||
require File.join(lib_dir, "pull")
|
||||
|
||||
case ARGV[0]
|
||||
when "pull"
|
||||
options = Pull.cli(argv[1..])
|
||||
if %w[en pt fa].include?(options.locale)
|
||||
wait spawn(libexec_dir, "quran.com", *argv[1..])
|
||||
elsif %w[ar].include?(options.locale)
|
||||
wait spawn(libexec_dir, "searchtruth.com", *argv[1..])
|
||||
end
|
||||
else
|
||||
warn "Usage: quran-pull pull|help [OPTIONS]"
|
||||
end
|
||||
end
|
||||
main(ARGV)
|
|
@ -1,22 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
##
|
||||
# This script is responsible for the creation "src/sql/seed.sql" -
|
||||
# a SQL file that contains the contents of The Qur'an in Arabic,
|
||||
# and as translations in English, Portuguese and Farsi. The
|
||||
# "src/json/" directory is used as the data source.
|
||||
|
||||
##
|
||||
# Dependencies
|
||||
require "json"
|
||||
require "erb"
|
||||
require_relative "../../binlib/sql"
|
||||
|
||||
base_dir = File.join("src", "sql")
|
||||
template = File.read File.join(base_dir, "seed.sql.erb")
|
||||
result = ERB.new(template)
|
||||
.result(SQL::Template.context)
|
||||
.each_line.map(&:strip)
|
||||
.reject(&:empty?).join($/)
|
||||
File.write File.join(base_dir, "seed.sql"), result
|
|
@ -1,116 +0,0 @@
|
|||
[
|
||||
"al-fatiha",
|
||||
"al-baqara",
|
||||
"aal-e-imran",
|
||||
"an-nisa",
|
||||
"al-maeda",
|
||||
"al-anaam",
|
||||
"al-araf",
|
||||
"al-anfal",
|
||||
"at-tawba",
|
||||
"yunus",
|
||||
"hud",
|
||||
"yusuf",
|
||||
"ar-rad",
|
||||
"ibrahim",
|
||||
"al-hijr",
|
||||
"an-nahl",
|
||||
"al-isra",
|
||||
"al-kahf",
|
||||
"maryam",
|
||||
"ta-ha",
|
||||
"al-anbiya",
|
||||
"al-hajj",
|
||||
"al-mumenoon",
|
||||
"an-nur",
|
||||
"al-furqan",
|
||||
"ash-shuara",
|
||||
"an-naml",
|
||||
"al-qasas",
|
||||
"al-ankabut",
|
||||
"ar-rum",
|
||||
"luqman",
|
||||
"as-sajda",
|
||||
"al-ahzab",
|
||||
"saba",
|
||||
"fatir",
|
||||
"ya-seen",
|
||||
"as-saaffat",
|
||||
"sad",
|
||||
"az-zamar",
|
||||
"ghafir",
|
||||
"fussilat",
|
||||
"ash-shura",
|
||||
"az-zukhruf",
|
||||
"ad-dukhan",
|
||||
"al-jathiya",
|
||||
"al-ahqaf",
|
||||
"muhammad",
|
||||
"al-fath",
|
||||
"al-hujraat",
|
||||
"qaf",
|
||||
"adh-dhariyat",
|
||||
"at-tur",
|
||||
"an-najm",
|
||||
"al-qamar",
|
||||
"ar-rahman",
|
||||
"al-waqia",
|
||||
"al-hadid",
|
||||
"al-mujadala",
|
||||
"al-hashr",
|
||||
"al-mumtahana",
|
||||
"as-saff",
|
||||
"al-jumua",
|
||||
"al-munafiqoon",
|
||||
"at-taghabun",
|
||||
"at-talaq",
|
||||
"at-tahrim",
|
||||
"al-mulk",
|
||||
"al-qalam",
|
||||
"al-haaqqa",
|
||||
"al-maarij",
|
||||
"nooh",
|
||||
"al-jinn",
|
||||
"al-muzzammil",
|
||||
"al-muddaththir",
|
||||
"al-qiyama",
|
||||
"al-insan",
|
||||
"al-mursalat",
|
||||
"an-naba",
|
||||
"an-naziat",
|
||||
"abasa",
|
||||
"at-takwir",
|
||||
"al-infitar",
|
||||
"al-mutaffifin",
|
||||
"al-inshiqaq",
|
||||
"al-burooj",
|
||||
"at-tariq",
|
||||
"al-ala",
|
||||
"al-ghashiya",
|
||||
"al-fajr",
|
||||
"al-balad",
|
||||
"ash-shams",
|
||||
"al-lail",
|
||||
"ad-dhuha",
|
||||
"al-sharh",
|
||||
"at-tin",
|
||||
"al-alaq",
|
||||
"al-qadr",
|
||||
"al-bayyina",
|
||||
"az-zalzala",
|
||||
"al-adiyat",
|
||||
"al-qaria",
|
||||
"at-takathur",
|
||||
"al-asr",
|
||||
"al-humaza",
|
||||
"al-fil",
|
||||
"quraish",
|
||||
"al-maun",
|
||||
"al-kauther",
|
||||
"al-kafiroon",
|
||||
"an-nasr",
|
||||
"al-masadd",
|
||||
"al-ikhlas",
|
||||
"al-falaq",
|
||||
"an-nas"
|
||||
]
|
|
@ -1,9 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module SQL
|
||||
require_relative "sql/language"
|
||||
require_relative "sql/chapter"
|
||||
require_relative "sql/verse"
|
||||
require_relative "sql/utils"
|
||||
require_relative "sql/template"
|
||||
end
|
|
@ -1,41 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class SQL::Chapter
|
||||
def initialize(path)
|
||||
@contents = JSON.parse(File.read(path))
|
||||
@metadata = @contents.shift
|
||||
@locale = File.basename(File.dirname(path))
|
||||
end
|
||||
|
||||
def number
|
||||
Integer(@metadata["id"])
|
||||
end
|
||||
|
||||
def name
|
||||
if @locale == "ar"
|
||||
@metadata["codepoints"].pack("U*")
|
||||
else
|
||||
@metadata["translated_name"]
|
||||
end
|
||||
end
|
||||
|
||||
def tr_name
|
||||
if @locale == "ar"
|
||||
name
|
||||
else
|
||||
@metadata["transliterated_name"]
|
||||
end
|
||||
end
|
||||
|
||||
def slug
|
||||
@metadata["slug"]
|
||||
end
|
||||
|
||||
def city
|
||||
@metadata["place_of_revelation"].capitalize
|
||||
end
|
||||
|
||||
def verses
|
||||
@contents.map { SQL::Verse.new(*_1) }
|
||||
end
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class SQL::Language < Struct.new(:locale)
|
||||
def chapters
|
||||
Dir.glob(File.join(
|
||||
"src", "json", locale, "*.json"
|
||||
)).map { SQL::Chapter.new(_1) }.sort_by(&:number)
|
||||
end
|
||||
end
|
|
@ -1,37 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class SQL::Template
|
||||
def self.context
|
||||
new.context
|
||||
end
|
||||
|
||||
def context
|
||||
context = binding
|
||||
locals.each { context.local_variable_set(_1, _2) }
|
||||
context
|
||||
end
|
||||
|
||||
def chapter_row(quran_id, chapter_id, chapter)
|
||||
[
|
||||
chapter_id, chapter.number, chapter.name,
|
||||
chapter.tr_name, chapter.slug, chapter.city,
|
||||
quran_id
|
||||
].map { Integer === _1 ? _1 : SQL::Utils.escape(_1) }.join(",")
|
||||
end
|
||||
|
||||
def verse_row(verse, quran_id, chapter_id)
|
||||
[
|
||||
verse.number, quran_id,
|
||||
chapter_id, verse.content
|
||||
].map { Integer === _1 ? _1 : SQL::Utils.escape(_1) }.join(",")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def locals
|
||||
{
|
||||
languages: %w(ar en pt fa).map { SQL::Language.new(_1) },
|
||||
chapter_id: 1
|
||||
}
|
||||
end
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module SQL::Utils
|
||||
module_function
|
||||
|
||||
def escape(str)
|
||||
char = "'"
|
||||
char + str.gsub(char, char * 2) + char
|
||||
end
|
||||
end
|
|
@ -1,4 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class SQL::Verse < Struct.new(:number, :content)
|
||||
end
|
37
lib/quran-pull/command.rb
Normal file
37
lib/quran-pull/command.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
module Command
|
||||
require "ryo"
|
||||
require "json"
|
||||
require "io/line"
|
||||
|
||||
def root_dir
|
||||
File.realpath File.join(__dir__, "..", "..")
|
||||
end
|
||||
|
||||
def share_dir
|
||||
File.join(root_dir, "share", "quran-pull")
|
||||
end
|
||||
|
||||
def data_dir
|
||||
File.join(share_dir, "data")
|
||||
end
|
||||
|
||||
def quran_dir
|
||||
File.join(share_dir, "TheQuran")
|
||||
end
|
||||
|
||||
def line
|
||||
@line ||= IO::Line.new($stdout)
|
||||
end
|
||||
|
||||
def count
|
||||
@count ||= Ryo.from(
|
||||
JSON.parse File.binread(File.join(data_dir, "count.json"))
|
||||
)
|
||||
end
|
||||
|
||||
def surah_info
|
||||
@surah_info ||= Ryo.from(
|
||||
JSON.parse File.binread(File.join(data_dir, "surahinfo.json"))
|
||||
)
|
||||
end
|
||||
end
|
77
lib/quran-pull/pull.rb
Normal file
77
lib/quran-pull/pull.rb
Normal file
|
@ -0,0 +1,77 @@
|
|||
class Pull
|
||||
require "ryo"
|
||||
require "json"
|
||||
require "net/http"
|
||||
require "fileutils"
|
||||
require "optparse"
|
||||
require_relative "command"
|
||||
include Command
|
||||
include FileUtils
|
||||
|
||||
attr_reader :options,
|
||||
:source,
|
||||
:http
|
||||
|
||||
def self.cli(argv)
|
||||
op = nil
|
||||
options = Ryo({locale: "en"})
|
||||
OptionParser.new do |o|
|
||||
op = o
|
||||
o.on("-l", "--locale LOCALE", "ar, en, pt, or fa (default: en)")
|
||||
end.parse(argv, into: options)
|
||||
options
|
||||
rescue
|
||||
puts op.help
|
||||
exit
|
||||
end
|
||||
|
||||
def initialize(options)
|
||||
@options = options
|
||||
@source = sources[options.locale]
|
||||
@http = Net::HTTP.new(source.http.hostname, 443).tap { _1.use_ssl = true }
|
||||
end
|
||||
|
||||
def pull_surah(surah_no, &b)
|
||||
pull req_path(vars(binding)), &b
|
||||
end
|
||||
|
||||
def pull_ayah(surah_no, ayah_no, &b)
|
||||
pull req_path(vars(binding)), &b
|
||||
end
|
||||
|
||||
def write(surah_no, rows)
|
||||
dir = File.join(quran_dir, options.locale)
|
||||
mkdir_p(dir)
|
||||
rows.unshift(Ryo.table_of(surah_info[surah_no - 1]))
|
||||
File.binwrite File.join(dir, "#{surah_no}.json"), JSON.pretty_generate(rows)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def req_path(vars)
|
||||
format source.http.path, source.http.vars.map { [_1.to_sym, vars[_1.to_sym]] }.to_h
|
||||
end
|
||||
|
||||
def pull(path)
|
||||
res = http.get(path)
|
||||
case res
|
||||
when Net::HTTPOK
|
||||
yield(res)
|
||||
else
|
||||
##
|
||||
# TODO: Handle error
|
||||
end
|
||||
end
|
||||
|
||||
def vars(binding)
|
||||
binding.local_variables.map do
|
||||
[_1.to_sym, binding.local_variable_get(_1)]
|
||||
end.to_h
|
||||
end
|
||||
|
||||
def sources
|
||||
@sources ||= Ryo.from(
|
||||
JSON.parse File.binread(File.join(data_dir, "sources.json"))
|
||||
)
|
||||
end
|
||||
end
|
32
libexec/quran-pull/quran.com
Executable file
32
libexec/quran-pull/quran.com
Executable file
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env ruby
|
||||
lib_dir = File.realpath File.join(__dir__, "..", "..", "lib", "quran-pull")
|
||||
require File.join(lib_dir, "pull")
|
||||
require "optparse"
|
||||
require "nokogiri"
|
||||
|
||||
def grep(res)
|
||||
html = Nokogiri::HTML(res.body)
|
||||
el = html.css("div[class^='TranslationText']").last
|
||||
el.text.gsub(/[0-9]/, "")
|
||||
end
|
||||
|
||||
##
|
||||
# main
|
||||
def main(argv)
|
||||
cmd = Pull.new(Pull.cli(argv))
|
||||
cmd.http.start
|
||||
1.upto(114) do |surah_no|
|
||||
rows = []
|
||||
1.upto(cmd.count[surah_no]) do |ayah_no|
|
||||
cmd.pull_ayah(surah_no, ayah_no) do |res|
|
||||
rows.concat([ayah_no, grep(res)])
|
||||
end
|
||||
cmd.line.rewind.print "Surah #{surah_no} [#{ayah_no}/#{cmd.count[surah_no]}]"
|
||||
end
|
||||
cmd.write(surah_no, rows)
|
||||
cmd.line.end
|
||||
end
|
||||
ensure
|
||||
cmd.http.finish
|
||||
end
|
||||
main(ARGV)
|
29
libexec/quran-pull/searchtruth.com
Executable file
29
libexec/quran-pull/searchtruth.com
Executable file
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env ruby
|
||||
lib_dir = File.realpath File.join(__dir__, "..", "..", "lib", "quran-pull")
|
||||
require File.join(lib_dir, "pull")
|
||||
require "optparse"
|
||||
require "nokogiri"
|
||||
|
||||
def grep(res)
|
||||
html = Nokogiri::HTML(res.body)
|
||||
html.css("table[dir='rtl'] tr td div:last-child").map { _1.text.strip }
|
||||
end
|
||||
|
||||
##
|
||||
# main
|
||||
def main(argv)
|
||||
cmd = Pull.new(Pull.cli(argv))
|
||||
cmd.http.start
|
||||
1.upto(114) do |surah_no|
|
||||
rows = []
|
||||
cmd.pull_surah(surah_no) do |res|
|
||||
rows.concat(grep(res).map.with_index(1) { [_2, _1] })
|
||||
end
|
||||
cmd.line.rewind.print "Surah #{surah_no} [#{surah_no}/114]"
|
||||
cmd.write(surah_no, rows)
|
||||
end
|
||||
cmd.line.end
|
||||
ensure
|
||||
cmd.http.finish
|
||||
end
|
||||
main(ARGV)
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue