Merge remote-tracking branch 'cweb/master'

This commit is contained in:
Aditi 2013-06-21 23:09:22 +05:30
commit 2719d546a5
625 changed files with 99416 additions and 0 deletions

37
.gitignore vendored Normal file
View File

@ -0,0 +1,37 @@
# / means repository root, not filesystem root
# Top-level files and directories
/dist/
/bin/
/develop-eggs/
/build/
/eggs/
/lib/
/local/
/include/
/parts/
/share/
/mediagoblin.egg-info
/docs/_build/
/docs/build
/api-docs/build
/api-docs/source/mediagoblin*
/user_dev/
/paste_local.ini
/mediagoblin_local.ini
/mediagoblin.db
/celery.db
/kombu.db
/server-log.txt
# Tests
/mediagoblin/tests/user_dev/
# File extensions
*.pyc
*.pyo
*~
*.swp
# The legacy of buildout
.installed.cfg

6
.gitmodules vendored Normal file
View File

@ -0,0 +1,6 @@
[submodule "pdf.js"]
path = pdf.js
url = git://github.com/mozilla/pdf.js.git
[submodule "extlib/pdf.js"]
path = extlib/pdf.js
url = git://github.com/mozilla/pdf.js.git

8
.tx/config Normal file
View File

@ -0,0 +1,8 @@
[mediagoblin.mediagoblin]
file_filter = mediagoblin/i18n/<lang>/LC_MESSAGES/mediagoblin.po
source_file = mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po
source_lang = en
[main]
host = https://www.transifex.net

82
AUTHORS Normal file
View File

@ -0,0 +1,82 @@
=========
AUTHORS
=========
This is a list of contributors to MediaGoblin. They contribute in a
variety of different ways and this software wouldn't exist without them.
Thank you!
* Aaron Williamson
* Aditi Mittal
* Aeva Ntsc
* Alejandro Villanueva
* Aleksandar Micovic
* Aleksej Serdjukov
* Alon Levy
* Alex Camelio
* András Veres-Szentkirályi
* Bassam Kurdali
* Bernhard Keller
* Brett Smith
* Caleb Forbes Davis V
* Corey Farwell
* Chris Moylan
* Christopher Allan Webber
* David Thompson
* Daniel Neel
* Deb Nicholson
* Derek Moore
* Duncan Paterson
* Elrond of Samba TNG
* Emily O'Leary
* Gabi Thume
* Gabriel Saldana
* Greg Grossmeier
* Hans Lo
* Jakob Kramer
* Jef van Schendel
* Jessica Tallon
* Jim Campbell
* Joar Wandborg
* Jorge Araya Navarro
* Karen Rustad
* Kuno Woudt
* Laura Arjona
* Larisa Hoffenbecker
* Luke Slater
* Manuel Urbano Santos
* Mark Holmquist
* Mats Sjöberg
* Matt Lee
* Michele Azzolari
* Mike Linksvayer
* Natalie Foust-Pilcher
* Nathan Yergler
* Odin Hørthe Omdal
* Osama Khalid
* Pablo J. Urbano Santos
* Praveen Kumar
* Rasmus Larsson
* Rodney Ewing
* Runar Petursson
* Sacha De'Angeli
* Sam Kleinman
* Sam Tuke
* Sebastian Spaeth
* Shawn Khan
* Simon Fondrie-Teitler
* Stefano Zacchiroli
* Tiberiu C. Turbureanu
* Tran Thanh Bao
* Tryggvi Björgvinsson
* Shawn Khan
* Will Kahn-Greene
If you think your name should be on this list, let us know!
We also are currently borrowing an image in
mediagoblin/static/images/media_thumbs/image.png from the wonderful
people at http://tango.freedesktop.org/ which is in the public
domain... thanks Tango folks!

69
COPYING Normal file
View File

@ -0,0 +1,69 @@
=========
COPYING
=========
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public
License along with this program, in the file ``licenses/AGPLv3.txt``.
If not, see <http://www.gnu.org/licenses/>.
Translation files located under ``mediagoblin/i18n/`` directory tree
are free software: you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
You should have received a copy of the GNU Affero General Public
License along with this program, in the file ``licenses/AGPLv3.txt``.
If not, see <http://www.gnu.org/licenses/>.
JavaScript files located in the ``mediagoblin/`` directory tree
are free software: you can redistribute and/or modify them under the
terms of the GNU Affero General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
You should have received a copy of the GNU Lesser General Public
License along with this program, in the file ``licenses/LGPLv3.txt``.
If not, see <http://www.gnu.org/licenses/>.
Documentation files located in the ``docs/`` directory tree and all
original documentation theme CSS and assets (including image files)
are released under a CC0 license. To the extent possible under law,
the author(s) have dedicated all copyright and related and neighboring
rights to these files to the public domain worldwide. These files are
distributed without any warranty.
You should have received a copy of the CC0 license in the file
``licenses/CC0_1.0.txt``. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
CSS, images and video located in the ``mediagoblin/`` directory tree are
released under a CC0 license. To the extent possible under law, the author(s)
have dedicated all copyright and related and neighboring rights to these
files to the public domain worldwide. These files are distributed without
any warranty.
You should have received a copy of the CC0 license in the file
``licenses/CC0_1.0.txt``. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
Additional library software has been made available in the ``extlib/``
directory. All of it is Free Software and can be distributed under
liberal terms, but those terms may differ in detail from the AGPL's
particulars. See each package's license file in the extlib directory
for additional terms.

11
MANIFEST.in Normal file
View File

@ -0,0 +1,11 @@
recursive-include mediagoblin/i18n *.mo
recursive-include mediagoblin *.js *.css *.png *.svg *.ico
recursive-include mediagoblin *.ini
recursive-include mediagoblin *.html *.txt
recursive-include docs *.rst *.html
include mediagoblin.ini mediagoblin/config_spec.ini paste.ini
include mediagoblin/config_spec.ini
graft extlib
graft licenses
include COPYING AUTHORS
include lazyserver.sh lazystarter.sh lazycelery.sh

41
README Normal file
View File

@ -0,0 +1,41 @@
========
README
========
What is GNU MediaGoblin?
========================
* Initially, a place to store all your photos thats as awesome as, if
not more awesome than, existing network services (Flickr, SmugMug,
Picasa, etc)
* Customizable!
* A place for people to collaborate and show off original and derived
creations. Free, as in freedom. Were a GNU project after all.
* Later, a place for all sorts of media, such as video, music, etc hosting.
* Later, federated with OStatus!
Is it ready for me to use?
==========================
Yes! But with caveats. The software is usable and there are instances
running, but it's still in its early stages.
Can I help/hang out/participate/whisper sweet nothings in your ear?
===================================================================
Yes! Please join us and hang out! For more information on where we
hang out, see `our Join page <http://mediagoblin.org/join/>`_
Where is the documentation?
===========================
The beginnings of a site administration manual is located in the ``docs/``
directory in HTML, Texinfo, and source (Restructured Text) forms. It's
also available online at http://docs.mediagoblin.org/ in HTML form.
Contributor/developer documentation as well as documentation on the
project processes and infrastructure is located on
`the wiki <http://wiki.mediagoblin.org/>`_.

161
api-docs/Makefile Normal file
View File

@ -0,0 +1,161 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXAPIDOC = sphinx-apidoc
PAPER =
BUILDDIR = build
SOURCEDIR = source
MEDIAGOBLIN_SOURCEDIR = ../mediagoblin
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
apidoc:
@echo "Generating API source docs"
$(SPHINXAPIDOC) -o $(SOURCEDIR) $(MEDIAGOBLIN_SOURCEDIR)
@echo "Done"
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/GNUMediaGoblin.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GNUMediaGoblin.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/GNUMediaGoblin"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GNUMediaGoblin"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

246
api-docs/source/conf.py Normal file
View File

@ -0,0 +1,246 @@
# -*- coding: utf-8 -*-
#
# GNU MediaGoblin documentation build configuration file, created by
# sphinx-quickstart on Sun Apr 1 01:11:46 2012.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('../../'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'GNU MediaGoblin'
copyright = u'2011, 2012, GNU MediaGoblin contributors'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.3.0-dev'
# The full version, including alpha/beta/rc tags.
release = '0.3.0-dev'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'mg'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ['themes']
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = 'logo_docs.png'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'GNUMediaGoblindoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'GNUMediaGoblin.tex', u'GNU MediaGoblin Documentation',
u'See AUTHORS', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'gnumediagoblin', u'GNU MediaGoblin Documentation',
[u'See AUTHORS'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'GNUMediaGoblin', u'GNU MediaGoblin Documentation',
u'See AUTHORS', 'GNUMediaGoblin', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}

22
api-docs/source/index.rst Normal file
View File

@ -0,0 +1,22 @@
.. GNU MediaGoblin documentation master file, created by
sphinx-quickstart on Sun Apr 1 01:11:46 2012.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to GNU MediaGoblin's API documentation!
===========================================
See the :ref:`modindex` or this ToC:
.. toctree::
:maxdepth: 10
mediagoblin
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -0,0 +1,7 @@
mediagoblin
===========
.. toctree::
:maxdepth: 4
mediagoblin

View File

@ -0,0 +1,29 @@
{#
default/layout.html
~~~~~~~~~~~~~~~~~~~
Sphinx layout template for the default theme.
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
#}
{% extends "basic/layout.html" %}
{% if theme_collapsiblesidebar|tobool %}
{% set script_files = script_files + ['_static/sidebar.js'] %}
{% endif %}
{%- block footer %}
<div class="footer">
<div>
MediaGoblin documentation released into the public domain via <a href="http://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.
{%- if last_updated %}
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
{%- endif %}
{% trans sphinx_version=sphinx_version|e %}Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %}
</div>
</div>
{%- endblock %}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,97 @@
Copyright (c) <dates>, <Copyright Holder> (<URL|email>),
with Reserved Font Name <Reserved Font Name>.
Copyright (c) <dates>, <additional Copyright Holder> (<URL|email>),
with Reserved Font Name <additional Reserved Font Name>.
Copyright (c) <dates>, <additional Copyright Holder> (<URL|email>).
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -0,0 +1,161 @@
/*
MediaGoblin theme - MediaGoblin-style Sphinx documentation theme
Written in 2012 by Jef van Schendel <mail@jefvanschendel.nl>
To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
@import url("basic.css");
/* text fonts and styles */
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 700;
src: local('Lato Bold'), local('Lato-Bold'), url('fonts/Lato-Bold.ttf') format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: italic;
font-weight: 400;
src: local('Lato Italic'), local('Lato-Italic'), url('fonts/Lato-Italic.ttf') format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: italic;
font-weight: 700;
src: local('Lato Bold Italic'), local('Lato-BoldItalic'), url('fonts/Lato-BoldItalic.ttf') format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url('fonts/Lato-Regular.ttf') format('truetype');
}
body {
font: 16px 'Lato',Helvetica,Arial,sans-serif;
background-color: #FCFCFC;
color: #3C3C3C;
margin: 0;
padding: 0;
}
h1, h2, h3, h4, h5, h6 {
border-bottom: 1px solid #CCCCCC;
background: none;
color: black;
font-weight: bold;
padding-bottom: 0.17em;
padding-top: 0.5em;
}
h1 {
font-size: 1.875em;
}
h2 {
font-size: 1.375em;
}
h3, h4, h5, h6 {
font-size: 1.125em;
}
p {
font-weight: normal;
margin: 0.4em 0 0.5em;
}
a {
color: #499776;
}
a:visited {
color: #2A5744;
}
a:active {
color: #65D1A3;
}
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
text-decoration: none;
}
div.topic, pre {
background-color: #F1F1F1;
border: 1px dashed #ccc;
color: black;
line-height: 1.1em;
padding: 1em;
}
code, tt {
font: 14px monospace,"Courier New";
background-color: #FFFFDD;
border: thin solid #bbb;
padding-left: 5px;
padding-right: 5px;
}
pre {
font: 14px monospace,"Courier New";
}
div.related a, div.related a:visited, div.related a:active {
color: #86D4B1;
}
/* layout */
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 270px;
}
div.body {
padding: 0 20px 30px 20px;
}
div.footer {
width: 100%;
padding: 9px 0 9px 0;
text-align: center;
font-size: 75%;
}
div.sphinxsidebar {
width: 240px;
}
div.sphinxsidebarwrapper {
padding: 10px 5px 0 30px;
}
div.sphinxsidebar ul {
margin: 10px 10px 10px 0;
padding: 0;
}
div.related {
line-height: 30px;
font-size: 90%;
width: 100%;
background-color: #161616;
color: #C3C3C3;
}
p.logo {
margin-top: 30px;
}

View File

@ -0,0 +1,5 @@
[theme]
inherit = basic
stylesheet = mg.css
pygments_style = sphinx

16
babel.ini Normal file
View File

