Class: Gourmand

Inherits:
Object
  • Object
show all
Defined in:
lib/gourmand.rb

Constant Summary collapse

SitesToClasses =

lambdas to get lazy loading

{
  "reddit" => lambda{
    require "reddit";
    Reddit::Liked
  },

  "stumbleupon" => lambda{
    require "stumbleupon"
    StumbleUpon::Favourites
  },
  "twitter" => lambda{
    require "twitter"
    Twitter::FriendsTimeline
  },
  "google-reader" => lambda{
    require "googlereader"
    GoogleReader
  }
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dir = File.join(ENV["HOME"], ".gourmand")) ⇒ Gourmand

Returns a new instance of Gourmand.



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/gourmand.rb', line 66

def initialize(dir=File.join(ENV["HOME"], ".gourmand"))
  @dir = dir
  @untiny_cache = if File.exists?(untiny_cache_file)
    JSON.parse(IO.read(untiny_cache_file))
  else
    {}
  end
  
  if File.exists?(details_file)
    Delicious.basic_auth(details["delicious_user"], details["delicious_password"])
  end
end

Instance Attribute Details

#dirObject

Returns the value of attribute dir.



65
66
67
# File 'lib/gourmand.rb', line 65

def dir
  @dir
end

Class Method Details

.site_namesObject



211
212
213
# File 'lib/gourmand.rb', line 211

def self.site_names
  SitesToClasses.keys
end

.versionObject



11
12
13
# File 'lib/gourmand.rb', line 11

def self.version
  Version.new(IO.read(File.join(File.dirname(__FILE__), "..", "VERSION")))
end

Instance Method Details

#bookmark_for(url) ⇒ Object



128
129
130
131
# File 'lib/gourmand.rb', line 128

def bookmark_for(url)    
  url = untiny_url(url)
  Post.new(:url=>url)
end

#create!(delicious, delicious_password) ⇒ Object



88
89
90
91
92
93
94
# File 'lib/gourmand.rb', line 88

def create!(delicious, delicious_password)
  Dir.mkdir(dir)
  File.open(version_file, "w"){|o| o.puts Gourmand.version}
  File.open(details_file, "w"){|o|
    o.puts({:delicious_user => delicious, :delicious_password => delicious_password}.to_json)
  }
end

#delicious_postsObject



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/gourmand.rb', line 133

def delicious_posts
  puts "Reading existing delicious bookmarks"
  delicious_post_file = File.join(@dir, "bookmarks.json")

  @existing_posts = nil

  if File.exist? delicious_post_file
    @existing_posts ||= JSON.parse(IO.read(delicious_post_file))
  end

  if !@existing_posts || (update_time > @existing_posts["updated"]) 
    puts "Bookmarks out of date. Fetching from server"
    posts = Delicious.get("/posts/all")["posts"]
    raise "error fetching all posts" unless posts 
    
    @existing_posts = {"updated" => posts["update"], "posts" => posts["post"] || []}
    File.open(delicious_post_file, "w") do |o|
      o.puts JSON.pretty_generate(@existing_posts)
    end
  else
    puts "Nothing to do here: Our existing bookmarks are up to date"    
  end
  
  posts = (@existing_posts["posts"] || []).map{|x| Post.new(x){|p| p.url = x["href"]; p.tags = x["tag"]}}
  puts "found #{posts.length} existing bookmarks"
  posts
end

#detailsObject



96
97
98
# File 'lib/gourmand.rb', line 96

def details
  @details ||= JSON.parse(IO.read(details_file))
end

#exists?Boolean

Returns:

  • (Boolean)


40
41
42
# File 'lib/gourmand.rb', line 40

def exists?
  File.exists?(@dir)
end

#from_the_future?Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/gourmand.rb', line 32

def from_the_future?
  version > Gourmand.version
end

#needs_update?Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/gourmand.rb', line 28

def needs_update?
  version < Gourmand.version
end

#site_for(x) ⇒ Object



83
84
85
86
# File 'lib/gourmand.rb', line 83

def site_for(x)
 c = SitesToClasses[x]
 c && c.call.new(self)
end

#sitesObject



79
80
81
# File 'lib/gourmand.rb', line 79

def sites
  @sites ||= Dir["#{@dir}/*"].map{|x| site_for(File.basename(x))}.compact
end

#transfer_to_deliciousObject



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/gourmand.rb', line 161

def transfer_to_delicious
  puts "Beginning import at #{Time.now}"
  puts "Found importers for #{sites.join(", ")}"
  new_updates = sites.map{|x| x.update!}.flatten
  update_untiny_cache
  
  puts "#{new_updates.length} urls to import"

  return if new_updates.empty?

  urls_to_posts = {}

  new_updates.each do |post|
    urls_to_posts[post.url] = post.merge(urls_to_posts[post.url])
  end

  puts "checking for existing bookmarks"
  delicious_posts.each do |post|
    update = urls_to_posts[post.url]
    if update
      puts "merging existing post for #{post.url}"
      urls_to_posts[post.url] = update.merge post
    end
  end

  new_updates = urls_to_posts.values.compact

  puts "#{new_updates.length} urls after merging"

  new_updates.each do |update|
    puts "importing #{update.description} (#{update.url})"
    
    update.fetch_metadata!

    res = Delicious.post("/posts/add", :query => update.to_h)
    if !res['result'] || res['result']['code'] != 'done'
      puts "error importing post: #{res.inspect}"
    end
    
    sleep(1)      
  end
  puts "Saving data to storage"
  sites.each{|x| x.save!}
      
  puts "Import complete"

  nil
end

#untiny_url(url, n = 0) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/gourmand.rb', line 112

def untiny_url(url, n=0)
 @untiny_cache[url] ||= begin      
    puts "untiny #{url}"          
    resp = Net::HTTP.get_response(URI.parse(url)) 
    url = resp['location'] || url
    if [301, 302].include?(resp.code.to_i) && n<=3 && resp['location']
      untiny_url(resp['location'], ++n) 
    else
      url
    end
  rescue Exception => e
    puts "WARNING: #{e}"
    url
  end          
end

#update!Object



36
37
38
# File 'lib/gourmand.rb', line 36

def update!
  Migrations.new(self).migrate!
end

#update_timeObject



100
101
102
103
104
105
106
# File 'lib/gourmand.rb', line 100

def update_time
  puts "Checking the server for last update time"
  sleep 1
  time = Delicious.get("/posts/update")["update"]["time"]
  puts "last updated at #{time}"
  time
end

#update_untiny_cacheObject



108
109
110
# File 'lib/gourmand.rb', line 108

def update_untiny_cache
  File.open(untiny_cache_file, 'w') { |f| f << JSON.pretty_generate(@untiny_cache) }
end

#versionObject



19
20
21
22
23
24
25
26
# File 'lib/gourmand.rb', line 19

def version
  if File.exists? version_file
    Version.new(IO.read(version_file))
  else
    # the version right before this feature was added
    Version.new("0.0.5") 
  end
end

#version_fileObject



15
16
17
# File 'lib/gourmand.rb', line 15

def version_file
  File.join(@dir, "VERSION")
end