| Home | Trees | Indices | Help |
|---|
|
|
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright (c) 2009, Thomas Jost <thomas.jost@gmail.com>
5 #
6 # Permission to use, copy, modify, and/or distribute this software for any
7 # purpose with or without fee is hereby granted, provided that the above
8 # copyright notice and this permission notice appear in all copies.
9 #
10 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 """Interact with FileDropper.com"""
19
20 import os.path, re, urllib, urllib2
21 from types import StringTypes
22
23 from BeautifulSoup import BeautifulSoup
24 import poster.encode, poster.streaminghttp
25
26 # Permissions
27 FD_PERM_PUBLIC = 0
28 FD_PERM_PASSWORD = 1
29 FD_PERM_PRIVATE = 2
30
31 # Prefix for all the URLs used in the module
32 FD_URL = "http://www.filedropper.com/"
33 FD_LOGIN_URL = FD_URL + "login.php"
34 FD_PREMIUM_URL = FD_URL + "premium.php"
35 FD_UPLOAD_URL = FD_URL + "index.php?xml=true"
36 FD_PERM_URL = FD_PREMIUM_URL + "?action=setpermissions&%(varset)s&id=%(id)d"
37 FD_DELETE_URL = FD_PREMIUM_URL + "?action=delete&id=%d"
38
39 # Max allowed size
40 FD_MAX_SIZE = 5*(1024**3)
41
42 # Error codes
43 FD_ERROR_NOT_LOGGED_IN = 1
44 FD_ERROR_PERMISSIONS = 2
45 FD_ERROR_FILE_TOO_BIG = 3
46 FD_ERROR_UPLOAD = 4
47 FD_ERROR_INVALID_PASSWORD = 5
48 FD_ERROR_REQUEST = 6
49
50 FD_ERRORS = {
51 FD_ERROR_NOT_LOGGED_IN : "Not logged in",
52 FD_ERROR_PERMISSIONS : "Invalid permissions",
53 FD_ERROR_FILE_TOO_BIG : "File is too big",
54 FD_ERROR_UPLOAD : "Error while uploading a file",
55 FD_ERROR_INVALID_PASSWORD: "Invalid password",
56 FD_ERROR_REQUEST : "Problem with the request",
57 }
58
59 # Regexp used for parsing HTML pages
60 FD_RE_LIST = re.compile("^unhide\('(\d+)'\)")
61
69
71 """Builds an empty FileDropper object that may be used for uploading files
72 to FileDropper.com, get details about files in a premium account, change
73 their permission or delete them."""
74
76 self.logged_in = False
77
78 # Init the streaming HTTP handler
79 #register_openers()
80
81 # Init the URL opener
82 #self.url = urllib2.build_opener(urllib2.HTTPCookieProcessor())
83 self.url = urllib2.build_opener(
84 poster.streaminghttp.StreamingHTTPHandler,
85 poster.streaminghttp.StreamingHTTPRedirectHandler,
86 urllib2.HTTPCookieProcessor
87 )
88
92
94 """Log into the premium account with the given username and password."""
95
96 # Build the data string to send with the POST request
97 data = urllib.urlencode({"username": username, "password": password})
98
99 # Send the request
100 res = self.url.open(FD_LOGIN_URL, data)
101
102 # What is our final URL?
103 dst_url = res.geturl()
104
105 self.logged_in = (res.getcode() == 200) and (dst_url == FD_PREMIUM_URL)
106 return self.logged_in
107
109 """Log out from a premium account."""
110
111 if not self.logged_in:
112 raise FileDropperException(FD_ERROR_NOT_LOGGED_IN)
113
114 self.url.open(FD_URL + "login.php?action=logout")
115
117 """Get a list of files in the file manager of a premium account.
118
119 The return value is a list of 7-value tuples of the form
120 (file_name, id, downloads, size, date, permissions, public_url)"""
121
122 if not self.logged_in:
123 raise FileDropperException(FD_ERROR_NOT_LOGGED_IN)
124
125 # Download the page
126 html = self.url.open(FD_PREMIUM_URL).read()
127
128 # Parse it
129 soup = BeautifulSoup(html)
130
131 # Get files info
132 tags = [tag.parent for tag in soup.findAll("a", onclick = FD_RE_LIST)]
133 files = []
134 for tag in tags:
135 # File name in the link
136 file_name = tag.a.string.strip()
137
138 # File ID found using the regexp
139 m = FD_RE_LIST.search(tag.a['onclick'])
140 file_id = int(m.group(1))
141
142 div = tag.div
143
144 # Some dirty searches in an ugly div section
145 downloads = int(div.contents[2].replace('|', '').strip())
146 size = div.contents[4].replace('|', '').strip() #TODO: parse it correctly
147 date = div.contents[6].replace(' ', '').strip() #TODO: parse it correctly
148
149 # Permissions: conversion from 2 strings to a symbol
150 raw_perm = div.find("span", id="fileperms[%d]" % file_id)
151 permissions = -1
152 if raw_perm.span.string == "Private":
153 permissions = FD_PERM_PRIVATE
154 elif raw_perm.span.string == "Public":
155 # If there is a <b> tag, it contains "No password"
156 if raw_perm.b is not None:
157 permissions = FD_PERM_PUBLIC
158 else:
159 permissions = FD_PERM_PASSWORD
160 else:
161 raise FileDropperException(FD_ERROR_PERMISSIONS)
162
163 # Public URL (may be published safely anywhere)
164 public_url = div.find("input", type="text")['value']
165
166 value = (file_name, file_id, downloads, size, date, permissions, public_url)
167 files.append(value)
168
169 return files
170
172 """Upload the specified file"""
173
174 # Check the file size
175 if os.path.getsize(filename) > FD_MAX_SIZE:
176 raise FileDropperException(FD_ERROR_FILE_TOO_BIG)
177
178 # Prepare the encoded data
179 base_name = os.path.basename(filename)
180
181 mp1 = poster.encode.MultipartParam("Filename", base_name)
182 mp2 = poster.encode.MultipartParam("file", filename=base_name, filetype="application/octet-stream", fileobj=open(filename))
183
184 data, headers = poster.encode.multipart_encode([mp1, mp2])
185
186 # Prepare the request
187 req = urllib2.Request(FD_UPLOAD_URL, data, headers)
188
189 # Send the request
190 res = self.url.open(req)
191
192 # Get the intermediate url
193 tmp_url = res.read()
194 #TODO: check if upload failed...
195
196 # Get the real file URL... and end with a 404 error :)
197 try:
198 res = self.url.open(FD_URL + tmp_url[1:])
199 except urllib2.HTTPError, exc:
200 if exc.code == 404:
201 return exc.geturl()
202 else:
203 raise exc
204
205 # We should not reach this point as there is supposed to be a 404 error
206 raise FileDropperException(FD_ERROR_UPLOAD)
207
209 """Set new permissions for the specified file"""
210
211 if not self.logged_in:
212 raise FileDropperException(FD_ERROR_NOT_LOGGED_IN)
213
214 # Prepare the query
215 query = {'id': file_id}
216
217 # Set to public
218 if perm == FD_PERM_PUBLIC:
219 query['varset'] = 'public=true'
220
221 # There's a weird bug when changing from password-protected
222 # to public: permissions don't get updated unless we change
223 # them to private first
224 self.set_perm(file_id, FD_PERM_PRIVATE)
225
226 # Set to private
227 elif perm == FD_PERM_PRIVATE:
228 query['varset'] = 'private=true'
229
230 # Set to password-protected
231 elif perm == FD_PERM_PASSWORD:
232 if (type(password) not in StringTypes) or (password.strip() == ""):
233 raise FileDropperException(FD_ERROR_INVALID_PASSWORD)
234 query['varset'] = urllib.urlencode({'password': password})
235
236 # Invalid case
237 else:
238 raise FileDropperException(FD_ERROR_PERMISSIONS)
239
240 # Prepare the request
241 url = FD_PERM_URL % query
242 res = self.url.open(url)
243
244 txt = res.read()
245 if res.getcode() != 200:
246 raise FileDropperException(FD_ERROR_REQUEST)
247
248 return txt
249
251 """Delete the specified file"""
252
253 if not self.logged_in:
254 raise FileDropperException(FD_ERROR_NOT_LOGGED_IN)
255
256 # Do the query
257 res = self.url.open(FD_DELETE_URL % file_id)
258
259 txt = res.read()
260 if res.getcode() != 200:
261 raise FileDropperException(FD_ERROR_REQUEST)
262
263 return txt
264
265
266 if __name__ == "__main__":
267 from getpass import getpass
268 import sys
269
270 fd = FileDropper()
271 user = raw_input("Username: ")
272 if user != "":
273 password = getpass()
274 if not fd.login(user, password):
275 print "Login failed"
276
277 print "Current files:"
278 print fd.list()
279 print
280
281 uploaded_file = fd.upload("test.txt")
282 print "Upload: %s" % uploaded_file
283 print
284
285 print "New files:"
286 lst = fd.list()
287 print lst
288 file_id = -1
289 for file_data in lst:
290 if file_data[6] == uploaded_file:
291 file_id = file_data[1]
292 break
293 if file_id == -1:
294 print "Can't find file ID :-("
295 sys.exit(1)
296 print
297
298 print "Making the file private:"
299 fd.set_perm(file_id, FD_PERM_PRIVATE)
300 print fd.list()
301 print
302
303 print "Making the file password-protected:"
304 fd.set_perm(file_id, FD_PERM_PASSWORD, "passtest")
305 print fd.list()
306 print
307
308 print "Making the file public again:"
309 fd.set_perm(file_id, FD_PERM_PUBLIC)
310 print fd.list()
311 print
312
313 print "Making the file private again:"
314 fd.set_perm(file_id, FD_PERM_PRIVATE)
315 print fd.list()
316 print
317
318 print "Deleting the file:"
319 fd.delete(file_id)
320 print fd.list()
321
| Home | Trees | Indices | Help |
|---|
| Generated by Epydoc 3.0 on Wed Feb 25 15:21:38 2009 | http://epydoc.sourceforge.net |