@ -0,0 +1,16 @@
# Extraction from Python source files
[python: mediagoblin/**.py]
# Extraction from Genshi HTML and text templates
[jinja2: mediagoblin/**/templates/**.html]
# Extract jinja templates (html)
encoding = utf-8
extensions = jinja2.ext.autoescape, mediagoblin.tools.template.TemplateHookExtension
[jinja2: mediagoblin/templates/**.txt]
# Extract jinja templates (text)
encoding = utf-8
extensions = jinja2.ext.autoescape
# # Extraction from JavaScript files
# [javascript: mediagoblin/static/js/**.js]
# extract_messages = $._, jQuery._

179
devtools/maketarball.sh Executable file
View File

@ -0,0 +1,179 @@
#!/bin/bash
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011, 2012 GNU MediaGoblin Contributors. See AUTHORS.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# usage: maketarball [-drh] REVISH
#
# Creates a tarball of the repository at rev REVISH.
# If -d is passed in, then it adds the date to the directory name.
#
# If -r is passed in, then it does some additional things required
# for a release-ready tarball.
#
# If -h is passed in, shows help and exits.
#
# Examples:
#
# ./maketarball v0.0.2
# ./maketarball -d master
# ./maketarball -r v0.0.2
USAGE="Usage: $0 -h | [-dr] REVISH"
REVISH="none"
PREFIX="none"
NOWDATE=""
RELEASE="no"
while getopts ":dhr" opt;
do
case "$opt" in
h)
echo "$USAGE"
echo ""
echo "Creates a tarball of the repository at rev REVISH."
echo ""
echo " -h Shows this help message"
echo " -d Includes date in tar file name and directory"
echo " -r Performs other release-related actions"
exit 0
;;
d)
NOWDATE=`date "+%Y-%m-%d-"`
shift $((OPTIND-1))
;;
r)
RELEASE="yes"
shift $((OPTIND-1))
;;
\?)
echo "Invalid option: -$OPTARG" >&2
echo "$USAGE" >&2
;;
esac
done
if [[ -z "$1" ]]; then
echo "$USAGE";
exit 1;
fi
REVISH=$1
PREFIX="$NOWDATE$REVISH"
# convert PREFIX to all lowercase and nix the v from tag names.
PREFIX=`echo "$PREFIX" | tr '[A-Z]' '[a-z]' | sed s/v//`
# build the filename base minus the .tar.gz stuff--this is also
# the directory in the tarball.
FNBASE="mediagoblin-$PREFIX"
STARTDIR=`pwd`
function cleanup {
pushd $STARTDIR
if [[ -e tmp ]]
then
echo "+ cleaning up tmp/"
rm -rf tmp
fi
popd
}
echo "+ Building tarball from: $REVISH"
echo "+ Using prefix: $PREFIX"
echo "+ Release?: $RELEASE"
echo ""
if [[ -e tmp ]]
then
echo "+ there's an existing tmp/. please remove it."
exit 1
fi
mkdir $STARTDIR/tmp
echo "+ generating archive...."
git archive \
--format=tar \
--prefix=$FNBASE/ \
$REVISH > tmp/$FNBASE.tar
if [[ $? -ne 0 ]]
then
echo "+ git archive command failed. See above text for reason."
cleanup
exit 1
fi
if [[ $RELEASE = "yes" ]]
then
pushd tmp/
tar -xvf $FNBASE.tar
pushd $FNBASE
pushd docs
echo "+ generating html docs"
make html
if [[ $? -ne 0 ]]
then
echo "+ sphinx docs generation failed. See above text for reason."
cleanup
exit 1
fi
# NOTE: this doesn't work for gmg prior to v0.0.4.
echo "+ generating texinfo docs (doesn't work prior to v0.0.4)"
make info
popd
echo "+ moving docs to the right place"
if [[ -e docs/build/html/ ]]
then
mv docs/build/html/ docs/html/
mv docs/build/texinfo/ docs/texinfo/
rm -rf docs/build/
else
# this is the old directory structure pre-0.0.4
mv docs/_build/html/ docs/html/
rm -rf docs/_build/
fi
# Remove .pyc files that may have been generated by sphinx
find mediagoblin -name '*.pyc' -exec rm {} \;
popd
tar -cvf $FNBASE.tar $FNBASE
popd
fi
echo "+ compressing...."
gzip tmp/$FNBASE.tar
echo "+ archive at tmp/$FNBASE.tar.gz"
echo "+ done."

56
devtools/update_translations.sh Executable file
View File

@ -0,0 +1,56 @@
#!/bin/bash
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011, 2012 GNU MediaGoblin contributors. See AUTHORS.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# exit if anything fails
set -e
echo "==> checking out master"
git checkout master
echo "==> pulling git master"
git pull
echo "==> pulling present translations"
./bin/tx pull -a
git add mediagoblin/i18n/
git commit -m "Committing present MediaGoblin translations before pushing extracted messages" \
|| true # Don't fail if nothing to commit
echo "==> Extracting translations"
./bin/pybabel extract -F babel.ini -o mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po .
echo "==> Pushing extracted translations to Transifex"
./bin/tx push -s
echo "==> Waiting 5 seconds, so the server can process the new stuff (hopefully)"
sleep 5
# gets the new strings added to all files
echo "==> Re-Pulling translations from Transifex"
./bin/tx pull -a
echo "==> Compiling .mo files"
./bin/pybabel compile -D mediagoblin -d mediagoblin/i18n/
echo "==> Committing to git"
git add mediagoblin/i18n/
git commit -m "Committing extracted and compiled translations" || true
echo "... done. Now consider pushing up those commits!"

153
docs/Makefile Normal file
View File

@ -0,0 +1,153 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/GNUMediaGoblin.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GNUMediaGoblin.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/GNUMediaGoblin"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GNUMediaGoblin"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
make -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

247
docs/source/conf.py Normal file
View File

@ -0,0 +1,247 @@
# -*- coding: utf-8 -*-
#
# GNU MediaGoblin documentation build configuration file, created by
# sphinx-quickstart on Thu Apr 7 20:10:27 2011.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath(os.path.join('..', '..')))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx']
intersphinx_mapping = {'python': ('http://docs.python.org/2.7', None)}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['source/_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'GNU MediaGoblin'
copyright = u'2011, 2012 GNU MediaGoblin contributors'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
try:
from mediagoblin._version import __version__
# The short X.Y version.
version = '.'.join(__version__.split('.')[0:2])
# The full version, including alpha/beta/rc tags.
release = __version__
except ImportError:
version = 'unknown'
release = 'unknown'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build', 'mgext', '_templates', '_static']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
# html_theme = 'default'
html_theme = 'mg'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ['themes']
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = 'logo_docs.png'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'GNUMediaGoblindoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'GNUMediaGoblin.tex', u'GNU MediaGoblin Documentation',
u'Chris Webber, et al', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'gnumediagoblin', u'GNU MediaGoblin Documentation',
[u'Chris Webber, et al'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'gnumediagoblin', u'GNU MediaGoblin Documentation', u'gnumediagoblin',
'GNU MediaGoblin', 'Media sharing web application.', 'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

View File

@ -0,0 +1,183 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
.. _codebase-chapter:
========================
Codebase Documentation
========================
.. contents:: Sections
:local:
This chapter covers the libraries that GNU MediaGoblin uses as well as
various recipes for getting things done.
.. Note::
This chapter is in flux. Clearly there are things here that aren't
documented. If there's something you have questions about, please
ask!
See `the join page on the website <http://mediagoblin.org/join/>`_
for where we hang out.
For more information on how to get started hacking on GNU MediaGoblin,
see `the wiki <http://wiki.mediagoblin.org/>`_, and specifically, go
through the
`Hacking HOWTO <http://wiki.mediagoblin.org/HackingHowto>`_
which explains generally how to get going with running an instance for
development.
What's where
============
After you've run checked out mediagoblin and followed the virtualenv
instantiation instructions, you're faced with the following directory
tree::
mediagoblin/
|- mediagoblin/ # source code
| |- db/ # database setup
| |- tools/ # various utilities
| |- init/ # "initialization" tools (arguably should be in tools/)
| |- tests/ # unit tests
| |- templates/ # templates for this application
| |- media_types/ # code for processing, displaying different media
| |- storage/ # different storage backends
| |- gmg_commands/ # command line tools (./bin/gmg)
| |- themes/ # pre-bundled themes
| |
| | # ... some submodules here as well for different sections
| | # of the application... here's just a few
| |- auth/ # authentication (login/registration) code
| |- user_dev/ # user pages (under /u/), including media pages
| \- submit/ # submitting media for processing
|
|- docs/ # documentation
|- devtools/ # some scripts for developer convenience
|
|- user_dev/ # local instance sessions, media, etc
|
| # the below directories are installed into your virtualenv checkout
|
|- bin/ # scripts
|- develop-eggs/
|- lib/ # python libraries installed into your virtualenv
|- include/
|- mediagoblin.egg-info/
\- parts/
As you can see, all the code for GNU MediaGoblin is in the
``mediagoblin`` directory.
Here are some interesting files and what they do:
:routing.py: maps url paths to views
:views.py: views handle http requests
:forms.py: wtforms stuff for this submodule
You'll notice that there are several sub-directories: tests,
templates, auth, submit, ...
``tests`` holds the unit test code.
``templates`` holds all the templates for the output.
``auth`` and ``submit`` are modules that enacpsulate authentication
and media item submission. If you look in these directories, you'll
see they have their own ``routing.py``, ``view.py``, and forms.py in
addition to some other code.
You'll also notice that mediagoblin/db/ contains quite a few things,
including the following:
:models.py: This is where the database is set up
:mixin.py: Certain functions appended to models from here
:migrations.py: When creating a new migration (a change to the
database structure), we put it here
Software Stack
==============
* Project infrastructure
* `Python <http://python.org/>`_: the language we're using to write
this
* `Py.Test <http://pytest.org/>`_:
for unit tests
* `virtualenv <http://www.virtualenv.org/>`_: for setting up an
isolated environment to keep mediagoblin and related packages
(potentially not required if MediaGoblin is packaged for your
distro)
* Data storage
* `SQLAlchemy <http://sqlalchemy.org/>`_: SQL ORM and database
interaction library for Python. Currently we support sqlite and
postgress as backends.
* Web application
* `Paste Deploy <http://pythonpaste.org/deploy/>`_ and
`Paste Script <http://pythonpaste.org/script/>`_: we'll use this for
configuring and launching the application
* `werkzeug <http://werkzeug.pocoo.org/>`_: nice abstraction layer
from HTTP requests, responses and WSGI bits
* `itsdangerous <http://pythonhosted.org/itsdangerous/>`_:
for handling sessions
* `Jinja2 <http://jinja.pocoo.org/docs/>`_: the templating engine
* `WTForms <http://wtforms.simplecodes.com/>`_: for handling,
validation, and abstraction from HTML forms
* `Celery <http://celeryproject.org/>`_: for task queuing (resizing
images, encoding video, ...)
* `Babel <http://babel.edgewall.org>`_: Used to extract and compile
translations.
* `Markdown (for python) <http://pypi.python.org/pypi/Markdown>`_:
implementation of `Markdown <http://daringfireball.net/projects/markdown/>`_
text-to-html tool to make it easy for people to write richtext
comments, descriptions, and etc.
* `lxml <http://lxml.de/>`_: nice xml and html processing for
python.
* Media processing libraries
* `Python Imaging Library <http://www.pythonware.com/products/pil/>`_:
used to resize and otherwise convert images for display.
* `GStreamer <http://gstreamer.freedesktop.org/>`_: (Optional, for
video hosting sites only) Used to transcode video, and in the
future, probably audio too.
* `chardet <http://pypi.python.org/pypi/chardet>`_: (Optional, for
ascii art hosting sites only) Used to make ascii art thumbnails.
* Front end
* `JQuery <http://jquery.com/>`_: for groovy JavaScript things

View File

@ -0,0 +1,336 @@
.. _original-design-decisions-chapter:
===========================
Original Design Decisions
===========================
.. contents:: Sections
:local:
This chapter talks a bit about design decisions.
Note: This is an outdated document. It's more or less the historical
reasons for a lot of things. That doesn't mean these decisions have
stayed the same or we haven't changed our minds on some things!
Why GNU MediaGoblin?
====================
Chris and Will on "Why GNU MediaGoblin":
Chris came up with the name MediaGoblin. The name is pretty fun.
It merges the idea that this is a Media hosting project with
Goblin which sort of sounds like gobbling. Here's a piece of
software that gobbles up your media for all to see.
`According to Wikipedia <http://en.wikipedia.org/wiki/Goblin>`_, a
goblin is:
a legendary evil or mischievous illiterate creature, described
as grotesquely evil or evil-like phantom
So are we evil? No. Are we mischievous or illiterate? Not
really. So what kind of goblin are we thinking about? We're
thinking about these goblins:
.. figure:: ../_static/goblin.png
:alt: Cute goblin with a beret.
*Figure 1: Cute goblin with a beret. llustrated by Chris
Webber*
.. figure:: ../_static/snugglygoblin.png
:scale: 50%
:alt: Snuggly goblin with a beret.
*Figure 2: Snuggly goblin. Illustrated by Karen Rustad*
Those are pretty cute goblins. Those are the kinds of goblins
we're thinking about.
Chris started doing work on the project after thinking about it
for a year. Then, after talking with Matt and Rob, it became an
official GNU project. Thus we now call it GNU MediaGoblin.
That's a lot of letters, though, so in the interest of brevity and
facilitating easier casual conversation and balancing that with
what's important to us, we have the following rules:
1. "GNU MediaGoblin" is the name we're going to use in all official
capacities: web site, documentation, press releases, ...
2. In casual conversation, it's ok to use more casual names.
3. If you're writing about the project, we ask that you call it GNU
MediaGoblin.
4. If you don't like the name, we kindly ask you to take a deep
breath, think a happy thought about cute little goblins playing
on a playground and taking cute pictures of themselves, and let
it go. (Will added this one.)
Why Python
==========
Chris Webber on "Why Python":
Because I know Python, love Python, am capable of actually making
this thing happen in Python (I've worked on a lot of large free
software web applications before in Python, including `Miro
Community`_, the `Miro Guide`_, a large portion of `Creative
Commons`_, and a whole bunch of things while working at `Imaginary
Landscape`_). Me starting a project like this makes sense if it's
done in Python.
You might say that PHP is way more deployable, that Rails has way
more cool developers riding around on fixie bikes---and all of
those things are true. But I know Python, like Python, and think
that Python is pretty great. I do think that deployment in Python
is not as good as with PHP, but I think the days of shared hosting
are (thankfully) coming to an end, and will probably be replaced
by cheap virtual machines spun up on the fly for people who want
that sort of stuff, and Python will be a huge part of that future,
maybe even more than PHP will. The deployment tools are getting
better. Maybe we can use something like Silver Lining. Maybe we
can just distribute as ``.debs`` or ``.rpms``. We'll figure it
out when we get there.
Regardless, if I'm starting this project, which I am, it's gonna
be in Python.
.. _Miro Community: http://mirocommunity.org/
.. _Miro Guide: http://miroguide.org/
.. _Creative Commons: http://creativecommons.org/
.. _Imaginary Landscape: http://www.imagescape.com/
Why WSGI Minimalism
===================
Chris Webber on "Why WSGI Minimalism":
If you notice in the technology list I list a lot of components
that are very "django-like", but not actually `Django`_
components. What can I say, I really like a lot of the ideas in
Django! Which leads to the question: why not just use Django?
While I really like Django's ideas and a lot of its components, I
also feel that most of the best ideas in Django I want have been
implemented as good or even better outside of Django. I could
just use Django and replace the templating system with Jinja2, and
the form system with wtforms, and the database with MongoDB and
MongoKit, but at that point, how much of Django is really left?
I also am sometimes saddened and irritated by how coupled all of
Django's components are. Loosely coupled yes, but still coupled.
WSGI has done a good job of providing a base layer for running
applications on and if you know how to do it yourself [1]_, it's
not hard or many lines of code at all to bind them together
without any framework at all (not even say `Pylons`_, `Pyramid`_
or `Flask`_ which I think are still great projects, especially for
people who want this sort of thing but have no idea how to get
started). And even at this already really early stage of writing
MediaGoblin, that glue work is mostly done.
Not to say I don't think Django isn't great for a lot of things.
For a lot of stuff, it's still the best, but not for MediaGoblin,
I think.
One thing that Django does super well though is documentation. It
still has some faults, but even with those considered I can hardly
think of any other project in Python that has as nice of
documentation as Django. It may be worth learning some lessons on
documentation from Django [2]_, on that note.
I'd really like to have a good, thorough hacking-howto and
deployment-howto, especially in the former making some notes on
how to make it easier for Django hackers to get started.
.. _Django: http://www.djangoproject.com/
.. _Pylons: http://pylonshq.com/
.. _Pyramid: http://docs.pylonsproject.org/projects/pyramid/dev/
.. _Flask: http://flask.pocoo.org/
.. [1] http://pythonpaste.org/webob/do-it-yourself.html
.. [2] http://pycon.blip.tv/file/4881071/
Why MongoDB
===========
(Note: We don't use MongoDB anymore. This is the original rationale,
however.)
Chris Webber on "Why MongoDB":
In case you were wondering, I am not a NOSQL fanboy, I do not go
around telling people that MongoDB is web scale. Actually my
choice for MongoDB isn't scalability, though scaling up really
nicely is a pretty good feature and sets us up well in case large
volume sites eventually do use MediaGoblin. But there's another
side of scalability, and that's scaling down, which is important
for federation, maybe even more important than scaling up in an
ideal universe where everyone ran servers out of their own
housing. As a memory-mapped database, MongoDB is pretty hungry,
so actually I spent a lot of time debating whether the inability
to scale down as nicely as something like SQL has with sqlite
meant that it was out.
But I decided in the end that I really want MongoDB, not for
scalability, but for flexibility. Schema evolution pains in SQL
are almost enough reason for me to want MongoDB, but not quite.
The real reason is because I want the ability to eventually handle
multiple media types through MediaGoblin, and also allow for
plugins, without the rigidity of tables making that difficult. In
other words, something like::
{"title": "Me talking until you are bored",
"description": "blah blah blah",
"media_type": "audio",
"media_data": {
"length": "2:30",
"codec": "OGG Vorbis"},
"plugin_data": {
"licensing": {
"license": "http://creativecommons.org/licenses/by-sa/3.0/"}}}
Being able to just dump media-specific information in a media_data
hashtable is pretty great, and even better is having a plugin
system where you can just let plugins have their own entire
key-value space cleanly inside the document that doesn't interfere
with anyone else's stuff. If we were to let plugins to deposit
their own information inside the database, either we'd let plugins
create their own tables which makes SQL migrations even harder
than they already are, or we'd probably end up creating a table
with a column for key, a column for value, and a column for type
in one huge table called "plugin_data" or something similar. (Yo
dawg, I heard you liked plugins, so I put a database in your
database so you can query while you query.) Gross.
I also don't want things to be too loose so that we forget or lose
the structure of things, and that's one reason why I want to use
MongoKit, because we can cleanly define a much structure as we
want and verify that documents match that structure generally
without adding too much bloat or overhead (MongoKit is a pretty
lightweight wrapper and doesn't inject extra MongoKit-specific
stuff into the database, which is nice and nicer than many other
ORMs in that way).
Why Sphinx for documentation
============================
Will Kahn-Greene on "Why Sphinx":
`Sphinx`_ is a fantastic tool for organizing documentation for a
Python-based project that makes it pretty easy to write docs that
are readable in source form and can be "compiled" into HTML, LaTeX
and other formats.
There are other doc systems out there, but given that GNU
MediaGoblin is being written in Python and I've done a ton of
documentation using Sphinx, it makes sense to use Sphinx for now.
.. _Sphinx: http://sphinx.pocoo.org/
Why AGPLv3 and CC0?
===================
Chris, Brett, Will, Rob, Matt, et al curated into a story where
everyone is the hero by Will on "Why AGPLv3 and CC0":
The `AGPL v3`_ preserves the freedoms guaranteed by the GPL v3 in
the context of software as a service. Using this license ensures
that users of the service have the ability to examine the source,
deploy their own instance, and implement their own version. This
is really important to us and a core mission component of this
project. Thus we decided that the software parts should be under
this license.
However, the project is made up of more than just software:
there's CSS, images, and other output-related things. We wanted
the templates/images/css side of the project all permissive and
permissive in the same absolutely permissive way. We're waiving
our copyrights to non-software things under the CC0 waiver.
That brings us to the templates where there's some code and some
output. The template engine we're using is called Jinja2. It
mixes HTML markup with Python code to render the output of the
software. We decided the templates are part of the output of the
software and not the software itself. We wanted the output of the
software to be licensed in a hassle-free way so that when someone
deploys their own GNU MediaGoblin instance with their own
templates, they don't have to deal with the copyleft aspects of
the AGPLv3 and we'd be fine with that because the changes they're
making are identity-related. So at first we decided to waive our
copyrights to the templates with a CC0 waiver and then add an
exception to the AGPLv3 for the software such that the templates
can make calls into the software and yet be a separately licensed
work. However, Brett brought up the question of whether this
allows some unscrupulous person to make changes to the software
through the templates in such a way that they're not bound by the
AGPLv3: i.e. a loophole. We thought about this loophole and
between this and the extra legalese involved in the exception to
the AGPLv3, we decided that it's just way simpler if the templates
were also licensed under the AGPLv3.
Then we have the licensing for the documentation. Given that the
documentation is tied to the software content-wise, we don't feel
like we have to worry about ensuring freedom of the documentation
or worry about attribution concerns. Thus we're waiving our
copyrights to the documentation under CC0 as well.
Lastly, we have branding. This covers logos and other things that
are distinctive to GNU MediaGoblin that we feel represents this
project. Since we don't currently have any branding, this is an
open issue, but we're thinking we'll go with a CC BY-SA license.
By licensing in this way, we make sure that users of the software
receive the freedoms that the AGPLv3 ensures regardless of what
fate befalls this project.
So to summarize:
* software (Python, JavaScript, HTML templates): licensed
under AGPLv3
* non-software things (CSS, images, video): copyrights waived
under CC0 because this is output of the software
* documentation: copyrights waived under CC0 because it's not part
of the software
* branding assets: we're kicking this can down the road, but
probably CC BY-SA
This is all codified in the ``COPYING`` file.
.. _AGPL v3: http://www.gnu.org/licenses/agpl.html
.. _CC0 v1: http://creativecommons.org/publicdomain/zero/1.0/
Why (non-mandatory) copyright assignment?
=========================================
Chris Webber on "Why copyright assignment?":
GNU MediaGoblin is a GNU project with non-mandatory but heavily
encouraged copyright assignment to the FSF. Most, if not all, of
the core contributors to GNU MediaGoblin will have done a
copyright assignment, but unlike some other GNU projects, it isn't
required here. We think this is the best choice for GNU
MediaGoblin: it ensures that the Free Software Foundation may
protect the software by enforcing the AGPL if the FSF sees fit,
but it also means that we can immediately merge in changes from a
new contributor. It also means that some significant non-FSF
contributors might also be able to enforce the AGPL if seen fit.
Again, assignment is not mandatory, but it is heavily encouraged,
even incentivized: significant contributors who do a copyright
assignment to the FSF are eligible to have a unique goblin drawing
produced for them by the project's main founder, Christopher Allan
Webber. See `the wiki <http://wiki.mediagoblin.org/>`_ for details.

View File

@ -0,0 +1,125 @@
=========
Storage
=========
The storage systems attached to your app
----------------------------------------
Dynamic content: queue_store and public_store
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Two instances of the StorageInterface come attached to your app. These
are:
+ **queue_store:** When a user submits a fresh piece of media for
their gallery, before the Processing stage, that piece of media sits
here in the queue_store. (It's possible that we'll rename this to
"private_store" and start storing more non-publicly-stored stuff in
the future...). This is a StorageInterface implementation
instance. Visitors to your site probably cannot see it... it isn't
designed to be seen, anyway.
+ **public_store:** After your media goes through processing it gets
moved to the public store. This is also a StorageInterface
implelementation, and is for stuff that's intended to be seen by
site visitors.
The workbench
~~~~~~~~~~~~~
In addition, there's a "workbench" used during
processing... it's just for temporary files during
processing, and also for making local copies of stuff that
might be on remote storage interfaces while transitionally
moving/converting from the queue_store to the public store.
See the workbench module documentation for more.
.. automodule:: mediagoblin.tools.workbench
:members:
:show-inheritance:
Static assets / staticdirect
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
On top of all that, there is some static media that comes bundled with your
application. This stuff is kept in:
mediagoblin/static/
These files are for mediagoblin base assets. Things like the CSS files,
logos, etc. You can mount these at whatever location is appropriate to you
(see the direct_remote_path option in the config file) so if your users
are keeping their static assets at http://static.mgoblin.example.org/ but
their actual site is at http://mgoblin.example.org/, you need to be able
to get your static files in a where-it's-mounted agnostic way. There's a
"staticdirector" attached to the request object. It's pretty easy to use;
just look at this bit taken from the
mediagoblin/templates/mediagoblin/base.html main template:
<link rel="stylesheet" type="text/css"
href="Template:Request.staticdirect('/css/extlib/text.css')"/>
see? Not too hard. As expected, if you configured direct_remote_path to be
http://static.mgoblin.example.org/ you'll get back
http://static.mgoblin.example.org/css/extlib/text.css just as you'd
probably expect.
StorageInterface and implementations
------------------------------------
The guts of StorageInterface and friends
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So, the StorageInterface!
So, the public and queue stores both use StorageInterface implementations
... but what does that mean? It's not too hard.
Open up:
mediagoblin/storage.py
In here you'll see a couple of things. First of all, there's the
StorageInterface class. What you'll see is that this is just a very simple
python class. A few of the methods actually implement things, but for the
most part, they don't. What really matters about this class is the
docstrings. Each expected method is documented as to how it should be
constructed. Want to make a new StorageInterface? Simply subclass it. Want
to know how to use the methods of your storage system? Read these docs,
they span all implementations.
There are a couple of implementations of these classes bundled in
storage.py as well. The most simple of these is BasicFileStorage, which is
also the default storage system used. As expected, this stores files
locally on your machine.
There's also a CloudFileStorage system. This provides a mapping to
[OpenStack's swift http://swift.openstack.org/] storage system (used by
RackSpace Cloud files and etc).
Between these two examples you should be able to get a pretty good idea of
how to write your own storage systems, for storing data across your
beowulf cluster of radioactive monkey brains, whatever.
Writing code to store stuff
~~~~~~~~~~~~~~~~~~~~~~~~~~~
So what does coding for StorageInterface implementations actually look
like? It's pretty simple, really. For one thing, the design is fairly
inspired by [Django's file storage API
https://docs.djangoproject.com/en/dev/ref/files/storage/]... with some
differences.
Basically, you access files on "file paths", which aren't exactly like
unix file paths, but are close. If you wanted to store a file on a path
like dir1/dir2/filename.jpg you'd actually write that file path like:
['dir1', 'dir2', 'filename.jpg']
This way we can be *sure* that each component is actually a component of
the path that's expected... we do some filename cleaning on each component.
Your StorageInterface should pass in and out "file like objects". In other
words, they should provide .read() and .write() at minimum, and probably
also .seek() and .close().

100
docs/source/index.rst Normal file
View File

@ -0,0 +1,100 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
===========================================
Welcome to GNU MediaGoblin's documentation!
===========================================
GNU MediaGoblin is a platform for sharing photos, video and other media
in an environment that respects our freedom and independence.
This is a Free Software project. It is built by contributors for all
to use and enjoy. If you're intrested in contributing, see `the wiki
<http://wiki.mediagoblin.org/>`_ which has pages that talk about the
ways someone can contribute.
Part 1: Site Administrator's Guide
==================================
This guide covers installing, configuring, deploying and running a GNU
MediaGoblin website. It is written for site administrators.
.. toctree::
:maxdepth: 1
siteadmin/foreword
siteadmin/about
siteadmin/deploying
siteadmin/production-deployments
siteadmin/configuration
siteadmin/media-types
siteadmin/help
siteadmin/relnotes
siteadmin/theming
siteadmin/plugins
.. _core-plugin-section:
Part 2: Core plugin documentation
=================================
.. toctree::
:maxdepth: 1
plugindocs/flatpagesfile
plugindocs/sampleplugin
plugindocs/oauth
plugindocs/trim_whitespace
plugindocs/raven
Part 3: Plugin Writer's Guide
=============================
This guide covers writing new GNU MediaGoblin plugins.
.. toctree::
:maxdepth: 1
pluginwriter/foreward
pluginwriter/quickstart
pluginwriter/database
pluginwriter/api
pluginwriter/tests
Part 4: Developer's Zone
========================
This chapter contains various information for developers.
.. toctree::
:maxdepth: 1
devel/codebase
devel/storage
devel/originaldesigndecisions
Indices and tables
==================
* :ref:`search`
* :ref:`genindex`
.. * :ref:`modindex`
This guide was built on |today|.

View File

@ -0,0 +1 @@
.. include:: ../../../mediagoblin/plugins/flatpagesfile/README.rst

View File

@ -0,0 +1 @@
.. include:: ../../../mediagoblin/plugins/oauth/README.rst

View File

@ -0,0 +1,2 @@
.. _raven-setup: Set up the raven plugin
.. include:: ../../../mediagoblin/plugins/raven/README.rst

View File

@ -0,0 +1 @@
.. include:: ../../../mediagoblin/plugins/sampleplugin/README.rst

View File

@ -0,0 +1 @@
.. include:: ../../../mediagoblin/plugins/trim_whitespace/README.rst

View File

@ -0,0 +1,296 @@
.. MediaGoblin Documentation
Written in 2013 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
.. _plugin-api-chapter:
==========
Plugin API
==========
This documents the general plugin API.
Please note, at this point OUR PLUGIN HOOKS MAY AND WILL CHANGE.
Authors are encouraged to develop plugins and work with the
MediaGoblin community to keep them up to date, but this API will be a
moving target for a few releases.
Please check the :ref:`release-notes` for updates!
How are hooks added? Where do I find them?
-------------------------------------------
Much of this document talks about hooks, both as in terms of regular
hooks and template hooks. But where do they come from, and how can
you find a list of them?
For the moment, the best way to find available hooks is to check the
source code itself. (Yes, we should start a more official hook
listing with descriptions soon.) But many hooks you may need do not
exist yet: what to do then?
The plan at present is that we are adding hooks as people need them,
with community discussion. If you find that you need a hook and
MediaGoblin at present doesn't provide it at present, please
`http://mediagoblin.org/pages/join.html <talk to us>`_! We'll
evaluate what to do from there.
:mod:`pluginapi` Module
-----------------------
.. automodule:: mediagoblin.tools.pluginapi
:members: get_config, register_routes, register_template_path,
register_template_hooks, get_hook_templates,
hook_handle, hook_runall, hook_transform
Configuration
-------------
Your plugin may define its own configuration defaults.
Simply add to the directory of your plugin a config_spec.ini file. An
example might look like::
[plugin_spec]
some_string = string(default="blork")
some_int = integer(default=50)
This means that when people enable your plugin in their config you'll
be able to provide defaults as well as type validation.
Context Hooks
-------------
View specific hooks
+++++++++++++++++++
You can hook up to almost any template called by any specific view
fairly easily. As long as the view directly or indirectly uses the
method ``render_to_response`` you can access the context via a hook
that has a key in the format of the tuple::
(view_symbolic_name, view_template_path)
Where the "view symbolic name" is the same parameter used in
``request.urlgen()`` to look up the view. So say we're wanting to add
something to the context of the user's homepage. We look in
mediagoblin/user_pages/routing.py and see::
add_route('mediagoblin.user_pages.user_home',
'/u/<string:user>/',
'mediagoblin.user_pages.views:user_home')
Aha! That means that the name is ``mediagoblin.user_pages.user_home``.
Okay, so then we look at the view at the
``mediagoblin.user_pages.user_home`` method::
@uses_pagination
def user_home(request, page):
# [...] whole bunch of stuff here
return render_to_response(
request,
'mediagoblin/user_pages/user.html',
{'user': user,
'user_gallery_url': user_gallery_url,
'media_entries': media_entries,
'pagination': pagination})
Nice! So the template appears to be
``mediagoblin/user_pages/user.html``. Cool, that means that the key
is::
("mediagoblin.user_pages.user_home",
"mediagoblin/user_pages/user.html")
The context hook uses ``hook_transform()`` so that means that if we're
hooking into it, our hook will both accept one argument, ``context``,
and should return that modified object, like so::
def add_to_user_home_context(context):
context['foo'] = 'bar'
return context
hooks = {
("mediagoblin.user_pages.user_home",
"mediagoblin/user_pages/user.html"): add_to_user_home_context}
Global context hooks
++++++++++++++++++++
If you need to add something to the context of *every* view, it is not
hard; there are two hooks hook that also uses hook_transform (like the
above) but make available what you are providing to *every* view.
Note that there is a slight, but critical, difference between the two.
The most general one is the ``'template_global_context'`` hook. This
one is run only once, and is read into the global context... all views
will get access to what are in this dict.
The slightly more expensive but more powerful one is
``'template_context_prerender'``. This one is not added to the global
context... it is added to the actual context of each individual
template render right before it is run! Because of this you also can
do some powerful and crazy things, such as checking the request object
or other parts of the context before passing them on.
Adding static resources
-----------------------
It's possible to add static resources for your plugin. Say your
plugin needs some special javascript and images... how to provide
them? Then how to access them? MediaGoblin has a way!
Attaching to the hook
+++++++++++++++++++++
First, you need to register your plugin's resources with the hook.
This is pretty easy actually: you just need to provide a function that
passes back a PluginStatic object.
.. autoclass:: mediagoblin.tools.staticdirect.PluginStatic
Running plugin assetlink
++++++++++++++++++++++++
In order for your plugin assets to be properly served by MediaGoblin,
your plugin's asset directory needs to be symlinked into the directory
that plugin assets are served from. To set this up, run::
./bin/gmg assetlink
Using staticdirect
++++++++++++++++++
Once you have this, you will want to be able to of course link to your
assets! MediaGoblin has a "staticdirect" tool; you want to use this
like so in your templates::
staticdirect("css/monkeys.css", "mystaticname")
Replace "mystaticname" with the name you passed to PluginStatic. The
staticdirect method is, for convenience, attached to the request
object, so you can access this in your templates like:
.. code-block:: html
<img alt="A funny bunny"
src="{{ request.staticdirect('images/funnybunny.png', 'mystaticname') }}" />
Additional hook tips
--------------------
This section aims to explain some tips in regards to adding hooks to
the MediaGoblin repository.
WTForms hooks
+++++++++++++
We haven't totally settled on a way to tranform wtforms form objects,
but here's one way. In your view::
from mediagoblin.foo.forms import SomeForm
def some_view(request)
form_class = hook_transform('some_form_transform', SomeForm)
form = form_class(request.form)
Then to hook into this form, do something in your plugin like::
import wtforms
class SomeFormAdditions(wtforms.Form):
new_datefield = wtforms.DateField()
def transform_some_form(orig_form):
class ModifiedForm(orig_form, SomeFormAdditions)
return ModifiedForm
hooks = {
'some_form_transform': transform_some_form}
Interfaces
++++++++++
If you want to add a pseudo-interface, it's not difficult to do so.
Just write the interface like so::
class FrobInterface(object):
"""
Interface for Frobbing.
Classes implementing this interface should provide defrob and frob.
They may also implement double_frob, but it is not required; if
not provided, we will use a general technique.
"""
def defrob(self, frobbed_obj):
"""
Take a frobbed_obj and defrob it. Returns the defrobbed object.
"""
raise NotImplementedError()
def frob(self, normal_obj):
"""
Take a normal object and frob it. Returns the frobbed object.
"""
raise NotImplementedError()
def double_frob(self, normal_obj):
"""
Frob this object and return it multiplied by two.
"""
return self.frob(normal_obj) * 2
def some_frob_using_method():
# something something something
frobber = hook_handle(FrobInterface)
frobber.frob(blah)
# alternately you could have a default
frobber = hook_handle(FrobInterface) or DefaultFrobber
frobber.defrob(foo)
It's fine to use your interface as the key instead of a string if you
like. (Usually this is messy, but since interfaces are public and
since you need to import them into your plugin anyway, interfaces
might as well be keys.)
Then a plugin providing your interface can be like::
from mediagoblin.foo.frobfrogs import FrobInterface
from frogfrobber import utils
class FrogFrobber(FrobInterface):
"""
Takes a frogputer science approach to frobbing.
"""
def defrob(self, frobbed_obj):
return utils.frog_defrob(frobbed_obj)
def frob(self, normal_obj):
return utils.frog_frob(normal_obj)
hooks = {
FrobInterface: lambda: return FrogFrobber}

View File

@ -0,0 +1,114 @@
.. MediaGoblin Documentation
Written in 2013 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
.. _plugin-database-chapter:
===========================
Database models for plugins
===========================
Accessing Existing Data
=======================
If your plugin wants to access existing data, this is quite
straight forward. Just import the appropiate models and use
the full power of SQLAlchemy. Take a look at the (upcoming)
database section in the Developer's Chapter.
Creating new Tables
===================
If your plugin needs some new space to store data, you
should create a new table. Please do not modify core
tables. Not doing so might seem inefficient and possibly
is. It will help keep things sane and easier to upgrade
versions later.
So if you create a new plugin and need new tables, create a
file named ``models.py`` in your plugin directory. You
might take a look at the core's db.models for some ideas.
Here's a simple one:
.. code-block:: python
from mediagoblin.db.base import Base
from sqlalchemy import Column, Integer, Unicode, ForeignKey
class MediaSecurity(Base):
__tablename__ = "yourplugin__media_security"
# The primary key *and* reference to the main media_entry
media_entry = Column(Integer, ForeignKey('core__media_entries.id'),
primary_key=True)
get_media_entry = relationship("MediaEntry",
backref=backref("security_rating", cascade="all, delete-orphan"))
rating = Column(Unicode)
MODELS = [MediaSecurity]
That's it.
Some notes:
* Make sure all your ``__tablename__`` start with your
plugin's name so the tables of various plugins can't
conflict in the database. (Conflicts in python naming are
much easier to fix later).
* Try to get your database design as good as possible in
the first attempt. Changing the database design later,
when people already have data using the old design, is
possible (see next chapter), but it's not easy.
Changing the Database Schema Later
==================================
If your plugin is in use and instances use it to store some
data, changing the database design is a tricky thing.
1. Make up your mind how the new schema should look like.
2. Change ``models.py`` to contain the new schema. Keep a
copy of the old version around for your personal
reference later.
3. Now make up your mind (possibly using your old and new
``models.py``) what steps in SQL are needed to convert
the old schema to the new one.
This is called a "migration".
4. Create a file ``migrations.py`` that will contain all
your migrations and add your new migration.
Take a look at the core's ``db/migrations.py`` for some
good examples on what you might be able to do. Here's a
simple one to add one column:
.. code-block:: python
from mediagoblin.db.migration_tools import RegisterMigration, inspect_table
from sqlalchemy import MetaData, Column, Integer
MIGRATIONS = {}
@RegisterMigration(1, MIGRATIONS)
def add_license_preference(db):
metadata = MetaData(bind=db.bind)
security_table = inspect_table(metadata, 'yourplugin__media_security')
col = Column('security_level', Integer)
col.create(security_table)
db.commit()

View File

@ -0,0 +1,43 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
========
Foreword
========
About the Plugin Writer's Guide
===============================
This guide covers writing plugins for GNU MediaGoblin. It's very much
a work in progress partially because we just started writing it and
partially because the plugin API is currently in flux.
Improving the Plugin Writer's Guide
===================================
There are a few ways---please pick whichever method is convenient for
you!
1. Write up a bug report in the bug tracker
2. Tell someone on IRC ``#mediagoblin`` on Freenode.
3. Write an email to the devel mailing list.
Information about the bugtracker, IRC and the mailing list is all on
the `join page`_.
.. _join page: http://mediagoblin.org/join/
Patches are the most helpful, but even feedback on what you think
could be improved and how to improve it is also helpful.

View File

@ -0,0 +1,188 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
===========
Quick Start
===========
This is a quick start. It's not comprehensive, but it walks through
writing a basic plugin called "sampleplugin" which logs "I've been
started!" when ``setup_plugin()`` has been called.
.. todo: Rewrite this to be a useful plugin
Step 1: Files and directories
=============================
GNU MediaGoblin plugins are Python projects at heart. As such, you should
use a standard Python project directory tree::
sampleplugin/
|- README
|- LICENSE
|- setup.py
|- sampleplugin/
|- __init__.py
The outer ``sampleplugin`` directory holds all the project files.
The ``README`` should cover what your plugin does, how to install it,
how to configure it, and all the sorts of things a README should
cover.
The ``LICENSE`` should have the license under which you're
distributing your plugin.
The inner ``sampleplugin`` directory is the Python package that holds
your plugin's code.
The ``__init__.py`` denotes that this is a Python package. It also
holds the plugin code and the ``hooks`` dict that specifies which
hooks the sampleplugin uses.
Step 2: README
==============
Here's a rough ``README``. Generally, you want more information
because this is the file that most people open when they want to learn
more about your project.
::
README
======
This is a sample plugin. It logs a line when ``setup__plugin()`` is
run.
Step 3: LICENSE
===============
GNU MediaGoblin plugins must be licensed under the AGPLv3 or later. So
the LICENSE file should be the AGPLv3 text which you can find at
`<http://www.gnu.org/licenses/agpl-3.0.html>`_
Step 4: setup.py
================
This file is used for packaging and distributing your plugin.
We'll use a basic one::
from setuptools import setup, find_packages
setup(
name='sampleplugin',
version='1.0',
packages=find_packages(),
include_package_data=True,
install_requires=[],
license='AGPLv3',
)
See `<http://docs.python.org/distutils/index.html#distutils-index>`_
for more details.
Step 5: the code
================
The code for ``__init__.py`` looks like this:
.. code-block:: python
:linenos:
:emphasize-lines: 12,23
import logging
from mediagoblin.tools.pluginapi import Plugin, get_config
# This creates a logger that you can use to log information to
# the console or a log file.
_log = logging.getLogger(__name__)
# This is the function that gets called when the setup
# hook fires.
def setup_plugin():
_log.info("I've been started!")
config = get_config('sampleplugin')
if config:
_log.info('%r' % config)
else:
_log.info('There is no configuration set.')
# This is a dict that specifies which hooks this plugin uses.
# This one only uses one hook: setup.
hooks = {
'setup': setup_plugin
}
Line 12 defines the ``setup_plugin`` function.
Line 23 defines ``hooks``. When MediaGoblin loads this file, it sees
``hooks`` and registers all the callables with their respective hooks.
Step 6: Installation and configuration
======================================
To install the plugin for development, you need to make sure it's
available to the Python interpreter that's running MediaGoblin.
There are a couple of ways to do this, but we're going to pick the
easy one.
Use ``python`` from your MediaGoblin virtual environment and do::
python setup.py develop
Any changes you make to your plugin will be available in your
MediaGoblin virtual environment.
Then adjust your ``mediagoblin.ini`` file to load the plugin::
[plugins]
[[sampleplugin]]
Step 7: That's it!
==================
When you launch MediaGoblin, it'll load the plugin and you'll see
evidence of that in the log file.
That's it for the quick start!
Where to go from here
=====================
See the documentation on the :ref:`plugin-api-chapter` for code
samples and other things you can use when building your plugin. If
your plugin needs its own database models, see
:ref:`plugin-database-chapter`.
See `Hitchhiker's Guide to Packaging
<http://guide.python-distribute.org/>`_ for more information on
packaging your plugin.

View File

@ -0,0 +1,64 @@
.. MediaGoblin Documentation
Written in 2013 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
==============================
Writing unit tests for plugins
==============================
Here's a brief guide to writing unit tests for plugins. However, it
isn't really ideal. It also hasn't been well tested... yes, there's
some irony there :)
Some notes: we're using py.test and webtest for unit testing stuff.
Keep that in mind.
My suggestion is to mime the behavior of `mediagoblin/tests/` and put
that in your own plugin, like `myplugin/tests/`. Copy over
`conftest.py` and `pytest.ini` to your tests directory, but possibly
change the `test_app` fixture to match your own tests' config needs.
For example::
import pkg_resources
# [...]
@pytest.fixture()
def test_app(request):
return get_app(
request,
mgoblin_config=pkg_resources.resource_filename(
'myplugin.tests', 'myplugin_mediagoblin.ini'))
In any test module in your tests directory you can then do::
def test_somethingorother(test_app):
# real code goes here
pass
And you'll get a mediagoblin application wrapped in webtest passed in
to your environment.
If your plugin needs to define multiple configuration setups, you can
actually set up multiple fixtures very easily for this. You can just
set up multiple fixtures with different names that point to different
configs and pass them in as that named argument.
To run the tests, from mediagoblin's directory (make sure that your
plugin has been added to your mediagoblin checkout's virtualenv!) do::
./runtests.sh /path/to/myplugin/tests/
replacing `/path/to/myplugin/` with the actual path to your plugin.
NOTE: again, the above is untested, but it should probably work. If
you run into trouble, `contact us
<http://mediagoblin.org/pages/join.html>`_, preferably on IRC!

View File

@ -0,0 +1,102 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
=======================
About GNU MediaGoblin
=======================
.. contents:: Sections
:local:
What is GNU MediaGoblin?
========================
In 2008, a number of free software developers and activists gathered
at the FSF to attempt to answer the question "What should software
freedom look like on the participatory web?" Their answer, the
`Franklin Street Statement`_ has lead to the development of
`autonomo.us`_ community, and free software projects including
`Identi.ca`_ and `Libre.fm`_.
.. _Franklin Street Statement: http://autonomo.us/2008/07/franklin-street-statement/
.. _autonomo.us: http://autonomo.us/
.. _identi.ca: http://identi.ca/
.. _Libre.fm: http://libre.fm/
Identi.ca and Libre.fm address the need for micro-blogging and music
sharing services and software that respect users' freedom and
autonomy.
GNU MediaGoblin emerges from this milieu to create a platform for us to share
photos, video and other media in an environment that respects our freedom and
independence. In the future MediaGoblin will provide tools to facilitate
collaboration on media projects.
Why Build GNU MediaGoblin?
==========================
The Internet is designed---and works best---as a complex and endlessly
resilient network. When key services and media outlets are
concentrated in centralized platforms, the network becomes less useful
and increasingly fragile. As always, the proprietary nature of these
systems, hinders users ability to develop, extend, and understand
their software; however, in the case of network services it also means
that users must forfeit control of their data to the service
providers.
Therefore, we believe that network services must be federated to avoid
centralization and that everyone ought to have control over their
data. In support of this, we've decided to help build the tools to
make these kinds of services possible. We hope you'll join us, both
as users and as contributors.
Who Contributes to the Project?
===============================
You do!
We are free software activists and folks who have worked on a variety
of other projects including: Libre.fm, GNU Social, Status.net, Miro,
Miro Community, and OpenHatch among others. We're programmers,
musicians, writers, and painters. We're friendly and dedicated to
software and network freedom.
How Can I Participate?
======================
See `Get Involved <http://mediagoblin.org/join/>`_ on the website. We
eagerly look forward to seeing you!
How is GNU MediaGoblin licensed?
================================
GNU MediaGoblin software is released under an AGPLv3 license.
See the ``COPYING`` file in the root of the source for details.
Is MediaGoblin an official GNU project? What does that mean?
=============================================================
MediaGoblin is an official GNU project! This status means that we the
meet the GNU Project's rigorous standards for free software. To find
out more about what that means, check out the `GNU website`_.
Please feel free to contact us with further questions!
.. _GNU website: http://gnu.org/

View File

@ -0,0 +1,131 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
.. _configuration-chapter:
========================
Configuring MediaGoblin
========================
So! You've got MediaGoblin up and running, but you need to adjust
some configuration parameters. Well you've come to the right place!
MediaGoblin's config files
==========================
When configuring MediaGoblin, there are two files you might want to
make local modified versions of, and one extra file that might be
helpful to look at. Let's examine these.
mediagoblin.ini
This is the config file for MediaGoblin, the application. If you want to
tweak settings for MediaGoblin, you'll usually tweak them here.
paste.ini
This is primarily a server configuration file, on the Python side
(specifically, on the WSGI side, via `paste deploy
<http://pythonpaste.org/deploy/>`_ / `paste script
<http://pythonpaste.org/script/>`_). It also sets up some
middleware that you can mostly ignore, except to configure
sessions... more on that later. If you are adding a different
Python server other than fastcgi / plain HTTP, you might configure
it here. You probably won't need to change this file very much.
There's one more file that you certainly won't change unless you're
making coding contributions to mediagoblin, but which can be useful to
read and reference:
mediagoblin/config_spec.ini
This file is actually a specification for mediagoblin.ini itself, as
a config file! It defines types and defaults. Sometimes it's a
good place to look for documentation... or to find that hidden
option that we didn't tell you about. :)
Making local copies
===================
Let's assume you're doing the virtualenv setup described elsewhere in this
manual, and you need to make local tweaks to the config files. How do you do
that? Let's see.
To make changes to mediagoblin.ini ::
cp mediagoblin.ini mediagoblin_local.ini
To make changes to paste.ini ::
cp paste.ini paste_local.ini
From here you should be able to make direct adjustments to the files,
and most of the commands described elsewhere in this manual will "notice"
your local config files and use those instead of the non-local version.
.. note::
Note that all commands provide a way to pass in a specific config
file also, usually by a ``-cf`` flag.
Common changes
==============
Enabling email notifications
----------------------------
You'll almost certainly want to enable sending email. By default,
MediaGoblin doesn't really do this... for the sake of developer
convenience, it runs in "email debug mode".
To make MediaGoblin send email, you need a mailer daemon.
Change this in your ``mediagoblin.ini`` file::
email_debug_mode = false
You should also change the "from" email address by setting
``email_sender_address``. For example::
email_sender_address = "foo@example.com"
If you have more custom SMTP settings, you also have the following
options at your disposal, which are all optional, and do exactly what
they sound like.
- email_smtp_host
- email_smtp_port
- email_smtp_user
- email_smtp_pass
All other configuration changes
-------------------------------
To be perfectly honest, there are quite a few options and we haven't had
time to document them all.
So here's a cop-out section saying that if you get into trouble, hop
onto IRC and we'll help you out. Details for the IRC channel is on the
`join page`_ of the website.
.. _join page: http://mediagoblin.org/join/
Celery
======
FIXME: List Celery configuration here.

View File

@ -0,0 +1,390 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
.. _deploying-chapter:
=====================
Deploying MediaGoblin
=====================
GNU MediaGoblin is fairly new and so at the time of writing, there
aren't easy package-manager-friendly methods to install MediaGoblin.
However, doing a basic install isn't too complex in and of itself.
There's an almost infinite way to deploy things... for now, we'll keep
it simple with some assumptions and use a setup that combines
mediagoblin + virtualenv + fastcgi + nginx on a .deb or .rpm based
GNU/Linux distro.
.. note::
These tools are for site administrators wanting to deploy a fresh
install. If instead you want to join in as a contributor, see our
`Hacking HOWTO <http://wiki.mediagoblin.org/HackingHowto>`_ instead.
There are also many ways to install servers... for the sake of
simplicity, our instructions below describe installing with nginx.
For more recipes, including Apache, see
`our wiki <http://wiki.mediagoblin.org/Deployment>`_.
Prepare System
--------------
Dependencies
~~~~~~~~~~~~
MediaGoblin has the following core dependencies:
- Python 2.6 or 2.7
- `python-lxml <http://lxml.de/>`_
- `git <http://git-scm.com/>`_
- `SQLite <http://www.sqlite.org/>`_/`PostgreSQL <http://www.postgresql.org/>`_
- `Python Imaging Library <http://www.pythonware.com/products/pil/>`_ (PIL)
- `virtualenv <http://www.virtualenv.org/>`_
On a DEB-based system (e.g Debian, gNewSense, Trisquel, Ubuntu, and
derivatives) issue the following command::
sudo apt-get install git-core python python-dev python-lxml \
python-imaging python-virtualenv
On a RPM-based system (e.g. Fedora, RedHat, and derivatives) issue the
following command::
yum install python-paste-deploy python-paste-script \
git-core python python-devel python-lxml python-imaging \
python-virtualenv
Configure PostgreSQL
~~~~~~~~~~~~~~~~~~~~
.. note::
MediaGoblin currently supports PostgreSQL and SQLite. The default is a
local SQLite database. This will "just work" for small deployments.
For medium to large deployments we recommend PostgreSQL.
If you don't want/need postgres, skip this section.
These are the packages needed for Debian Wheezy (testing)::
sudo apt-get install postgresql postgresql-client python-psycopg2
The installation process will create a new *system* user named ``postgres``,
it will have privilegies sufficient to manage the database. We will create a
new database user with restricted privilegies and a new database owned by our
restricted database user for our MediaGoblin instance.
In this example, the database user will be ``mediagoblin`` and the database
name will be ``mediagoblin`` too.
To create our new user, run::
sudo -u postgres createuser mediagoblin
then answer NO to *all* the questions::
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
then create the database all our MediaGoblin data should be stored in::
sudo -u postgres createdb -E UNICODE -O mediagoblin mediagoblin
where the first ``mediagoblin`` is the database owner and the second
``mediagoblin`` is the database name.
.. caution:: Where is the password?
These steps enable you to authenticate to the database in a password-less
manner via local UNIX authentication provided you run the MediaGoblin
application as a user with the same name as the user you created in
PostgreSQL.
More on this in :ref:`Drop Privileges for MediaGoblin <drop-privileges-for-mediagoblin>`.
.. _drop-privileges-for-mediagoblin:
Drop Privileges for MediaGoblin
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As MediaGoblin does not require special permissions or elevated
access, you should run MediaGoblin under an existing non-root user or
preferably create a dedicated user for the purpose of running
MediaGoblin. Consult your distribution's documentation on how to
create "system account" or dedicated service user. Ensure that it is
not possible to log in to your system with as this user.
You should create a working directory for MediaGoblin. This document
assumes your local git repository will be located at
``/srv/mediagoblin.example.org/mediagoblin/`` for this documentation.
Substitute your prefer ed local deployment path as needed.
This document assumes that all operations are performed as this
user. To drop privileges to this user, run the following command::
su - [mediagoblin]
Where, "``[mediagoblin]``" is the username of the system user that will
run MediaGoblin.
Install MediaGoblin and Virtualenv
----------------------------------
.. note::
MediaGoblin is still developing rapidly. As a result
the following instructions recommend installing from the ``master``
branch of the git repository. Eventually production deployments will
want to transition to running from more consistent releases.
Issue the following commands, to create and change the working
directory. Modify these commands to reflect your own environment::
mkdir -p /srv/mediagoblin.example.org/
cd /srv/mediagoblin.example.org/
Clone the MediaGoblin repository::
git clone git://gitorious.org/mediagoblin/mediagoblin.git
And set up the in-package virtualenv::
cd mediagoblin
(virtualenv --system-site-packages . || virtualenv .) && ./bin/python setup.py develop
.. note::
If you have problems here, consider trying to install virtualenv
with the ``--distribute`` or ``--no-site-packages`` options. If
your system's default Python is in the 3.x series you may need to
run ``virtualenv`` with the ``--python=python2.7`` or
``--python=python2.6`` options.
The above provides an in-package install of ``virtualenv``. While this
is counter to the conventional ``virtualenv`` configuration, it is
more reliable and considerably easier to configure and illustrate. If
you're familiar with Python packaging you may consider deploying with
your preferred method.
Assuming you are going to deploy with FastCGI, you should also install
flup::
./bin/easy_install flup
(Sometimes this breaks because flup's site is flakey. If it does for
you, try)::
./bin/easy_install https://pypi.python.org/pypi/flup/1.0.3.dev-20110405
This concludes the initial configuration of the development
environment. In the future, when you update your
codebase, you should also run::
./bin/python setup.py develop --upgrade && ./bin/gmg dbupdate
Note: If you are running an active site, depending on your server
configuration, you may need to stop it first or the dbupdate command
may hang (and it's certainly a good idea to restart it after the
update)
Deploy MediaGoblin Services
---------------------------
Edit site configuration
~~~~~~~~~~~~~~~~~~~~~~~
A few basic properties must be set before MediaGoblin will work. First
make a copy of ``mediagoblin.ini`` for editing so the original config
file isn't lost::
cp mediagoblin.ini mediagoblin_local.ini
Then:
- Set ``email_sender_address`` to the address you wish to be used as
the sender for system-generated emails
- Edit ``direct_remote_path``, ``base_dir``, and ``base_url`` if
your mediagoblin directory is not the root directory of your
vhost.
Configure MediaGoblin to use the PostgreSQL database
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you are using postgres, edit the ``[mediagoblin]`` section in your
``mediagoblin_local.ini`` and put in::
sql_engine = postgresql:///mediagoblin
if you are running the MediaGoblin application as the same 'user' as the
database owner.
Update database data structures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Before you start using the database, you need to run::
./bin/gmg dbupdate
to populate the database with the MediaGoblin data structures.
Test the Server
~~~~~~~~~~~~~~~
At this point MediaGoblin should be properly installed. You can
test the deployment with the following command::
./lazyserver.sh --server-name=broadcast
You should be able to connect to the machine on port 6543 in your
browser to confirm that the service is operable.
.. _webserver-config:
FastCGI and nginx
~~~~~~~~~~~~~~~~~
This configuration example will use nginx, however, you may
use any webserver of your choice as long as it supports the FastCGI
protocol. If you do not already have a web server, consider nginx, as
the configuration files may be more clear than the
alternatives.
Create a configuration file at
``/srv/mediagoblin.example.org/nginx.conf`` and create a symbolic link
into a directory that will be included in your ``nginx`` configuration
(e.g. "``/etc/nginx/sites-enabled`` or ``/etc/nginx/conf.d``) with
one of the following commands (as the root user)::
ln -s /srv/mediagoblin.example.org/nginx.conf /etc/nginx/conf.d/
ln -s /srv/mediagoblin.example.org/nginx.conf /etc/nginx/sites-enabled/
Modify these commands and locations depending on your preferences and
the existing configuration of your nginx instance. The contents of
this ``nginx.conf`` file should be modeled on the following::
server {
#################################################
# Stock useful config options, but ignore them :)
#################################################
include /etc/nginx/mime.types;
autoindex off;
default_type application/octet-stream;
sendfile on;
# Gzip
gzip on;
gzip_min_length 1024;
gzip_buffers 4 32k;
gzip_types text/plain text/html application/x-javascript text/javascript text/xml text/css;
#####################################
# Mounting MediaGoblin stuff
# This is the section you should read
#####################################
# Change this to update the upload size limit for your users
client_max_body_size 8m;
# prevent attacks (someone uploading a .txt file that the browser
# interprets as an HTML file, etc.)
add_header X-Content-Type-Options nosniff;
server_name mediagoblin.example.org www.mediagoblin.example.org;
access_log /var/log/nginx/mediagoblin.example.access.log;
error_log /var/log/nginx/mediagoblin.example.error.log;
# MediaGoblin's stock static files: CSS, JS, etc.
location /mgoblin_static/ {
alias /srv/mediagoblin.example.org/mediagoblin/mediagoblin/static/;
}
# Instance specific media:
location /mgoblin_media/ {
alias /srv/mediagoblin.example.org/mediagoblin/user_dev/media/public/;
}
# Theme static files (usually symlinked in)
location /theme_static/ {
alias /srv/mediagoblin.example.org/mediagoblin/user_dev/theme_static/;
}
# Plugin static files (usually symlinked in)
location /plugin_static/ {
alias /srv/mediagoblin.example.org/mediagoblin/user_dev/plugin_static/;
}
# Mounting MediaGoblin itself via FastCGI.
location / {
fastcgi_pass 127.0.0.1:26543;
include /etc/nginx/fastcgi_params;
# our understanding vs nginx's handling of script_name vs
# path_info don't match :)
fastcgi_param PATH_INFO $fastcgi_script_name;
fastcgi_param SCRIPT_NAME "";
}
}
Now, nginx instance is configured to serve the MediaGoblin
application. Perform a quick test to ensure that this configuration
works. Restart nginx so it picks up your changes, with a command that
resembles one of the following (as the root user)::
sudo /etc/init.d/nginx restart
sudo /etc/rc.d/nginx restart
Now start MediaGoblin. Use the following command sequence as an
example::
cd /srv/mediagoblin.example.org/mediagoblin/
./lazyserver.sh --server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543
Visit the site you've set up in your browser by visiting
<http://mediagoblin.example.org>. You should see MediaGoblin!
.. note::
The configuration described above is sufficient for development and
smaller deployments. However, for larger production deployments
with larger processing requirements, see the
":doc:`production-deployments`" documentation.
Apache
~~~~~~
Instructions and scripts for running MediaGoblin on an Apache server
can be found on the `MediaGoblin wiki <http://wiki.mediagoblin.org/Deployment>`_.
Security Considerations
~~~~~~~~~~~~~~~~~~~~~~~
.. warning::
The directory ``user_dev/crypto/`` contains some very
sensitive files.
Especially the ``itsdangeroussecret.bin`` is very important
for session security. Make sure not to leak its contents anywhere.
If the contents gets leaked nevertheless, delete your file
and restart the server, so that it creates a new secret key.
All previous sessions will be invalifated then.

View File

@ -0,0 +1,48 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
========
Foreword
========
About the Site Administrator's Guide
====================================
This is the site administrator manual for GNU MediaGoblin. It covers
how to set up and configure MediaGoblin and the kind of information
that someone running MediaGoblin would need to know.
We have other documentation at:
* http://mediagoblin.org/join/ for general "join us" information
* http://wiki.mediagoblin.org/ for our contributor/developer-focused wiki
Improving the Site Administrator's Guide
========================================
There are a few ways---please pick whichever method is convenient for
you!
1. Write up a bug report in the bug tracker
2. Tell someone on IRC ``#mediagoblin`` on Freenode.
3. Write an email to the devel mailing list.
Information about the bugtracker, IRC and the mailing list is all on
the `join page`_.
.. _join page: http://mediagoblin.org/join/
Patches are the most helpful, but even feedback on what you think
could be improved and how to improve it is also helpful.

View File

@ -0,0 +1,29 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
==================================
How to Get Help with MediaGoblin
==================================
There are a couple of ways to get help with problems with MediaGoblin:
1. ask for help on IRC
2. ask for help on the devel mailing list
Details for both IRC and the mailing list are on the `join page`_ of the
website.
.. _join page: http://mediagoblin.org/join/

View File

@ -0,0 +1,245 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
.. _media-types-chapter:
====================
Media Types
====================
In the future, there will be all sorts of media types you can enable,
but in the meanwhile there are three additional media types: video, audio
and ascii art.
First, you should probably read ":doc:`configuration`" to make sure
you know how to modify the mediagoblin config file.
Enabling Media Types
====================
Media types are enabled in your mediagoblin configuration file, typically it is
created by copying ``mediagoblin.ini`` to ``mediagoblin_local.ini`` and then
applying your changes to ``mediagoblin_local.ini``. If you don't already have a
``mediagoblin_local.ini``, create one in the way described.
Most media types have additional dependencies that you will have to install.
You will find descriptions on how to satisfy the requirements of each media type
on this page.
To enable a media type, edit the ``media_types`` list in your
``mediagoblin_local.ini``. For example, if your system supported image and
video media types, then the list would look like this::
media_types = mediagoblin.media_types.image, mediagoblin.media_types.video
Note that after enabling new media types, you must run dbupdate like so::
./bin/gmg dbupdate
If you are running an active site, depending on your server
configuration, you may need to stop it first (and it's certainly a
good idea to restart it after the update).
How does MediaGoblin decide which media type to use for a file?
===============================================================
MediaGoblin has two methods for finding the right media type for an uploaded
file. One is based on the file extension of the uploaded file; every media type
maintains a list of supported file extensions. The second is based on a sniffing
handler, where every media type may inspect the uploaded file and tell if it
will accept it.
The file-extension-based approach is used before the sniffing-based approach,
if the file-extension-based approach finds a match, the sniffing-based approach
will be skipped as it uses far more processing power.
Video
=====
To enable video, first install gstreamer and the python-gstreamer
bindings (as well as whatever gstremaer extensions you want,
good/bad/ugly). On Debianoid systems
.. code-block:: bash
sudo apt-get install python-gst0.10 \
gstreamer0.10-plugins-base \
gstreamer0.10-plugins-bad \
gstreamer0.10-plugins-good \
gstreamer0.10-plugins-ugly \
gstreamer0.10-ffmpeg
Add ``mediagoblin.media_types.video`` to the ``media_types`` list in your
``mediagoblin_local.ini`` and restart MediaGoblin.
Run
.. code-block:: bash
./bin/gmg dbupdate
Now you should be able to submit videos, and mediagoblin should
transcode them.
.. note::
You almost certainly want to separate Celery from the normal
paste process or your users will probably find that their connections
time out as the video transcodes. To set that up, check out the
":doc:`production-deployments`" section of this manual.
Audio
=====
To enable audio, install the gstreamer and python-gstreamer bindings (as well
as whatever gstreamer plugins you want, good/bad/ugly), scipy and numpy are
also needed for the audio spectrograms.
To install these on Debianoid systems, run::
sudo apt-get install python-gst0.10 gstreamer0.10-plugins-{base,bad,good,ugly} \
gstreamer0.10-ffmpeg python-numpy python-scipy
The ``scikits.audiolab`` package you will install in the next step depends on the
``libsndfile1-dev`` package, so we should install it.
On Debianoid systems, run
.. code-block:: bash
sudo apt-get install libsndfile1-dev
.. note::
scikits.audiolab will display a warning every time it's imported if you do
not compile it with alsa support. Alsa support is not necessary for the GNU
MediaGoblin application but if you do not wish the alsa warnings from
audiolab you should also install ``libasound2-dev`` before installing
scikits.audiolab.
Then install ``scikits.audiolab`` for the spectrograms::
./bin/pip install scikits.audiolab
Add ``mediagoblin.media_types.audio`` to the ``media_types`` list in your
``mediagoblin_local.ini`` and restart MediaGoblin.
Run
.. code-block:: bash
./bin/gmg dbupdate
You should now be able to upload and listen to audio files!
Ascii art
=========
To enable ascii art support, first install the
`chardet <http://pypi.python.org/pypi/chardet>`_
library, which is necessary for creating thumbnails of ascii art
.. code-block:: bash
./bin/easy_install chardet
Next, modify (and possibly copy over from ``mediagoblin.ini``) your
``mediagoblin_local.ini``. In the ``[mediagoblin]`` section, add
``mediagoblin.media_types.ascii`` to the ``media_types`` list.
For example, if your system supported image and ascii art media types, then
the list would look like this::
media_types = mediagoblin.media_types.image, mediagoblin.media_types.ascii
Run
.. code-block:: bash
./bin/gmg dbupdate
Now any .txt file you uploaded will be processed as ascii art!
STL / 3d model support
======================
To enable the "STL" 3d model support plugin, first make sure you have
a recentish `Blender <http://blender.org>`_ installed and available on
your execution path. This feature has been tested with Blender 2.63.
It may work on some earlier versions, but that is not guaranteed (and
is surely not to work prior to Blender 2.5X).
Add ``mediagoblin.media_types.stl`` to the ``media_types`` list in your
``mediagoblin_local.ini`` and restart MediaGoblin.
Run
.. code-block:: bash
./bin/gmg dbupdate
You should now be able to upload .obj and .stl files and MediaGoblin
will be able to present them to your wide audience of admirers!
PDF and Document
================
To enable the "PDF and Document" support plugin, you need:
1. pdftocairo and pdfinfo for pdf only support.
2. unoconv with headless support to support converting libreoffice supported
documents as well, such as doc/ppt/xls/odf/odg/odp and more.
For the full list see mediagoblin/media_types/pdf/processing.py,
unoconv_supported.
All executables must be on your execution path.
To install this on Fedora:
.. code-block:: bash
sudo yum install -y poppler-utils unoconv libreoffice-headless
Note: You can leave out unoconv and libreoffice-headless if you want only pdf
support. This will result in a much smaller list of dependencies.
pdf.js relies on git submodules, so be sure you have fetched them:
.. code-block:: bash
git submodule init
git submodule update
This feature has been tested on Fedora with:
poppler-utils-0.20.2-9.fc18.x86_64
unoconv-0.5-2.fc18.noarch
libreoffice-headless-3.6.5.2-8.fc18.x86_64
It may work on some earlier versions, but that is not guaranteed.
Add ``mediagoblin.media_types.pdf`` to the ``media_types`` list in your
``mediagoblin_local.ini`` and restart MediaGoblin.
Run
.. code-block:: bash
./bin/gmg dbupdate

View File

@ -0,0 +1,177 @@
=========
Plugins
=========
GNU MediaGoblin supports plugins that allow you to augment MediaGoblin's
behavior.
This chapter covers discovering, installing, configuring and removing
plugins.
Discovering plugins
===================
MediaGoblin comes with core plugins. Core plugins are located in the
``mediagoblin.plugins`` module of the MediaGoblin code. Because they
come with MediaGoblin, you don't have to install them, but you do have
to add them to your config file if you're interested in using them.
You can also write your own plugins and additionally find plugins
elsewhere on the Internet. Once you find a plugin you like, you need
to first install it, then add it to your configuration.
.. todo: how do you find plugins on the internet?
Installing plugins
==================
Core plugins
------------
MediaGoblin core plugins don't need to be installed because they come
with MediaGoblin. Further, when you upgrade MediaGoblin, you will also
get updates to the core plugins.
Other plugins
-------------
If the plugin is available on the `Python Package Index
<http://pypi.python.org/pypi>`_, then you can install the plugin with pip::
pip install <plugin-name>
For example, if we wanted to install the plugin named
"mediagoblin-licenses" (which allows you to customize the licenses you
offer for your media), we would do::
pip install mediagoblin-licenses
.. Note::
If you're using a virtual environment, make sure to activate the
virtual environment before installing with pip. Otherwise the plugin
may get installed in a different environment than the one MediaGoblin
is installed in. Also make sure, you use e.g. pip-2.7 if your default
python (and thus pip) is python 3 (e.g. in Ubuntu).
Once you've installed the plugin software, you need to tell
MediaGoblin that this is a plugin you want MediaGoblin to use. To do
that, you edit the ``mediagoblin.ini`` file and add the plugin as a
subsection of the plugin section.
For example, say the "mediagoblin-licenses" plugin has the Python
package path ``mediagoblin_licenses``, then you would add ``mediagoblin_licenses`` to
the ``plugins`` section as a subsection::
[plugins]
[[mediagoblin_licenses]]
license_01=abbrev1, name1, http://url1
license_02=abbrev2, name1, http://url2
Configuring plugins
===================
Configuration for a plugin goes in the subsection for that plugin. Core
plugins are documented in the administration guide. Other plugins
should come with documentation that tells you how to configure them.
Example 1: Core MediaGoblin plugin
If you wanted to use the core MediaGoblin flatpages plugin, the module
for that is ``mediagoblin.plugins.flatpagesfile`` and you would add
that to your ``.ini`` file like this::
[plugins]
[[mediagoblin.plugins.flatpagesfile]]
# configuration for flatpagesfile plugin here!
about-view = '/about', about.html
terms-view = '/terms', terms.html
(Want to know more about the flatpagesfile plugin? See
:ref:`flatpagesfile-chapter`)
Example 2: Plugin that is not a core MediaGoblin plugin
If you installed a hypothetical restrictfive plugin which is in the
module ``restrictfive``, your ``.ini`` file might look like this (with
comments making the bits clearer)::
[plugins]
[[restrictfive]]
# configuration for restrictfive here!
Check the plugin's documentation for what configuration options are
available.
Removing plugins
================
To remove a plugin, use ``pip uninstall``. For example::
pip uninstall mediagoblin-licenses
.. Note::
If you're using a virtual environment, make sure to activate the
virtual environment before uninstalling with pip. Otherwise the
plugin may get installed in a different environment.
Upgrading plugins
=================
Core plugins
------------
Core plugins get upgraded automatically when you upgrade MediaGoblin
because they come with MediaGoblin.
Other plugins
-------------
For plugins that you install with pip, you can upgrade them with pip::
pip install -U <plugin-name>
The ``-U`` tells pip to upgrade the package.
Troubleshooting plugins
=======================
Sometimes plugins just don't work right. When you're having problems
with plugins, think about the following:
1. Check the log files.
Some plugins will log errors to the log files and you can use that
to diagnose the problem.
2. Try running MediaGoblin without that plugin.
It's easy to disable a plugin from MediaGoblin. Add a ``-`` to the
name in your config file.
For example, change::
[[mediagoblin.plugins.flatpagesfile]]
to::
[[-mediagoblin.plugins.flatpagesfile]]
That'll prevent the ``mediagoblin.plugins.flatpagesfile`` plugin from
loading.
3. If it's a core plugin that comes with MediaGoblin, ask us for help!
If it's a plugin you got from somewhere else, ask them for help!

View File

@ -0,0 +1,133 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
=========================================
Considerations for Production Deployments
=========================================
This document contains a number of suggestions for deploying
MediaGoblin in actual production environments. Consider
":doc:`deploying`" for a basic overview of how to deploy MediaGoblin.
Deploy with Paste
-----------------
The MediaGoblin WSGI application instance you get with ``./lazyserver.sh`` is
not ideal for a production MediaGoblin deployment. Ideally, you should be able
to use an "init" or "control" script to launch and restart the MediaGoblin
process.
Use the following command as the basis for such a script:
.. code-block:: bash
CELERY_ALWAYS_EAGER=true \
/srv/mediagoblin.example.org/mediagoblin/bin/paster serve \
/srv/mediagoblin.example.org/mediagoblin/paste.ini \
--pid-file=/var/run/mediagoblin.pid \
--server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543
The above configuration places MediaGoblin in "always eager" mode
with Celery, this means that submissions of content will be processed
synchronously, and the user will advance to the next page only after
processing is complete. If we take Celery out of "always eager mode,"
the user will be able to immediately return to the MediaGoblin site
while processing is ongoing. In these cases, use the following command
as the basis for your script:
.. code-block:: bash
CELERY_ALWAYS_EAGER=false \
/srv/mediagoblin.example.org/mediagoblin/bin/paster serve \
/srv/mediagoblin.example.org/mediagoblin/paste.ini \
--pid-file=/var/run/mediagoblin.pid \
--server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543
Separate Celery
---------------
MediaGoblin uses `Celery`_ to handle heavy and long-running tasks. Celery can
be launched in two ways:
1. Embedded in the MediaGoblin WSGI application [#f-mediagoblin-wsgi-app]_.
This is the way ``./lazyserver.sh`` does it for you. It's simple as you
only have to run one process. The only bad thing with this is that the
heavy and long-running tasks will run *in* the webserver, keeping the user
waiting each time some heavy lifting is needed as in for example processing
a video. This could lead to problems as an aborted connection will halt any
processing and since most front-end web servers *will* terminate your
connection if it doesn't get any response from the MediaGoblin WSGI
application in a while.
2. As a separate process communicating with the MediaGoblin WSGI application
via a `broker`_. This offloads the heavy lifting from the MediaGoblin WSGI
application and users will be able to continue to browse the site while the
media is being processed in the background.
.. _`broker`: http://docs.celeryproject.org/en/latest/getting-started/brokers/
.. _`celery`: http://www.celeryproject.org/
.. [#f-mediagoblin-wsgi-app] The MediaGoblin WSGI application is the part that
of MediaGoblin that processes HTTP requests.
To launch Celery separately from the MediaGoblin WSGI application:
1. Make sure that the ``CELERY_ALWAYS_EAGER`` environment variable is unset or
set to ``false`` when launching the MediaGoblin WSGI application.
2. Start the ``celeryd`` main process with
.. code-block:: bash
CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_celery ./bin/celeryd
.. _sentry:
Set up sentry to monitor exceptions
-----------------------------------
We have a plugin for `raven`_ integration, see the ":doc:`/plugindocs/raven`"
documentation.
.. _`raven`: http://raven.readthedocs.org
.. _init-script:
Use an Init Script
------------------
Look in your system's ``/etc/init.d/`` or ``/etc/rc.d/`` directory for
examples of how to build scripts that will start, stop, and restart
MediaGoblin and Celery. These scripts will vary by
distribution/operating system.
These are scripts provided by the MediaGoblin community:
Debian
* `GNU MediaGoblin init scripts
<https://github.com/joar/mediagoblin-init-scripts>`_
by `Joar Wandborg <http://wandborg.se>`_
Arch Linux
* `MediaGoblin - ArchLinux rc.d scripts
<http://whird.jpope.org/2012/04/14/mediagoblin-archlinux-rcd-scripts>`_
by `Jeremy Pope <http://jpope.org/>`_
* `Mediagoblin init script on Archlinux
<http://chimo.chromic.org/2012/03/01/mediagoblin-init-script-on-archlinux/>`_
by `Chimo <http://chimo.chromic.org/>`_
.. TODO insert init script here
.. TODO are additional concerns ?
.. Other Concerns
.. --------------

View File

@ -0,0 +1,300 @@
.. MediaGoblin Documentation
Written in 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
.. _release-notes:
=============
Release Notes
=============
This chapter has important information for releases in it.
If you're upgrading from a previous release, please read it
carefully, or at least skim over it.
0.4.0
=====
**Do this to upgrade**
1. Make sure to run ``bin/gmg dbupdate`` after upgrading.
2. See "For Theme authors" if you have a custom theme.
3. Note that ``./bin/gmg theme assetlink`` is now just
``./bin/gmg assetlink`` and covers both plugins and assets.
Keep on reading to hear more about new plugin features.
4. If you want to take advantage of new plugins that have statically
served assets, you are going to need to add the new "plugin_static"
section to your nginx config. Basically the following for nginx::
# Plugin static files (usually symlinked in)
location /plugin_static/ {
alias /srv/mediagoblin.example.org/mediagoblin/user_dev/plugin_static/;
}
Similarly, if you've got a modified paste config, you may want to
borrow the app:plugin_static section from the default paste.ini
file.
5. We now use itsdangerous for sessions; if you had any references to
beaker in your paste config you can remove them. Again, see the
default paste.ini config
**For theme authors**
If you have your own theme or you have any "user modified templates",
please note the following:
* mediagoblin/bits/ files above-content.html, body-end.html,
body-start.html now are renamed... they have underscores instead of
dashes in the filenames now :)
* There's a new file: ``mediagoblin/bits/frontpage_welcome.html``.
You can easily customize this to give a welcome page appropriate to
your site.
**New features**
* PDF media type!
* Improved plugin system. More flexible, better documented, with a
new plugin authoring section of the docs.
* itsdangerous based sessions. No more beaker!
* New, experimental Piwigo-based API. This means you should be able
to use MediaGoblin with something like Shotwell. (Again, a word of
caution: this is *very experimental*!)
* Human readable timestamps, and the option to display the original
date of an image when available (available as the
"original_date_visible" variable)
* Moved unit testing system from nosetests to py.test so we can better
handle issues with sqlalchemy exploding with different database
configurations. Long story :)
* You can now disable the ability to post comments.
* Tags now can be up to length 255 characters by default.
0.3.3
=====
**Do this to upgrade**
1. Make sure to run ``bin/gmg dbupdate`` after upgrading.
2. OpenStreetMap is now a plugin, so if you want to use it, add the
following to your config file:
.. code-block:: ini
[plugins]
[[mediagoblin.plugins.geolocation]]
If you have your own theme, you may need to make some adjustments to
it as some theme related things may have changed in this release. If
you run into problems, don't hesitate to
`contact us <http://mediagoblin.org/pages/join.html>`_
(IRC is often best).
**New features**
* New dropdown menu for accessing various features.
* Significantly improved URL generation. Now mediagoblin won't give
up on making a slug if it looks like there will be a duplicate;
it'll try extra hard to generate a meaningful one instead.
Similarly, linking to an id no longer can possibly conflict with
linking to a slug; /u/username/m/id:35/ is the kind of reference we
now use to linking to entries with ids. However, old links with
entries that linked to ids should work just fine with our migration.
The only urls that might break in this release are ones using colons
or equal signs.
* New template hooks for plugin authoring.
* As a demonstration of new template hooks for plugin authoring,
openstreetmap support now moved to a plugin!
* Method to add media to collections switched from icon of paperclip
to button with "add to collection" text.
* Bug where videos often failed to produce a proper thumbnail fixed!
* Copying around files in MediaGoblin now much more efficient, doesn't
waste gobs of memory.
* Video transcoding now optional for videos that meet certain
criteria. By default, MediaGoblin will not transcode webm videos
that are smaller in resolution than the MediaGoblin defaults, and
MediaGoblin can also be configured to allow theora files to not be
transcoded as well.
* Per-user license preference option; always want your uploads to be
BY-SA and tired of changing that field? You can now set your
license preference in your user settings.
* Video player now responsive; better for mobile!
* You can now delete your account from the user preferences page if
you so wish.
**Other changes**
* Plugin writers: Internal restructuring led to mediagoblin.db.sql* be
mediagoblin.db.* starting from 0.3.3
* Dependency list has been reduced not requiring the "webob" package anymore.
* And many small fixes/improvements, too numerous to list!
0.3.2
=====
This will be the last release that is capable of converting from an earlier
MongoDB-based MediaGoblin instance to the newer SQL-based system.
**Do this to upgrade**
# directory of your mediagoblin install
cd /srv/mediagoblin.example.org
# copy source for this release
git fetch
git checkout tags/v0.3.2
# perform any needed database updates
bin/gmg dbupdate
# restart your servers however you do that, e.g.,
sudo service mediagoblin-paster restart
sudo service mediagoblin-celeryd restart
**New features**
* **3d model support!**
You can now upload STL and OBJ files and display them in
MediaGoblin. Requires a recent-ish Blender; for details see:
:ref:`deploying-chapter`
* **trim_whitespace**
We bundle the optional plugin trim_whitespace which reduces the size
of the delivered html output by reducing redundant whitespace.
See :ref:`core-plugin-section` for plugin documentation
* **A new API!**
It isn't well documented yet but we do have an API. There is an
`android application in progress <https://gitorious.org/mediagoblin/mediagoblin-android>`_
which makes use of it, and there are some demo applications between
`automgtic <https://github.com/jwandborg/automgtic>`_, an
automatic media uploader for your desktop
and `OMGMG <https://github.com/jwandborg/omgmg>`_, an example of
a web application hooking up to the API.
This is a plugin, so you have to enable it in your mediagoblin
config file by adding a section under [plugins] like::
[plugins]
[[mediagoblin.plugins.api]]
Note that the API works but is not nailed down... the way it is
called may change in future releases.
* **OAuth login support**
For applications that use OAuth to connect to the API.
This is a plugin, so you have to enable it in your mediagoblin
config file by adding a section under [plugins] like::
[plugins]
[[mediagoblin.plugins.oauth]]
* **Collections**
We now have user-curated collections support. These are arbitrary
galleries that are customizable by users. You can add media to
these by clicking on the paperclip icon when logged in and looking
at a media entry.
* **OpenStreetMap licensing display improvements**
More accurate display of OSM licensing, and less disruptive: you
click to "expand" the display of said licensing.
Geolocation is also now on by default.
* **Miscelaneous visual improvements**
We've made a number of small visual improvements including newer and
nicer looking thumbnails and improved checkbox placement.
0.3.1
=====
**Do this to upgrade**
1. Make sure to run ``bin/gmg dbuptdate`` after upgrading.
2. If you set up your server config with an older version of
mediagoblin and the mediagoblin docs, it's possible you don't
have the "theme static files" alias, so double check to make
sure that section is there if you are having problems.
**New features**
* **theming support**
MediaGoblin now also includes theming support, which you can
read about in the section :ref:`theming-chapter`.
* **flatpages**
MediaGoblin has a flatpages plugin allowing you to add pages that
are aren't media-related like "About this site...", "Terms of
service...", etc.
See :ref:`core-plugin-section` for plugin documentation
0.3.0
=====
This release has one important change. You need to act when
upgrading from a previous version!
This release changes the database system from MongoDB to
SQL(alchemy). If you want to setup a fresh instance, just
follow the instructions in the deployment chapter. If on
the other hand you want to continue to use one instance,
read on.
To convert your data from MongoDB to SQL(alchemy), you need
to follow these steps:
1. Make sure your MongoDB is still running and has your
data, it's needed for the conversion.
2. Configure the ``sql_engine`` URI in the config to represent
your target database (see: :ref:`deploying-chapter`)
3. You need an empty database.
4. Then run the following command::
bin/gmg [-cf mediagoblin_config.ini] convert_mongo_to_sql
5. Start your server and investigate.
6. That's it.

View File

@ -0,0 +1,281 @@
.. MediaGoblin Documentation
Written in 2011, 2012 by MediaGoblin contributors
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to
the public domain worldwide. This software is distributed without
any warranty.
You should have received a copy of the CC0 Public Domain
Dedication along with this software. If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
.. _theming-chapter:
=====================
Theming MediaGoblin
=====================
We try to provide a nice theme for MediaGoblin by default, but of
course, you might want something different! Maybe you want something
more light and colorful, or maybe you want something specifically
tailored to your organization. Have no fear---MediaGoblin has theming
support! This guide should walk you through installing and making
themes.
Installing a theme
==================
.. _theming-installing-section:
Installing the archive
----------------------
Say you have a theme archive such as ``goblincities.tar.gz`` and you
want to install this theme! Don't worry, it's fairly painless.
1. ``cd ./user_dev/themes/``
2. Move the theme archive into this directory
3. ``tar -xzvf <tar-archive>``
4. Open your configuration file (probably named
``mediagoblin_local.ini``) and set the theme name::
[mediagoblin]
# ...
theme = goblincities
5. Link the assets so that they can be served by your web server::
$ ./bin/gmg assetlink
.. Note::
If you ever change the current theme in your config file, you
should re-run the above command!
(In the near future this should be even easier ;))
.. In the future, this might look more like:
.. Installing a theme in MediaGoblin is fairly easy! Assuming you
.. already have a theme package, just do this::
..
.. $ ./bin/gmg theme install --fullsetup goblincities.tar.gz
..
.. This would install the theme, set it as current, and symlink its
.. assets.
Set up your webserver to serve theme assets
-------------------------------------------
If you followed the nginx setup example in :ref:`webserver-config` you
should already have theme asset setup. However, if you set up your
server config with an older version of mediagoblin and the mediagoblin
docs, it's possible you don't have the "theme static files" alias, so
double check to make sure that section is there if you are having
problems.
If you are simply using this for local development and serving the
whole thing via paste/lazyserver, assuming you don't have a
paste_local.ini, the asset serving should be done for you.
Configuring where things go
---------------------------
By default, MediaGoblin's install directory for themes is
``./user_dev/themes/`` (relative to the MediaGoblin checkout or base
config file.) However, you can change this location easily with the
``theme_install_dir`` setting in the ``[mediagoblin]`` section.
For example::
[mediagoblin]
# ... other parameters go here ...
theme_install_dir = /path/to/themes/
Other variables you may consider setting:
`theme_web_path`
When theme-specific assets are specified, this is where MediaGoblin
will set the urls. By default this is ``"/theme_static/"`` so in
the case that your theme was trying to access its file
``"images/shiny_button.png"`` MediaGoblin would link
to ``/theme_static/images/shiny_button.png``.
`theme_linked_assets_dir`
Your web server needs to serve the theme files out of some directory,
and MediaGoblin will symlink the current theme's assets here. See
the "Link the assets" step in :ref:`theming-installing-section`.
Making a theme
==============
Okay, so a theme layout is pretty simple. Let's assume we're making a
theme for an instance about hedgehogs! We'll call this the
"hedgehogified" theme.
Change to where your ``theme_install_dir`` is set to (by default,
``./user_dev/themes/`` ... make those directories or otherwise adjust
if necessary)::
hedgehogified/
|- theme.cfg # configuration file for this theme
|- templates/ # override templates
| '- mediagoblin/
| |- base.html # overriding mediagoblin/base.html
| '- root.html # overriding mediagoblin/root.html
'- assets/
| '- images/
| | |- im_a_hedgehog.png # hedgehog-containing image used by theme
| | '- custom_logo.png # your theme's custom logo
| '- css/
| '- hedgehog.css # your site's hedgehog-specific css
|- README.txt # Optionally, a readme file (not required)
|- AGPLv3.txt # AGPL license file for your theme. (good practice)
'- CC0_1.0.txt # CC0 1.0 legalcode for the assets [if appropriate!]
The top level directory of your theme should be the symbolic name for
your theme. This is the name that users will use to refer to activate
your theme.
.. Note::
It's important to note that templates based on MediaGoblin's code
should be released as AGPLv3 (or later), like MediaGoblin's code
itself. However, all the rest of your assets are up to you. In this
case, we are waiving our copyright for images and CSS into the public
domain via CC0 (as MediaGoblin does) but do what's appropriate to you.
The config file
===============
The config file is not presently strictly required, though it is nice to have.
Only a few things need to go in here::
[theme]
name = Hedgehog-ification
description = For hedgehog lovers ONLY
licensing = AGPLv3 or later templates; assets (images/css) waived under CC0 1.0
The name and description fields here are to give users an idea of what
your theme is about. For the moment, we don't have any listing
directories or admin interface, so this probably isn't useful, but
feel free to set it in anticipation of a more glorious future.
Licensing field is likewise a textual description of the stuff here;
it's recommended that you preserve the "AGPLv3 or later templates" and
specify whatever is appropriate to your assets.
Templates
---------
Your template directory is where you can put any override and custom
templates for MediaGoblin.
These follow the general MediaGoblin theming layout, which means that
the MediaGoblin core templates are all kept under the ``./mediagoblin/``
prefix directory.
You can copy files right out of MediaGoblin core and modify them in
this matter if you wish.
To fit with best licensing form, you should either preserve the
MediaGoblin copyright header borrowing from a MediaGoblin template, or
you may include one like the following::
{#
# [YOUR THEME], a MediaGoblin theme
# Copyright (C) [YEAR] [YOUR NAME]
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
Assets
------
Put any files, such as images, CSS, etc, that are specific to your
theme in here.
You can reference these in your templates like so::
<img src="{{ request.staticdirect('/images/im_a_shark.png', 'theme') }}" />
This will tell MediaGoblin to reference this image from the current theme.
Licensing file(s)
-----------------
You should include AGPLv3.txt with your theme as this is required for
the assets. You can copy this from ``mediagoblin/licenses/``.
In the above example, we also use CC0 to waive our copyrights to
images and css, so we also included CC0_1.0.txt
A README.txt file
-----------------
A README file is not strictly required, but probably a good idea. You
can put whatever in here, but restating the license choice clearly is
probably a good idea.
Simple theming by adding CSS
----------------------------
Many themes won't require anything other than the ability to override
some of MediaGoblin's core css. Thankfully, doing so is easy if you
combine the above steps!
In your theme, do the following (make sure you make the necessary
directories and cd to your theme's directory first)::
$ cp /path/to/mediagoblin/mediagoblin/templates/mediagoblin/extra_head.html templates/mediagoblin/
Great, now open that file and add something like this at the end::
<link rel="stylesheet" type="text/css"
href="{{ request.staticdirect('/css/theme.css', 'theme') }}"/>
You can name the css file whatever you like. Now make the directory
for ``assets/css/`` and add the file ``assets/css/theme.css``.
You can now put custom CSS files in here and any CSS you add will
override default MediaGoblin CSS.
Packaging it up!
----------------
Packaging a theme is really easy. It's just a matter of making an archive!
Change to the installed themes directory and run the following::
tar -cvfz yourtheme.tar.gz yourtheme
Where "yourtheme" is replaced with your theme name.
That's it!

View File

@ -0,0 +1,29 @@
{#
default/layout.html
~~~~~~~~~~~~~~~~~~~
Sphinx layout template for the default theme.
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
#}
{% extends "basic/layout.html" %}
{% if theme_collapsiblesidebar|tobool %}
{% set script_files = script_files + ['_static/sidebar.js'] %}
{% endif %}
{%- block footer %}
<div class="footer">
<div>
MediaGoblin documentation released into the public domain via <a href="http://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.
{%- if last_updated %}
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
{%- endif %}
{% trans sphinx_version=sphinx_version|e %}Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %}
</div>
</div>
{%- endblock %}

View File

@ -0,0 +1 @@
../../../../../../extlib/lato/Lato-Bold.ttf

View File

@ -0,0 +1 @@
../../../../../../extlib/lato/Lato-BoldItalic.ttf

View File

@ -0,0 +1 @@
../../../../../../extlib/lato/Lato-Italic.ttf

View File

@ -0,0 +1 @@
../../../../../../extlib/lato/Lato-Regular.ttf

View File

@ -0,0 +1 @@
../../../../../../extlib/lato/OFL_1.1.txt

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -0,0 +1,161 @@
/*
MediaGoblin theme - MediaGoblin-style Sphinx documentation theme
Written in 2012 by Jef van Schendel <mail@jefvanschendel.nl>
To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
@import url("basic.css");
/* text fonts and styles */
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 700;
src: local('Lato Bold'), local('Lato-Bold'), url('fonts/Lato-Bold.ttf') format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: italic;
font-weight: 400;
src: local('Lato Italic'), local('Lato-Italic'), url('fonts/Lato-Italic.ttf') format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: italic;
font-weight: 700;
src: local('Lato Bold Italic'), local('Lato-BoldItalic'), url('fonts/Lato-BoldItalic.ttf') format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url('fonts/Lato-Regular.ttf') format('truetype');
}
body {
font: 16px 'Lato',Helvetica,Arial,sans-serif;
background-color: #FCFCFC;
color: #3C3C3C;
margin: 0;
padding: 0;
}
h1, h2, h3, h4, h5, h6 {
border-bottom: 1px solid #CCCCCC;
background: none;
color: black;
font-weight: bold;
padding-bottom: 0.17em;
padding-top: 0.5em;
}
h1 {
font-size: 1.875em;
}
h2 {
font-size: 1.375em;
}
h3, h4, h5, h6 {
font-size: 1.125em;
}
p {
font-weight: normal;
margin: 0.4em 0 0.5em;
}
a {
color: #499776;
}
a:visited {
color: #2A5744;
}
a:active {
color: #65D1A3;
}
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
text-decoration: none;
}
div.topic, pre {
background-color: #F1F1F1;
border: 1px dashed #ccc;
color: black;
line-height: 1.1em;
padding: 1em;
}
code, tt {
font: 14px monospace,"Courier New";
background-color: #FFFFDD;
border: thin solid #bbb;
padding-left: 5px;
padding-right: 5px;
}
pre {
font: 14px monospace,"Courier New";
}
div.related a, div.related a:visited, div.related a:active {
color: #86D4B1;
}
/* layout */
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 270px;
}
div.body {
padding: 0 20px 30px 20px;
}
div.footer {
width: 100%;
padding: 9px 0 9px 0;
text-align: center;
font-size: 75%;
}
div.sphinxsidebar {
width: 240px;
}
div.sphinxsidebarwrapper {
padding: 10px 5px 0 30px;
}
div.sphinxsidebar ul {
margin: 10px 10px 10px 0;
padding: 0;
}
div.related {
line-height: 30px;
font-size: 90%;
width: 100%;
background-color: #161616;
color: #C3C3C3;
}
p.logo {
margin-top: 30px;
}

