stashboxr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "stashboxr"
8
+ gem.summary = %Q{A ruby api for the stashbox.org website}
9
+ gem.description = %Q{Upload files to stashbox.org and manage their metadata. User accounts or anonymous uploads!}
10
+ gem.email = "jphastings@gmail.com"
11
+ gem.homepage = "http://github.com/jphastings/StashboxR"
12
+ gem.authors = ["JP Hastings-Spital"]
13
+ gem.add_dependency "mechanize",'>= 1.0.0'
14
+ gem.add_development_dependency "Shoulda"
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/stashboxr.rb ADDED
@@ -0,0 +1,253 @@
1
+ require 'rubygems'
2
+ require 'mechanize'
3
+
4
+ # Allows percentages to be inspected and stringified in human
5
+ # form "33.3%", but kept in a float format for mathmatics
6
+ class Percentage < DelegateClass(Float)
7
+ def to_s(decimalplaces = 0)
8
+ (((self * 10**(decimalplaces+2)).round)/10**decimalplaces).to_s+"%"
9
+ end
10
+ alias :inspect :to_s
11
+ end
12
+
13
+ # A library for dealing with files on http://stashbox.org
14
+ class Stashboxr
15
+ # Settings for the browser emulation
16
+ Agent = Mechanize.new { |agent| agent.user_agent = 'Stashboxr' }
17
+
18
+ # Log into stashbox
19
+ def self.login(username,password)
20
+ res = Agent.post('http://stashbox.org/',{
21
+ :dologin => 1,
22
+ :user => username,
23
+ :password => password
24
+ })
25
+
26
+ raise RuntimeError, "Log in failed" if res.code != "200"
27
+ @@username = username
28
+ end
29
+
30
+ # Log out of stashbox
31
+ def self.logout
32
+ Agent.get('http://stashbox.org/logout.php')
33
+ @@username = nil
34
+ true
35
+ end
36
+
37
+ # Is someone logged in?
38
+ def self.loggedin?
39
+ !@@username.nil?
40
+ end
41
+
42
+ # Username of current logged in user (nil if not logged in)
43
+ def self.username
44
+ @@username
45
+ end
46
+
47
+ # Search stashbox.org - the site has this advice for formatting searches:
48
+ #
49
+ # You can use any number of terms in your search, all of which will be required in the results. You can also use the following search types (using "type:*the_type*" format): archives, audio, code, documents, images, movies
50
+ #
51
+ # Search types can be combined with normal search keywords to refine your results.
52
+ #
53
+ # In addition, remember you can search for both full and partial mimetypes, ie _application/pdf_.
54
+ def self.search(q)
55
+ res = Nokogiri::XML(Agent.get("http://stashbox.org/browse.php?wants_rss=1&q=#{URI.encode(q)}").body)
56
+
57
+ res.search('//item').collect do |item|
58
+ File.new(item.search('link').inner_text)
59
+ end
60
+ end
61
+
62
+ class File
63
+ attr_reader :filename, :url, :unsaved
64
+ attr_reader :know_code, :uploaded_on, :size, :views, :rating
65
+ attr_accessor :title, :description
66
+ attr_accessor :autosave
67
+
68
+ SIZES = {
69
+ '' => 9.765625e-4,
70
+ 'K' => 1,
71
+ 'M' => 1024
72
+ }
73
+
74
+ # Upload a file to stashbox and return a Stashbox::File object referencing it (which can be used to edit the metadata)
75
+ def self.upload(local_file,is_public = true)
76
+ # Does file exist?
77
+ raise RuntimeError, "This file does not exist - I can't upload it!" if !::File.exists? local_file
78
+ # Upload the file
79
+ res = Agent.post('http://stashbox.org/upload.php',{
80
+ :upload_type => "local_file",
81
+ :wants_rss => 1,
82
+ :file => open(local_file),
83
+ :is_public => is_public
84
+ })
85
+ body = Nokogiri::XML(res.body)
86
+
87
+ case res.code.to_i
88
+ when 200
89
+ new(body.search('//url').inner_text)
90
+ else
91
+ reason = body.search('//error').inner_text rescue nil
92
+ raise RuntimeError, "The upload wasn't allowed"<<((reason.nil?) ? "" : " because '#{reason}'")
93
+ end
94
+ end
95
+
96
+ def initialize(url)
97
+ if (url =~ /(?:http:\/\/)?(?:stashbox\.org)?(?:\/v)?\/?([0-9]+\/(.+))$/)
98
+ @stashboxid = $1
99
+ @filename = $2
100
+ else
101
+ raise RuntimeError, "That isn't a valid stashbox URL"
102
+ end
103
+
104
+ @autosave = true
105
+ @saved = true
106
+ end
107
+
108
+ # Has metadata been loaded
109
+ def has_metadata?; @metadata; end
110
+ # If you make alterations to the file's metadata with autosave turned off, this will become true until to #save it.
111
+ def autosave=(pref); @autosave = (pref != false); end
112
+ # Returns true if there are unsaved changes to the metadata for the file
113
+ def unsaved?; !@saved; end
114
+ def url; "http://stashbox.org/#{@stashboxid}"; end
115
+ def tags; refresh if not @metadata; @tags; end
116
+ def title; refresh if not @metadata; @title; end
117
+ def description; refresh if not @metadata; @description; end
118
+ def uploaded_on; refresh if not @metadata; @uploaded_on; end
119
+ def size; refresh if not @metadata; @size; end
120
+ def views; refresh if not @metadata; @views; end
121
+ def rating; refresh if not @metadata; @rating; end
122
+ def sfw?; refresh if not @metadata; @sfw; end
123
+ def public?; refresh if not @metadata; @public; end
124
+
125
+ # Add tags to the file on stashbox
126
+ def add_tag(new_tags)
127
+ # TODO: Parse input tags?
128
+ @tags = (tags + parse_tags(new_tags)).uniq
129
+ @saved = false
130
+ save if @autosave
131
+ end
132
+ alias :add_tags :add_tag
133
+
134
+ # Remove tags from the file on stashbox
135
+ def remove_tag(new_tags)
136
+ @tags = (tags - parse_tags(new_tags)).uniq
137
+ @saved = false
138
+ save if @autosave
139
+ end
140
+ alias :remove_tags :remove_tag
141
+
142
+ # Reset the tags for this file to the ones in the given array
143
+ def set_tags(new_tags)
144
+ @tags = parse_tags(new_tags)
145
+ @saved = false
146
+ save if @autosave
147
+ end
148
+
149
+ def title=(title)
150
+ @title = title
151
+ @saved = false
152
+ save if @autosave
153
+ end
154
+
155
+ def description=(description)
156
+ @description = description
157
+ @saved = false
158
+ save if @autosave
159
+ end
160
+
161
+ def sfw=(sfw)
162
+ @sfw = (sfw == true)
163
+ @saved = false
164
+ save if @autosave
165
+ end
166
+
167
+ def public=(ispublic)
168
+ @public = (ispublic == true)
169
+ @saved = false
170
+ save if @autosave
171
+ end
172
+
173
+ # Save the metadata to Stashboxr. Called automatically with any changes by default.
174
+ def save
175
+ res = Agent.post("http://stashbox.org/manage_file/"<<@stashboxid,{
176
+ :tags => @tags * " ",
177
+ :meta_title => @title,
178
+ :meta_description => @details,
179
+ :is_nsfw => !@sfw,
180
+ :is_public => @public
181
+ })
182
+
183
+ raise RuntimeError, "You don't have permission to edit this file" if res.body =~ /don't have permission/
184
+
185
+ return res.code == "200"
186
+ end
187
+
188
+ # Delete this file (permanently!) from stashbox.org
189
+ def delete
190
+ res = Agent.post("http://stashbox.org/delete_upload/"<<@stashboxid)
191
+
192
+ raise RuntimeError, "You don't have permission to delete this file" if res.body =~ /don't have permission/
193
+
194
+ return res.code == "200"
195
+ end
196
+
197
+ def inspect
198
+ keys = [@public ? "public" : "private"]
199
+ keys.push("nsfw") if !@sfw and @metadata
200
+ "<Stash: #{@filename} (#{keys * ", "})>"
201
+ end
202
+
203
+ # Grab metadata from stashbox.org
204
+ def refresh
205
+ # Get extended information
206
+ doc = Agent.get "http://stashbox.org/v/"<<@stashboxid
207
+
208
+ doc.search("//div[@class='subsection']").each do |sub|
209
+ value = sub.search("div[@class='value']").inner_text.strip
210
+ case sub.search("div[@class='label']").inner_text
211
+ when "Size"
212
+ @size = value[/^(\d+\.\d+)\ ([K|M]?)B$/,1].to_f * SIZES[$2]
213
+ when "Uploaded On"
214
+ @uploaded_on = Time.parse(value)
215
+ when "Views"
216
+ @size = value[/^(\d+)\ \(/,1].to_i
217
+ when "Rating"
218
+ @rating = Percentage.new(value[/(\d+\.\d+)\/5\ $/,1].to_f/5.0)
219
+ when "Tags"
220
+ @tags = sub.search("div[@class='value']/a").collect do |tag|
221
+ tag.inner_text
222
+ end
223
+ when "Title"
224
+ if sub.search("div[@class='value']/i").inner_text == ""
225
+ @title = value
226
+ else
227
+ @title = nil
228
+ end
229
+ when "KnowCode"
230
+ @know_code = value
231
+ when "Description"
232
+ if sub.search("div[@class='value']/i").inner_text == ""
233
+ @description = value
234
+ else
235
+ @description = nil
236
+ end
237
+ when "Is this file work safe?"
238
+ @sfw = (value == "Yes")
239
+ end
240
+ end
241
+ @metadata = true
242
+ return
243
+ end
244
+
245
+ private
246
+ def parse_tags(new_tags)
247
+ [new_tags].flatten.collect do |tag|
248
+ tag.downcase.gsub(/[^a-z0-9_-]/,"")
249
+ tag = nil if tag.empty?
250
+ end.compact.uniq
251
+ end
252
+ end
253
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'dmap'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,6 @@
1
+ require 'helper'
2
+
3
+ # TODO: Complete Tests!
4
+ class TestStashboxr < Test::Unit::TestCase
5
+
6
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stashboxr
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - JP Hastings-Spital
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-06-08 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: mechanize
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 0
34
+ version: 1.0.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: Shoulda
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :development
50
+ version_requirements: *id002
51
+ description: Upload files to stashbox.org and manage their metadata. User accounts or anonymous uploads!
52
+ email: jphastings@gmail.com
53
+ executables: []
54
+
55
+ extensions: []
56
+
57
+ extra_rdoc_files: []
58
+
59
+ files:
60
+ - Rakefile
61
+ - VERSION
62
+ - lib/stashboxr.rb
63
+ - test/helper.rb
64
+ - test/test_stashboxr.rb
65
+ has_rdoc: true
66
+ homepage: http://github.com/jphastings/StashboxR
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options:
71
+ - --charset=UTF-8
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ hash: 3
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ requirements: []
93
+
94
+ rubyforge_project:
95
+ rubygems_version: 1.3.7
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: A ruby api for the stashbox.org website
99
+ test_files:
100
+ - test/helper.rb
101
+ - test/test_stashboxr.rb