delish 0.6.1 → 0.7.7
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/README +6 -3
- data/bin/delish +1 -0
- data/bin/import_delicious +2 -80
- data/bin/update_delicious +22 -0
- data/lib/delish_bookmark_search.rb +250 -247
- data/lib/import_delish.rb +169 -0
- data/test/tests +2 -1
- metadata +5 -3
- data/test/test_db +0 -0
data/README
CHANGED
@@ -12,6 +12,12 @@ And then import your bookmarks.
|
|
12
12
|
|
13
13
|
You can access these bookmarks with the <tt>delish</tt> command. See more below.
|
14
14
|
|
15
|
+
Once you have set the environment variables, you can update your bookmarks with
|
16
|
+
|
17
|
+
<tt>update_delicious</tt>
|
18
|
+
|
19
|
+
I recommend that you update as often as you add between one and ten bookmarks. Updating any more than ten bookmarks will be slow and inefficient.
|
20
|
+
|
15
21
|
= delish
|
16
22
|
|
17
23
|
Conveniently access del.icio.us bookmarks from a local database via commandline
|
@@ -79,11 +85,8 @@ Dates begin with a character specifying which date to check against. The charac
|
|
79
85
|
* "search" tags
|
80
86
|
* zsh configuration section
|
81
87
|
* Month, minute, and second support
|
82
|
-
* Tags table in underlying database to improve searching speed
|
83
88
|
* Profile the code to increase speed
|
84
|
-
* Date Unit Tests
|
85
89
|
* "Build Script"
|
86
|
-
* Incremental updates instead of always importing all bookmarks
|
87
90
|
|
88
91
|
== Links
|
89
92
|
|
data/bin/delish
CHANGED
data/bin/import_delicious
CHANGED
@@ -10,86 +10,8 @@ pass = ENV['delish_pass']
|
|
10
10
|
|
11
11
|
db = SQLite3::Database.new( "#{ENV['HOME']}/.delish" )
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
#{{{ initialize(user, pass, db)
|
16
|
-
def initialize(user, pass, db)
|
17
|
-
@user = user
|
18
|
-
@pass = pass
|
19
|
-
@db = db
|
20
|
-
end
|
21
|
-
#}}}
|
22
|
-
|
23
|
-
#{{{ create_database
|
24
|
-
def create_database
|
25
|
-
# Create the table!!!
|
26
|
-
@db.execute %{
|
27
|
-
CREATE TABLE posts (
|
28
|
-
url VARCHAR(16384),
|
29
|
-
description VARCHAR(255),
|
30
|
-
extended VARCHAR(255),
|
31
|
-
created DATETIME,
|
32
|
-
hash CHAR(32) PRIMARY KEY,
|
33
|
-
accessed DATETIME
|
34
|
-
);
|
35
|
-
}
|
36
|
-
|
37
|
-
@db.execute %{
|
38
|
-
CREATE TABLE post_tags (
|
39
|
-
hash CHAR(32),
|
40
|
-
tag_id INTEGER
|
41
|
-
);}
|
42
|
-
|
43
|
-
@db.execute %{
|
44
|
-
CREATE TABLE tags (
|
45
|
-
tag VARCHAR(255) UNIQUE,
|
46
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT
|
47
|
-
);}
|
48
|
-
end
|
49
|
-
#}}}
|
50
|
-
|
51
|
-
#{{{ get_all_tags
|
52
|
-
def get_all_tags
|
53
|
-
# User-Agent: required for del.icio.us api
|
54
|
-
agent = 'delish commandline client 0.6.1'
|
55
|
-
|
56
|
-
http = Net::HTTP.new('api.del.icio.us', 443)
|
57
|
-
http.use_ssl = true
|
58
|
-
http.start do |http|
|
59
|
-
request = Net::HTTP::Get.new('/v1/posts/all', {'User-Agent' => agent})
|
60
|
-
request.basic_auth @user, @pass
|
61
|
-
response = http.request(request)
|
62
|
-
|
63
|
-
data = REXML::Document.new(response.body)
|
64
|
-
data.elements.each("/posts/post") do |post|
|
65
|
-
@db.execute(
|
66
|
-
"INSERT INTO posts
|
67
|
-
(url, description, extended, created, accessed, hash) VALUES
|
68
|
-
(?, ?, ?, JULIANDAY(?), JULIANDAY(?), ?);",
|
69
|
-
post.attributes['href'],
|
70
|
-
post.attributes['description'],
|
71
|
-
post.attributes['extended'],
|
72
|
-
post.attributes['time'].chop,
|
73
|
-
post.attributes['time'].chop,
|
74
|
-
post.attributes['hash'])
|
75
|
-
|
76
|
-
post.attributes['tag'].split(' ').each do |tag|
|
77
|
-
@db.execute(
|
78
|
-
%{INSERT OR IGNORE INTO tags (tag) VALUES (?);},
|
79
|
-
tag)
|
80
|
-
tag_id = @db.execute( %{ SELECT id FROM tags WHERE tag = ?}, tag)[0]
|
81
|
-
@db.execute(
|
82
|
-
"INSERT INTO post_tags (hash, tag_id)
|
83
|
-
VALUES (?, ?);",
|
84
|
-
post.attributes['hash'],
|
85
|
-
tag_id)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
#}}}
|
91
|
-
|
92
|
-
end
|
13
|
+
require 'import_delish.rb'
|
14
|
+
include Delish
|
93
15
|
|
94
16
|
import = ImportDelish.new(user, pass, db)
|
95
17
|
import.create_database
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rexml/document'
|
5
|
+
require 'net/https'
|
6
|
+
require 'sqlite3'
|
7
|
+
|
8
|
+
user = ENV['delish_user']
|
9
|
+
pass = ENV['delish_pass']
|
10
|
+
|
11
|
+
db = SQLite3::Database.new( "#{ENV['HOME']}/.delish" )
|
12
|
+
|
13
|
+
require 'import_delish.rb'
|
14
|
+
include Delish
|
15
|
+
|
16
|
+
import = ImportDelish.new(user, pass, db)
|
17
|
+
unless ARGV[0].nil?
|
18
|
+
import.update_bookmarks { |url, title| puts "New bookmark: #{title}[#{url}]" }
|
19
|
+
else
|
20
|
+
import.update_bookmarks
|
21
|
+
end
|
22
|
+
|
@@ -1,286 +1,289 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
2
|
+
module Delish
|
3
|
+
|
4
|
+
class SuperSQL
|
5
|
+
def initialize(order)
|
6
|
+
@statement = ""
|
7
|
+
@variables = []
|
8
|
+
if order.is_a? Integer
|
9
|
+
@order = order
|
10
|
+
else
|
11
|
+
throw "Not a good order."
|
12
|
+
end
|
11
13
|
end
|
14
|
+
attr_reader :statement
|
15
|
+
attr_reader :variables
|
16
|
+
attr_reader :order
|
17
|
+
attr_writer :statement
|
18
|
+
attr_writer :variables
|
12
19
|
end
|
13
|
-
attr_reader :statement
|
14
|
-
attr_reader :variables
|
15
|
-
attr_reader :order
|
16
|
-
attr_writer :statement
|
17
|
-
attr_writer :variables
|
18
|
-
end
|
19
20
|
|
20
|
-
class Delish_Bookmark_Search
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
class Delish_Bookmark_Search
|
22
|
+
#---
|
23
|
+
#{{{ initialize(search, database)
|
24
|
+
#+++
|
25
|
+
def initialize(search, database)
|
26
|
+
@db = database
|
26
27
|
|
27
|
-
|
28
|
-
|
28
|
+
@TAG_SPLIT = ','
|
29
|
+
@SPLIT = ':'
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
@search_string = search
|
32
|
+
@sss = []
|
32
33
|
|
33
|
-
|
34
|
-
|
34
|
+
@date_greater_or_equal = SuperSQL.new(0)
|
35
|
+
@date_greater_or_equal.statement = 'TYPE >= JULIANDAY(CURRENT_THING) - ?'
|
35
36
|
|
36
|
-
|
37
|
-
|
37
|
+
@date_less_than = SuperSQL.new(0)
|
38
|
+
@date_less_than.statement = 'TYPE < JULIANDAY(CURRENT_THING) - ?'
|
38
39
|
|
39
|
-
|
40
|
-
|
40
|
+
@use_tags = false
|
41
|
+
@tag_count = 0
|
41
42
|
|
42
|
-
|
43
|
+
self.search
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
45
|
+
end
|
46
|
+
#---
|
47
|
+
#}}}
|
48
|
+
#+++
|
49
|
+
|
50
|
+
#---
|
51
|
+
#{{{ search
|
52
|
+
#+++
|
53
|
+
def search
|
54
|
+
if @search_string =~ /^(.*?)(\((.*)\))?$/
|
55
|
+
self.main_search($1)
|
56
|
+
unless $2.nil?
|
57
|
+
@submatches = $3.split(@SPLIT)
|
58
|
+
self.sub_search_parse
|
59
|
+
end
|
60
|
+
self.execute(false)
|
58
61
|
end
|
59
|
-
self.execute(false)
|
60
62
|
end
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
#+++
|
63
|
+
#---
|
64
|
+
#}}}
|
65
|
+
#+++
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
#---
|
68
|
+
#{{{ main_search
|
69
|
+
#+++
|
70
|
+
def main_search(main_search_string)
|
71
|
+
@main_search = main_search_string
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
|
73
|
+
ssql = SuperSQL.new(40)
|
74
|
+
ssql.statement = "(url LIKE ? OR description LIKE ? OR extended LIKE ?)"
|
75
|
+
3.times { ssql.variables << "%#{main_search_string}%" }
|
75
76
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
77
|
+
@sss << ssql
|
78
|
+
end
|
79
|
+
#---
|
80
|
+
#}}}
|
81
|
+
#+++
|
82
|
+
|
83
|
+
#---
|
84
|
+
#{{{ sub_search_parse
|
85
|
+
#+++
|
86
|
+
def sub_search_parse
|
87
|
+
@submatches.each do |i|
|
88
|
+
if i =~ /^t(.*)$/
|
89
|
+
self.tag_equality_search($1)
|
90
|
+
elsif i =~ /^s(.*)$/
|
91
|
+
self.tag_begin_search($1)
|
92
|
+
elsif i =~ /^i(.*)$/
|
93
|
+
self.tag_inside_search($1)
|
94
|
+
elsif i =~ /^([ca])([Mwhms]|)([+-]|)(\d+)$/
|
95
|
+
self.date_search($1, $2, $3, $4)
|
96
|
+
end
|
95
97
|
end
|
96
98
|
end
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
@sss << ssql
|
112
|
-
end
|
113
|
-
#---
|
114
|
-
#}}}
|
115
|
-
#+++
|
116
|
-
|
117
|
-
#---
|
118
|
-
#{{{ tag_begin_search(i)
|
119
|
-
#+++
|
120
|
-
def tag_begin_search(tag_string)
|
121
|
-
@use_tags = true
|
122
|
-
|
123
|
-
ssql = SuperSQL.new(10)
|
124
|
-
ssql.variables = tag_string.split(@TAG_SPLIT).map { |i| "#{i}%" }
|
125
|
-
ssql.statement = ssql.variables.map { @tag_count += 1; 'PLACEHOLDER LIKE ?' }.join(' AND ')
|
126
|
-
@sss << ssql
|
127
|
-
end
|
128
|
-
#---
|
129
|
-
#}}}
|
130
|
-
#+++
|
131
|
-
|
132
|
-
#---
|
133
|
-
#{{{ tag_inside_search(i)
|
134
|
-
#+++
|
135
|
-
def tag_inside_search(tag_string)
|
136
|
-
@use_tags = true
|
137
|
-
|
138
|
-
ssql = SuperSQL.new(20)
|
139
|
-
ssql.variables = tag_string.split(@TAG_SPLIT).map { |i| "%#{i}%" }
|
140
|
-
ssql.statement = ssql.variables.map { @tag_count += 1; 'PLACEHOLDER LIKE ?' }.join(' AND ')
|
141
|
-
@sss << ssql
|
142
|
-
end
|
143
|
-
#---
|
144
|
-
#}}}
|
145
|
-
#+++
|
146
|
-
|
147
|
-
# This needs cleanup
|
148
|
-
#---
|
149
|
-
#{{{ date_search
|
150
|
-
#+++
|
151
|
-
def date_search(search_type, date_type, search_inner_type, amount)
|
152
|
-
|
153
|
-
type = ""
|
154
|
-
how_much = ""
|
155
|
-
date_or_time = ""
|
156
|
-
if search_type == 'c'
|
157
|
-
type = 'created'
|
158
|
-
else
|
159
|
-
type = 'accessed'
|
99
|
+
#---
|
100
|
+
#}}}
|
101
|
+
#+++
|
102
|
+
|
103
|
+
#---
|
104
|
+
#{{{ tag_equality_search(tag_string
|
105
|
+
#+++
|
106
|
+
def tag_equality_search(tag_string)
|
107
|
+
@use_tags = true
|
108
|
+
|
109
|
+
ssql = SuperSQL.new(5)
|
110
|
+
ssql.variables = tag_string.split(@TAG_SPLIT)
|
111
|
+
ssql.statement = ssql.variables.map { @tag_count += 1; 'PLACEHOLDER = ?' }.join(' AND ')
|
112
|
+
@sss << ssql
|
160
113
|
end
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
114
|
+
#---
|
115
|
+
#}}}
|
116
|
+
#+++
|
117
|
+
|
118
|
+
#---
|
119
|
+
#{{{ tag_begin_search(i)
|
120
|
+
#+++
|
121
|
+
def tag_begin_search(tag_string)
|
122
|
+
@use_tags = true
|
123
|
+
|
124
|
+
ssql = SuperSQL.new(10)
|
125
|
+
ssql.variables = tag_string.split(@TAG_SPLIT).map { |i| "#{i}%" }
|
126
|
+
ssql.statement = ssql.variables.map { @tag_count += 1; 'PLACEHOLDER LIKE ?' }.join(' AND ')
|
127
|
+
@sss << ssql
|
167
128
|
end
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
@
|
177
|
-
|
129
|
+
#---
|
130
|
+
#}}}
|
131
|
+
#+++
|
132
|
+
|
133
|
+
#---
|
134
|
+
#{{{ tag_inside_search(i)
|
135
|
+
#+++
|
136
|
+
def tag_inside_search(tag_string)
|
137
|
+
@use_tags = true
|
138
|
+
|
139
|
+
ssql = SuperSQL.new(20)
|
140
|
+
ssql.variables = tag_string.split(@TAG_SPLIT).map { |i| "%#{i}%" }
|
141
|
+
ssql.statement = ssql.variables.map { @tag_count += 1; 'PLACEHOLDER LIKE ?' }.join(' AND ')
|
142
|
+
@sss << ssql
|
178
143
|
end
|
144
|
+
#---
|
145
|
+
#}}}
|
146
|
+
#+++
|
147
|
+
|
148
|
+
# This needs cleanup
|
149
|
+
#---
|
150
|
+
#{{{ date_search
|
151
|
+
#+++
|
152
|
+
def date_search(search_type, date_type, search_inner_type, amount)
|
153
|
+
|
154
|
+
type = ""
|
155
|
+
how_much = ""
|
156
|
+
date_or_time = ""
|
157
|
+
if search_type == 'c'
|
158
|
+
type = 'created'
|
159
|
+
else
|
160
|
+
type = 'accessed'
|
161
|
+
end
|
162
|
+
if date_type == 'h'
|
163
|
+
how_much = Date.time_to_day_fraction(amount.to_i, 0, 0)
|
164
|
+
elsif date_type == ''
|
165
|
+
how_much = amount
|
166
|
+
elsif date_type == 'w'
|
167
|
+
how_much = amount * 7
|
168
|
+
end
|
169
|
+
if search_inner_type == '-'
|
170
|
+
date_or_time = "CURRENT_TIMESTAMP"
|
171
|
+
@date_greater_or_equal.variables << how_much
|
172
|
+
elsif search_inner_type == '+'
|
173
|
+
date_or_time = "CURRENT_TIMESTAMP"
|
174
|
+
@date_less_than.variables << how_much
|
175
|
+
else
|
176
|
+
date_or_time = "CURRENT_DATE"
|
177
|
+
@date_greater_or_equal.variables << how_much
|
178
|
+
@date_less_than.variables << (how_much.to_i + 1).to_s
|
179
|
+
end
|
179
180
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
#---
|
190
|
-
#{{{ execute
|
191
|
-
#+++
|
192
|
-
def execute(access)
|
193
|
-
@sss << @date_greater_or_equal unless @date_greater_or_equal.variables.empty?
|
194
|
-
@sss << @date_less_than unless @date_less_than.variables.empty?
|
181
|
+
@date_greater_or_equal.statement["TYPE"] = type
|
182
|
+
@date_less_than.statement["TYPE"] = type
|
183
|
+
@date_greater_or_equal.statement["CURRENT_THING"] = date_or_time
|
184
|
+
@date_less_than.statement["CURRENT_THING"] = date_or_time
|
185
|
+
end
|
186
|
+
#---
|
187
|
+
#}}}
|
188
|
+
#+++
|
195
189
|
|
196
|
-
|
190
|
+
#---
|
191
|
+
#{{{ execute
|
192
|
+
#+++
|
193
|
+
def execute(access)
|
194
|
+
@sss << @date_greater_or_equal unless @date_greater_or_equal.variables.empty?
|
195
|
+
@sss << @date_less_than unless @date_less_than.variables.empty?
|
197
196
|
|
198
|
-
|
197
|
+
@sss.sort! { |a, b| a.order <=> b.order }
|
199
198
|
|
200
|
-
|
199
|
+
statement, variables = self.build_statement(access)
|
201
200
|
|
202
|
-
|
203
|
-
hashes = []
|
204
|
-
@results.each { |i| hashes << i[1] }
|
205
|
-
self.mark_accessed(hashes)
|
206
|
-
end
|
201
|
+
@results = @db.execute(statement, variables)
|
207
202
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
203
|
+
if access
|
204
|
+
hashes = []
|
205
|
+
@results.each { |i| hashes << i[1] }
|
206
|
+
self.mark_accessed(hashes)
|
207
|
+
end
|
212
208
|
|
213
|
-
|
214
|
-
|
215
|
-
|
209
|
+
end
|
210
|
+
#---
|
211
|
+
#}}}
|
212
|
+
#+++
|
216
213
|
|
217
|
-
|
218
|
-
|
219
|
-
#+++
|
220
|
-
def each_with_index
|
221
|
-
@results.each_with_index { |result| yield(result) }
|
222
|
-
end
|
223
|
-
#---
|
224
|
-
#}}}
|
225
|
-
#+++
|
226
|
-
|
227
|
-
#---
|
228
|
-
#{{{ each
|
229
|
-
#+++
|
230
|
-
def each
|
231
|
-
@results.each { |result| yield(result) }
|
232
|
-
end
|
233
|
-
#---
|
234
|
-
#}}}
|
235
|
-
#+++
|
236
|
-
|
237
|
-
#---
|
238
|
-
#{{{ build_statement(access)
|
239
|
-
#+++
|
240
|
-
def build_statement(access)
|
241
|
-
variables = []
|
242
|
-
|
243
|
-
statement = "SELECT url"
|
244
|
-
|
245
|
-
unless access
|
246
|
-
statement += ", description"
|
247
|
-
else
|
248
|
-
statement += ", posts.hash"
|
214
|
+
def [](index)
|
215
|
+
@results[index]
|
249
216
|
end
|
250
217
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
218
|
+
#---
|
219
|
+
#{{{ each_with_index
|
220
|
+
#+++
|
221
|
+
def each_with_index
|
222
|
+
@results.each_with_index { |result| yield(result) }
|
223
|
+
end
|
224
|
+
#---
|
225
|
+
#}}}
|
226
|
+
#+++
|
227
|
+
|
228
|
+
#---
|
229
|
+
#{{{ each
|
230
|
+
#+++
|
231
|
+
def each
|
232
|
+
@results.each { |result| yield(result) }
|
233
|
+
end
|
234
|
+
#---
|
235
|
+
#}}}
|
236
|
+
#+++
|
237
|
+
|
238
|
+
#---
|
239
|
+
#{{{ build_statement(access)
|
240
|
+
#+++
|
241
|
+
def build_statement(access)
|
242
|
+
variables = []
|
243
|
+
|
244
|
+
statement = "SELECT url"
|
245
|
+
|
246
|
+
unless access
|
247
|
+
statement += ", description"
|
248
|
+
else
|
249
|
+
statement += ", posts.hash"
|
250
|
+
end
|
255
251
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
252
|
+
statement += " FROM posts"
|
253
|
+
@tag_count.times { |i| statement += ", post_tags AS pt#{i}, tags AS t#{i}" }
|
254
|
+
statement += " WHERE "
|
255
|
+
@tag_count.times { |i| statement += "pt#{i}.hash == posts.hash AND pt#{i}.tag_id = t#{i}.id AND " }
|
256
|
+
|
257
|
+
tag_count = 0
|
258
|
+
@sss.each_with_index do |ssql,i|
|
259
|
+
while ssql.statement.include? "PLACEHOLDER"
|
260
|
+
ssql.statement.sub!("PLACEHOLDER", "t#{tag_count}.tag")
|
261
|
+
tag_count += 1
|
262
|
+
end
|
263
|
+
statement += ssql.statement
|
264
|
+
statement += ' AND ' unless i + 1 == @sss.length
|
265
|
+
|
266
|
+
variables += ssql.variables
|
261
267
|
end
|
262
|
-
statement += ssql.statement
|
263
|
-
statement += ' AND ' unless i + 1 == @sss.length
|
264
268
|
|
265
|
-
|
269
|
+
statement += ' ORDER BY accessed'
|
270
|
+
return statement, variables
|
271
|
+
end
|
272
|
+
#---
|
273
|
+
#}}}
|
274
|
+
#+++
|
275
|
+
|
276
|
+
#---
|
277
|
+
#{{{ mark_accessed(hashes)
|
278
|
+
#+++
|
279
|
+
def mark_accessed(hashes)
|
280
|
+
statement = "UPDATE posts SET accessed = JULIANDAY(CURRENT_TIMESTAMP) WHERE hash IN (" + hashes.map {"?"}.join(",") + ")"
|
281
|
+
@db.execute(statement, hashes)
|
266
282
|
end
|
283
|
+
#---
|
284
|
+
#}}}
|
285
|
+
#+++
|
267
286
|
|
268
|
-
statement += ' ORDER BY accessed'
|
269
|
-
return statement, variables
|
270
|
-
end
|
271
|
-
#---
|
272
|
-
#}}}
|
273
|
-
#+++
|
274
|
-
|
275
|
-
#---
|
276
|
-
#{{{ mark_accessed(hashes)
|
277
|
-
#+++
|
278
|
-
def mark_accessed(hashes)
|
279
|
-
statement = "UPDATE posts SET accessed = JULIANDAY(CURRENT_TIMESTAMP) WHERE hash IN (" + hashes.map {"?"}.join(",") + ")"
|
280
|
-
@db.execute(statement, hashes)
|
281
287
|
end
|
282
|
-
#---
|
283
|
-
#}}}
|
284
|
-
#+++
|
285
288
|
|
286
289
|
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module Delish
|
2
|
+
|
3
|
+
#{{{
|
4
|
+
class ImportDelish
|
5
|
+
|
6
|
+
#{{{ initialize(user, pass, db)
|
7
|
+
def initialize(user, pass, db)
|
8
|
+
@user = user
|
9
|
+
@pass = pass
|
10
|
+
@db = db
|
11
|
+
# Version should somehow be gotten from GEM
|
12
|
+
@agent = 'delish commandline client 0.7.7'
|
13
|
+
end
|
14
|
+
#}}}
|
15
|
+
|
16
|
+
#{{{ create_database
|
17
|
+
def create_database
|
18
|
+
@db.execute %{
|
19
|
+
CREATE TABLE posts (
|
20
|
+
url VARCHAR(16384),
|
21
|
+
description VARCHAR(255),
|
22
|
+
extended VARCHAR(255),
|
23
|
+
created DATETIME,
|
24
|
+
hash CHAR(32) PRIMARY KEY,
|
25
|
+
accessed DATETIME
|
26
|
+
);
|
27
|
+
}
|
28
|
+
|
29
|
+
@db.execute %{
|
30
|
+
CREATE TABLE post_tags (
|
31
|
+
hash CHAR(32),
|
32
|
+
tag_id INTEGER
|
33
|
+
);}
|
34
|
+
|
35
|
+
@db.execute %{
|
36
|
+
CREATE TABLE tags (
|
37
|
+
tag VARCHAR(255) UNIQUE,
|
38
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT
|
39
|
+
);}
|
40
|
+
|
41
|
+
@db.execute "CREATE TABLE vars ( lastupdate CHAR(20));"
|
42
|
+
|
43
|
+
@db.execute "INSERT INTO vars (lastupdate) VALUES ('0000-00-00T00:00:00Z');"
|
44
|
+
end
|
45
|
+
#}}}
|
46
|
+
|
47
|
+
#{{{ insert_post(url, description, extended, created, accessed, hash, tags)
|
48
|
+
def insert_post(url, description, extended, created, accessed, hash, tags)
|
49
|
+
@db.execute(
|
50
|
+
"INSERT INTO posts (url, description, extended, created, accessed, hash) VALUES (?, ?, ?, JULIANDAY(?), JULIANDAY(?), ?);",
|
51
|
+
url,
|
52
|
+
description,
|
53
|
+
extended,
|
54
|
+
created,
|
55
|
+
accessed,
|
56
|
+
hash)
|
57
|
+
|
58
|
+
tags.split(' ').each do |tag|
|
59
|
+
@db.execute(
|
60
|
+
"INSERT OR IGNORE INTO tags (tag) VALUES (?);", tag)
|
61
|
+
|
62
|
+
tag_id =
|
63
|
+
@db.get_first_row( "SELECT id FROM tags WHERE tag = ?;", tag)
|
64
|
+
|
65
|
+
@db.execute(
|
66
|
+
"INSERT INTO post_tags (hash, tag_id) VALUES (?, ?);",
|
67
|
+
hash, tag_id)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
#}}}
|
71
|
+
|
72
|
+
#{{{ insert_post_xml_helper
|
73
|
+
def insert_post_xml_helper(post)
|
74
|
+
self.insert_post(
|
75
|
+
post.attributes['href'],
|
76
|
+
post.attributes['description'],
|
77
|
+
post.attributes['extended'],
|
78
|
+
post.attributes['time'].chop,
|
79
|
+
post.attributes['time'].chop,
|
80
|
+
post.attributes['hash'],
|
81
|
+
post.attributes['tag'])
|
82
|
+
end
|
83
|
+
#}}}
|
84
|
+
|
85
|
+
#{{{ get_all_tags
|
86
|
+
def get_all_tags
|
87
|
+
self.delicious_communication('/v1/posts/all') do |data|
|
88
|
+
data.elements.each("/posts/post") { |post| self.insert_post_xml_helper(post) }
|
89
|
+
end
|
90
|
+
self.set_last_update
|
91
|
+
end
|
92
|
+
#}}}
|
93
|
+
|
94
|
+
#{{{ update_exists?
|
95
|
+
def update_exists?
|
96
|
+
self.delicious_communication('/v1/posts/update') do |data|
|
97
|
+
@last_post = data.elements['update'].attributes['time']
|
98
|
+
@last_update = (@db.get_first_row("SELECT lastupdate FROM vars;"))[0]
|
99
|
+
return @last_post != @last_update
|
100
|
+
end
|
101
|
+
end
|
102
|
+
#}}}
|
103
|
+
|
104
|
+
#{{{ set_last_update
|
105
|
+
def set_last_update
|
106
|
+
self.update_exists? if @last_post.nil?
|
107
|
+
@db.execute("UPDATE vars SET lastupdate = ?;", @last_post)
|
108
|
+
end
|
109
|
+
#}}}
|
110
|
+
|
111
|
+
# This function is STILL TOO LONG
|
112
|
+
#{{{ update_bookmarks
|
113
|
+
def update_bookmarks(&block)
|
114
|
+
|
115
|
+
if self.update_exists?
|
116
|
+
|
117
|
+
found = false
|
118
|
+
amount = 10
|
119
|
+
increment = 10
|
120
|
+
|
121
|
+
# Maximum for del.icio.us api is 100
|
122
|
+
until found == true or amount >= 100
|
123
|
+
self.delicious_communication("/v1/posts/recent?count=#{amount}") do |data|
|
124
|
+
|
125
|
+
elements = data.elements.to_a("/posts/post")
|
126
|
+
# Remove the ones we already went through
|
127
|
+
elements.slice(increment, amount - increment)
|
128
|
+
|
129
|
+
elements.each do |post,i|
|
130
|
+
if post.attributes['time'] <= @last_update
|
131
|
+
found = true
|
132
|
+
else
|
133
|
+
# Output should be able to be surpressed
|
134
|
+
yield(post.attributes['href'], post.attributes['description']) unless block.nil?
|
135
|
+
self.insert_post_xml_helper(post)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
amount += increment
|
141
|
+
end
|
142
|
+
end
|
143
|
+
self.set_last_update
|
144
|
+
end
|
145
|
+
|
146
|
+
#}}}
|
147
|
+
|
148
|
+
#{{{ delicious_communication(path, &block)
|
149
|
+
def delicious_communication(path, &block)
|
150
|
+
http = Net::HTTP.new('api.del.icio.us', 443)
|
151
|
+
http.use_ssl = true
|
152
|
+
http.start do |http|
|
153
|
+
request = Net::HTTP::Get.new(path, {'User-Agent' => @agent})
|
154
|
+
request.basic_auth @user, @pass
|
155
|
+
response = http.request(request)
|
156
|
+
sleep 1
|
157
|
+
|
158
|
+
data = REXML::Document.new(response.body)
|
159
|
+
|
160
|
+
yield(data)
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
164
|
+
#}}}
|
165
|
+
|
166
|
+
end
|
167
|
+
#}}}
|
168
|
+
|
169
|
+
end
|
data/test/tests
CHANGED
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: delish
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-07-
|
6
|
+
version: 0.7.7
|
7
|
+
date: 2007-07-09 00:00:00 -06:00
|
8
8
|
summary: Allows use of del.icio.us bookmarksfrom the commandline with minimum keystrokes
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -31,9 +31,10 @@ authors:
|
|
31
31
|
files:
|
32
32
|
- bin/delish
|
33
33
|
- bin/import_delicious
|
34
|
+
- bin/update_delicious
|
34
35
|
- lib/delish_bookmark_search.rb
|
36
|
+
- lib/import_delish.rb
|
35
37
|
- test/tests
|
36
|
-
- test/test_db
|
37
38
|
- README
|
38
39
|
test_files:
|
39
40
|
- test/tests
|
@@ -48,6 +49,7 @@ extra_rdoc_files:
|
|
48
49
|
executables:
|
49
50
|
- delish
|
50
51
|
- import_delicious
|
52
|
+
- update_delicious
|
51
53
|
extensions: []
|
52
54
|
|
53
55
|
requirements: []
|
data/test/test_db
DELETED
Binary file
|