View File

@ -0,0 +1,5 @@
[theme]
inherit = basic
stylesheet = mg.css
pygments_style = sphinx

84
extlib/README Normal file
View File

@ -0,0 +1,84 @@
=========================
External Library README
=========================
DO NOT "FIX" CODE IN THIS DIRECTORY.
ONLY UPSTREAM VERSIONS OF SOFTWARE GO IN THIS DIRECTORY.
This directory is provided as a courtesy to our users who might be
unable or unwilling to find and install libraries we depend on.
If we "fix" software in this directory, we hamstring users who do the
right thing and keep a single version of upstream libraries in a
system-wide library. We introduce subtle and maddening bugs where
our code is "accidentally" using the "wrong" library version. We may
unwittingly interfere with other software that depends on the
canonical release versions of those same libraries!
Forking upstream software for trivial reasons makes us bad citizens in
the Free Software community and adds unnecessary heartache for our
users. Don't make us "that" project.
FAQ
===
:Q: What should we do when we find a bug in upstream software?
:A: First and foremost, REPORT THE BUG, and if possible send in a patch.
Watch for a release of the upstream software and integrate with it
when it's released.
In the meantime, work around the bug, if at all possible. Usually,
it's quite possible, if slightly harder or less efficient.
:Q: What if the bug can't be worked around?
:A: If the upstream developers have accepted a bug patch, it's
undesirable but acceptable to apply that patch to the library in
the ``extlib/`` dir. Ideally, use a release version for upstream or a
version control system snapshot.
Note that this is a last resort.
:Q: What if upstream is unresponsive or won't accept a patch?
:A: Try again.
:Q: I tried again, and upstream is still unresponsive and nobody's
checked on my patch. Now what?
:A: If the upstream project is moribund and there's a way to adopt it,
propose having the MediaGoblin dev team adopt the project. Or, adopt
it yourself.
:Q: What if there's no upstream authority and it can't be adopted?
:A: Then we fork it. Make a new name and a new version. Include it in
``lib/`` instead of ``extlib/``, and use the GMG_* prefix to change
the namespace to avoid collisions (or something like that).
This is a last resort; consult with the rest of the dev group
before taking this radical step.
:Q: What about submodules?
:A: pdf.js is supplied as a submodule, and other software may use that too,
to add a new submodule:
git submodule add <git-repo-of-fun-project> extlib/fun-project
Use it just like a snapshotted extlib directory. When a new clone of mediagoblin
is made you need to run
git submodule init
git submodule update
As noted in HackingHowto
Thanks
======
This policy originally copied from Status.net. Many many thanks to them
for working out such a nice system for doing things.

