delish 0.6.1 → 0.7.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|