livejournaller 0.04

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/bin/ljpost +51 -0
  2. data/bin/ljsend +55 -0
  3. data/lib/livejournaller.rb +205 -0
  4. data/share/template +8 -0
  5. metadata +59 -0
data/bin/ljpost ADDED
@@ -0,0 +1,51 @@
1
+ #!/opt/bin/ruby
2
+
3
+ LJPOSTDIR=File.join(ENV["HOME"],"/.ljpost")
4
+
5
+ if not File.exists?(LJPOSTDIR)
6
+ Dir.mkdir(LJPOSTDIR)
7
+ Dir.mkdir File.join(LJPOSTDIR,"outgoing")
8
+ Dir.mkdir File.join(LJPOSTDIR,"sent")
9
+ end
10
+
11
+ require "tempfile"
12
+ require "yaml"
13
+ require "time"
14
+
15
+ template=File.join(File.dirname(File.dirname(__FILE__)),"share","template")
16
+
17
+ t=Tempfile.new("ljpost")
18
+ t.write(File.read(template))
19
+ t.close
20
+
21
+ system(ENV["VISUAL"],t.path)
22
+
23
+ fh=File.open(t.path,File::RDONLY)
24
+
25
+ text=fh.read
26
+ (headertext,bodytext)=text.split(/^--text follows this line--$/,2);
27
+ headers=Hash.new
28
+ headertext.split(/\n/).each do |line|
29
+ header,value=line.split(/: ?/,2)
30
+ headers[header]=value
31
+ end
32
+ headers["Body"]=bodytext
33
+
34
+ if headers["Date"] != "" then
35
+ headers["Date"]=Time.parse(headers["Date"])
36
+ headers["Backdate"] = true
37
+ else
38
+ headers["Date"]=Time.now
39
+ end
40
+
41
+ # convert "Preformatted" boolean tag to actual boolean
42
+ headers["Preformatted"] = {
43
+ ?t => true,
44
+ ?y => true,
45
+ ?f => false,
46
+ ?n => false } [ headers["Preformatted"].downcase[0] ]
47
+
48
+ File.open("#{LJPOSTDIR}/outgoing/"+headers["Date"].strftime("%Y%m%d%H%M%S"),
49
+ "w") do |f|
50
+ f.write(headers.to_yaml)
51
+ end
data/bin/ljsend ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/ruby
2
+
3
+ LJPOSTDIR = File.join(ENV["HOME"],"/.ljpost")
4
+ LIVEJOURNALRC = File.join(ENV["HOME"],".livejournal.rc")
5
+
6
+ require "livejournaller"
7
+ require "tempfile"
8
+ require "yaml"
9
+ require "open3"
10
+
11
+ outgoingdir = File.join(LJPOSTDIR,"/outgoing")
12
+ sentdir = File.join(LJPOSTDIR,"sent")
13
+ ljparams = YAML.load(File.read(LIVEJOURNALRC))
14
+
15
+ Dir.open("#{outgoingdir}") do |d|
16
+ d.each do |filename|
17
+ pathname="#{outgoingdir}/#{filename}"
18
+ if File.stat(pathname).file?
19
+ posting=Hash.new("")
20
+ YAML.load(File.read(pathname)).each_pair do |key,value|
21
+ posting[key]=value
22
+ end
23
+
24
+ opts = {}
25
+
26
+ {
27
+ "Mood" => :mood,
28
+ "Music" => :current_music,
29
+ "Userpic" => :picture,
30
+ "Security" => :security,
31
+ "Preformatted" => :preformatted,
32
+ "Backdate" => :backdated
33
+ }.each do |header, option|
34
+ if posting[header] != "" then
35
+ opts[option] = posting[header]
36
+ end
37
+ end
38
+
39
+ if posting["Date"] != "" then
40
+ unless posting["Date"].respond_to? :strftime
41
+ posting["Date"] = DateTime.parse(posting["Date"])
42
+ end
43
+ opts[:date] = posting["Date"]
44
+ end
45
+
46
+ lj=LiveJournaller.new ljparams["user"], ljparams["password"]
47
+ retval = lj.post posting["Subject"], posting["Body"], opts
48
+
49
+ if retval["anum"] then
50
+ puts "Successfully posted item #{retval["anum"]} to LiveJournal."
51
+ File.rename pathname, File.join(sentdir,filename)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require "rubygems"
4
+ gem "hpricot"
5
+
6
+ require "xmlrpc/client"
7
+ require "md5"
8
+ require "yaml"
9
+ require "hpricot"
10
+
11
+ class LiveJournaller
12
+ private
13
+
14
+ # Handles the challenge-response sequence before LiveJournal lets
15
+ # you call an API method.
16
+ def get_challenge
17
+ result = @client.call("LJ.XMLRPC.getchallenge")
18
+ challenge = result["challenge"]
19
+ response = MD5.md5(challenge + @password).to_s
20
+
21
+ @paramhash["auth_challenge"] = challenge
22
+ @paramhash["auth_response"] = response
23
+ end
24
+
25
+ # Calls a LiveJournal function name after handling the challenge
26
+ # that LJ goes through before you're allowed to use the API.
27
+ #
28
+ # This is a low-level support method.
29
+ def ljcall(ljfnname,params = {})
30
+ get_challenge
31
+ paramhash = @paramhash.merge Hash[*(params.map do |a,b|
32
+ [a.to_s,b]
33
+ end.flatten)]
34
+ @client.call "LJ.XMLRPC.#{ljfnname.to_s}", paramhash
35
+ end
36
+
37
+ public
38
+
39
+ # Creates a new LiveJournaller object.
40
+ #
41
+ # The parameters are your username, your password, and optionally
42
+ # a server. So, for instance, you could say:
43
+ #
44
+ # lj = LiveJournaller.new("myusername", "mypassword")
45
+ #
46
+ # to log into LiveJournal, or alternatively you could say
47
+ #
48
+ # gj = LiveJournaller.new("myusername, "mypassword",
49
+ # "www.greatestjournal.com")
50
+ #
51
+ # to log into Greatest Journal.
52
+ def initialize(user, password, server="www.livejournal.com")
53
+ @client = XMLRPC::Client.new server, "/interface/xmlrpc"
54
+ @user = user
55
+ @password = MD5.md5(password).to_s
56
+ @paramhash = { "username" => user,
57
+ "auth_method" => "challenge",
58
+ "ver" => 1 }
59
+ @restful_ish_client = Net::HTTP.new("www.livejournal.com")
60
+ @restful_ish_client_headers = {
61
+ "User-Agent" => "RubyLJ",
62
+ "Content-Type" => "text/xml; charset=UTF-8",
63
+ "Connection" => "keep-alive"
64
+ }
65
+ @comment_cache_dir = "db/ljcomments"
66
+ @comment_cache = File.join(@comment_cache_dir, "allcomments.xml")
67
+ end
68
+
69
+ attr_reader :logindetails
70
+
71
+ # Defines a LiveJournal API function as a method, for those
72
+ # LiveJournal APIs that I figure it's safe to just define
73
+ # explicitly.
74
+ def self.lj_api *meths
75
+ meths.each do |meth|
76
+ eval %[
77
+ def #{meth.to_s} params = {}
78
+ ljcall :#{meth}, params
79
+ end
80
+ ]
81
+ end
82
+ end
83
+
84
+ lj_api :checkfriends, :consolecommand, :editevent, :editfriendgroups,
85
+ :editfriends, :friendof, :getdaycounts, :getevents, :getfriends,
86
+ :getfriendgroups, :login, :postevent, :sessionexpire,
87
+ :sessiongenerate, :syncitems
88
+
89
+ # Returns a hash of your user details
90
+ def user_details; @user_details ||= login end
91
+
92
+ # Returns an array of your friend groups.
93
+ def friendgroups; user_details["friendgroups"] end
94
+
95
+ # Returns a list of all items you posted ever.
96
+ def all_items
97
+ @allitems ||= syncitems :lastsync => "1970-01-01 00:00:00"
98
+ end
99
+
100
+ def friends; @friends ||= getfriends["friends"] end
101
+
102
+ # Returns a livejournal entry with id +id+.
103
+ def item id
104
+ ljcall :getevents, :selecttype => "one",
105
+ :lastsync => "1970-01-01 00:00:00",
106
+ :itemid => id
107
+ end
108
+
109
+ private
110
+ def sessioncookie
111
+ @sessioncookie ||= sessiongenerate
112
+ "ljsession=#{@sessioncookie["ljsession"]}"
113
+ end
114
+
115
+ public
116
+ def comment_summaries start_id = 0
117
+ @restful_ish_client_headers["Cookie"] ||= sessioncookie
118
+ unless @comments
119
+ @restful_ish_client.start do
120
+ response = @restful_ish_client.get("/export_comments.bml?get=comment_meta&startid=#{start_id}", @restful_ish_client_headers)
121
+ rexml = REXML::Document.new(response.body)
122
+ @max_comment_id = rexml.elements["//maxid"].text.to_i
123
+ @comment_summaries = rexml.elements.each("//comment") { }.sort_by do |c|
124
+ c.attributes["id"].to_i
125
+ end
126
+ @usermap = {}
127
+ rexml.elements.each("//usermap") do |elem|
128
+ @usermap[elem.attribute("id").value] =
129
+ elem.attribute("user").value
130
+ end
131
+ end
132
+ end
133
+ @comment_summaries
134
+ end
135
+
136
+ def export_comments start_id=0
137
+ @restful_ish_client_headers["Cookie"] ||= sessioncookie
138
+
139
+ unless @comment_bodies
140
+ if File.exists?(@comment_cache)
141
+ @comment_bodies = File.read(@comment_cache)
142
+ end
143
+
144
+ @restful_ish_client.start do
145
+ response = @restful_ish_client.get("/export_comments.bml?get=comment_body&startid=#{start_id}", @restful_ish_client_headers)
146
+ @comment_bodies = response.body
147
+ end
148
+ end
149
+ @comment_bodies
150
+ end
151
+
152
+ # Post an item to livejournal
153
+ # Required fields are +subject+ and +text+
154
+ # Optional fields: date, mood, music, preformatted, nocomments, picture,
155
+ # noemail
156
+ def post subject, text, options = {}
157
+ date = if options[:date] then
158
+ if String === options[:date] then
159
+ DateTime.parse(options[:date])
160
+ else
161
+ options[:date]
162
+ end
163
+ else
164
+ DateTime.now
165
+ end
166
+
167
+
168
+ callhash = {
169
+ :event => text,
170
+ :subject => subject,
171
+ :year => date.year,
172
+ :mon => date.month,
173
+ :day => date.day,
174
+ :hour => date.hour,
175
+ :min => date.min,
176
+ :lineendings => "unix",
177
+ :props => {}
178
+ }
179
+
180
+ if options[:security] then
181
+ callhash[:security]=options[:security]
182
+ end
183
+
184
+ {
185
+ :mood => :current_mood,
186
+ :music => :current_music,
187
+ :preformatted => :opt_preformatted,
188
+ :nocomments => :opt_nocomments,
189
+ :picture => :picture_keyword,
190
+ :noemail => :opt_noemail,
191
+ :backdated => :opt_backdated
192
+ }.each do |option_name, lj_option_name|
193
+ if options[option_name] then
194
+ callhash[:props][lj_option_name] = options[option_name]
195
+ end
196
+ end
197
+
198
+ postevent callhash
199
+ end
200
+
201
+ def poster posterid, start_id = 0
202
+ comment_summaries start_id
203
+ @usermap[posterid.to_s]
204
+ end
205
+ end
data/share/template ADDED
@@ -0,0 +1,8 @@
1
+ Subject:
2
+ Date:
3
+ Mood:
4
+ Userpic:
5
+ Music:
6
+ Security:
7
+ Preformatted: true
8
+ --text follows this line--
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: livejournaller
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.04"
5
+ platform: ruby
6
+ authors:
7
+ - Dave Brown
8
+ autorequire: livejournaller
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-27 00:00:00 +09:00
13
+ default_executable: ljpost
14
+ dependencies: []
15
+
16
+ description: " This is a library to access the LiveJournal API from Ruby, and a\n script or two to let you write and submit LiveJournal entries from\n the command line.\n"
17
+ email: livejournaller@dagbrown.com
18
+ executables:
19
+ - ljpost
20
+ - ljsend
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - lib/livejournaller.rb
27
+ - bin/ljpost
28
+ - bin/ljsend
29
+ - share/template
30
+ has_rdoc: true
31
+ homepage:
32
+ licenses: []
33
+
34
+ post_install_message:
35
+ rdoc_options: []
36
+
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ requirements: []
52
+
53
+ rubyforge_project:
54
+ rubygems_version: 1.3.5
55
+ signing_key:
56
+ specification_version: 3
57
+ summary: A LiveJournal access library.
58
+ test_files: []
59
+