1896
extlib/exif/EXIF.py Executable file

File diff suppressed because it is too large Load Diff

1
extlib/exif/LICENSE Normal file
View File

@ -0,0 +1 @@
See top of EXIF.py for license and copyright.

131
extlib/exif/changes.txt Normal file
View File

@ -0,0 +1,131 @@
~ EXIF.py Changelog ~
2012-11-30 - Gregory Dudek (date of merge).
Patches and changes:
Overflow error fixes added (related to 2**31 size)
GPS tags added.
2012-09-26 - Ianaré Sévi
Merge patches:
Add GPS tags
Add better endian debug info
2012-06-13 - Ianaré Sévi
Merge patches:
Support malformed last IFD by fhats
Light source, Flash and Metering mode dictionaries update by gryfik
2008-07-31 - Ianaré Sévi
Wikipedia Commons hunt for suitable test case images,
testing new code additions.
2008-07-09 - Stephen H. Olson
Fix a problem with reading MakerNotes out of NEF files.
Add some more Nikon MakerNote tags.
2008-07-08 - Stephen H. Olson
An error check for large tags totally borked MakerNotes.
With Nikon anyway, valid MakerNotes can be pretty big.
Add error check for a crash caused by nikon_ev_bias being
called with the wrong args.
Drop any garbage after a null character in string
(patch from Andrew McNabb <amcnabb@google.com>).
2008-02-12 - Ianaré Sévi
Fix crash on invalid MakerNote
Fix crash on huge Makernote (temp fix)
Add printIM tag 0xC4A5, needs decoding info
Add 0x9C9B-F range of tags
Add a bunch of tag definitions from:
http://owl.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
Add 'strict' variable and command line option
2008-01-18 - Gunter Ohrner
Add 'GPSDate' tag
2007-12-12 - Ianaré Sévi
Fix quick option on certain image types
Add note on tag naming in documentation
2007-11-30 - Ianaré Sévi
Changed -s option to -t
Put changelog into separate file
2007-10-28 - Ianaré Sévi
Merged changes from MoinMoin:ReimarBauer
Added command line option for debug, stop
processing on tag.
2007-09-27 - Ianaré Sévi
Add some Olympus Makernote tags.
2007-09-26 - Stephen H. Olson
Don't error out on invalid Olympus 'SpecialMode'.
Add a few more Olympus/Minolta tags.
2007-09-22 - Stephen H. Olson
Don't error on invalid string
Improved Nikon MakerNote support
2007-05-03 - Martin Stone <mj_stone@users.sourceforge.net>
Fix for inverted detailed flag and Photoshop header
2007-03-24 - Ianaré Sévi
Can now ignore MakerNotes Tags for faster processing.
2007-01-18 - Ianaré Sévi <ianare@gmail.com>
Fixed a couple errors and assuming maintenance of the library.
2006-08-04 MoinMoin:ReimarBauer
Added an optional parameter name to process_file and dump_IFD. Using this parameter the
loop is breaked after that tag_name is processed.
some PEP8 changes
---------------------------- original notices -------------------------
Contains code from "exifdump.py" originally written by Thierry Bousch
<bousch@topo.math.u-psud.fr> and released into the public domain.
Updated and turned into general-purpose library by Gene Cash
Patch Contributors:
* Simon J. Gerraty <sjg@crufty.net>
s2n fix & orientation decode
* John T. Riedl <riedl@cs.umn.edu>
Added support for newer Nikon type 3 Makernote format for D70 and some
other Nikon cameras.
* Joerg Schaefer <schaeferj@gmx.net>
Fixed subtle bug when faking an EXIF header, which affected maker notes
using relative offsets, and a fix for Nikon D100.
1999-08-21 TB Last update by Thierry Bousch to his code.
2002-01-17 CEC Discovered code on web.
Commented everything.
Made small code improvements.
Reformatted for readability.
2002-01-19 CEC Added ability to read TIFFs and JFIF-format JPEGs.
Added ability to extract JPEG formatted thumbnail.
Added ability to read GPS IFD (not tested).
Converted IFD data structure to dictionaries indexed by
tag name.
Factored into library returning dictionary of IFDs plus
thumbnail, if any.
2002-01-20 CEC Added MakerNote processing logic.
Added Olympus MakerNote.
Converted data structure to single-level dictionary, avoiding
tag name collisions by prefixing with IFD name. This makes
it much easier to use.
2002-01-23 CEC Trimmed nulls from end of string values.
2002-01-25 CEC Discovered JPEG thumbnail in Olympus TIFF MakerNote.
2002-01-26 CEC Added ability to extract TIFF thumbnails.
Added Nikon, Fujifilm, Casio MakerNotes.
2003-11-30 CEC Fixed problem with canon_decode_tag() not creating an
IFD_Tag() object.
2004-02-15 CEC Finally fixed bit shift warning by converting Y to 0L.

