rss-reader 1.0.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 +7 -0
- data/README.md +24 -0
- data/exe/rss-reader +5 -0
- data/lib/client.rb +144 -0
- data/lib/core.rb +142 -0
- data/lib/patch.rb +56 -0
- data/lib/utils.rb +27 -0
- data/rss-reader.gemspec +27 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 91651a5c206fb1a61bf999096c56371739054035f3159b24d35be455c6c3240a
|
4
|
+
data.tar.gz: 2f61494a072baa0e3eb0f36d75ecd91b6c96758acf94cc1846ce3af16ec8e1f0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2c6e70a3269a5b89e6d7a06453ffc2d490db113210154e4f053d171e3e1ac37fd0572e4e1d5d40de43f651297a635356ff41740319d23dd139ba50d700f817dd
|
7
|
+
data.tar.gz: b38b14167613eb6c76f2f4c4c7b11444912a2720daff9a11ac414d263dc67a88c03b4b455171915bf65a709d9b3634d65e5af267d2b7e3fb6e25aa7a698b731f
|
data/README.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# RSS Reader
|
2
|
+
|
3
|
+
CLI RSS reader by Ruby lang
|
4
|
+
|
5
|
+
## 安装
|
6
|
+
|
7
|
+
`gem install rss-reader`
|
8
|
+
|
9
|
+
## 使用
|
10
|
+
|
11
|
+
启动
|
12
|
+
|
13
|
+
`rss-reader`
|
14
|
+
|
15
|
+
查看帮助
|
16
|
+
|
17
|
+
`h` 或者 `help`
|
18
|
+
|
19
|
+
|
20
|
+
## 订阅链接
|
21
|
+
|
22
|
+
编辑 `~/subscribe-rss.list` 格式(目前只支持 RSS 格式订阅)
|
23
|
+
|
24
|
+
`#` 是注释符号
|
data/exe/rss-reader
ADDED
data/lib/client.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative './core'
|
5
|
+
require 'readline'
|
6
|
+
|
7
|
+
LIST = %w[
|
8
|
+
help
|
9
|
+
clear
|
10
|
+
quit
|
11
|
+
exit
|
12
|
+
update
|
13
|
+
reset
|
14
|
+
channel
|
15
|
+
].sort
|
16
|
+
|
17
|
+
HELP_DOC = <<~HELP
|
18
|
+
Help:
|
19
|
+
help/h: \t print help message
|
20
|
+
clear/c: \t clear screen
|
21
|
+
quit/exit: \t quit
|
22
|
+
exit: \t quit
|
23
|
+
update: \t update all channel data
|
24
|
+
reset/r: \t channel list
|
25
|
+
q: \t quit current view
|
26
|
+
|
27
|
+
Config:
|
28
|
+
~/subscribe-rss.list
|
29
|
+
|
30
|
+
HELP
|
31
|
+
comp = proc { |s| LIST.grep(/^#{Regexp.escape(s)}/) }
|
32
|
+
Readline.completion_append_character = ' '
|
33
|
+
Readline.completion_proc = comp
|
34
|
+
|
35
|
+
# RSS Client
|
36
|
+
class RssClient
|
37
|
+
# rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/AbcSize,Metrics/BlockLength,Metrics/PerceivedComplexity
|
38
|
+
def initialize
|
39
|
+
@rss = nil
|
40
|
+
@channel_index = -1
|
41
|
+
@item_index = -1
|
42
|
+
@debug = false
|
43
|
+
init_rss
|
44
|
+
end
|
45
|
+
|
46
|
+
def init_rss
|
47
|
+
puts 'RSS Reader'.green
|
48
|
+
puts 'loading....'.green
|
49
|
+
@rss = RSSManager.new
|
50
|
+
system('clear')
|
51
|
+
render
|
52
|
+
end
|
53
|
+
|
54
|
+
def render
|
55
|
+
# TODO: index check & catch
|
56
|
+
if @channel_index == -1 && @item_index == -1
|
57
|
+
# render channels list
|
58
|
+
puts '[RSS Reader]'.blue
|
59
|
+
puts '----'
|
60
|
+
puts @rss.channel_titles
|
61
|
+
elsif @channel_index >= 0 && @item_index == -1
|
62
|
+
# render channel item list
|
63
|
+
puts "[Channel] #{@rss.channel_title_by_index(@channel_index)}".blue
|
64
|
+
puts '----'
|
65
|
+
puts @rss.channel_items(@channel_index)
|
66
|
+
elsif @channel_index >= 0 && @item_index >= 0
|
67
|
+
# render item content
|
68
|
+
channel = @rss.channels[@channel_index]
|
69
|
+
content = channel.content_by_index(@item_index)
|
70
|
+
Utils.display_by_reader(content)
|
71
|
+
@item_index = -1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def reset_index
|
76
|
+
@channel_index = -1
|
77
|
+
@item_index = -1
|
78
|
+
end
|
79
|
+
|
80
|
+
def back_index
|
81
|
+
reset_index
|
82
|
+
end
|
83
|
+
|
84
|
+
def print_index
|
85
|
+
return unless @debug
|
86
|
+
|
87
|
+
puts "@channel_index: #{@channel_index}"
|
88
|
+
puts "@item_index: #{@item_index}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def update_channels
|
92
|
+
puts 'Updating channels ... '.green
|
93
|
+
@rss.update_channels
|
94
|
+
puts "Updated #{Time.now}".green
|
95
|
+
end
|
96
|
+
|
97
|
+
def run
|
98
|
+
loop do
|
99
|
+
line = Readline.readline('> ', true)
|
100
|
+
break if line.nil? || line == 'quit'
|
101
|
+
|
102
|
+
line = line.strip
|
103
|
+
case line
|
104
|
+
when 'quit', 'exit'
|
105
|
+
exit 0
|
106
|
+
when 'h', 'help'
|
107
|
+
puts HELP_DOC
|
108
|
+
when /(\d+)/
|
109
|
+
index = ::Regexp.last_match(1)
|
110
|
+
index = index.strip.to_i
|
111
|
+
if @channel_index >= 0
|
112
|
+
@item_index = index if index >= 0 && index < @rss.channels[@channel_index].items.length
|
113
|
+
elsif index >= 0 && index < @rss.channels.length
|
114
|
+
@channel_index = index
|
115
|
+
end
|
116
|
+
print_index
|
117
|
+
render
|
118
|
+
when 'c', 'clear'
|
119
|
+
puts 'clear channel'
|
120
|
+
system('clear')
|
121
|
+
print_index
|
122
|
+
render
|
123
|
+
when 'r', 'reset'
|
124
|
+
puts 'reset channel'
|
125
|
+
reset_index
|
126
|
+
print_index
|
127
|
+
render
|
128
|
+
when 'q'
|
129
|
+
back_index
|
130
|
+
print_index
|
131
|
+
system('clear')
|
132
|
+
render
|
133
|
+
when 'update'
|
134
|
+
update_channels
|
135
|
+
print_index
|
136
|
+
render
|
137
|
+
else
|
138
|
+
# do nothing
|
139
|
+
print_index
|
140
|
+
puts 'nothing happened...'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
data/lib/core.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './patch'
|
4
|
+
require_relative './utils'
|
5
|
+
require 'rss'
|
6
|
+
require 'open-uri'
|
7
|
+
require 'async'
|
8
|
+
|
9
|
+
# RSS Channel class
|
10
|
+
class RSSChannel
|
11
|
+
attr_accessor :feed
|
12
|
+
|
13
|
+
def initialize(channel_url)
|
14
|
+
@channel_url = channel_url
|
15
|
+
@feed = nil
|
16
|
+
|
17
|
+
fetch_channel
|
18
|
+
end
|
19
|
+
|
20
|
+
def fetch_channel
|
21
|
+
URI.open(@channel_url) do |rss|
|
22
|
+
@feed = RSS::Parser.parse(rss)
|
23
|
+
# Utils.display_by_reader(@feed)
|
24
|
+
end
|
25
|
+
rescue OpenURI::HTTPError
|
26
|
+
puts "[Request Error] #{@channel_url}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def items
|
30
|
+
items = []
|
31
|
+
@feed.items.each_with_index do |item, index|
|
32
|
+
items.push "#{"[#{index}]".green} #{Utils.url_text(item.title.to_s.dark_green, item.link)}"
|
33
|
+
end
|
34
|
+
items
|
35
|
+
end
|
36
|
+
|
37
|
+
def open_url_by_index(index)
|
38
|
+
item = @feed.items[index]
|
39
|
+
Utils.open_url(item.link)
|
40
|
+
end
|
41
|
+
|
42
|
+
def description_by_index(index)
|
43
|
+
item = @feed.items[index]
|
44
|
+
item.description
|
45
|
+
end
|
46
|
+
|
47
|
+
def content_by_index(index)
|
48
|
+
Utils.html_to_text(description_by_index(index))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# RSS Manager: Core Channel Manager Class
|
53
|
+
class RSSManager
|
54
|
+
attr_accessor :channels, :current_channel_index
|
55
|
+
|
56
|
+
def initialize
|
57
|
+
config_file = File.join(ENV['HOME'], 'subscribe-rss.list')
|
58
|
+
unless File.exist?(config_file)
|
59
|
+
File.open(config_file, 'w') do |f|
|
60
|
+
f << 'https://www.ruby-lang.org/en/feeds/news.rss'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
@channel_config_path = config_file
|
64
|
+
@channel_urls = []
|
65
|
+
@channels = []
|
66
|
+
|
67
|
+
init_pipeline
|
68
|
+
end
|
69
|
+
|
70
|
+
def load_channel_urls
|
71
|
+
channel_lines = File.open(@channel_config_path).readlines.map(&:strip)
|
72
|
+
@channel_urls = channel_lines.filter do |x|
|
73
|
+
x != '' && x.index('#') != 0
|
74
|
+
end
|
75
|
+
@channel_urls
|
76
|
+
end
|
77
|
+
|
78
|
+
def init_channels
|
79
|
+
@channel_urls.each do |channel_url|
|
80
|
+
@channels.push(RSSChannel.new(channel_url))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def update_channels
|
85
|
+
time_start = Time.now
|
86
|
+
async_fetch
|
87
|
+
time_end = Time.now
|
88
|
+
puts "use: #{time_end - time_start}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def sync_fetch
|
92
|
+
# use: 6.022412
|
93
|
+
@channels.each(&:fetch_channel)
|
94
|
+
end
|
95
|
+
|
96
|
+
def async_fetch
|
97
|
+
# use: 2.854694
|
98
|
+
Async do |task|
|
99
|
+
@channels.each do |ch|
|
100
|
+
task.async do
|
101
|
+
ch.fetch_channel
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def init_pipeline
|
108
|
+
load_channel_urls
|
109
|
+
init_channels
|
110
|
+
update_channels
|
111
|
+
end
|
112
|
+
|
113
|
+
def channel_titles
|
114
|
+
titles = []
|
115
|
+
@channels.each_with_index do |x, index|
|
116
|
+
titles.push "#{"[#{index}]".green} #{x.feed.channel.title.to_s.blue} (#{x.feed.channel.items.length}) \n"
|
117
|
+
end
|
118
|
+
titles
|
119
|
+
end
|
120
|
+
|
121
|
+
def channel_title_by_index(channel_index)
|
122
|
+
channel = @channels[channel_index]
|
123
|
+
channel.feed.channel.title
|
124
|
+
end
|
125
|
+
|
126
|
+
def channel_by_index(channel_index)
|
127
|
+
@channels[channel_index]
|
128
|
+
end
|
129
|
+
|
130
|
+
def channel_items(channel_index = 0)
|
131
|
+
@channels[channel_index].items
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# rss_atom = RSSChannel.new('https://www.ruby-lang.org/en/feeds/news.rss')
|
136
|
+
# rss_atom.open_url_by_index(1)
|
137
|
+
# puts rss_atom.content_by_index(1)
|
138
|
+
#
|
139
|
+
# m = RSSManager.new
|
140
|
+
# puts m.channel_titles
|
141
|
+
# first = m.channel_by_index(1)
|
142
|
+
# puts first.items
|
data/lib/patch.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'colorize'
|
2
|
+
|
3
|
+
class String
|
4
|
+
def red = colorize(self, "\e[1m\e[31m")
|
5
|
+
def green = colorize(self, "\e[1m\e[32m")
|
6
|
+
def dark_green = colorize(self, "\e[32m")
|
7
|
+
def yellow = colorize(self, "\e[1m\e[33m")
|
8
|
+
def blue = colorize(self, "\e[1m\e[34m")
|
9
|
+
def dark_blue = colorize(self, "\e[34m")
|
10
|
+
def purple = colorize(self, "\e[35m")
|
11
|
+
def dark_purple = colorize(self, "\e[1;35m")
|
12
|
+
def cyan = colorize(self, "\e[1;36m")
|
13
|
+
def dark_cyan = colorize(self, "\e[36m")
|
14
|
+
def pure = colorize(self, "\e[0m\e[28m")
|
15
|
+
def bold = colorize(self, "\e[1m")
|
16
|
+
def colorize(text, color_code) = "#{color_code}#{text}\e[0m"
|
17
|
+
end
|
18
|
+
|
19
|
+
class String
|
20
|
+
def mv_up(n = 1)
|
21
|
+
cursor(self, "\033[#{n}A")
|
22
|
+
end
|
23
|
+
|
24
|
+
def mv_down(n = 1)
|
25
|
+
cursor(self, "\033[#{n}B")
|
26
|
+
end
|
27
|
+
|
28
|
+
def mv_fw(n = 1)
|
29
|
+
cursor(self, "\033[#{n}C")
|
30
|
+
end
|
31
|
+
|
32
|
+
def mv_bw(n = 1)
|
33
|
+
cursor(self, "\033[#{n}D")
|
34
|
+
end
|
35
|
+
|
36
|
+
def cls_upline
|
37
|
+
cursor(self, "\e[K")
|
38
|
+
end
|
39
|
+
|
40
|
+
def cls
|
41
|
+
# cursor(self, "\033[2J")
|
42
|
+
cursor(self, "\e[H\e[2J")
|
43
|
+
end
|
44
|
+
|
45
|
+
def save_position
|
46
|
+
cursor(self, "\033[s")
|
47
|
+
end
|
48
|
+
|
49
|
+
def restore_position
|
50
|
+
cursor(self, "\033[u")
|
51
|
+
end
|
52
|
+
|
53
|
+
def cursor(text, position)
|
54
|
+
"\r#{position}#{text}"
|
55
|
+
end
|
56
|
+
end
|
data/lib/utils.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'tty-link'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module Utils
|
5
|
+
def self.url_text(text, url)
|
6
|
+
TTY::Link.link_to(text, url)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.html_to_text(html_text)
|
10
|
+
Nokogiri::HTML(html_text).text
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.display_by_reader(content)
|
14
|
+
system("echo '#{content}' | less")
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.open_url(url)
|
18
|
+
cmd = case RbConfig::CONFIG['host_os']
|
19
|
+
when /mswin|mingw|cygwin/ then 'start '
|
20
|
+
when /darwin/ then 'open '
|
21
|
+
when /linux|bsd/ then 'xdg-open '
|
22
|
+
else raise 'No OS detected'
|
23
|
+
end
|
24
|
+
|
25
|
+
system cmd + url
|
26
|
+
end
|
27
|
+
end
|
data/rss-reader.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'rss-reader'
|
3
|
+
s.version = '1.0.0'
|
4
|
+
s.summary = 'RSS Reader!'
|
5
|
+
s.description = 'A simple cli RSS Reader'
|
6
|
+
s.authors = ['Mark24']
|
7
|
+
s.email = 'mark.zhangyoung@gmail.com'
|
8
|
+
s.files = ['lib/*.rb']
|
9
|
+
s.homepage =
|
10
|
+
'https://github.com/Mark24Code/rss-reader'
|
11
|
+
s.license = 'MIT'
|
12
|
+
|
13
|
+
s.files = Dir.chdir(__dir__) do
|
14
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
15
|
+
(File.expand_path(f) == __FILE__) ||
|
16
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
s.bindir = 'exe'
|
20
|
+
s.executables = s.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
21
|
+
s.require_paths = ['lib']
|
22
|
+
s.add_dependency 'async', '~> 2.6'
|
23
|
+
s.add_dependency 'colorize', '~> 1.1.0'
|
24
|
+
s.add_dependency 'nokogiri', '~> 1.15.4'
|
25
|
+
s.add_dependency 'rss', '~> 0.3.0'
|
26
|
+
s.add_dependency 'tty-link', '~> 0.1.1'
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rss-reader
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mark24
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-10-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: async
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: colorize
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.1.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.1.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.15.4
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.15.4
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rss
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.3.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.3.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: tty-link
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.1.1
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.1.1
|
83
|
+
description: A simple cli RSS Reader
|
84
|
+
email: mark.zhangyoung@gmail.com
|
85
|
+
executables:
|
86
|
+
- rss-reader
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- README.md
|
91
|
+
- exe/rss-reader
|
92
|
+
- lib/client.rb
|
93
|
+
- lib/core.rb
|
94
|
+
- lib/patch.rb
|
95
|
+
- lib/utils.rb
|
96
|
+
- rss-reader.gemspec
|
97
|
+
homepage: https://github.com/Mark24Code/rss-reader
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
metadata: {}
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubygems_version: 3.4.19
|
117
|
+
signing_key:
|
118
|
+
specification_version: 4
|
119
|
+
summary: RSS Reader!
|
120
|
+
test_files: []
|