在建立我們要的新模組之前,先修改一下既有的樣板
進到mediagoblin/mediagoblin/templates/mediagoblin裡

cd mediagoblin/mediagoblin/templates/mediagoblin

編輯base.html

<a class="button_action" href="{{ request.urlgen('mediagoblin.submit.start') }}">{%- trans %}Add media{% endtrans -%}</a>  
<!--在這邊新增一個buttonimport flickr-->  
<a class="button_action" href="{{ request.urlgen('mediagoblin.import_flickr.start') }}">Import photo from Flickr</a>  
<a class="button_action" href="{{ request.urlgen('mediagoblin.submit.collection') }}">{%- trans %}Create new collection{% endtrans -%}</a>

接著新增import_flickr資料夾

mkdir import_flickr

在裡面建立一個start.html

{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}

{% block title -%}  
{% trans %}Import Photos form Flickr!{% endtrans %} &mdash; {{ super() }}  
{%- endblock %}

{% block mediagoblin_content %}  
<form action="{{ request.urlgen('mediagoblin.import_flickr.start') }}"  method="POST" enctype="multipart/form-data">  
    <div class="form_box_xl">  
        <h1>{% trans %}Import Photos form Flickr!{% endtrans %}</h1>  
            {{ wtforms_util.render_divs(submit_form) }}  
        <div class="form_submit_buttons">  
            {{ csrf_token }}  
            <input type="submit" value="{% trans %}Add{% endtrans %}" class="button_form" />  
        </div>  
    </div>  
</form>  
{% endblock %}

新增模組
先退到上兩層的mediagoblin/mediagoblin裡

建立新的資料夾叫import_flickr

mkdir import_flickr

裡面我們會需要幾個檔案,如下所示:

import_flickr/
|-__init__.py
|- forms.py
|- lib.py
|- routing.py
|- views.py

forms.py:

import wtforms

from mediagoblin.tools.text import tag_length_validator  
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _  
from mediagoblin.tools.licenses import licenses_as_choices

class SubmitStartForm(wtforms.Form):  
    file = wtforms.FileField(_('File'),description=_("""Only zip file accepted.<br>You can use <a href="http://code.google.com/p/offlickr/">Offickr</a> to download the package photo."""))

lib.py:

import logging  
import uuid  
from werkzeug.utils import secure_filename  
from werkzeug.datastructures import FileStorage  
from mediagoblin.db.models import MediaEntry  
from mediagoblin.processing import mark_entry_failed  
from mediagoblin.processing.task import process_media

_log = logging.getLogger(__name__)

def check_file_field(request, field_name):  
    """Check if a file field meets minimal criteria"""  
    retval = (field_name in request.files and isinstance(request.files[field_name], FileStorage) and request.files[field_name].stream)
    if not retval:  
        _log.debug("Form did not contain proper file field %s", field_name)  
        return retval

def new_upload_entry(user):  
    """Create a new MediaEntry for uploading"""
    entry = MediaEntry()  
    entry.uploader = user.id  
    entry.license = user.license_preference  
    return entry

def prepare_queue_task(app, entry, filename):
    """Prepare a MediaEntry for the processing queue and get a queue file"""
    # We generate this ourselves so we know what the task id is for
    # retrieval later.

    # (If we got it off the task's auto-generation, there'd be
    # a risk of a race condition when we'd save after sending
    # off the task)
    task_id = unicode(uuid.uuid4())
    entry.queued_task_id = task_id

    # Now store generate the queueing related filename
    queue_filepath = app.queue_store.get_unique_filepath(['media_entries', task_id, secure_filename(filename)])

    # queue appropriately
    queue_file = app.queue_store.get_file(queue_filepath, 'wb')

    # Add queued filename to the entry
    entry.queued_media_file = queue_filepath

    return queue_file

def run_process_media(entry, feed_url=None):
    """Process the media asynchronously
    :param entry: MediaEntry() instance to be processed.
    :param feed_url: A string indicating the feed_url that the PuSH servers should be notified of. This will be sth like: `request.urlgen('mediagoblin.user_pages.atom_feed',qualified=True, user=request.user.username)`"""
    try:
        process_media.apply_async([entry.id, feed_url], {},task_id=entry.queued_task_id)
    except BaseException as exc:
        # The purpose of this section is because when running in "lazy"
        # or always-eager-with-exceptions-propagated celery mode that
        # the failure handling won't happen on Celery end.  Since we
        # expect a lot of users to run things in this way we have to
        # capture stuff here.
        #
        # ... not completely the diaper pattern because the
        # exception is re-raised :)
        mark_entry_failed(entry.id, exc)
        # re-raise the exception
        raise

routing.py:

from mediagoblin.tools.routing import add_route

add_route('mediagoblin.import_flickr.start','/import_flickr/', 'mediagoblin.import_flickr.views:submit_start')

views.py:

from mediagoblin import messages  
import mediagoblin.mg_globals as mg_globals  
from os.path import splitext

import logging  
import uuid  
import zipfile  
import imghdr  
from xml.etree import ElementTree  
_log = logging.getLogger(__name__)