31
extlib/flask-wtf/LICENSE Normal file
View File

@ -0,0 +1,31 @@
Copyright (c) 2010 by Dan Jacob.
Some rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

125
extlib/flask-wtf/html5.py Normal file
View File

@ -0,0 +1,125 @@
from wtforms import TextField
from wtforms import IntegerField as _IntegerField
from wtforms import DecimalField as _DecimalField
from wtforms import DateField as _DateField
from wtforms.widgets import Input
class DateInput(Input):
"""
Creates `<input type=date>` widget
"""
input_type = "date"
class NumberInput(Input):
"""
Creates `<input type=number>` widget
"""
input_type="number"
class RangeInput(Input):
"""
Creates `<input type=range>` widget
"""
input_type="range"
class URLInput(Input):
"""
Creates `<input type=url>` widget
"""
input_type = "url"
class EmailInput(Input):
"""
Creates `<input type=email>` widget
"""
input_type = "email"
class SearchInput(Input):
"""
Creates `<input type=search>` widget
"""
input_type = "search"
class TelInput(Input):
"""
Creates `<input type=tel>` widget
"""
input_type = "tel"
class SearchField(TextField):
"""
**TextField** using **SearchInput** by default
"""
widget = SearchInput()
class DateField(_DateField):
"""
**DateField** using **DateInput** by default
"""
widget = DateInput()
class URLField(TextField):
"""
**TextField** using **URLInput** by default
"""
widget = URLInput()
class EmailField(TextField):
"""
**TextField** using **EmailInput** by default
"""
widget = EmailInput()
class TelField(TextField):
"""
**TextField** using **TelInput** by default
"""
widget = TelInput()
class IntegerField(_IntegerField):
"""
**IntegerField** using **NumberInput** by default
"""
widget = NumberInput()
class DecimalField(_DecimalField):
"""
**DecimalField** using **NumberInput** by default
"""
widget = NumberInput()
class IntegerRangeField(_IntegerField):
"""
**IntegerField** using **RangeInput** by default
"""
widget = RangeInput()
class DecimalRangeField(_DecimalField):
"""
**DecimalField** using **RangeInput** by default
"""
widget = RangeInput()

