lideo 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/lideo +3 -0
- data/lib/channel.rb +12 -0
- data/lib/cli.rb +119 -0
- data/lib/feed.rb +17 -0
- data/lib/fetcher.rb +19 -0
- data/lib/headline.rb +18 -0
- data/lib/html.rb +24 -0
- data/lib/lideo_controller.rb +35 -0
- data/lib/lideo_dao.rb +46 -0
- data/lib/printer.rb +18 -0
- data/lib/templates/news_feed.mustache +40 -0
- metadata +57 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9cc1aab3e6fd0b769bfa1dc673e99c29ef5757d2d2bc95c59411feae16f326b1
|
4
|
+
data.tar.gz: efb80dfc49a95d65b0a58f1a1e0ab260473ebba1172c064f5cde36011fbbd9df
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e3324132230af14b6cb33edc877849a644c5c5793dbfac189a698331d0e199f7433ce31577df8ed328090af45676e0eaf0c0a82f329aa7576fd911deced1e58e
|
7
|
+
data.tar.gz: c833964727045b18d3b6685a44ad028b6220fa43828c46c6d024e108723d21f65f6f6410af9b9438dacc2df54b27b51388385151440766078aa869839d42bae2
|
data/bin/lideo
ADDED
data/lib/channel.rb
ADDED
data/lib/cli.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'lideo_controller'
|
4
|
+
require 'html'
|
5
|
+
|
6
|
+
BANNER = "+-+-+-+-+-+ +-+-+-+\n" +
|
7
|
+
"|L|i|d|e|o| |R|S|S|\n" +
|
8
|
+
"+-+-+-+-+-+ +-+-+-+\n"
|
9
|
+
|
10
|
+
class Cli < Thor
|
11
|
+
map %w[--version -v] => :__print_version
|
12
|
+
|
13
|
+
desc '--version -v', 'Prints the current version'
|
14
|
+
|
15
|
+
def __print_version
|
16
|
+
puts version
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'add [URL]', 'Adds an RSS feed url. Use -g flag to specify a group.'
|
20
|
+
options g: :string
|
21
|
+
|
22
|
+
def add(url)
|
23
|
+
unless valid_url?(url)
|
24
|
+
puts 'Invalid URL'
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
LideoController.new.add(url, group(options))
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'fetch', 'Fetches and prints out the headlines of your feeds. Use -g flag to specify a group.'
|
32
|
+
long_desc <<-LONGDESC
|
33
|
+
Fetches and prints out the headlines of your feeds. Available flags:
|
34
|
+
|
35
|
+
With -g Fetches feeds for the specified group only
|
36
|
+
|
37
|
+
With --to [OPTION] Fetches the feeds and outputs to the method specified in the option parameter. If omitted will output to the console.
|
38
|
+
Available options:
|
39
|
+
|
40
|
+
HTML
|
41
|
+
LONGDESC
|
42
|
+
options g: :string
|
43
|
+
options to: :string
|
44
|
+
|
45
|
+
def fetch
|
46
|
+
headlines = LideoController.new.fetch(group(options))
|
47
|
+
puts 'No news for you this time' if headlines.empty?
|
48
|
+
|
49
|
+
export_html(headlines) && return if options[:to] && options[:to].downcase == 'html'
|
50
|
+
|
51
|
+
puts "#{banner}#{format_headlines_output(headlines)}" unless headlines.empty? || !options[:to].nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
desc 'feeds', 'Outputs a list of your feeds. Use -r [URL] to remove a feed'
|
55
|
+
options r: :string
|
56
|
+
|
57
|
+
def feeds
|
58
|
+
url_to_remove = from_r_option(options)
|
59
|
+
if url_to_remove.nil?
|
60
|
+
list_feeds
|
61
|
+
else
|
62
|
+
remove_feed(url_to_remove)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def list_feeds
|
69
|
+
s = StringIO.new
|
70
|
+
LideoController.new.feeds.map { |feed| s << "#{feed.to_s}\n" }
|
71
|
+
output = !s.string.empty? ? s.string : 'You have not added any feeds yet'
|
72
|
+
puts output
|
73
|
+
end
|
74
|
+
|
75
|
+
def remove_feed(url)
|
76
|
+
LideoController.new.remove_feed(url)
|
77
|
+
end
|
78
|
+
|
79
|
+
def export_html(headlines)
|
80
|
+
puts Html.new.export(headlines)
|
81
|
+
end
|
82
|
+
|
83
|
+
def group(options)
|
84
|
+
options[:g].nil? || options[:g].empty? ? 'default' : options[:g]
|
85
|
+
end
|
86
|
+
|
87
|
+
def from_r_option(options)
|
88
|
+
options[:r] unless options[:r].nil? || options[:r].empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
def valid_url?(url)
|
92
|
+
uri = URI.parse(url)
|
93
|
+
uri.is_a?(URI::HTTP) && !uri.host.nil?
|
94
|
+
rescue URI::InvalidURIError
|
95
|
+
false
|
96
|
+
end
|
97
|
+
|
98
|
+
def version
|
99
|
+
@version ||= Gem::Specification.load('lideo.gemspec').version
|
100
|
+
end
|
101
|
+
|
102
|
+
def banner
|
103
|
+
s = StringIO.new
|
104
|
+
s << BANNER
|
105
|
+
s << "#{version}\n"
|
106
|
+
s.string
|
107
|
+
end
|
108
|
+
|
109
|
+
def format_headlines_output(headlines_grouped)
|
110
|
+
s = StringIO.new
|
111
|
+
headlines_grouped.each_key do |channel|
|
112
|
+
s << "\n#{channel}\n"
|
113
|
+
headlines_grouped[channel].each do |headline|
|
114
|
+
s << " > #{headline}\n"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
s.string
|
118
|
+
end
|
119
|
+
end
|
data/lib/feed.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Feed
|
2
|
+
attr_reader :url, :group
|
3
|
+
|
4
|
+
def initialize(url, group)
|
5
|
+
@url = url
|
6
|
+
@group = group
|
7
|
+
end
|
8
|
+
|
9
|
+
def ==(other)
|
10
|
+
!other.nil? && @url == other.url && @group == other.group
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"[#{@group}] #{@url}"
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/lib/fetcher.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'headline'
|
2
|
+
require 'rss'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'rss/atom'
|
5
|
+
|
6
|
+
class Fetcher
|
7
|
+
def fetch(feed)
|
8
|
+
open(feed.url) do |rss|
|
9
|
+
fetched = RSS::Parser.parse(rss)
|
10
|
+
fetched.items.map do |item|
|
11
|
+
title = fetched.is_a?(RSS::Atom::Feed) ? item.title.content : item.title
|
12
|
+
link = fetched.is_a?(RSS::Atom::Feed) ? item.link.href : item.link
|
13
|
+
channel = fetched.is_a?(RSS::Atom::Feed) ? fetched.author.name.content : fetched.channel.title
|
14
|
+
|
15
|
+
Headline.new(title, link, channel)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/headline.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class Headline
|
2
|
+
attr_reader :title, :url, :channel
|
3
|
+
|
4
|
+
def initialize(title, url, channel = '')
|
5
|
+
@title = title
|
6
|
+
@url = url
|
7
|
+
@channel = channel
|
8
|
+
end
|
9
|
+
|
10
|
+
def ==(other)
|
11
|
+
!other.nil? && other.is_a?(Headline) && @title == other.title &&
|
12
|
+
@url == other.url && @channel == other.channel
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"#{title} [#{url}]"
|
17
|
+
end
|
18
|
+
end
|
data/lib/html.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'mustache'
|
2
|
+
require 'channel'
|
3
|
+
|
4
|
+
class Html
|
5
|
+
HOME_FOLDER = File.expand_path('~')
|
6
|
+
|
7
|
+
def export(headlines)
|
8
|
+
Mustache.template_file = File.dirname(__FILE__) + '/templates/news_feed.mustache'
|
9
|
+
view = Mustache.new
|
10
|
+
view[:channels] = to_channel_array(headlines)
|
11
|
+
view[:generated_at] = Time.now.strftime('%d/%m/%Y %H:%M')
|
12
|
+
|
13
|
+
file_name = "#{HOME_FOLDER}/lideo_news_feed.html"
|
14
|
+
open(file_name, 'w') { |f|
|
15
|
+
f.write(view.render)
|
16
|
+
}
|
17
|
+
|
18
|
+
file_name
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_channel_array(headlines)
|
22
|
+
headlines.collect { |key, value| Channel.new(key, value) }
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'feed'
|
3
|
+
require 'lideo_dao'
|
4
|
+
require 'fetcher'
|
5
|
+
|
6
|
+
class LideoController
|
7
|
+
def add(url, group)
|
8
|
+
LideoDao.new.save(Feed.new(url, group))
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch(group)
|
12
|
+
LideoDao.new.find(group)
|
13
|
+
.map { |feed| fetcher.fetch(feed) }
|
14
|
+
.flatten
|
15
|
+
.group_by(&:channel)
|
16
|
+
end
|
17
|
+
|
18
|
+
def feeds
|
19
|
+
LideoDao.new.all
|
20
|
+
end
|
21
|
+
|
22
|
+
def remove_feed(url)
|
23
|
+
LideoDao.new.delete_feed(url)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def fetcher
|
29
|
+
@fetcher ||= Fetcher.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def save_to_file(headlines)
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
data/lib/lideo_dao.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'pstore'
|
2
|
+
|
3
|
+
class LideoDao
|
4
|
+
DB_FILE_NAME = 'lideo.pstore'
|
5
|
+
DB_FOLDER = '.lideo'
|
6
|
+
HOME_FOLDER = File.expand_path('~')
|
7
|
+
FULL_DB_FILE_PATH = "#{HOME_FOLDER}/#{DB_FOLDER}/#{DB_FILE_NAME}"
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
db_folder_full_path = "#{HOME_FOLDER}/#{DB_FOLDER}"
|
11
|
+
unless File.directory?(db_folder_full_path)
|
12
|
+
FileUtils.mkdir_p(db_folder_full_path)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def save(feed)
|
17
|
+
PStore.new(FULL_DB_FILE_PATH).transaction { |store| store[feed.url] = feed }
|
18
|
+
end
|
19
|
+
|
20
|
+
def find(group)
|
21
|
+
store = PStore.new(FULL_DB_FILE_PATH)
|
22
|
+
list = []
|
23
|
+
store.transaction(true) do
|
24
|
+
store.roots
|
25
|
+
.map { |root| list << store[root] if store[root].group == group }
|
26
|
+
end
|
27
|
+
list
|
28
|
+
end
|
29
|
+
|
30
|
+
def all
|
31
|
+
store = PStore.new(FULL_DB_FILE_PATH)
|
32
|
+
list = []
|
33
|
+
store.transaction(true) do
|
34
|
+
store.roots.map { |root| list << store[root] }
|
35
|
+
end
|
36
|
+
list
|
37
|
+
end
|
38
|
+
|
39
|
+
def delete_feed(url)
|
40
|
+
PStore.new(FULL_DB_FILE_PATH).transaction do |store|
|
41
|
+
raise ArgumentError, "Feed #{url} not found" if store[url].nil?
|
42
|
+
|
43
|
+
store.delete(url)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/printer.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class Printer
|
2
|
+
def to_html(headlines)
|
3
|
+
puts ''
|
4
|
+
end
|
5
|
+
#def print_to_file(filename, content)
|
6
|
+
# if content.empty?
|
7
|
+
# puts "No content found"
|
8
|
+
# else
|
9
|
+
# open("~/#{filename}", 'w') { |f|
|
10
|
+
# content.each do |channel, headlines|
|
11
|
+
# f.puts "#{channel}"
|
12
|
+
# headlines.each { |headline| f.puts " > #{headline}" }
|
13
|
+
# puts ''
|
14
|
+
# end
|
15
|
+
# }
|
16
|
+
# end
|
17
|
+
#end
|
18
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Lideo</title>
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
6
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
|
7
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
|
8
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
|
12
|
+
<div class="container">
|
13
|
+
<h2 style="text-align:left;float:left;">Lideo RSS Reader</h2>
|
14
|
+
<h4 style="text-align:right;float:left;">v1.0.0</h4>
|
15
|
+
<hr style="clear:both;"/>
|
16
|
+
<p><strong>Generated at:</strong> {{ generated_at }}</p>
|
17
|
+
<div class="panel-group" id="accordion">
|
18
|
+
{{#channels}}
|
19
|
+
<div class="panel panel-default">
|
20
|
+
<div class="panel-heading">
|
21
|
+
<h4 class="panel-title">
|
22
|
+
<a data-toggle="collapse" data-parent="#accordion" href="#collapse-{{ id }}">{{ name }}</a>
|
23
|
+
</h4>
|
24
|
+
</div>
|
25
|
+
<div id="collapse-{{ id }}" class="panel-collapse collapse">
|
26
|
+
<div class="panel-body">
|
27
|
+
{{#headlines}}
|
28
|
+
<a href="{{ url }}" class="block" target="_blank">
|
29
|
+
<p> {{ title }} </p>
|
30
|
+
</a>
|
31
|
+
{{/headlines}}
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
{{/channels}}
|
36
|
+
</div>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
</body>
|
40
|
+
</html>
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lideo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gyowanny Queiroz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-03-09 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A simple RSS aggregator CLI where you can read the headlines from your
|
14
|
+
terminal
|
15
|
+
email:
|
16
|
+
- gyowanny@gmail.com
|
17
|
+
executables:
|
18
|
+
- lideo
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- bin/lideo
|
23
|
+
- lib/channel.rb
|
24
|
+
- lib/cli.rb
|
25
|
+
- lib/feed.rb
|
26
|
+
- lib/fetcher.rb
|
27
|
+
- lib/headline.rb
|
28
|
+
- lib/html.rb
|
29
|
+
- lib/lideo_controller.rb
|
30
|
+
- lib/lideo_dao.rb
|
31
|
+
- lib/printer.rb
|
32
|
+
- lib/templates/news_feed.mustache
|
33
|
+
homepage: http://rubygems.org/gems/lideo
|
34
|
+
licenses:
|
35
|
+
- MIT
|
36
|
+
metadata:
|
37
|
+
source_code_uri: https://github.com/gyoqueiroz/lideo
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubygems_version: 3.0.3
|
54
|
+
signing_key:
|
55
|
+
specification_version: 4
|
56
|
+
summary: Lideo RSS Aggregator
|
57
|
+
test_files: []
|