from mediagoblin.tools.text import convert_to_tag_list_of_dicts  
from mediagoblin.tools.translate import pass_to_ugettext as _  
from mediagoblin.tools.response import render_to_response, redirect  
from mediagoblin.decorators import require_active_login  
from mediagoblin.import_flickr import forms as submit_forms  
from mediagoblin.messages import add_message, SUCCESS  
from mediagoblin.media_types import sniff_media, \InvalidFileType, FileTypeNotSupported  
from mediagoblin.import_flickr.lib import check_file_field, prepare_queue_task, \run_process_media, new_upload_entry  
from mediagoblin.notifications import add_comment_subscription  
@require_active_login  
def submit_start(request):  
    """First view for submitting a file."""  
    submit_form = submit_forms.SubmitStartForm(request.form, license=request.user.license_preference)

if request.method == 'POST' and submit_form.validate():  
    if not check_file_field(request, 'file'):  
        submit_form.file.errors.append(_(u'You must provide a file.'))  
    else:  
        try:  
            filename = request.files['file'].filename

            # If the filename contains non ascii generate a unique name  
            if not all(ord(c) < 128 for c in filename):  
                filename = unicode(uuid.uuid4()) + splitext(filename)[-1]


            # Sniff the submitted media to determine which  
            # media plugin should handle processing  
            # I've modified ../media_types/__init__.py so that a zip file can pass the checking system  
            # It will be seen as an image file  
            media_type, media_manager = sniff_media(request.files['file'])

            # Read the zip file and processing each photo with its metadata  
            zf = zipfile.ZipFile(request.files['file'], 'r')  
            for name in zf.namelist():  
                try:  
                    data = zf.read(name)  
                    if imghdr.what(name, data):  
                        metadata = ElementTree.ElementTree(ElementTree.fromstring(zf.read(name.split(".")[0]+'.xml')))

                        # Fetch the data in metadata that matches the format in mediagoblin  
                        # Not yet finish the whole checking problem, some data may not exist  
                        img_title = metadata.find('title').text  
                        img_description = metadata.find('description').text  
                        img_tags = ''  
                        for tag in metadata.find('tags'):  
                            img_tags = img_tags + ', ' + tag.text

                        upload_data = data  
                        upload_filename = name.lstrip('dst/')

                        # create entry and save in database  
                        entry = new_upload_entry(request.user)  
                        entry.media_type = unicode(media_type)

                        entry.title = unicode(img_title)

                        entry.description = unicode(img_description)#unicode(submit_form.description.data)

                        entry.license = unicode('http://creativecommons.org/publicdomain/mark/1.0/')#unicode(submit_form.license.data) or None

                        # Process the user's folksonomy "tags"  
                        entry.tags = convert_to_tag_list_of_dicts(img_tags)

                        # Generate a slug from the title  
                        entry.generate_slug()

                        queue_file = prepare_queue_task(request.app, entry, upload_filename)

                        with queue_file:  
                        queue_file.write(upload_data)#request.files['file'].stream.read())

                        # Save now so we have this data before kicking off processing  
                        entry.save()  
                        feed_url = request.urlgen('mediagoblin.user_pages.atom_feed', qualified=True, user=request.user.username)  
                        run_process_media(entry, feed_url)  
                    except KeyError:  
                        print 'ERROR: Did not find %s in zip file' % name

                # Pass off to processing  
                # (... don't change entry after this point to avoid race  
                # conditions with changes to the document via processing code)  
                add_message(request, SUCCESS, _('Woohoo! Submitted!'))

                add_comment_subscription(request.user, entry)

                return redirect(request, "mediagoblin.user_pages.user_home", user=request.user.username)

            except Exception as e:  
            '''This section is intended to catch exceptions raised in mediagoblin.media_types'''
            if isinstance(e, InvalidFileType) or \isinstance(e, FileTypeNotSupported):  
                submit_form.file.errors.append(e)  
            else:  
                raise

        return render_to_response(request,'mediagoblin/import_flickr/start.html',{'submit_form': submit_form,'app_config': mg_globals.app_config})

最後,要回到上一層的mediagoblin資料夾裡

編輯routing.py:

import logging

from mediagoblin.tools.routing import add_route, mount, url_map  
from mediagoblin.tools.pluginapi import PluginManager  
from mediagoblin.admin.routing import admin_routes  
from mediagoblin.auth.routing import auth_routes

_log = logging.getLogger(__name__)


def get_url_map():  
    add_route('index', '/', 'mediagoblin.views:root_view')  
    mount('/auth', auth_routes)  
    mount('/a', admin_routes)

    import mediagoblin.submit.routing  
    #####在這邊插入下面這行#####  
    import mediagoblin.import_flickr.routing  
    import mediagoblin.user_pages.routing  
    import mediagoblin.edit.routing  
    import mediagoblin.webfinger.routing  
    import mediagoblin.listings.routing  
    import mediagoblin.notifications.routing

    for route in PluginManager().get_routes():  
        add_route(*route)

    return url_map

如此一來便大功告成,在mediagoblin這一端的部分結束。