livejournaller 0.04

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.
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
+