View File

@ -0,0 +1,616 @@
#!/usr/bin/env python
# processing.py -- various audio processing functions
# Copyright (C) 2008 MUSIC TECHNOLOGY GROUP (MTG)
# UNIVERSITAT POMPEU FABRA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Authors:
# Bram de Jong <bram.dejong at domain.com where domain in gmail>
# 2012, Joar Wandborg <first name at last name dot se>
from PIL import Image, ImageDraw, ImageColor #@UnresolvedImport
from functools import partial
import math
import numpy
import os
import re
import signal
def get_sound_type(input_filename):
sound_type = os.path.splitext(input_filename.lower())[1].strip(".")
if sound_type == "fla":
sound_type = "flac"
elif sound_type == "aif":
sound_type = "aiff"
return sound_type
try:
import scikits.audiolab as audiolab
except ImportError:
print "WARNING: audiolab is not installed so wav2png will not work"
import subprocess
class AudioProcessingException(Exception):
pass
class TestAudioFile(object):
"""A class that mimics audiolab.sndfile but generates noise instead of reading
a wave file. Additionally it can be told to have a "broken" header and thus crashing
in the middle of the file. Also useful for testing ultra-short files of 20 samples."""
def __init__(self, num_frames, has_broken_header=False):
self.seekpoint = 0
self.nframes = num_frames
self.samplerate = 44100
self.channels = 1
self.has_broken_header = has_broken_header
def seek(self, seekpoint):
self.seekpoint = seekpoint
def read_frames(self, frames_to_read):
if self.has_broken_header and self.seekpoint + frames_to_read > self.num_frames / 2:
raise RuntimeError()
num_frames_left = self.num_frames - self.seekpoint
will_read = num_frames_left if num_frames_left < frames_to_read else frames_to_read
self.seekpoint += will_read
return numpy.random.random(will_read)*2 - 1
def get_max_level(filename):
max_value = 0
buffer_size = 4096
audio_file = audiolab.Sndfile(filename, 'r')
n_samples_left = audio_file.nframes
while n_samples_left:
to_read = min(buffer_size, n_samples_left)
try:
samples = audio_file.read_frames(to_read)
except RuntimeError:
# this can happen with a broken header
break
# convert to mono by selecting left channel only
if audio_file.channels > 1:
samples = samples[:,0]
max_value = max(max_value, numpy.abs(samples).max())
n_samples_left -= to_read
audio_file.close()
return max_value
class AudioProcessor(object):
"""
The audio processor processes chunks of audio an calculates the spectrac centroid and the peak
samples in that chunk of audio.
"""
def __init__(self, input_filename, fft_size, window_function=numpy.hanning):
max_level = get_max_level(input_filename)
self.audio_file = audiolab.Sndfile(input_filename, 'r')
self.fft_size = fft_size
self.window = window_function(self.fft_size)
self.spectrum_range = None
self.lower = 100
self.higher = 22050
self.lower_log = math.log10(self.lower)
self.higher_log = math.log10(self.higher)
self.clip = lambda val, low, high: min(high, max(low, val))
# figure out what the maximum value is for an FFT doing the FFT of a DC signal
fft = numpy.fft.rfft(numpy.ones(fft_size) * self.window)
max_fft = (numpy.abs(fft)).max()
# set the scale to normalized audio and normalized FFT
self.scale = 1.0/max_level/max_fft if max_level > 0 else 1
def read(self, start, size, resize_if_less=False):
""" read size samples starting at start, if resize_if_less is True and less than size
samples are read, resize the array to size and fill with zeros """
# number of zeros to add to start and end of the buffer
add_to_start = 0
add_to_end = 0
if start < 0:
# the first FFT window starts centered around zero
if size + start <= 0:
return numpy.zeros(size) if resize_if_less else numpy.array([])
else:
self.audio_file.seek(0)
add_to_start = -start # remember: start is negative!
to_read = size + start
if to_read > self.audio_file.nframes:
add_to_end = to_read - self.audio_file.nframes
to_read = self.audio_file.nframes
else:
self.audio_file.seek(start)
to_read = size
if start + to_read >= self.audio_file.nframes:
to_read = self.audio_file.nframes - start
add_to_end = size - to_read
try:
samples = self.audio_file.read_frames(to_read)
except RuntimeError:
# this can happen for wave files with broken headers...
return numpy.zeros(size) if resize_if_less else numpy.zeros(2)
# convert to mono by selecting left channel only
if self.audio_file.channels > 1:
samples = samples[:,0]
if resize_if_less and (add_to_start > 0 or add_to_end > 0):
if add_to_start > 0:
samples = numpy.concatenate((numpy.zeros(add_to_start), samples), axis=1)
if add_to_end > 0:
samples = numpy.resize(samples, size)
samples[size - add_to_end:] = 0
return samples
def spectral_centroid(self, seek_point, spec_range=110.0):
""" starting at seek_point read fft_size samples, and calculate the spectral centroid """
samples = self.read(seek_point - self.fft_size/2, self.fft_size, True)
samples *= self.window
fft = numpy.fft.rfft(samples)
spectrum = self.scale * numpy.abs(fft) # normalized abs(FFT) between 0 and 1
length = numpy.float64(spectrum.shape[0])
# scale the db spectrum from [- spec_range db ... 0 db] > [0..1]
db_spectrum = ((20*(numpy.log10(spectrum + 1e-60))).clip(-spec_range, 0.0) + spec_range)/spec_range
energy = spectrum.sum()
spectral_centroid = 0
if energy > 1e-60:
# calculate the spectral centroid
if self.spectrum_range == None:
self.spectrum_range = numpy.arange(length)
spectral_centroid = (spectrum * self.spectrum_range).sum() / (energy * (length - 1)) * self.audio_file.samplerate * 0.5
# clip > log10 > scale between 0 and 1
spectral_centroid = (math.log10(self.clip(spectral_centroid, self.lower, self.higher)) - self.lower_log) / (self.higher_log - self.lower_log)
return (spectral_centroid, db_spectrum)
def peaks(self, start_seek, end_seek):
""" read all samples between start_seek and end_seek, then find the minimum and maximum peak
in that range. Returns that pair in the order they were found. So if min was found first,
it returns (min, max) else the other way around. """
# larger blocksizes are faster but take more mem...
# Aha, Watson, a clue, a tradeof!
block_size = 4096
max_index = -1
max_value = -1
min_index = -1
min_value = 1
if start_seek < 0:
start_seek = 0
if end_seek > self.audio_file.nframes:
end_seek = self.audio_file.nframes
if end_seek <= start_seek:
samples = self.read(start_seek, 1)
return (samples[0], samples[0])
if block_size > end_seek - start_seek:
block_size = end_seek - start_seek
for i in range(start_seek, end_seek, block_size):
samples = self.read(i, block_size)
local_max_index = numpy.argmax(samples)
local_max_value = samples[local_max_index]
if local_max_value > max_value:
max_value = local_max_value
max_index = local_max_index
local_min_index = numpy.argmin(samples)
local_min_value = samples[local_min_index]
if local_min_value < min_value:
min_value = local_min_value
min_index = local_min_index
return (min_value, max_value) if min_index < max_index else (max_value, min_value)
def interpolate_colors(colors, flat=False, num_colors=256):
""" given a list of colors, create a larger list of colors interpolating
the first one. If flatten is True a list of numers will be returned. If
False, a list of (r,g,b) tuples. num_colors is the number of colors wanted
in the final list """
palette = []
for i in range(num_colors):
index = (i * (len(colors) - 1))/(num_colors - 1.0)
index_int = int(index)
alpha = index - float(index_int)
if alpha > 0:
r = (1.0 - alpha) * colors[index_int][0] + alpha * colors[index_int + 1][0]
g = (1.0 - alpha) * colors[index_int][1] + alpha * colors[index_int + 1][1]
b = (1.0 - alpha) * colors[index_int][2] + alpha * colors[index_int + 1][2]
else:
r = (1.0 - alpha) * colors[index_int][0]
g = (1.0 - alpha) * colors[index_int][1]
b = (1.0 - alpha) * colors[index_int][2]
if flat:
palette.extend((int(r), int(g), int(b)))
else:
palette.append((int(r), int(g), int(b)))
return palette
def desaturate(rgb, amount):
"""
desaturate colors by amount
amount == 0, no change
amount == 1, grey
"""
luminosity = sum(rgb) / 3.0
desat = lambda color: color - amount * (color - luminosity)
return tuple(map(int, map(desat, rgb)))
class WaveformImage(object):
"""
Given peaks and spectral centroids from the AudioProcessor, this class will construct
a wavefile image which can be saved as PNG.
"""
def __init__(self, image_width, image_height, palette=1):
if image_height % 2 == 0:
raise AudioProcessingException, "Height should be uneven: images look much better at uneven height"
if palette == 1:
background_color = (0,0,0)
colors = [
(50,0,200),
(0,220,80),
(255,224,0),
(255,70,0),
]
elif palette == 2:
background_color = (0,0,0)
colors = [self.color_from_value(value/29.0) for value in range(0,30)]
elif palette == 3:
background_color = (213, 217, 221)
colors = map( partial(desaturate, amount=0.7), [
(50,0,200),
(0,220,80),
(255,224,0),
])
elif palette == 4:
background_color = (213, 217, 221)
colors = map( partial(desaturate, amount=0.8), [self.color_from_value(value/29.0) for value in range(0,30)])
self.image = Image.new("RGB", (image_width, image_height), background_color)
self.image_width = image_width
self.image_height = image_height
self.draw = ImageDraw.Draw(self.image)
self.previous_x, self.previous_y = None, None
self.color_lookup = interpolate_colors(colors)
self.pix = self.image.load()
def color_from_value(self, value):
""" given a value between 0 and 1, return an (r,g,b) tuple """
return ImageColor.getrgb("hsl(%d,%d%%,%d%%)" % (int( (1.0 - value) * 360 ), 80, 50))
def draw_peaks(self, x, peaks, spectral_centroid):
""" draw 2 peaks at x using the spectral_centroid for color """
y1 = self.image_height * 0.5 - peaks[0] * (self.image_height - 4) * 0.5
y2 = self.image_height * 0.5 - peaks[1] * (self.image_height - 4) * 0.5
line_color = self.color_lookup[int(spectral_centroid*255.0)]
if self.previous_y != None:
self.draw.line([self.previous_x, self.previous_y, x, y1, x, y2], line_color)
else:
self.draw.line([x, y1, x, y2], line_color)
self.previous_x, self.previous_y = x, y2
self.draw_anti_aliased_pixels(x, y1, y2, line_color)
def draw_anti_aliased_pixels(self, x, y1, y2, color):
""" vertical anti-aliasing at y1 and y2 """
y_max = max(y1, y2)
y_max_int = int(y_max)
alpha = y_max - y_max_int
if alpha > 0.0 and alpha < 1.0 and y_max_int + 1 < self.image_height:
current_pix = self.pix[x, y_max_int + 1]
r = int((1-alpha)*current_pix[0] + alpha*color[0])
g = int((1-alpha)*current_pix[1] + alpha*color[1])
b = int((1-alpha)*current_pix[2] + alpha*color[2])
self.pix[x, y_max_int + 1] = (r,g,b)
y_min = min(y1, y2)
y_min_int = int(y_min)
alpha = 1.0 - (y_min - y_min_int)
if alpha > 0.0 and alpha < 1.0 and y_min_int - 1 >= 0:
current_pix = self.pix[x, y_min_int - 1]
r = int((1-alpha)*current_pix[0] + alpha*color[0])
g = int((1-alpha)*current_pix[1] + alpha*color[1])
b = int((1-alpha)*current_pix[2] + alpha*color[2])
self.pix[x, y_min_int - 1] = (r,g,b)
def save(self, filename):
# draw a zero "zero" line
a = 25
for x in range(self.image_width):
self.pix[x, self.image_height/2] = tuple(map(lambda p: p+a, self.pix[x, self.image_height/2]))
self.image.save(filename)
class SpectrogramImage(object):
"""
Given spectra from the AudioProcessor, this class will construct a wavefile image which
can be saved as PNG.
"""
def __init__(self, image_width, image_height, fft_size):
self.image_width = image_width
self.image_height = image_height
self.fft_size = fft_size
self.image = Image.new("RGBA", (image_height, image_width))
colors = [
(0, 0, 0, 0),
(58/4, 68/4, 65/4, 255),
(80/2, 100/2, 153/2, 255),
(90, 180, 100, 255),
(224, 224, 44, 255),
(255, 60, 30, 255),
(255, 255, 255, 255)
]
self.palette = interpolate_colors(colors)
# generate the lookup which translates y-coordinate to fft-bin
self.y_to_bin = []
f_min = 100.0
f_max = 22050.0
y_min = math.log10(f_min)
y_max = math.log10(f_max)
for y in range(self.image_height):
freq = math.pow(10.0, y_min + y / (image_height - 1.0) *(y_max - y_min))
bin = freq / 22050.0 * (self.fft_size/2 + 1)
if bin < self.fft_size/2:
alpha = bin - int(bin)
self.y_to_bin.append((int(bin), alpha * 255))
# this is a bit strange, but using image.load()[x,y] = ... is
# a lot slower than using image.putadata and then rotating the image
# so we store all the pixels in an array and then create the image when saving
self.pixels = []
def draw_spectrum(self, x, spectrum):
# for all frequencies, draw the pixels
for (index, alpha) in self.y_to_bin:
self.pixels.append( self.palette[int((255.0-alpha) * spectrum[index] + alpha * spectrum[index + 1])] )
# if the FFT is too small to fill up the image, fill with black to the top
for y in range(len(self.y_to_bin), self.image_height): #@UnusedVariable
self.pixels.append(self.palette[0])
def save(self, filename, quality=80):
assert filename.lower().endswith(".jpg")
self.image.putdata(self.pixels)
self.image.transpose(Image.ROTATE_90).save(filename, quality=quality)
def create_wave_images(input_filename, output_filename_w, output_filename_s, image_width, image_height, fft_size, progress_callback=None):
"""
Utility function for creating both wavefile and spectrum images from an audio input file.
"""
processor = AudioProcessor(input_filename, fft_size, numpy.hanning)
samples_per_pixel = processor.audio_file.nframes / float(image_width)
waveform = WaveformImage(image_width, image_height)
spectrogram = SpectrogramImage(image_width, image_height, fft_size)
for x in range(image_width):
if progress_callback and x % (image_width/10) == 0:
progress_callback((x*100)/image_width)
seek_point = int(x * samples_per_pixel)
next_seek_point = int((x + 1) * samples_per_pixel)
(spectral_centroid, db_spectrum) = processor.spectral_centroid(seek_point)
peaks = processor.peaks(seek_point, next_seek_point)
waveform.draw_peaks(x, peaks, spectral_centroid)
spectrogram.draw_spectrum(x, db_spectrum)
if progress_callback:
progress_callback(100)
waveform.save(output_filename_w)
spectrogram.save(output_filename_s)
class NoSpaceLeftException(Exception):
pass
def convert_to_pcm(input_filename, output_filename):
"""
converts any audio file type to pcm audio
"""
if not os.path.exists(input_filename):
raise AudioProcessingException, "file %s does not exist" % input_filename
sound_type = get_sound_type(input_filename)
if sound_type == "mp3":
cmd = ["lame", "--decode", input_filename, output_filename]
elif sound_type == "ogg":
cmd = ["oggdec", input_filename, "-o", output_filename]
elif sound_type == "flac":
cmd = ["flac", "-f", "-d", "-s", "-o", output_filename, input_filename]
else:
return False
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdout, stderr) = process.communicate()
if process.returncode != 0 or not os.path.exists(output_filename):
if "No space left on device" in stderr + " " + stdout:
raise NoSpaceLeftException
raise AudioProcessingException, "failed converting to pcm data:\n" + " ".join(cmd) + "\n" + stderr + "\n" + stdout
return True
def stereofy_and_find_info(stereofy_executble_path, input_filename, output_filename):
"""
converts a pcm wave file to two channel, 16 bit integer
"""
if not os.path.exists(input_filename):
raise AudioProcessingException, "file %s does not exist" % input_filename
cmd = [stereofy_executble_path, "--input", input_filename, "--output", output_filename]
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdout, stderr) = process.communicate()
if process.returncode != 0 or not os.path.exists(output_filename):
if "No space left on device" in stderr + " " + stdout:
raise NoSpaceLeftException
raise AudioProcessingException, "failed calling stereofy data:\n" + " ".join(cmd) + "\n" + stderr + "\n" + stdout
stdout = (stdout + " " + stderr).replace("\n", " ")
duration = 0
m = re.match(r".*#duration (?P<duration>[\d\.]+).*", stdout)
if m != None:
duration = float(m.group("duration"))
channels = 0
m = re.match(r".*#channels (?P<channels>\d+).*", stdout)
if m != None:
channels = float(m.group("channels"))
samplerate = 0
m = re.match(r".*#samplerate (?P<samplerate>\d+).*", stdout)
if m != None:
samplerate = float(m.group("samplerate"))
bitdepth = None
m = re.match(r".*#bitdepth (?P<bitdepth>\d+).*", stdout)
if m != None:
bitdepth = float(m.group("bitdepth"))
bitrate = (os.path.getsize(input_filename) * 8.0) / 1024.0 / duration if duration > 0 else 0
return dict(duration=duration, channels=channels, samplerate=samplerate, bitrate=bitrate, bitdepth=bitdepth)
def convert_to_mp3(input_filename, output_filename, quality=70):
"""
converts the incoming wave file to a mp3 file
"""
if not os.path.exists(input_filename):
raise AudioProcessingException, "file %s does not exist" % input_filename
command = ["lame", "--silent", "--abr", str(quality), input_filename, output_filename]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdout, stderr) = process.communicate()
if process.returncode != 0 or not os.path.exists(output_filename):
raise AudioProcessingException, stdout
def convert_to_ogg(input_filename, output_filename, quality=1):
"""
converts the incoming wave file to n ogg file
"""
if not os.path.exists(input_filename):
raise AudioProcessingException, "file %s does not exist" % input_filename
command = ["oggenc", "-q", str(quality), input_filename, "-o", output_filename]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdout, stderr) = process.communicate()
if process.returncode != 0 or not os.path.exists(output_filename):
raise AudioProcessingException, stdout
def convert_using_ffmpeg(input_filename, output_filename):
"""
converts the incoming wave file to stereo pcm using fffmpeg
"""
TIMEOUT = 3 * 60
def alarm_handler(signum, frame):
raise AudioProcessingException, "timeout while waiting for ffmpeg"
if not os.path.exists(input_filename):
raise AudioProcessingException, "file %s does not exist" % input_filename
command = ["ffmpeg", "-y", "-i", input_filename, "-ac","1","-acodec", "pcm_s16le", "-ar", "44100", output_filename]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
signal.signal(signal.SIGALRM,alarm_handler)
signal.alarm(TIMEOUT)
(stdout, stderr) = process.communicate()
signal.alarm(0)
if process.returncode != 0 or not os.path.exists(output_filename):
raise AudioProcessingException, stdout

