diff options
-rw-r--r-- | apps/blog/models.py | 10 | ||||
-rw-r--r-- | apps/links/models.py | 8 | ||||
-rw-r--r-- | apps/links/tumblr.py | 239 | ||||
-rw-r--r-- | apps/links/utils.py | 36 | ||||
-rw-r--r-- | base_urls.py | 8 | ||||
-rw-r--r-- | templates/feeds/blog_description.html | 1 | ||||
-rw-r--r-- | templates/feeds/links_description.html | 1 |
7 files changed, 290 insertions, 13 deletions
diff --git a/apps/blog/models.py b/apps/blog/models.py index d9cea69..e598f14 100644 --- a/apps/blog/models.py +++ b/apps/blog/models.py @@ -98,4 +98,14 @@ class BlogSitemap(Sitemap): def lastmod(self, obj): return obj.pub_date +class LatestFull(Feed): + title = "Luxagraf: Topographical Writings" + link = "/writing/" + description = "Latest postings to luxagraf.net" + description_template = 'feeds/blog_description.html' + + def items(self): + return Entry.objects.filter(status__exact=1).order_by('-pub_date')[:10] + + #signals.post_save.connect(create_location_item, sender=Entry)
\ No newline at end of file diff --git a/apps/links/models.py b/apps/links/models.py index cac4aa2..00a6f54 100644 --- a/apps/links/models.py +++ b/apps/links/models.py @@ -41,7 +41,7 @@ class Link(models.Model): return self.title def get_absolute_url(self): - return "/link/%s/" % (self.id) + return self.url def get_model_name(self): return 'link' @@ -73,9 +73,9 @@ class LinkSitemap(Sitemap): class LatestLinks(Feed): title = "Luxagraf: Links" - link = "/collections/" - description = "Latest Links posted to luxagraf.net" - description_template = 'feeds/collections_description.html' + link = "http://ma.gnolia.com/people/luxagraf/bookmarks" + description = "Links to interesting stuff" + description_template = 'feeds/links_description.html' def items(self): return Link.objects.filter(status__exact=1).order_by('-pub_date')[:10] diff --git a/apps/links/tumblr.py b/apps/links/tumblr.py new file mode 100644 index 0000000..09c3394 --- /dev/null +++ b/apps/links/tumblr.py @@ -0,0 +1,239 @@ +#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright 2008 Ryan Cox ( ryan.a.cox@gmail.com ) All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+'''A wrapper library for Tumblr's public web API: http://www.tumblr.com/api'''
+
+__author__ = 'ryan.a.cox@gmail.com'
+__version__ = '0.1'
+
+
+from urllib2 import Request, urlopen, URLError, HTTPError
+from urllib import urlencode, quote
+import base64
+import re
+
+try:
+ import simplejson
+except ImportError:
+ from django.utils import simplejson
+
+GENERATOR = 'python-tumblr'
+PAGESIZE = 50
+
+
+class TumblrError(Exception):
+ ''' General Tumblr error '''
+ def __init__(self, msg):
+ self.msg = msg
+
+ def __str__(self):
+ return self.msg
+
+class TumblrAuthError(TumblrError):
+ ''' Wraps a 403 result '''
+ pass
+
+class TumblrRequestError(TumblrError):
+ ''' Wraps a 400 result '''
+ pass
+
+class TumblrIterator:
+ def __init__(self, name, start, max, type):
+ self.name = name
+ self.start = start
+ self.max = max
+ self.type = type
+ self.results = None
+ self.index = 0
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if not self.results or (self.index == len(self.results['posts'])):
+ self.start += self.index
+ self.index = 0
+ url = "http://%s.tumblr.com/api/read/json?start=%s&num=%s" % (self.name,self.start, PAGESIZE)
+ if self.type:
+ url += "&type=" + self.type
+ response = urlopen(url)
+ page = response.read()
+ m = re.match("^.*?({.*}).*$", page,re.DOTALL | re.MULTILINE | re.UNICODE)
+ self.results = simplejson.loads(m.group(1))
+
+ if (self.index >= self.max) or len(self.results['posts']) == 0:
+ raise StopIteration
+
+ self.index += 1
+ return self.results['posts'][self.index-1]
+
+class Api:
+ def __init__(self, name, email=None, password=None ):
+ self.name = name
+ self.is_authenticated = False
+ self.email = email
+ self.password = password
+
+ def auth_check(self):
+ if self.is_authenticated:
+ return
+ url = 'http://www.tumblr.com/api/write'
+ values = {
+ 'action': 'authenticate',
+ 'generator' : GENERATOR,
+ 'email': self.email,
+ 'password' : self.password }
+
+ data = urlencode(values)
+ req = Request(url, data)
+ try:
+ response = urlopen(req)
+ page = response.read()
+ self.url = page
+ self.is_authenticated = True
+ return
+ except HTTPError, e:
+ if 403 == e.code:
+ raise TumblrAuthError(str(e))
+ if 400 == e.code:
+ raise TumblrRequestError(str(e))
+ except Exception, e:
+ raise TumblrError(str(e))
+
+
+ def write_regular(self, title=None, body=None, **args):
+ if title:
+ args['title'] = title
+ if body:
+ args['body'] = body
+ args = self._fixnames(args)
+ if not 'title' in args and not 'body' in args:
+ raise TumblrError("Must supply either body or title argument")
+
+ self.auth_check()
+ args['type'] = 'regular'
+ return self._write(args)
+
+ def write_photo(self, source=None, **args):
+ if source:
+ args['source'] = source
+
+ args = self._fixnames(args)
+ if 'source' in args and 'data' in args:
+ raise TumblrError("Must NOT supply both source and data arguments")
+
+ if not 'source' in args and not 'data' in args:
+ raise TumblrError("Must supply source or data argument")
+
+ self.auth_check()
+ args['type'] = 'photo'
+ return self._write(args)
+
+ def write_quote(self, quote=None, **args):
+ if quote:
+ args['quote'] = quote
+ args = self._fixnames(args)
+ if not 'quote' in args:
+ raise TumblrError("Must supply quote arguments")
+
+ self.auth_check()
+ args['type'] = 'quote'
+ return self._write(args)
+
+ def write_link(self, url=None, **args):
+ if url:
+ args['url'] = url
+ args = self._fixnames(args)
+ if not 'url' in args:
+ raise TumblrError("Must supply url argument")
+
+ self.auth_check()
+ args['type'] = 'link'
+ return self._write(args)
+
+ def write_conversation(self, conversation=None, **args):
+ if conversation:
+ args['conversation'] = conversation
+ args = self._fixnames(args)
+ if not 'conversation' in args:
+ raise TumblrError("Must supply conversation argument")
+
+ self.auth_check()
+ args['type'] = 'conversation'
+ return self._write(args)
+
+ def write_video(self, embed=None, **args):
+ if embed:
+ args['embed'] = embed
+ args = self._fixnames(args)
+ if 'embed' in args and 'data' in args:
+ raise TumblrError("Must NOT supply both embed and data arguments")
+
+ if not 'embed' in args and not 'data' in args:
+ raise TumblrError("Must supply embed or data argument")
+
+ self.auth_check()
+ args['type'] = 'video'
+ return self._write(args)
+
+ def _fixnames(self, args):
+ for key in args:
+ if '_' in key:
+ value = args[key]
+ del args[key]
+ args[key.replace('_', '-')] = value
+ return args
+
+ def _write(self, params, headers=None):
+ self.auth_check()
+ url = 'http://www.tumblr.com/api/write'
+ params['email'] = self.email
+ params['password'] = self.password
+ params['generator'] = GENERATOR
+ data = urlencode(params)
+ if headers:
+ req = Request(url, data, headers)
+ else:
+ req = Request(url, data)
+ newid = None
+ try:
+ urlopen(req)
+ raise TumblrError("Error writing post")
+
+ except HTTPError, e:
+ if 201 == e.code:
+ newid = e.read()
+ return self.read(id=newid)
+ raise TumblrError(e.read())
+
+ def read(self, id=None, start=0,max=2**31-1,type=None):
+ if id:
+ url = "http://%s.tumblr.com/api/read/json?id=%s" % (self.name,id)
+ response = urlopen(url)
+ page = response.read()
+ m = re.match("^.*?({.*}).*$", page,re.DOTALL | re.MULTILINE | re.UNICODE)
+ results = simplejson.loads(m.group(1))
+ if len(results['posts']) == 0:
+ return None
+
+ return results['posts'][0]
+ else:
+ return TumblrIterator(self.name,start,max,type)
+
+if __name__ == "__main__":
+ pass
diff --git a/apps/links/utils.py b/apps/links/utils.py index a575f4f..2649dde 100644 --- a/apps/links/utils.py +++ b/apps/links/utils.py @@ -1,4 +1,4 @@ -import time, datetime +import time, datetime, urllib from django.core.exceptions import ObjectDoesNotExist from django.template.defaultfilters import slugify,striptags @@ -7,7 +7,6 @@ from django.utils.encoding import smart_unicode from strutils import safestr,unquotehtml from APIClients import MagnoliaClient -from urlgrabber.grabber import URLGrabber import pydelicious as delicious import markdown2 as markdown @@ -64,6 +63,9 @@ def sync_magnolia_links(*args, **kwargs): email_link(l) send_to_delicious(l) + if l.status == 1: + post_to_tumblr(l) + send_to_deliciousfb(l) if(dupe): break """ @@ -123,11 +125,29 @@ def send_to_delicious(link): tags = link.tags.split(',') for tag in tags: del_tags += tag.strip().replace(' ','_')+' ' - print del_tags - delicious.add('luxagraf', 'translinguis#', link.url, link.title, tags = del_tags, extended = link.description, dt =safestr(link.pub_date), replace="no") + delicious.add(settings.DELICIOUS_USER, settings.DELICIOUS_PASS, link.url, link.title, tags = del_tags, extended = striptags(link.description), dt =safestr(link.pub_date), replace="no") def copy_file(url, id): - g = URLGrabber() - filename="/home2/luxagraf/webapps/images/magnolia_thumbs/%s/%s.jpg" %(datetime.datetime.today().strftime("%b").lower(), id) - local_filename = g.urlgrab(url, filename) - return id
\ No newline at end of file + filename="/home/luxagraf/webapps/static/images/magnolia_thumbs/%s/%s.jpg" %(datetime.datetime.today().strftime("%b").lower(), id) + urllib.urlretrieve(url, filename) + return id + +def post_to_tumblr(link): + from links import tumblr + blog = settings.TUMBLR_URL + user= settings.TUMBLR_USER + password = settings.TUMBLR_PASSWORD + api = tumblr.Api(blog,user,password) + post = api.write_link(link.url,name=link.title,description=link.description,date=safestr(link.pub_date)) + +def send_to_deliciousfb(link): + """Wanted my links to go to Facebook and since the Facebook API is needlessly complex + I just created a second delicious account and added the feed via facebook""" + del_tags = '' + tags = link.tags.split(',') + for tag in tags: + del_tags += tag.strip().replace(' ','_')+' ' + desc = link.description.replace('<blockquote>','\n“') + desc = desc.replace('</blockquote>','”\n') + desc = striptags(desc) + delicious.add(settings.DELTOFACEUSER, settings.DELTOFACEPASS, link.url, link.title, tags = del_tags, extended = desc, dt =safestr(link.pub_date), replace="no") diff --git a/base_urls.py b/base_urls.py index 95e4b8f..6e9e4ca 100644 --- a/base_urls.py +++ b/base_urls.py @@ -5,8 +5,9 @@ from django.views.generic.simple import redirect_to,direct_to_template from django.contrib.sitemaps import FlatPageSitemap from django.conf import settings -from blog.models import BlogSitemap +from blog.models import BlogSitemap,LatestFull from locations.models import WritingbyLocationSitemap +from links.models import LatestLinks admin.autodiscover() @@ -16,6 +17,10 @@ sitemaps = { 'flatpages': FlatPageSitemap, #'locations': WritingbyLocationSitemap } +feeds = { + 'writing': LatestFull, + 'fblinks' : LatestLinks, +} # old page redirects @@ -32,6 +37,7 @@ if settings.DEVELOPMENT: ) urlpatterns += patterns('', + (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}), (r'^admin/doc/', include('django.contrib.admindocs.urls')), (r'^admin/(.*)', admin.site.root), (r'^robots.txt$', direct_to_template, {'template': 'archives/robots.html'}), diff --git a/templates/feeds/blog_description.html b/templates/feeds/blog_description.html new file mode 100644 index 0000000..29c4f44 --- /dev/null +++ b/templates/feeds/blog_description.html @@ -0,0 +1 @@ +{{obj.body_html|safe}}
\ No newline at end of file diff --git a/templates/feeds/links_description.html b/templates/feeds/links_description.html new file mode 100644 index 0000000..09d5411 --- /dev/null +++ b/templates/feeds/links_description.html @@ -0,0 +1 @@ +<img style="float: left; padding: 0 5px 5px 0;"src="http://images.luxagraf.net/magnolia_thumbs/{{obj.screen_url}}" />{{obj.description|safe }}
\ No newline at end of file |