Merge remote-tracking branch 'cweb/master'
This commit is contained in:
commit
2719d546a5
37
.gitignore
vendored
Normal file
37
.gitignore
vendored
Normal 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
6
.gitmodules
vendored
Normal 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
8
.tx/config
Normal 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
82
AUTHORS
Normal 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
69
COPYING
Normal 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
11
MANIFEST.in
Normal 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
41
README
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
========
|
||||||
|
README
|
||||||
|
========
|
||||||
|
|
||||||
|
What is GNU MediaGoblin?
|
||||||
|
========================
|
||||||
|
|
||||||
|
* Initially, a place to store all your photos that’s 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. We’re 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
161
api-docs/Makefile
Normal 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
246
api-docs/source/conf.py
Normal 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
22
api-docs/source/index.rst
Normal 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`
|
||||||
|
|
7
api-docs/source/modules.rst
Normal file
7
api-docs/source/modules.rst
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
mediagoblin
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 4
|
||||||
|
|
||||||
|
mediagoblin
|
29
api-docs/source/themes/mg/layout.html
Normal file
29
api-docs/source/themes/mg/layout.html
Normal 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 %}
|
BIN
api-docs/source/themes/mg/static/fonts/Lato-Bold.ttf
Normal file
BIN
api-docs/source/themes/mg/static/fonts/Lato-Bold.ttf
Normal file
Binary file not shown.
BIN
api-docs/source/themes/mg/static/fonts/Lato-BoldItalic.ttf
Normal file
BIN
api-docs/source/themes/mg/static/fonts/Lato-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
api-docs/source/themes/mg/static/fonts/Lato-Italic.ttf
Normal file
BIN
api-docs/source/themes/mg/static/fonts/Lato-Italic.ttf
Normal file
Binary file not shown.
BIN
api-docs/source/themes/mg/static/fonts/Lato-Regular.ttf
Normal file
BIN
api-docs/source/themes/mg/static/fonts/Lato-Regular.ttf
Normal file
Binary file not shown.
97
api-docs/source/themes/mg/static/fonts/OFL_1.1.txt
Normal file
97
api-docs/source/themes/mg/static/fonts/OFL_1.1.txt
Normal 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.
|
BIN
api-docs/source/themes/mg/static/logo_docs.png
Normal file
BIN
api-docs/source/themes/mg/static/logo_docs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
161
api-docs/source/themes/mg/static/mg.css
Normal file
161
api-docs/source/themes/mg/static/mg.css
Normal 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;
|
||||||
|
}
|
5
api-docs/source/themes/mg/theme.conf
Normal file
5
api-docs/source/themes/mg/theme.conf
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[theme]
|
||||||
|
inherit = basic
|
||||||
|
stylesheet = mg.css
|
||||||
|
pygments_style = sphinx
|
||||||
|
|
16
babel.ini
Normal file
16
babel.ini
Normal 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
179
devtools/maketarball.sh
Executable 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
56
devtools/update_translations.sh
Executable 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
153
docs/Makefile
Normal 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."
|
BIN
docs/source/_static/goblin.png
Normal file
BIN
docs/source/_static/goblin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
0
docs/source/_static/placeholder
Normal file
0
docs/source/_static/placeholder
Normal file
BIN
docs/source/_static/snugglygoblin.png
Normal file
BIN
docs/source/_static/snugglygoblin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 160 KiB |
247
docs/source/conf.py
Normal file
247
docs/source/conf.py
Normal 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'
|
183
docs/source/devel/codebase.rst
Normal file
183
docs/source/devel/codebase.rst
Normal 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
|
||||||
|
|
||||||
|
|
336
docs/source/devel/originaldesigndecisions.rst
Normal file
336
docs/source/devel/originaldesigndecisions.rst
Normal 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.
|
||||||
|
|
||||||
|
|
125
docs/source/devel/storage.rst
Normal file
125
docs/source/devel/storage.rst
Normal 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
100
docs/source/index.rst
Normal 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|.
|
1
docs/source/plugindocs/flatpagesfile.rst
Normal file
1
docs/source/plugindocs/flatpagesfile.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
.. include:: ../../../mediagoblin/plugins/flatpagesfile/README.rst
|
1
docs/source/plugindocs/oauth.rst
Normal file
1
docs/source/plugindocs/oauth.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
.. include:: ../../../mediagoblin/plugins/oauth/README.rst
|
2
docs/source/plugindocs/raven.rst
Normal file
2
docs/source/plugindocs/raven.rst
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.. _raven-setup: Set up the raven plugin
|
||||||
|
.. include:: ../../../mediagoblin/plugins/raven/README.rst
|
1
docs/source/plugindocs/sampleplugin.rst
Normal file
1
docs/source/plugindocs/sampleplugin.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
.. include:: ../../../mediagoblin/plugins/sampleplugin/README.rst
|
1
docs/source/plugindocs/trim_whitespace.rst
Normal file
1
docs/source/plugindocs/trim_whitespace.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
.. include:: ../../../mediagoblin/plugins/trim_whitespace/README.rst
|
296
docs/source/pluginwriter/api.rst
Normal file
296
docs/source/pluginwriter/api.rst
Normal 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}
|
114
docs/source/pluginwriter/database.rst
Normal file
114
docs/source/pluginwriter/database.rst
Normal 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()
|
43
docs/source/pluginwriter/foreward.rst
Normal file
43
docs/source/pluginwriter/foreward.rst
Normal 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.
|
||||||
|
|
188
docs/source/pluginwriter/quickstart.rst
Normal file
188
docs/source/pluginwriter/quickstart.rst
Normal 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.
|
64
docs/source/pluginwriter/tests.rst
Normal file
64
docs/source/pluginwriter/tests.rst
Normal 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!
|
102
docs/source/siteadmin/about.rst
Normal file
102
docs/source/siteadmin/about.rst
Normal 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/
|
131
docs/source/siteadmin/configuration.rst
Normal file
131
docs/source/siteadmin/configuration.rst
Normal 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.
|
390
docs/source/siteadmin/deploying.rst
Normal file
390
docs/source/siteadmin/deploying.rst
Normal 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.
|
48
docs/source/siteadmin/foreword.rst
Normal file
48
docs/source/siteadmin/foreword.rst
Normal 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.
|
||||||
|
|
29
docs/source/siteadmin/help.rst
Normal file
29
docs/source/siteadmin/help.rst
Normal 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/
|
||||||
|
|
||||||
|
|
245
docs/source/siteadmin/media-types.rst
Normal file
245
docs/source/siteadmin/media-types.rst
Normal 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
|
||||||
|
|
||||||
|
|
177
docs/source/siteadmin/plugins.rst
Normal file
177
docs/source/siteadmin/plugins.rst
Normal 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!
|
133
docs/source/siteadmin/production-deployments.rst
Normal file
133
docs/source/siteadmin/production-deployments.rst
Normal 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
|
||||||
|
.. --------------
|
300
docs/source/siteadmin/relnotes.rst
Normal file
300
docs/source/siteadmin/relnotes.rst
Normal 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.
|
281
docs/source/siteadmin/theming.rst
Normal file
281
docs/source/siteadmin/theming.rst
Normal 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!
|
29
docs/source/themes/mg/layout.html
Normal file
29
docs/source/themes/mg/layout.html
Normal 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 %}
|
1
docs/source/themes/mg/static/fonts/Lato-Bold.ttf
Symbolic link
1
docs/source/themes/mg/static/fonts/Lato-Bold.ttf
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../../extlib/lato/Lato-Bold.ttf
|
1
docs/source/themes/mg/static/fonts/Lato-BoldItalic.ttf
Symbolic link
1
docs/source/themes/mg/static/fonts/Lato-BoldItalic.ttf
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../../extlib/lato/Lato-BoldItalic.ttf
|
1
docs/source/themes/mg/static/fonts/Lato-Italic.ttf
Symbolic link
1
docs/source/themes/mg/static/fonts/Lato-Italic.ttf
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../../extlib/lato/Lato-Italic.ttf
|
1
docs/source/themes/mg/static/fonts/Lato-Regular.ttf
Symbolic link
1
docs/source/themes/mg/static/fonts/Lato-Regular.ttf
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../../extlib/lato/Lato-Regular.ttf
|
1
docs/source/themes/mg/static/fonts/OFL_1.1.txt
Symbolic link
1
docs/source/themes/mg/static/fonts/OFL_1.1.txt
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../../extlib/lato/OFL_1.1.txt
|
BIN
docs/source/themes/mg/static/logo_docs.png
Normal file
BIN
docs/source/themes/mg/static/logo_docs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
161
docs/source/themes/mg/static/mg.css
Normal file
161
docs/source/themes/mg/static/mg.css
Normal 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;
|
||||||
|
}
|
5
docs/source/themes/mg/theme.conf
Normal file
5
docs/source/themes/mg/theme.conf
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[theme]
|
||||||
|
inherit = basic
|
||||||
|
stylesheet = mg.css
|
||||||
|
pygments_style = sphinx
|
||||||
|
|
84
extlib/README
Normal file
84
extlib/README
Normal 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
1896
extlib/exif/EXIF.py
Executable file
File diff suppressed because it is too large
Load Diff
1
extlib/exif/LICENSE
Normal file
1
extlib/exif/LICENSE
Normal file
@ -0,0 +1 @@
|
|||||||
|
See top of EXIF.py for license and copyright.
|
131
extlib/exif/changes.txt
Normal file
131
extlib/exif/changes.txt
Normal 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
31
extlib/flask-wtf/LICENSE
Normal 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
125
extlib/flask-wtf/html5.py
Normal 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()
|
616
extlib/freesound/audioprocessing.py
Normal file
616
extlib/freesound/audioprocessing.py
Normal 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
|
268
extlib/html5slider/html5slider.js
Normal file
268
extlib/html5slider/html5slider.js
Normal 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');
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
4
extlib/inconsolata/INFO.txt
Normal file
4
extlib/inconsolata/INFO.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Inconsolata
|
||||||
|
-----------
|
||||||
|
|
||||||
|
This font is found at http://www.levien.com/type/myfonts/inconsolata.html
|
BIN
extlib/inconsolata/Inconsolata.otf
Normal file
BIN
extlib/inconsolata/Inconsolata.otf
Normal file
Binary file not shown.
1088
extlib/inconsolata/Inconsolata.pfa
Normal file
1088
extlib/inconsolata/Inconsolata.pfa
Normal file
File diff suppressed because it is too large
Load Diff
5730
extlib/inconsolata/Inconsolata.sfd
Normal file
5730
extlib/inconsolata/Inconsolata.sfd
Normal file
File diff suppressed because it is too large
Load Diff
97
extlib/inconsolata/OFL_1.1.txt
Normal file
97
extlib/inconsolata/OFL_1.1.txt
Normal 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.
|
BIN
extlib/inconsolata/textest.pdf
Normal file
BIN
extlib/inconsolata/textest.pdf
Normal file
Binary file not shown.
21
extlib/jquery/MIT-LICENSE.txt
Normal file
21
extlib/jquery/MIT-LICENSE.txt
Normal 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
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
BIN
extlib/lato/Lato-Bold.ttf
Normal file
Binary file not shown.
BIN
extlib/lato/Lato-BoldItalic.ttf
Normal file
BIN
extlib/lato/Lato-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
extlib/lato/Lato-Italic.ttf
Normal file
BIN
extlib/lato/Lato-Italic.ttf
Normal file
Binary file not shown.
BIN
extlib/lato/Lato-Regular.ttf
Normal file
BIN
extlib/lato/Lato-Regular.ttf
Normal file
Binary file not shown.
97
extlib/lato/OFL_1.1.txt
Normal file
97
extlib/lato/OFL_1.1.txt
Normal 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.
|
88
extlib/leaflet/CHANGELOG.md
Normal file
88
extlib/leaflet/CHANGELOG.md
Normal 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
22
extlib/leaflet/LICENSE
Normal 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
10
extlib/leaflet/README.md
Normal 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)
|
65
extlib/leaflet/build/Makefile
Normal file
65
extlib/leaflet/build/Makefile
Normal 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
|
65
extlib/leaflet/build/build.bat
Normal file
65
extlib/leaflet/build/build.bat
Normal 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
|
208
extlib/leaflet/build/build.html
Normal file
208
extlib/leaflet/build/build.html
Normal 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>
|
211
extlib/leaflet/build/deps.js
Normal file
211
extlib/leaflet/build/deps.js
Normal 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'
|
||||||
|
}
|
||||||
|
};
|
29
extlib/leaflet/debug/control/map-control.html
Normal file
29
extlib/leaflet/debug/control/map-control.html
Normal 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>
|
6
extlib/leaflet/debug/css/mobile.css
Normal file
6
extlib/leaflet/debug/css/mobile.css
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
html, body, #map {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
5
extlib/leaflet/debug/css/screen.css
Normal file
5
extlib/leaflet/debug/css/screen.css
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#map {
|
||||||
|
width: 800px;
|
||||||
|
height: 600px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
50
extlib/leaflet/debug/geojson/geojson-sample.js
Normal file
50
extlib/leaflet/debug/geojson/geojson-sample.js
Normal 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]]]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
56
extlib/leaflet/debug/geojson/geojson.html
Normal file
56
extlib/leaflet/debug/geojson/geojson.html
Normal 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 © 2011 OpenStreetMap contributors, Imagery © 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>
|
100
extlib/leaflet/debug/leaflet-include.js
Normal file
100
extlib/leaflet/debug/leaflet-include.js
Normal 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>");
|
||||||
|
}
|
||||||
|
})();
|
46
extlib/leaflet/debug/map/canvas.html
Normal file
46
extlib/leaflet/debug/map/canvas.html
Normal 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>
|
42
extlib/leaflet/debug/map/map-mobile.html
Normal file
42
extlib/leaflet/debug/map/map-mobile.html
Normal 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 © 2011 OpenStreetMap contributors, Imagery © 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>
|
56
extlib/leaflet/debug/map/map.html
Normal file
56
extlib/leaflet/debug/map/map.html
Normal 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 © 2011 OpenStreetMap contributors, Imagery © 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>
|
30
extlib/leaflet/debug/map/wms-marble.html
Normal file
30
extlib/leaflet/debug/map/wms-marble.html
Normal 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 © NASA Blue Marble, image service by OpenGeo",
|
||||||
|
minZoom: 2,
|
||||||
|
maxZoom: 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
map.addLayer(bluemarble).fitWorld();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
37
extlib/leaflet/debug/map/wms.html
Normal file
37
extlib/leaflet/debug/map/wms.html
Normal 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 © 2011 OpenStreetMap contributors, Imagery © 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 © 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
Loading…
x
Reference in New Issue
Block a user