View File

@ -0,0 +1,268 @@
/*
html5slider - a JS implementation of <input type=range> for Firefox 4 and up
https://github.com/fryn/html5slider
Copyright (c) 2010-2011 Frank Yan, <http://frankyan.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
(function() {
// test for native support
var test = document.createElement('input');
try {
test.type = 'range';
if (test.type == 'range')
return;
} catch (e) {
return;
}
// test for required property support
if (!document.mozSetImageElement || !('MozAppearance' in test.style))
return;
var scale;
var isMac = navigator.platform == 'MacIntel';
var thumb = {
radius: isMac ? 9 : 6,
width: isMac ? 22 : 12,
height: isMac ? 16 : 20
};
var track = '-moz-linear-gradient(top, transparent ' + (isMac ?
'6px, #999 6px, #999 7px, #ccc 9px, #bbb 11px, #bbb 12px, transparent 12px' :
'9px, #999 9px, #bbb 10px, #fff 11px, transparent 11px') +
', transparent)';
var styles = {
'min-width': thumb.width + 'px',
'min-height': thumb.height + 'px',
'max-height': thumb.height + 'px',
padding: 0,
border: 0,
'border-radius': 0,
cursor: 'default',
'text-indent': '-999999px' // -moz-user-select: none; breaks mouse capture
};
var onChange = document.createEvent('HTMLEvents');
onChange.initEvent('change', true, false);
if (document.readyState == 'loading')
document.addEventListener('DOMContentLoaded', initialize, true);
else
initialize();
function initialize() {
// create initial sliders
Array.forEach(document.querySelectorAll('input[type=range]'), transform);
// create sliders on-the-fly
document.addEventListener('DOMNodeInserted', onNodeInserted, true);
}
function onNodeInserted(e) {
check(e.target);
if (e.target.querySelectorAll)
Array.forEach(e.target.querySelectorAll('input'), check);
}
function check(input, async) {
if (input.localName != 'input' || input.type == 'range');
else if (input.getAttribute('type') == 'range')
transform(input);
else if (!async)
setTimeout(check, 0, input, true);
}
function transform(slider) {
var isValueSet, areAttrsSet, isChanged, isClick, prevValue, rawValue, prevX;
var min, max, step, range, value = slider.value;
// lazily create shared slider affordance
if (!scale) {
scale = document.body.appendChild(document.createElement('hr'));
style(scale, {
'-moz-appearance': isMac ? 'scale-horizontal' : 'scalethumb-horizontal',
display: 'block',
visibility: 'visible',
opacity: 1,
position: 'fixed',
top: '-999999px'
});
document.mozSetImageElement('__sliderthumb__', scale);
}
// reimplement value and type properties
var getValue = function() { return '' + value; };
var setValue = function setValue(val) {
value = '' + val;
isValueSet = true;
draw();
delete slider.value;
slider.value = value;
slider.__defineGetter__('value', getValue);
slider.__defineSetter__('value', setValue);
};
slider.__defineGetter__('value', getValue);
slider.__defineSetter__('value', setValue);
slider.__defineGetter__('type', function() { return 'range'; });
// sync properties with attributes
['min', 'max', 'step'].forEach(function(prop) {
if (slider.hasAttribute(prop))
areAttrsSet = true;
slider.__defineGetter__(prop, function() {
return this.hasAttribute(prop) ? this.getAttribute(prop) : '';
});
slider.__defineSetter__(prop, function(val) {
val === null ? this.removeAttribute(prop) : this.setAttribute(prop, val);
});
});
// initialize slider
slider.readOnly = true;
style(slider, styles);
update();
slider.addEventListener('DOMAttrModified', function(e) {
// note that value attribute only sets initial value
if (e.attrName == 'value' && !isValueSet) {
value = e.newValue;
draw();
}
else if (~['min', 'max', 'step'].indexOf(e.attrName)) {
update();
areAttrsSet = true;
}
}, true);
slider.addEventListener('mousedown', onDragStart, true);
slider.addEventListener('keydown', onKeyDown, true);
slider.addEventListener('focus', onFocus, true);
slider.addEventListener('blur', onBlur, true);
function onDragStart(e) {
isClick = true;
setTimeout(function() { isClick = false; }, 0);
if (e.button || !range)
return;
var width = parseFloat(getComputedStyle(this, 0).width);
var multiplier = (width - thumb.width) / range;
if (!multiplier)
return;
// distance between click and center of thumb
var dev = e.clientX - this.getBoundingClientRect().left - thumb.width / 2 -
(value - min) * multiplier;
// if click was not on thumb, move thumb to click location
if (Math.abs(dev) > thumb.radius) {
isChanged = true;
this.value -= -dev / multiplier;
}
rawValue = value;
prevX = e.clientX;
this.addEventListener('mousemove', onDrag, true);
this.addEventListener('mouseup', onDragEnd, true);
}
function onDrag(e) {
var width = parseFloat(getComputedStyle(this, 0).width);
var multiplier = (width - thumb.width) / range;
if (!multiplier)
return;
rawValue += (e.clientX - prevX) / multiplier;
prevX = e.clientX;
isChanged = true;
this.value = rawValue;
}
function onDragEnd() {
this.removeEventListener('mousemove', onDrag, true);
this.removeEventListener('mouseup', onDragEnd, true);
}
function onKeyDown(e) {
if (e.keyCode > 36 && e.keyCode < 41) { // 37-40: left, up, right, down
onFocus.call(this);
isChanged = true;
this.value = value + (e.keyCode == 38 || e.keyCode == 39 ? step : -step);
}
}
function onFocus() {
if (!isClick)
this.style.boxShadow = !isMac ? '0 0 0 2px #fb0' :
'0 0 2px 1px -moz-mac-focusring, inset 0 0 1px -moz-mac-focusring';
}
function onBlur() {
this.style.boxShadow = '';
}
// determines whether value is valid number in attribute form
function isAttrNum(value) {
return !isNaN(value) && +value == parseFloat(value);
}
// validates min, max, and step attributes and redraws
function update() {
min = isAttrNum(slider.min) ? +slider.min : 0;
max = isAttrNum(slider.max) ? +slider.max : 100;
if (max < min)
max = min > 100 ? min : 100;
step = isAttrNum(slider.step) && slider.step > 0 ? +slider.step : 1;
range = max - min;
draw(true);
}
// recalculates value property
function calc() {
if (!isValueSet && !areAttrsSet)
value = slider.getAttribute('value');
if (!isAttrNum(value))
value = (min + max) / 2;;
// snap to step intervals (WebKit sometimes does not - bug?)
value = Math.round((value - min) / step) * step + min;
if (value < min)
value = min;
else if (value > max)
value = min + ~~(range / step) * step;
}
// renders slider using CSS background ;)
function draw(attrsModified) {
calc();
if (isChanged && value != prevValue)
slider.dispatchEvent(onChange);
isChanged = false;
if (!attrsModified && value == prevValue)
return;
prevValue = value;
var position = range ? (value - min) / range * 100 : 0;
var bg = '-moz-element(#__sliderthumb__) ' + position + '% no-repeat, ';
style(slider, { background: bg + track });
}
}
function style(element, styles) {
for (var prop in styles)
element.style.setProperty(prop, styles[prop], 'important');
}
})();

View File

@ -0,0 +1,4 @@
Inconsolata
-----------
This font is found at http://www.levien.com/type/myfonts/inconsolata.html

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,97 @@
Copyright (c) <dates>, <Copyright Holder> (<URL|email>),
with Reserved Font Name <Reserved Font Name>.
Copyright (c) <dates>, <additional Copyright Holder> (<URL|email>),
with Reserved Font Name <additional Reserved Font Name>.
Copyright (c) <dates>, <additional Copyright Holder> (<URL|email>).
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

View File

@ -0,0 +1,21 @@
Copyright 2013 jQuery Foundation and other contributors
http://jquery.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

4
extlib/jquery/jquery.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
extlib/lato/Lato-Bold.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
extlib/lato/Lato-Italic.ttf Normal file

Binary file not shown.

Binary file not shown.

97
extlib/lato/OFL_1.1.txt Normal file
View File

@ -0,0 +1,97 @@
Copyright (c) <dates>, <Copyright Holder> (<URL|email>),
with Reserved Font Name <Reserved Font Name>.
Copyright (c) <dates>, <additional Copyright Holder> (<URL|email>),
with Reserved Font Name <additional Reserved Font Name>.
Copyright (c) <dates>, <additional Copyright Holder> (<URL|email>).
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -0,0 +1,88 @@
Leaflet Changelog
=================
## 0.3 (master)
## 0.2.1 (2011-06-18)
* Fixed regression that caused error in `TileLayer.Canvas`
## 0.2 (2011-06-17)
### Major features
* Added **WMS** support (`TileLayer.WMS` layer).
* Added different **projections** support, having `EPSG:3857`, `EPSG:4326` and `EPSG:3395` out of the box (through `crs` option in `Map`). Thanks to [@Miroff](https://github.com/Miroff) & [@Komzpa](https://github.com/Komzpa) for great advice and explanation regarding this.
* Added **GeoJSON** layer support.
### Improvements
#### Usability improvements
* Improved panning performance in Chrome and FF considerably with the help of `requestAnimationFrame`. [#130](https://github.com/CloudMade/Leaflet/issues/130)
* Improved click responsiveness in mobile WebKit (now it happens without delay). [#26](https://github.com/CloudMade/Leaflet/issues/26)
* Added tap tolerance (so click happens even if you moved your finger slighly when tapping).
* Improved geolocation error handling: better error messages, explicit timeout, set world view on locateAndSetView failure. [#61](https://github.com/CloudMade/Leaflet/issues/61)
#### API improvements
* Added **MultiPolyline** and **MultiPolygon** layers. [#77](https://github.com/CloudMade/Leaflet/issues/77)
* Added **LayerGroup** and **FeatureGroup** layers for grouping other layers.
* Added **TileLayer.Canvas** for easy creation of canvas-based tile layers.
* Changed `Circle` to be zoom-dependent (with radius in meters); circle of a permanent size is now called `CircleMarker`.
* Added `mouseover` and `mouseout` events to map, markers and paths; added map `mousemove` event.
* Added `setLatLngs`, `spliceLatLngs`, `addLatLng`, `getLatLngs` methods to polylines and polygons.
* Added `setLatLng` and `setRadius` methods to `Circle` and `CircleMarker`.
* Improved `LatLngBounds contains` method to accept `LatLng` in addition to `LatLngBounds`, the same for `Bounds contains` and `Point`
* Improved `LatLngBounds` & `Bounds` to allow their instantiation without arguments (by [@snc](https://github.com/snc)).
* Added TMS tile numbering support through `TileLayer` `scheme: 'tms'` option (by [@tmcw](https://github.com/tmcw)).
* Added `TileLayer` `noWrap` option to disable wrapping `x` tile coordinate (by [@jasondavies](https://github.com/jasondavies)).
* Added `opacity` option and `setOpacity` method to `TileLayer`.
* Added `setLatLng` and `setIcon` methods to `Marker`.
* Added `title` option to `Marker`.
* Added `maxZoom` argument to `map.locateAndSetView` method.
* Added ability to pass Geolocation options to map `locate` and `locateAndSetView` methods (by [@JasonSanford](https://github.com/JasonSanford)).
* Improved `Popup` to accept HTML elements in addition to strings as its content.
#### Development workflow improvements
* Added `Makefile` for building `leaflet.js` on non-Windows machines (by [@tmcw](https://github.com/tmcw)).
* Improved `debug/leaflet-include.js` script to allow using it outside of `debug` folder (by [@antonj](https://github.com/antonj)).
* Improved `L` definition to be compatible with CommonJS. [#122](https://github.com/CloudMade/Leaflet/issues/122)
### Bug fixes
#### General bugfixes
* Fixed a bug where zooming is broken if the map contains a polygon and you zoom to an area where it's not visible. [#47](https://github.com/CloudMade/Leaflet/issues/47)
* Fixed a bug where closed polylines would not appear on the map.
* Fixed a bug where marker that was added, removed and then added again would not appear on the map. [#66](https://github.com/CloudMade/Leaflet/issues/66)
* Fixed a bug where tile layer that was added, removed and then added again would not appear on the map.
* Fixed a bug where some tiles would not load when panning across the date line. [#97](https://github.com/CloudMade/Leaflet/issues/97)
* Fixed a bug where map div with `position: absolute` is reset to `relative`. [#100](https://github.com/CloudMade/Leaflet/issues/100)
* Fixed a bug that caused an error when trying to add a marker without shadow in its icon.
* Fixed a bug where popup content would not update on `setContent` call. [#94](https://github.com/CloudMade/Leaflet/issues/94)
* Fixed a bug where double click zoom wouldn't work if popup is opened on map click
* Fixed a bug with click propagation on popup close button. [#99](https://github.com/CloudMade/Leaflet/issues/99)
* Fixed inability to remove ImageOverlay layer.
#### Browser bugfixes
* Fixed a bug where paths would not appear in IE8.
* Fixed a bug where there were occasional slowdowns before zoom animation in WebKit. [#123](https://github.com/CloudMade/Leaflet/issues/123)
* Fixed incorrect zoom animation & popup styling in Opera 11.11.
* Fixed popup fade animation in Firefox and Opera.
* Fixed a bug where map isn't displayed in Firefox when there's an `img { max-width: 100% }` rule.
#### Mobile browsers bugfixes
* Fixed a bug that prevented panning on some Android 2.1 (and possibly older) devices. [#84](https://github.com/CloudMade/Leaflet/issues/84)
* Disabled zoom animation on Android by default because it's buggy on some devices (will be enabled back when it's stable enough). [#32](https://github.com/CloudMade/Leaflet/issues/32)
* Fixed a bug where map would occasionally break while multi-touch-zooming on iOS. [#32](https://github.com/CloudMade/Leaflet/issues/32)
* Fixed a bug that prevented panning/clicking on Android 3 tablets. [#121](https://github.com/CloudMade/Leaflet/issues/121)
* Fixed a bug that prevented panning/clicking on Opera Mobile. [#138](https://github.com/CloudMade/Leaflet/issues/138)
* Fixed potentional memory leak on WebKit when removing tiles, thanks to [@Scalar4eg](https://github.com/Scalar4eg). [#107](https://github.com/CloudMade/Leaflet/issues/107)
## 0.1 (2011-05-13)
* Initial Leaflet release.

22
extlib/leaflet/LICENSE Normal file
View File

@ -0,0 +1,22 @@
Copyright (c) 2010-2011, CloudMade, Vladimir Agafonkin
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

10
extlib/leaflet/README.md Normal file
View File

@ -0,0 +1,10 @@
<img src="http://leaflet.cloudmade.com/docs/images/logo.png" alt="Leaflet" />
Leaflet is a modern, lightweight BSD-licensed JavaScript library for making tile-based interactive maps for both desktop and mobile web browsers, developed by [CloudMade](http://cloudmade.com) to form the core of its next generation JavaScript API.
It is built from the ground up to work efficiently and smoothly on both platforms, utilizing cutting-edge technologies included in HTML5. Its top priorities are usability, performance and small size, [A-grade](http://developer.yahoo.com/yui/articles/gbs/) browser support, flexibility and easy to use API. The OOP-based code of the library is designed to be modular, extensible and very easy to understand.
Check out the website for more information: [leaflet.cloudmade.com](http://leaflet.cloudmade.com)
## Contributing to Leaflet
Let's make the best open-source library for maps that can possibly exist! Please send your pull requests to [Vladimir Agafonkin](http://github.com/mourner) (Leaflet maintainer) - we'll be happy to accept your contributions! [List of Leaflet contributors](http://github.com/CloudMade/Leaflet/contributors)

View File

@ -0,0 +1,65 @@
../dist/leaflet.js: Makefile
java -jar ../lib/closure-compiler/compiler.jar \
--js ../src/Leaflet.js \
--js ../src/core/Util.js \
--js ../src/core/Class.js \
--js ../src/core/Events.js \
--js ../src/core/Browser.js \
--js ../src/geometry/Point.js \
--js ../src/geometry/Bounds.js \
--js ../src/geometry/Transformation.js \
--js ../src/geometry/LineUtil.js \
--js ../src/geometry/PolyUtil.js \
--js ../src/dom/DomEvent.js \
--js ../src/dom/DomEvent.DoubleTap.js \
--js ../src/dom/DomUtil.js \
--js ../src/dom/Draggable.js \
--js ../src/dom/transition/Transition.js \
--js ../src/dom/transition/Transition.Native.js \
--js ../src/dom/transition/Transition.Timer.js \
--js ../src/geo/LatLng.js \
--js ../src/geo/LatLngBounds.js \
--js ../src/geo/projection/Projection.js \
--js ../src/geo/projection/Projection.SphericalMercator.js \
--js ../src/geo/projection/Projection.LonLat.js \
--js ../src/geo/projection/Projection.Mercator.js \
--js ../src/geo/crs/CRS.js \
--js ../src/geo/crs/CRS.EPSG3857.js \
--js ../src/geo/crs/CRS.EPSG4326.js \
--js ../src/geo/crs/CRS.EPSG3395.js \
--js ../src/layer/LayerGroup.js \
--js ../src/layer/FeatureGroup.js \
--js ../src/layer/tile/TileLayer.js \
--js ../src/layer/tile/TileLayer.WMS.js \
--js ../src/layer/tile/TileLayer.Canvas.js \
--js ../src/layer/ImageOverlay.js \
--js ../src/layer/Popup.js \
--js ../src/layer/marker/Icon.js \
--js ../src/layer/marker/Marker.js \
--js ../src/layer/marker/Marker.Popup.js \
--js ../src/layer/vector/Path.js \
--js ../src/layer/vector/Path.VML.js \
--js ../src/layer/vector/Path.Popup.js \
--js ../src/layer/vector/Polyline.js \
--js ../src/layer/vector/Polygon.js \
--js ../src/layer/vector/MultiPoly.js \
--js ../src/layer/vector/Circle.js \
--js ../src/layer/vector/CircleMarker.js \
--js ../src/layer/GeoJSON.js \
--js ../src/handler/Handler.js \
--js ../src/handler/MapDrag.js \
--js ../src/handler/TouchZoom.js \
--js ../src/handler/ScrollWheelZoom.js \
--js ../src/handler/DoubleClickZoom.js \
--js ../src/handler/ShiftDragZoom.js \
--js ../src/handler/MarkerDrag.js \
--js ../src/control/Control.js \
--js ../src/control/Control.Zoom.js \
--js ../src/control/Control.Attribution.js \
--js ../src/map/Map.js \
--js ../src/map/ext/Map.Geolocation.js \
--js ../src/map/ext/Map.Popup.js \
--js ../src/map/ext/Map.PanAnimation.js \
--js ../src/map/ext/Map.ZoomAnimation.js \
--js ../src/map/ext/Map.Control.js \
--js_output_file ../dist/leaflet.js

View File

@ -0,0 +1,65 @@
@echo off
java -jar ../lib/closure-compiler/compiler.jar ^
--js ../src/Leaflet.js ^
--js ../src/core/Util.js ^
--js ../src/core/Class.js ^
--js ../src/core/Events.js ^
--js ../src/core/Browser.js ^
--js ../src/geometry/Point.js ^
--js ../src/geometry/Bounds.js ^
--js ../src/geometry/Transformation.js ^
--js ../src/geometry/LineUtil.js ^
--js ../src/geometry/PolyUtil.js ^
--js ../src/dom/DomEvent.js ^
--js ../src/dom/DomEvent.DoubleTap.js ^
--js ../src/dom/DomUtil.js ^
--js ../src/dom/Draggable.js ^
--js ../src/dom/transition/Transition.js ^
--js ../src/dom/transition/Transition.Native.js ^
--js ../src/dom/transition/Transition.Timer.js ^
--js ../src/geo/LatLng.js ^
--js ../src/geo/LatLngBounds.js ^
--js ../src/geo/projection/Projection.js ^
--js ../src/geo/projection/Projection.SphericalMercator.js ^
--js ../src/geo/projection/Projection.LonLat.js ^
--js ../src/geo/projection/Projection.Mercator.js ^
--js ../src/geo/crs/CRS.js ^
--js ../src/geo/crs/CRS.EPSG3857.js ^
--js ../src/geo/crs/CRS.EPSG4326.js ^
--js ../src/geo/crs/CRS.EPSG3395.js ^
--js ../src/layer/LayerGroup.js ^
--js ../src/layer/FeatureGroup.js ^
--js ../src/layer/tile/TileLayer.js ^
--js ../src/layer/tile/TileLayer.WMS.js ^
--js ../src/layer/tile/TileLayer.Canvas.js ^
--js ../src/layer/ImageOverlay.js ^
--js ../src/layer/Popup.js ^
--js ../src/layer/marker/Icon.js ^
--js ../src/layer/marker/Marker.js ^
--js ../src/layer/marker/Marker.Popup.js ^
--js ../src/layer/vector/Path.js ^
--js ../src/layer/vector/Path.VML.js ^
--js ../src/layer/vector/Path.Popup.js ^
--js ../src/layer/vector/Polyline.js ^
--js ../src/layer/vector/Polygon.js ^
--js ../src/layer/vector/MultiPoly.js ^
--js ../src/layer/vector/Circle.js ^
--js ../src/layer/vector/CircleMarker.js ^
--js ../src/layer/GeoJSON.js ^
--js ../src/handler/Handler.js ^
--js ../src/handler/MapDrag.js ^
--js ../src/handler/TouchZoom.js ^
--js ../src/handler/ScrollWheelZoom.js ^
--js ../src/handler/DoubleClickZoom.js ^
--js ../src/handler/ShiftDragZoom.js ^
--js ../src/handler/MarkerDrag.js ^
--js ../src/control/Control.js ^
--js ../src/control/Control.Zoom.js ^
--js ../src/control/Control.Attribution.js ^
--js ../src/map/Map.js ^
--js ../src/map/ext/Map.Geolocation.js ^
--js ../src/map/ext/Map.Popup.js ^
--js ../src/map/ext/Map.PanAnimation.js ^
--js ../src/map/ext/Map.ZoomAnimation.js ^
--js ../src/map/ext/Map.Control.js ^
--js_output_file ../dist/leaflet.js

View File

@ -0,0 +1,208 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Build Helper</title>
<script type="text/javascript" src="deps.js"></script>
<style type="text/css">
body {
font: 12px/1.4 Verdana, sans-serif;
text-align: center;
padding: 2em 0;
}
#container {
text-align: left;
margin: 0 auto;
width: 600px;
}
#deplist {
list-style: none;
padding: 0;
}
#deplist li {
padding-top: 10px;
padding-bottom: 10px;
border-top: 1px solid #eee;
}
#deplist li.heading {
border: none;
background: #eee;
padding: 5px 10px;
margin-top: 10px;
}
#deplist input {
float: left;
margin-right: 5px;
display: inline;
}
#deplist label {
float: left;
width: 190px;
font-weight: bold;
}
#deplist div {
display: table-cell;
height: 1%;
}
#deplist .desc {
}
#deplist .deps {
color: #777;
}
#command {
width: 100%;
}
</style>
</head>
<body>
<div id="container">
<h1>Leaflet Build Helper</h1>
<p>
<a id="select-all" href="#all">Select All</a> |
<a id="deselect-all" href="#none">Deselect All</a>
</p>
<ul id="deplist"></ul>
<p>
Run this command in the build directory:<br />
<input type="text" id="command" />
</p>
</div>
<script type="text/javascript">
var deplist = document.getElementById('deplist'),
commandInput = document.getElementById('command');
document.getElementById('select-all').onclick = function() {
var checks = deplist.getElementsByTagName('input');
for (var i = 0; i < checks.length; i++) {
checks[i].checked = true;
}
updateCommand();
return false;
};
document.getElementById('deselect-all').onclick = function() {
var checks = deplist.getElementsByTagName('input');
for (var i = 0; i < checks.length; i++) {
if (!checks[i].disabled) {
checks[i].checked = false;
}
}
updateCommand();
return false;
};
function updateCommand() {
var files = {};
var checks = deplist.getElementsByTagName('input');
for (var i = 0; i < checks.length; i++) {
if (checks[i].checked) {
var srcs = deps[checks[i].id].src;
for (var j = 0; j < srcs.length; j++) {
files[srcs[j]] = true;
}
}
}
var command = 'java -jar ../lib/closure-compiler/compiler.jar ';
for (var src in files) {
command += '--js ../src/' + src + ' ';
}
command += '--js_output_file ../dist/leaflet-custom.js';
commandInput.value = command;
}
commandInput.onclick = function() {
commandInput.focus();
commandInput.select();
};
function onCheckboxChange() {
if (this.checked) {
var depDeps = deps[this.id].deps;
if (!depDeps) { return; }
for (var i = 0; i < depDeps.length; i++) {
var check = document.getElementById(depDeps[i]);
if (!check.checked) {
check.checked = true;
check.onchange();
}
}
} else {
var checks = deplist.getElementsByTagName('input');
for (var i = 0; i < checks.length; i++) {
var dep = deps[checks[i].id];
if (!dep.deps) { continue; }
for (var j = 0; j < dep.deps.length; j++) {
if (dep.deps[j] == this.id) {
if (checks[i].checked) {
checks[i].checked = false;
checks[i].onchange();
}
}
}
}
}
updateCommand();
}
for (var name in deps) {
var li = document.createElement('li');
if (deps[name].heading) {
var heading = document.createElement('li');
heading.className = 'heading';
heading.appendChild(document.createTextNode(deps[name].heading));
deplist.appendChild(heading);
}
var div = document.createElement('div');
var label = document.createElement('label');
var check = document.createElement('input');
check.type = 'checkbox';
check.id = name;
label.appendChild(check);
check.onchange = onCheckboxChange;
if (name == 'Core') {
check.checked = true;
check.disabled = true;
}
label.appendChild(document.createTextNode(name));
label.htmlFor = name;
li.appendChild(label);
var desc = document.createElement('span');
desc.className = 'desc';
desc.appendChild(document.createTextNode(deps[name].desc));
var depText = deps[name].deps && deps[name].deps.join(', ');
if (depText) {
var depspan = document.createElement('span');
depspan.className = 'deps';
depspan.appendChild(document.createTextNode('Deps: ' + depText));
}
div.appendChild(desc);
div.appendChild(document.createElement('br'));
if (depText) { div.appendChild(depspan); }
li.appendChild(div);
deplist.appendChild(li);
}
updateCommand();
</script>
</body>
</html>

View File

@ -0,0 +1,211 @@
var deps = {
Core: {
src: ['Leaflet.js',
'core/Browser.js',
'core/Class.js',
'core/Events.js',
'core/Util.js',
'dom/DomUtil.js',
'geo/LatLng.js',
'geo/LatLngBounds.js',
'geo/projection/Projection.js',
'geo/projection/Projection.SphericalMercator.js',
'geo/projection/Projection.LonLat.js',
'geo/crs/CRS.js',
'geo/crs/CRS.EPSG3857.js',
'geo/crs/CRS.EPSG4326.js',
'geometry/Bounds.js',
'geometry/Point.js',
'geometry/Transformation.js',
'map/Map.js'],
desc: 'The core of the library, including OOP, events, DOM facilities, basic units, projections (EPSG:3857 and EPSG:4326) and the base Map class.'
},
EPSG3395: {
src: ['geo/projection/Projection.Mercator.js',
'geo/crs/CRS.EPSG3395.js'],
desc: 'EPSG:3395 projection (used by some map providers).',
heading: 'Additional projections'
},
TileLayer: {
src: ['layer/tile/TileLayer.js'],
desc: 'The base class for displaying tile layers on the map.',
heading: 'Layers'
},
TileLayerWMS: {
src: ['layer/tile/TileLayer.WMS.js'],
desc: 'WMS tile layer.',
deps: ['TileLayer']
},
TileLayerCanvas: {
src: ['layer/tile/TileLayer.Canvas.js'],
desc: 'Tile layer made from canvases (for custom drawing purposes).',
deps: ['TileLayer']
},
ImageOverlay: {
src: ['layer/ImageOverlay.js'],
desc: 'Used to display an image over a particular rectangular area of the map.'
},
Marker: {
src: ['layer/marker/Icon.js', 'layer/marker/Marker.js'],
desc: 'Markers to put on the map.'
},
Popup: {
src: ['layer/Popup.js', 'layer/marker/Marker.Popup.js', 'map/ext/Map.Popup.js'],
deps: ['Marker'],
desc: 'Used to display the map popup (used mostly for binding HTML data to markers and paths on click).'
},
LayerGroup: {
src: ['layer/LayerGroup.js'],
desc: 'Allows grouping several layers to handle them as one.'
},
FeatureGroup: {
src: ['layer/FeatureGroup.js'],
deps: ['LayerGroup', 'Popup'],
desc: 'Extends LayerGroup with mouse events and bindPopup method shared between layers.'
},
Path: {
src: ['layer/vector/Path.js', 'layer/vector/Path.Popup.js'],
desc: 'Vector rendering core (SVG-powered), enables overlaying the map with SVG paths.',
heading: 'Vector layers'
},
PathVML: {
src: ['layer/vector/Path.VML.js'],
desc: 'VML fallback for vector rendering core (IE 6-8).'
},
Polyline: {
src: ['geometry/LineUtil.js', 'layer/vector/Polyline.js'],
deps: ['Path'],
desc: 'Polyline overlays.'
},
Polygon: {
src: ['geometry/PolyUtil.js', 'layer/vector/Polygon.js'],
deps: ['Polyline'],
desc: 'Polygon overlays.'
},
MultiPoly: {
src: ['layer/vector/MultiPoly.js'],
deps: ['FeatureGroup', 'Polyline', 'Polygon'],
desc: 'MultiPolygon and MultyPolyline layers.'
},
Circle: {
src: ['layer/vector/Circle.js'],
deps: ['Path'],
desc: 'Circle overlays (with radius in meters).'
},
CircleMarker: {
src: ['layer/vector/CircleMarker.js'],
deps: ['Circle'],
desc: 'Circle overlays with a constant pixel radius.'
},
GeoJSON: {
src: ['layer/GeoJSON.js'],
deps: ['Marker', 'MultiPoly', 'FeatureGroup'],
desc: 'GeoJSON layer, parses the data and adds corresponding layers above.'
},
MapDrag: {
src: ['dom/DomEvent.js',
'dom/Draggable.js',
'handler/Handler.js',
'handler/MapDrag.js'],
desc: 'Makes the map draggable (by mouse or touch).',
heading: 'Interaction'
},
MouseZoom: {
src: ['dom/DomEvent.js',
'handler/Handler.js',
'handler/DoubleClickZoom.js',
'handler/ScrollWheelZoom.js'],
desc: 'Scroll wheel zoom and double click zoom on the map.'
},
TouchZoom: {
src: ['dom/DomEvent.js',
'dom/DomEvent.DoubleTap.js',
'handler/Handler.js',
'handler/TouchZoom.js'],
deps: ['MapAnimationZoom'],
desc: 'Enables smooth touch zooming on iOS and double tap on iOS/Android.'
},
ShiftDragZoom: {
src: ['handler/ShiftDragZoom.js'],
desc: 'Enables zooming to bounding box by shift-dragging the map.'
},
MarkerDrag: {
src: ['handler/MarkerDrag.js'],
desc: 'Makes markers draggable (by mouse or touch).'
},
ControlZoom: {
src: ['control/Control.js',
'map/ext/Map.Control.js',
'control/Control.Zoom.js'],
heading: 'Controls',
desc: 'Basic zoom control with two buttons (zoom in / zoom out).'
},
ControlZoom: {
src: ['control/Control.js',
'map/ext/Map.Control.js',
'control/Control.Attribution.js'],
desc: 'Attribution control.'
},
MapAnimationNative: {
src: ['dom/DomEvent.js',
'dom/transition/Transition.js',
'dom/transition/Transition.Native.js'],
desc: 'Animation core that uses CSS3 Transitions (for powering pan & zoom animations). Works on mobile webkit-powered browsers and some modern desktop browsers.',
heading: 'Visual effects'
},
MapAnimationFallback: {
src: ['dom/transition/Transition.Timer.js'],
deps: ['MapAnimationNative'],
desc: 'Timer-based animation fallback for browsers that don\'t support CSS3 transitions.'
},
MapAnimationPan: {
src: ['map/ext/Map.PanAnimation.js'],
deps: ['MapAnimationNative'],
desc: 'Panning animation. Can use both native and timer-based animation.'
},
MapAnimationZoom: {
src: ['map/ext/Map.ZoomAnimation.js'],
deps: ['MapAnimationPan', 'MapAnimationNative'],
desc: 'Smooth zooming animation. So far it works only on browsers that support CSS3 Transitions.'
},
MapGeolocation: {
src: ['map/ext/Map.Geolocation.js'],
desc: 'Adds Map#locate method and related events to make geolocation easier.',
heading: 'Misc'
}
};

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet debug page</title>
<link rel="stylesheet" href="../../dist/leaflet.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
<link rel="stylesheet" href="../css/screen.css" />
<script src="../include.js"></script>
</head>
<body>
<div id="map"></div>
<script type="text/javascript">
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18}),
latlng = new L.LatLng(50.5, 30.51);
var map = new L.Map('map').addLayer(cloudmade).setView(latlng, 15);
var zoomControl = new L.Control.Zoom();
map.addControl(zoomControl);
</script>
</body>
</html>

View File

@ -0,0 +1,6 @@
html, body, #map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}

View File

@ -0,0 +1,5 @@
#map {
width: 800px;
height: 600px;
border: 1px solid #ccc;
}

View File

@ -0,0 +1,50 @@
var geojsonSample = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [102.0, 0.5]
},
"properties": {
"prop0": "value0",
"color": "blue"
}
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]]
},
"properties": {
"color": "red",
"prop1": 0.0
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]
},
"properties": {
"color": "green",
"prop1": {
"this": "that"
}
}
},
{
"type": "Feature",
"geometry": {
"type": "MultiPolygon",
"coordinates": [[[[100.0, 1.5], [100.5, 1.5], [100.5, 2.0], [100.0, 2.0], [100.0, 1.5]]], [[[100.5, 2.0], [100.5, 2.5], [101.0, 2.5], [101.0, 2.0], [100.5, 2.0]]]]
}
}
]
};

View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet debug page</title>
<link rel="stylesheet" href="../../dist/leaflet.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
<link rel="stylesheet" href="../css/screen.css" />
<script src="../leaflet-include.js"></script>
</head>
<body>
<div id="map" style="width: 600px; height: 600px; border: 1px solid #ccc"></div>
<button id="populate">Populate with 10 markers</button>
<script type="text/javascript" src="geojson-sample.js"></script>
<script type="text/javascript">
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
cloudmadeAttribution = 'Map data &copy; 2011 OpenStreetMap contributors, Imagery &copy; 2011 CloudMade',
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution});
var map = new L.Map('map', {
center: new L.LatLng(0.78, 102.37),
zoom: 7,
layers: [cloudmade]
});
var geojson = new L.GeoJSON();
/* points are rendered as markers by default, but you can change this:
var geojson = new L.GeoJSON(null, {
pointToLayer: function(latlng) { return new L.CircleMarker(latlng); }
});
*/
geojson.on('featureparse', function(e) {
// you can style features depending on their properties, etc.
var popupText = 'geometry type: ' + e.geometryType + '<br/>';
if (e.layer instanceof L.Path) {
e.layer.setStyle({color: e.properties.color});
popupText += 'color: ' + e.properties.color;
}
e.layer.bindPopup(popupText);
});
geojson.addGeoJSON(geojsonSample);
map.addLayer(geojson);
</script>
</body>
</html>

