summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/blog/models.py10
-rw-r--r--apps/links/models.py8
-rw-r--r--apps/links/tumblr.py239
-rw-r--r--apps/links/utils.py36
-rw-r--r--base_urls.py8
-rw-r--r--templates/feeds/blog_description.html1
-rw-r--r--templates/feeds/links_description.html1
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&#8220;')
+ desc = desc.replace('</blockquote>','&#8221;\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