lideo 1.0.6

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 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
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'cli'
3
+ Cli.start(ARGV)
data/lib/channel.rb ADDED
@@ -0,0 +1,12 @@
1
+ class Channel
2
+ attr_reader :name, :headlines
3
+
4
+ def initialize(name, headlines)
5
+ @name = name
6
+ @headlines = headlines
7
+ end
8
+
9
+ def id
10
+ @name.gsub(/[^0-9a-z]/i, '')
11
+ end
12
+ end
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: []