View File

@ -0,0 +1,100 @@
(function() {
//TODO replace script list with the one from ../buid/deps.js
var scripts = [
'Leaflet.js',
'core/Util.js',
'core/Class.js',
'core/Events.js',
'core/Browser.js',
'geometry/Point.js',
'geometry/Bounds.js',
'geometry/Transformation.js',
'geometry/LineUtil.js',
'geometry/PolyUtil.js',
'dom/DomEvent.js',
'dom/DomEvent.DoubleTap.js',
'dom/DomUtil.js',
'dom/Draggable.js',
'dom/transition/Transition.js',
'dom/transition/Transition.Native.js',
'dom/transition/Transition.Timer.js',
'geo/LatLng.js',
'geo/LatLngBounds.js',
'geo/projection/Projection.js',
'geo/projection/Projection.SphericalMercator.js',
'geo/projection/Projection.LonLat.js',
'geo/projection/Projection.Mercator.js',
'geo/crs/CRS.js',
'geo/crs/CRS.EPSG3857.js',
'geo/crs/CRS.EPSG4326.js',
'geo/crs/CRS.EPSG3395.js',
'layer/LayerGroup.js',
'layer/FeatureGroup.js',
'layer/tile/TileLayer.js',
'layer/tile/TileLayer.WMS.js',
'layer/tile/TileLayer.Canvas.js',
'layer/ImageOverlay.js',
'layer/Popup.js',
'layer/marker/Icon.js',
'layer/marker/Marker.js',
'layer/marker/Marker.Popup.js',
'layer/vector/Path.js',
'layer/vector/Path.VML.js',
'layer/vector/Path.Popup.js',
'layer/vector/Polyline.js',
'layer/vector/Polygon.js',
'layer/vector/MultiPoly.js',
'layer/vector/Circle.js',
'layer/vector/CircleMarker.js',
'layer/GeoJSON.js',
'handler/Handler.js',
'handler/MapDrag.js',
'handler/TouchZoom.js',
'handler/DoubleClickZoom.js',
'handler/ScrollWheelZoom.js',
'handler/ShiftDragZoom.js',
'handler/MarkerDrag.js',
'control/Control.js',
'control/Control.Zoom.js',
'control/Control.Attribution.js',
'map/Map.js',
'map/ext/Map.Geolocation.js',
'map/ext/Map.Popup.js',
'map/ext/Map.PanAnimation.js',
'map/ext/Map.ZoomAnimation.js',
'map/ext/Map.Control.js'
];
function getSrcUrl() {
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
var src = scripts[i].src;
if (src) {
var res = src.match(/^(.*)leaflet-include\.js$/);
if (res) {
return res[1] + '../src/';
}
}
}
}
var path = getSrcUrl();
for (var i = 0; i < scripts.length; i++) {
document.writeln("<script type='text/javascript' src='" + path + "../src/" + scripts[i] + "'></script>");
}
})();

View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet debug page</title>
<link rel="stylesheet" href="../../dist/leaflet.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
<link rel="stylesheet" href="../css/screen.css" />
<script src="../leaflet-include.js"></script>
</head>
<body>
<div id="map" style="width: 600px; height: 600px; border: 1px solid #ccc"></div>
<script type="text/javascript">
var tiles = new L.TileLayer.Canvas();
tiles.drawTile = function(canvas, tile, zoom) {
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, 255, 255);
ctx.fillStyle = 'black';
ctx.fillText('x: ' + tile.x + ', y: ' + tile.y + ', zoom:' + zoom, 20, 20);
ctx.strokeStyle = 'red';
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(255, 0);
ctx.lineTo(255, 255);
ctx.lineTo(0, 255);
ctx.closePath();
ctx.stroke();
}
var map = new L.Map('map', {center: new L.LatLng(50.5, 30.51), zoom: 15, layers: [tiles]});
</script>
</body>
</html>

View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet debug page</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<link rel="stylesheet" href="../../dist/leaflet.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
<link rel="stylesheet" href="../css/mobile.css" />
<script src="../leaflet-include.js"></script>
</head>
<body>
<div id="map"></div>
<script type="text/javascript">
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
cloudmadeAttribution = 'Map data &copy; 2011 OpenStreetMap contributors, Imagery &copy; 2011 CloudMade',
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution});
var map = new L.Map('map').addLayer(cloudmade);
map.on('locationfound', function(e) {
var marker = new L.Marker(e.latlng);
map.addLayer(marker);
marker.bindPopup("<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec odio. Quisque volutpat mattis eros. Nullam malesuada erat ut turpis. Suspendisse urna nibh, viverra non, semper suscipit, posuere a, pede.</p><p>Donec nec justo eget felis facilisis fermentum. Aliquam porttitor mauris sit amet orci. Aenean dignissim pellentesque felis.</p>");
});
map.on('locationerror', function(e) {
alert(e.message);
map.fitWorld();
});
map.locateAndSetView();
</script>
</body>
</html>

View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet debug page</title>
<link rel="stylesheet" href="../../dist/leaflet.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
<link rel="stylesheet" href="../css/screen.css" />
<script src="../leaflet-include.js"></script>
</head>
<body>
<div id="map" style="width: 600px; height: 600px; border: 1px solid #ccc"></div>
<button id="populate">Populate with 10 markers</button>
<script type="text/javascript">
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
cloudmadeAttribution = 'Map data &copy; 2011 OpenStreetMap contributors, Imagery &copy; 2011 CloudMade',
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution}),
latlng = new L.LatLng(50.5, 30.51);
var map = new L.Map('map', {center: latlng, zoom: 15, layers: [cloudmade]});
var markers = new L.FeatureGroup();
function populate() {
var bounds = map.getBounds(),
southWest = bounds.getSouthWest(),
northEast = bounds.getNorthEast(),
lngSpan = northEast.lng - southWest.lng,
latSpan = northEast.lat - southWest.lat;
for (var i = 0; i < 10; i++) {
var latlng = new L.LatLng(
southWest.lat + latSpan * Math.random(),
southWest.lng + lngSpan * Math.random());
markers.addLayer(new L.Marker(latlng));
}
return false;
};
markers.bindPopup("<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec odio. Quisque volutpat mattis eros. Nullam malesuada erat ut turpis. Suspendisse urna nibh, viverra non, semper suscipit, posuere a, pede.</p><p>Donec nec justo eget felis facilisis fermentum. Aliquam porttitor mauris sit amet orci. Aenean dignissim pellentesque.</p>");
map.addLayer(markers);
populate();
L.DomUtil.get('populate').onclick = populate;
</script>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet debug page</title>
<link rel="stylesheet" href="../../dist/leaflet.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
<link rel="stylesheet" href="../css/screen.css" />
<script src="../leaflet-include.js"></script>
</head>
<body>
<div id="map" style="width: 1024px; height: 440px; border: 1px solid #ccc"></div>
<script type="text/javascript">
var map = new L.Map('map', {crs: L.CRS.EPSG4326});
var bluemarble = new L.TileLayer.WMS("http://maps.opengeo.org/geowebcache/service/wms", {
layers: 'bluemarble',
attribution: "Data &copy; NASA Blue Marble, image service by OpenGeo",
minZoom: 2,
maxZoom: 5,
});
map.addLayer(bluemarble).fitWorld();
</script>
</body>
</html>

View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet debug page</title>
<link rel="stylesheet" href="../../dist/leaflet.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
<link rel="stylesheet" href="../css/screen.css" />
<script src="../leaflet-include.js"></script>
</head>
<body>
<div id="map" style="width: 800px; height: 600px; border: 1px solid #ccc"></div>
<script type="text/javascript">
var map = new L.Map('map');
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
cloudmadeAttribution = 'Map data &copy; 2011 OpenStreetMap contributors, Imagery &copy; 2011 CloudMade',
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution});
var nexrad = new L.TileLayer.WMS("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", {
layers: 'nexrad-n0r-900913',
format: 'image/png',
transparent: true,
attribution: "Weather data &copy; 2011 IEM Nexrad",
opacity: 0.4
});
var bounds = new L.LatLngBounds(new L.LatLng(32, -126), new L.LatLng(50, -64));
map.addLayer(cloudmade).addLayer(nexrad).fitBounds(bounds);
</script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More