vnews 0.0.1
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.
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +19 -0
- data/MIT-LICENSE.txt +21 -0
- data/Rakefile +37 -0
- data/bin/vnews-client +19 -0
- data/lib/create.sql +36 -0
- data/lib/vnews.rb +63 -0
- data/lib/vnews.vim +472 -0
- data/lib/vnews/autodiscoverer.rb +24 -0
- data/lib/vnews/config.rb +122 -0
- data/lib/vnews/display.rb +157 -0
- data/lib/vnews/exceptions.rb +4 -0
- data/lib/vnews/feed.rb +77 -0
- data/lib/vnews/folder.rb +29 -0
- data/lib/vnews/opml.rb +50 -0
- data/lib/vnews/sql.rb +190 -0
- data/lib/vnews/version.rb +4 -0
- data/recreate.sh +3 -0
- data/vnews.gemspec +27 -0
- metadata +111 -0
data/lib/vnews/sql.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'mysql2'
|
2
|
+
class Vnews
|
3
|
+
class Sql
|
4
|
+
attr_accessor :config, :client
|
5
|
+
|
6
|
+
def self.shell_escape(string)
|
7
|
+
require 'shellwords'
|
8
|
+
Shellwords.shellescape(string)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.create_db(config)
|
12
|
+
config = symbolize_config(config)
|
13
|
+
create_sql = File.join(File.dirname(__FILE__), '..', 'create.sql')
|
14
|
+
passwordarg = config[:password] ? ("-p #{shell_escape(config[:password])}") : ''
|
15
|
+
puts `mysqladmin -h #{shell_escape config[:host]} -u #{shell_escape config[:username]} #{passwordarg} create #{shell_escape config[:database]}`
|
16
|
+
puts `mysql -h #{shell_escape config[:host]} -D #{shell_escape config[:database]} -u #{shell_escape config[:username]} #{passwordarg} < #{create_sql}`
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.symbolize_config(config)
|
20
|
+
config = config.inject({}) do |memo, (key, value)|
|
21
|
+
memo[key.to_sym] = value
|
22
|
+
memo
|
23
|
+
end
|
24
|
+
config
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(config = {})
|
28
|
+
config = Vnews::Sql.symbolize_config(config)
|
29
|
+
defaults = {:host => 'localhost', :database => 'vnews', :username => 'root', :password => nil}
|
30
|
+
@config = defaults.update(config)
|
31
|
+
@client = Mysql2::Client.new @config
|
32
|
+
end
|
33
|
+
|
34
|
+
def insert_feed(title, feed_url, link, folder=nil)
|
35
|
+
if folder.nil?
|
36
|
+
folder = 'Misc'
|
37
|
+
end
|
38
|
+
@client.query "INSERT IGNORE INTO feeds (title, feed_url, link) VALUES ('#{e title}', '#{e feed_url}', '#{e link}')"
|
39
|
+
if folder
|
40
|
+
@client.query "INSERT IGNORE INTO feeds_folders (feed, folder) VALUES ('#{e feed_url}', '#{e folder}')"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def delete_feed_items(feed_url)
|
45
|
+
puts @client.query("DELETE from items where feed = '#{e feed_url}'")
|
46
|
+
end
|
47
|
+
|
48
|
+
def delete_feed(feed_url)
|
49
|
+
@client.query "DELETE from feeds where feed_url = '#{e feed_url}'"
|
50
|
+
# Delete all unstarred items from these feeds
|
51
|
+
@client.query "DELETE from items where feed = '#{e feed_url}' and starred = false"
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete_feed_folder(feed, folder)
|
55
|
+
@client.query "DELETE from feeds_folders where feed = '#{e feed}' and folder = '#{e folder}'"
|
56
|
+
end
|
57
|
+
|
58
|
+
def insert_item(item)
|
59
|
+
# not sure if this is efficient
|
60
|
+
@client.query "DELETE from items WHERE guid = '#{e item[:guid]}' and feed = '#{e item[:feed_title]}'"
|
61
|
+
@client.query "INSERT IGNORE INTO items (guid, feed, feed_title, title, link, pub_date, author, text, word_count)
|
62
|
+
VALUES (
|
63
|
+
'#{e item[:guid]}',
|
64
|
+
'#{e item[:feed]}',
|
65
|
+
'#{e item[:feed_title]}',
|
66
|
+
'#{e item[:title]}',
|
67
|
+
'#{e item[:link]}',
|
68
|
+
'#{item[:pub_date]}',
|
69
|
+
'#{e item[:author]}',
|
70
|
+
'#{e item[:content][:text]}',
|
71
|
+
'#{item[:content][:text].scan(/\S+/).size}'
|
72
|
+
)"
|
73
|
+
end
|
74
|
+
|
75
|
+
# queries:
|
76
|
+
|
77
|
+
def folders
|
78
|
+
all = @client.query("SELECT 'All' as folder, count(*) as count from items where items.unread = true").first
|
79
|
+
starred = @client.query("SELECT 'Starred' as folder, count(*) as count from items
|
80
|
+
where items.starred = true").first
|
81
|
+
folders = @client.query("SELECT folder, count(*) as count from feeds_folders
|
82
|
+
inner join items i on i.feed = feeds_folders.feed
|
83
|
+
where i.unread = true group by folder order by folder")
|
84
|
+
folders = [all, starred] + folders.to_a
|
85
|
+
folders
|
86
|
+
end
|
87
|
+
|
88
|
+
def configured_folders
|
89
|
+
folders = @client.query("SELECT distinct(folder) from feeds_folders order by folder asc")
|
90
|
+
end
|
91
|
+
|
92
|
+
def configured_feeds_folders
|
93
|
+
@client.query("SELECT feed,folder from feeds_folders order by folder asc").map {|x| [x['feed'], x['folder']]}
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def feeds(order)
|
98
|
+
if order == 0
|
99
|
+
# "feeds.title asc"
|
100
|
+
@client.query("SELECT feeds.*, count(*) as item_count from feeds
|
101
|
+
inner join items i on i.feed = feeds.feed_url
|
102
|
+
where i.unread = true
|
103
|
+
group by feeds.feed_url
|
104
|
+
order by feeds.title asc")
|
105
|
+
else
|
106
|
+
@client.query("SELECT feeds.*, feeds.num_items_read as item_count from feeds
|
107
|
+
order by num_items_read desc, title asc")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def feeds_in_folder(folder)
|
112
|
+
case folder
|
113
|
+
when "All"
|
114
|
+
@client.query("SELECT feed_url from feeds order by title asc").map {|x| x['feed_url']}
|
115
|
+
when "Starred"
|
116
|
+
return []
|
117
|
+
else
|
118
|
+
@client.query("SELECT feed from feeds_folders ff where ff.folder = '#{e folder}'").map {|x| x['feed']}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Not perfect because some feeds may have dup titles, but ok for now
|
123
|
+
def feed_items(feed_title)
|
124
|
+
# update last_viewed_at
|
125
|
+
@client.query "UPDATE feeds SET last_viewed_at = now() where title = '#{e feed_title}'"
|
126
|
+
query = "SELECT items.title, guid, feed, feed_title, pub_date, word_count, starred, unread from items where items.feed_title = '#{e feed_title}' order by pub_date asc"
|
127
|
+
@client.query(query)
|
128
|
+
end
|
129
|
+
|
130
|
+
def feed_by_title(feed_title)
|
131
|
+
query = "SELECT * from feeds where title = '#{e feed_title}'"
|
132
|
+
@client.query(query).first["feed_url"]
|
133
|
+
end
|
134
|
+
|
135
|
+
def folder_items(folder)
|
136
|
+
query = case folder
|
137
|
+
when 'Starred'
|
138
|
+
"SELECT items.title, items.guid, items.feed,
|
139
|
+
items.feed_title, items.pub_date, items.word_count, items.starred, items.unread from items
|
140
|
+
where items.starred = true order by items.pub_date asc"
|
141
|
+
when 'All'
|
142
|
+
"SELECT items.title, items.guid, items.feed,
|
143
|
+
items.feed_title, items.pub_date, items.word_count, items.starred, items.unread from items
|
144
|
+
order by items.pub_date asc limit 10000"
|
145
|
+
else
|
146
|
+
# update last_viewed_at
|
147
|
+
@client.query "UPDATE feeds_folders SET last_viewed_at = now() where folder = '#{e folder}'"
|
148
|
+
|
149
|
+
"SELECT items.title, items.guid, items.feed,
|
150
|
+
items.feed_title, items.pub_date, items.word_count, items.starred, items.unread from items
|
151
|
+
inner join feeds_folders ff on ff.feed = items.feed
|
152
|
+
where ff.folder = '#{e folder}' order by items.pub_date asc"
|
153
|
+
end
|
154
|
+
@client.query query
|
155
|
+
end
|
156
|
+
|
157
|
+
def show_item(guid, inc_read_count=false)
|
158
|
+
# mark item as read
|
159
|
+
@client.query "UPDATE items set unread = false where guid = '#{e guid}'"
|
160
|
+
|
161
|
+
if inc_read_count
|
162
|
+
# increment the read count for the feed
|
163
|
+
@client.query "UPDATE feeds set num_items_read = num_items_read + 1 where feed_url = (select feed from items where items.guid = '#{e guid}')"
|
164
|
+
end
|
165
|
+
|
166
|
+
query = "SELECT items.* from items where guid = '#{e guid}'"
|
167
|
+
@client.query query
|
168
|
+
end
|
169
|
+
|
170
|
+
def star_item(guid, star=true)
|
171
|
+
@client.query "UPDATE items set starred = #{star} where guid = '#{e guid}'"
|
172
|
+
end
|
173
|
+
|
174
|
+
def delete_item(guid)
|
175
|
+
@client.query "DELETE from items where guid = '#{e guid}'"
|
176
|
+
end
|
177
|
+
|
178
|
+
def search_items(term)
|
179
|
+
query = "select * from items where match(title, text) against('#{e term}')"
|
180
|
+
@client.query query
|
181
|
+
end
|
182
|
+
|
183
|
+
def e(value)
|
184
|
+
return unless value
|
185
|
+
@client.escape(value)
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
data/recreate.sh
ADDED
data/vnews.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "vnews/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "vnews"
|
7
|
+
s.version = Vnews::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Daniel Choi"]
|
10
|
+
s.email = ["dhchoi@gmail.com"]
|
11
|
+
s.homepage = "http://danielchoi.com/software/vnews.html"
|
12
|
+
s.summary = %q{A Vim news reader}
|
13
|
+
s.description = %q{Read your feeds in Vim}
|
14
|
+
|
15
|
+
s.rubyforge_project = "vnews"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency 'feed_yamlizer', '>=0.0.6'
|
23
|
+
s.add_dependency 'nokogiri'
|
24
|
+
|
25
|
+
# remember to say in readme that fmt and tidy are required
|
26
|
+
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vnews
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Daniel Choi
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-02-21 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: feed_yamlizer
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
- 0
|
31
|
+
- 6
|
32
|
+
version: 0.0.6
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: nokogiri
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
description: Read your feeds in Vim
|
49
|
+
email:
|
50
|
+
- dhchoi@gmail.com
|
51
|
+
executables:
|
52
|
+
- vnews-client
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- Gemfile
|
60
|
+
- Gemfile.lock
|
61
|
+
- MIT-LICENSE.txt
|
62
|
+
- Rakefile
|
63
|
+
- bin/vnews-client
|
64
|
+
- lib/create.sql
|
65
|
+
- lib/vnews.rb
|
66
|
+
- lib/vnews.vim
|
67
|
+
- lib/vnews/autodiscoverer.rb
|
68
|
+
- lib/vnews/config.rb
|
69
|
+
- lib/vnews/display.rb
|
70
|
+
- lib/vnews/exceptions.rb
|
71
|
+
- lib/vnews/feed.rb
|
72
|
+
- lib/vnews/folder.rb
|
73
|
+
- lib/vnews/opml.rb
|
74
|
+
- lib/vnews/sql.rb
|
75
|
+
- lib/vnews/version.rb
|
76
|
+
- recreate.sh
|
77
|
+
- vnews.gemspec
|
78
|
+
has_rdoc: true
|
79
|
+
homepage: http://danielchoi.com/software/vnews.html
|
80
|
+
licenses: []
|
81
|
+
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
requirements: []
|
104
|
+
|
105
|
+
rubyforge_project: vnews
|
106
|
+
rubygems_version: 1.3.7
|
107
|
+
signing_key:
|
108
|
+
specification_version: 3
|
109
|
+
summary: A Vim news reader
|
110
|
+
test_files: []
|
111
|
+
|