diff --git a/commons/res/layout/detail_main_panel.xml b/commons/res/layout/detail_main_panel.xml
index dd6f9ae15..2a321f856 100644
--- a/commons/res/layout/detail_main_panel.xml
+++ b/commons/res/layout/detail_main_panel.xml
@@ -31,6 +31,14 @@
android:text="Description of the media goes here. This can potentially be fairly long, and will need to wrap across multiple lines. We hope it looks nice though."
android:id="@+id/mediaDetailDesc"
android:layout_gravity="left|start"/>
+
Download
License
+
CC\u00A0Attribution-ShareAlike\u00A03.0
CC\u00A0Attribution\u00A03.0
CC0
+
+
+ CC BY-SA 3.0
+ CC BY-SA 3.0 (Austria)
+ CC BY-SA 3.0 (Germany)
+ CC BY-SA 3.0 (Estonia)
+ CC BY-SA 3.0 (Spain)
+ CC BY-SA 3.0 (Croatia)
+ CC BY-SA 3.0 (Luxembourg)
+ CC BY-SA 3.0 (Netherlands)
+ CC BY-SA 3.0 (Norway)
+ CC BY-SA 3.0 (Poland)
+ CC BY-SA 3.0 (Romania)
+ CC BY 3.0
+ CC Zero
+ own-pd
+ CC BY-SA 2.5
+ CC BY 2.5
+ CC BY-SA 2.0
+ CC BY-SA 2.0
+ CC BY 2.0
+ Free Art License
+ Public domain (author died over 100 years ago)
+ Public domain (copyright expired)
+ Public domain (art)
+ Public domain (US)
+ Public domain (US government)
+ Public domain (NASA)
+ Public domain (ineligible for copyright)
+ Attribution
+ GNU Free Documentation License
+
Contribute your images. Help Wikipedia articles come to life!
Images on Wikipedia come from Wikimedia Commons.
Your images help educate people around the world.
diff --git a/commons/res/xml/wikimedia_licenses.xml b/commons/res/xml/wikimedia_licenses.xml
new file mode 100644
index 000000000..e23bcbfc5
--- /dev/null
+++ b/commons/res/xml/wikimedia_licenses.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/commons/src/main/java/org/wikimedia/commons/License.java b/commons/src/main/java/org/wikimedia/commons/License.java
new file mode 100644
index 000000000..caa9bc4d6
--- /dev/null
+++ b/commons/src/main/java/org/wikimedia/commons/License.java
@@ -0,0 +1,46 @@
+package org.wikimedia.commons;
+
+public class License {
+ String key;
+ String template;
+ String url;
+ String name;
+
+ public License(String key, String template, String url, String name) {
+ if (key == null) {
+ throw new RuntimeException("License.key must not be null");
+ }
+ if (template == null) {
+ throw new RuntimeException("License.template must not be null");
+ }
+ this.key = key;
+ this.template = template;
+ this.url = url;
+ this.name = name;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getTemplate() {
+ return template;
+ }
+
+ public String getName() {
+ if (name == null) {
+ // hack
+ return getKey();
+ } else {
+ return name;
+ }
+ }
+
+ public String getUrl(String language) {
+ if (url == null) {
+ return null;
+ } else {
+ return url.replace("$lang", language);
+ }
+ }
+}
diff --git a/commons/src/main/java/org/wikimedia/commons/LicenseList.java b/commons/src/main/java/org/wikimedia/commons/LicenseList.java
new file mode 100644
index 000000000..b9da572b2
--- /dev/null
+++ b/commons/src/main/java/org/wikimedia/commons/LicenseList.java
@@ -0,0 +1,75 @@
+package org.wikimedia.commons;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.util.Log;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class LicenseList {
+ Map licenses = new HashMap();
+ Resources res;
+
+ private static String XMLNS_LICENSE = "https://www.mediawiki.org/wiki/Extension:UploadWizard/xmlns/licenses";
+
+ public LicenseList(Activity activity) {
+ res = activity.getResources();
+ XmlPullParser parser = res.getXml(R.xml.wikimedia_licenses);
+ while (Utils.xmlFastForward(parser, XMLNS_LICENSE, "license")) {
+ String id = parser.getAttributeValue(null, "id");
+ String template = parser.getAttributeValue(null, "template");
+ String url = parser.getAttributeValue(null, "url");
+ String name = nameForTemplate(template);
+ License license = new License(id, template, url, name);
+ licenses.put(id, license);
+ }
+
+ }
+
+ public Set keySet() {
+ return licenses.keySet();
+ }
+
+ public Collection values() {
+ return licenses.values();
+ }
+
+ public License get(String key) {
+ return licenses.get(key);
+ }
+
+ public License licenseForTemplate(String template) {
+ String ucTemplate = Utils.capitalize(template);
+ for (License license : values()) {
+ if (ucTemplate.equals(Utils.capitalize(license.getTemplate()))) {
+ return license;
+ }
+ }
+ return null;
+ }
+
+ public String nameIdForTemplate(String template) {
+ // hack :D
+ // cc-by-sa-3.0 -> cc_by_sa_3_0
+ return "license_name_" + template.toLowerCase().replace("-", "_").replace(".", "_");
+ }
+
+ private int stringIdByName(String stringId) {
+ return res.getIdentifier("org.wikimedia.commons:string/" + stringId, null, null);
+ }
+
+ public String nameForTemplate(String template) {
+ Log.d("Commons", "LicenseList.nameForTemplate: template: " + template);
+ String stringId = nameIdForTemplate(template);
+ Log.d("Commons", "LicenseList.nameForTemplate: stringId: " + stringId);
+ int nameId = stringIdByName(stringId);
+ Log.d("Commons", "LicenseList.nameForTemplate: nameId: " + nameId);
+ String name = res.getString(nameId);
+ Log.d("Commons", "LicenseList.nameForTemplate: name: " + name);
+ return name;
+ }
+}
diff --git a/commons/src/main/java/org/wikimedia/commons/MediaDataExtractor.java b/commons/src/main/java/org/wikimedia/commons/MediaDataExtractor.java
index 8f0c049dd..357025615 100644
--- a/commons/src/main/java/org/wikimedia/commons/MediaDataExtractor.java
+++ b/commons/src/main/java/org/wikimedia/commons/MediaDataExtractor.java
@@ -33,16 +33,19 @@ public class MediaDataExtractor {
private Map descriptions;
private String author;
private Date date;
+ private String license;
+ private LicenseList licenseList;
/**
* @param filename of the target media object, should include 'File:' prefix
*/
- public MediaDataExtractor(String filename) {
+ public MediaDataExtractor(String filename, LicenseList licenseList) {
this.filename = filename;
categories = new ArrayList();
descriptions = new HashMap();
fetched = false;
processed = false;
+ this.licenseList = licenseList;
}
/**
@@ -114,7 +117,41 @@ public class MediaDataExtractor {
descriptions = getMultilingualText(descriptionNode);
Node authorNode = findTemplateParameter(templateNode, "author");
- author = Utils.getStringFromDOM(authorNode);
+ author = getFlatText(authorNode);
+ }
+
+ /*
+ Pull up the license data list...
+ look for the templates in two ways:
+ * look for 'self' template and check its first parameter
+ * if none, look for any of the known templates
+ */
+ Log.d("Commons", "MediaDataExtractor searching for license");
+ Node selfLicenseNode = findTemplate(doc.getDocumentElement(), "self");
+ if (selfLicenseNode != null) {
+ Node firstNode = findTemplateParameter(selfLicenseNode, 1);
+ String licenseTemplate = getFlatText(firstNode);
+ License license = licenseList.licenseForTemplate(licenseTemplate);
+ if (license == null) {
+ Log.d("Commons", "MediaDataExtractor found no matching license for self parameter: " + licenseTemplate + "; faking it");
+ this.license = licenseTemplate; // hack hack! For non-selectable licenses that are still in the system.
+ } else {
+ // fixme: record the self-ness in here too... sigh
+ // all this needs better server-side metadata
+ this.license = license.getKey();
+ Log.d("Commons", "MediaDataExtractor found self-license " + this.license);
+ }
+ } else {
+ for (License license : licenseList.values()) {
+ String templateName = license.getTemplate();
+ Node template = findTemplate(doc.getDocumentElement(), templateName);
+ if (template != null) {
+ // Found!
+ this.license = license.getKey();
+ Log.d("Commons", "MediaDataExtractor found non-self license " + this.license);
+ break;
+ }
+ }
}
}
@@ -201,6 +238,10 @@ public class MediaDataExtractor {
throw new IOException("No matching template parameter node found.");
}
+ private String getFlatText(Node parentNode) throws IOException {
+ return parentNode.getTextContent();
+ }
+
// Extract a dictionary of multilingual texts from a subset of the parse tree.
// Texts are wrapped in things like {{en|foo} or {{en|1=foo bar}}.
// Text outside those wrappers is stuffed into a 'default' faux language key if present.
@@ -246,6 +287,9 @@ public class MediaDataExtractor {
media.setCategories(categories);
media.setDescriptions(descriptions);
+ if (license != null) {
+ media.setLicense(license);
+ }
// add author, date, etc fields
}
diff --git a/commons/src/main/java/org/wikimedia/commons/Utils.java b/commons/src/main/java/org/wikimedia/commons/Utils.java
index 49868d57d..54e5f3013 100644
--- a/commons/src/main/java/org/wikimedia/commons/Utils.java
+++ b/commons/src/main/java/org/wikimedia/commons/Utils.java
@@ -10,6 +10,8 @@ import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.net.URLCodec;
import org.w3c.dom.Node;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import javax.xml.transform.*;
import java.io.*;
@@ -194,4 +196,33 @@ public class Utils {
String uriStr = CommonsApplication.HOME_URL + urlEncode(underscored);
return Uri.parse(uriStr);
}
+
+ /**
+ * Fast-forward an XmlPullParser to the next instance of the given element
+ * in the input stream (namespaced).
+ *
+ * @param parser
+ * @param namespace
+ * @param element
+ * @return true on match, false on failure
+ */
+ public static boolean xmlFastForward(XmlPullParser parser, String namespace, String element) {
+ try {
+ while (parser.next() != XmlPullParser.END_DOCUMENT) {
+ if (parser.getEventType() == XmlPullParser.START_TAG &&
+ parser.getNamespace().equals(namespace) &&
+ parser.getName().equals(element)) {
+ // We found it!
+ return true;
+ }
+ }
+ return false;
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ return false;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
}
diff --git a/commons/src/main/java/org/wikimedia/commons/media/MediaDetailFragment.java b/commons/src/main/java/org/wikimedia/commons/media/MediaDetailFragment.java
index e06d441b8..a09638bd3 100644
--- a/commons/src/main/java/org/wikimedia/commons/media/MediaDetailFragment.java
+++ b/commons/src/main/java/org/wikimedia/commons/media/MediaDetailFragment.java
@@ -59,6 +59,7 @@ public class MediaDetailFragment extends SherlockFragment {
private TextView title;
private TextView desc;
+ private TextView license;
private ListView listView;
private ArrayList categoryNames;
private boolean categoriesLoaded = false;
@@ -133,6 +134,7 @@ public class MediaDetailFragment extends SherlockFragment {
spacer = (MediaDetailSpacer) detailView.findViewById(R.id.mediaDetailSpacer);
title = (TextView) detailView.findViewById(R.id.mediaDetailTitle);
desc = (TextView) detailView.findViewById(R.id.mediaDetailDesc);
+ license = (TextView) detailView.findViewById(R.id.mediaDetailLicense);
// Enable or disable editing on the title
/*
@@ -160,10 +162,12 @@ public class MediaDetailFragment extends SherlockFragment {
// FIXME: cache this data
detailFetchTask = new AsyncTask() {
private MediaDataExtractor extractor;
+ private LicenseList licenseList;
@Override
protected void onPreExecute() {
- extractor = new MediaDataExtractor(media.getFilename());
+ licenseList = new LicenseList(getActivity());
+ extractor = new MediaDataExtractor(media.getFilename(), licenseList);
}
@Override
@@ -187,6 +191,16 @@ public class MediaDetailFragment extends SherlockFragment {
// Fill some fields
desc.setText(media.getDescription("en"));
+ String licenseKey = media.getLicense();
+ License licenseObj = licenseList.get(licenseKey);
+ if (licenseObj == null) {
+ license.setText(licenseKey);
+ } else {
+ license.setText(licenseObj.getName());
+ }
+ Log.d("Commons", "Media license is: " + media.getLicense());
+
+
categoryNames.removeAll(categoryNames);
categoryNames.addAll(media.getCategories());
@@ -231,7 +245,8 @@ public class MediaDetailFragment extends SherlockFragment {
}
title.setText(media.getDisplayTitle());
- desc.setText("");
+ desc.setText(""); // fill in from network...
+ license.setText(""); // fill in from network...
/*
title.addTextChangedListener(new TextWatcher() {
diff --git a/update-license-info/Makefile b/update-license-info/Makefile
new file mode 100644
index 000000000..a234667a5
--- /dev/null
+++ b/update-license-info/Makefile
@@ -0,0 +1,14 @@
+.FAKE : build update clean install
+
+build : ../commons/res/xml/wikimedia_licenses.xml
+
+../commons/res/xml/wikimedia_licenses.xml : licenses.php mediawiki-extensions-UploadWizard
+ php licenses.php > ../commons/res/xml/wikimedia_licenses.xml
+
+mediawiki-extensions-UploadWizard : update
+
+update :
+ if [ -d mediawiki-extensions-UploadWizard ]; then (cd mediawiki-extensions-UploadWizard && git pull origin master); else git clone https://gerrit.wikimedia.org/r/mediawiki/extensions/UploadWizard mediawiki-extensions-UploadWizard; fi
+
+clean :
+ rm -rf mediawiki-extensions-UploadWizard
diff --git a/update-license-info/include-stubs.php b/update-license-info/include-stubs.php
new file mode 100644
index 000000000..c0a01a0d6
--- /dev/null
+++ b/update-license-info/include-stubs.php
@@ -0,0 +1,68 @@
+ 'English' );
+ }
+}
+$wgMemc = new FakeMemc();
+
+class FakeMessage {
+ function plain() {
+ return 'stub-message-plain';
+ }
+ function parse() {
+ return 'stub-message-parsed';
+ }
+}
+
+function wfMessage() {
+ return new FakeMessage();
+}
+
+/**
+ * Converts shorthand byte notation to integer form
+ *
+ * @param $string String
+ * @return Integer
+ */
+function wfShorthandToInteger( $string = '' ) {
+ $string = trim( $string );
+ if ( $string === '' ) {
+ return -1;
+ }
+ $last = $string[strlen( $string ) - 1];
+ $val = intval( $string );
+ switch ( $last ) {
+ case 'g':
+ case 'G':
+ $val *= 1024;
+ // break intentionally missing
+ case 'm':
+ case 'M':
+ $val *= 1024;
+ // break intentionally missing
+ case 'k':
+ case 'K':
+ $val *= 1024;
+ }
+
+ return $val;
+}
+
+$wgAPIModules = array();
diff --git a/update-license-info/licenses.php b/update-license-info/licenses.php
new file mode 100644
index 000000000..badda1a08
--- /dev/null
+++ b/update-license-info/licenses.php
@@ -0,0 +1,71 @@
+
+// 2013-09-30
+
+require 'include-stubs.php';
+$config = require "mediawiki-extensions-UploadWizard/UploadWizard.config.php";
+require "mediawiki-extensions-UploadWizard/UploadWizard.i18n.php";
+$licenseList = array();
+
+foreach ( $config['licenses'] as $key => $license ) {
+ // Determine template -> license mappings
+ if ( isset( $license['templates'] ) ) {
+ $templates = $license['templates'];
+ } else {
+ $templates = array( $key );
+ }
+
+ if ( count( $templates ) < 1 ) {
+ throw new Exception("No templates for $key, this is wrong.");
+ }
+ if ( count( $templates ) > 1 ) {
+ //echo "Skipping multi-template license: $key\n";
+ continue;
+ }
+ $template = $templates[0];
+ if ( preg_match( '/^subst:/i', $template ) ) {
+ //echo "Skipping subst license: $key\n";
+ continue;
+ }
+
+ $msg = $messages['en'][$license['msg']];
+
+ $licenseInfo = array(
+ 'desc' => $msg,
+ 'template' => $template
+ );
+ if ( isset( $license['url'] ) ) {
+ $url = $license['url'];
+ if ( substr( $url, 0, 2 ) == '//' ) {
+ $url = 'https:' . $url;
+ }
+ if ( isset( $license['languageCodePrefix'] ) ) {
+ $url .= $license['languageCodePrefix'] . '$lang';
+ }
+ $licenseInfo['url'] = $url;
+ }
+ $licenseList[$key] = $licenseInfo;
+}
+
+//var_dump( $licenseList );
+
+echo "\n";
+echo "\n";
+foreach( $licenseList as $key => $licenseInfo ) {
+ $encId = htmlspecialchars( $key );
+ echo " \n";
+
+}
+echo "\n";
+
\ No newline at end of file