Merge "Extract and show license key"

This commit is contained in:
Brion Vibber 2013-10-09 21:09:13 +00:00 committed by Gerrit Code Review
commit 9206e78e34
11 changed files with 440 additions and 4 deletions

View file

@ -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"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="License link"
android:id="@+id/mediaDetailLicense"
android:layout_gravity="left|start"
android:textColor="@android:color/white"
android:textSize="18sp" /> <!-- 18sp == MediumText -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View file

@ -93,9 +93,42 @@
<string name="menu_download">Download</string>
<string name="preference_license">License</string>
<!-- These three are semi-legacy entries, and should be changed in future -->
<string name="license_name_cc_by_sa">CC\u00A0Attribution-ShareAlike\u00A03.0</string>
<string name="license_name_cc_by">CC\u00A0Attribution\u00A03.0</string>
<string name="license_name_cc0">CC0</string>
<!-- Licenses from the default UploadWizard selection list -->
<string name="license_name_cc_by_sa_3_0">CC BY-SA 3.0</string>
<string name="license_name_cc_by_sa_3_0_at">CC BY-SA 3.0 (Austria)</string>
<string name="license_name_cc_by_sa_3_0_de">CC BY-SA 3.0 (Germany)</string>
<string name="license_name_cc_by_sa_3_0_ee">CC BY-SA 3.0 (Estonia)</string>
<string name="license_name_cc_by_sa_3_0_es">CC BY-SA 3.0 (Spain)</string>
<string name="license_name_cc_by_sa_3_0_hr">CC BY-SA 3.0 (Croatia)</string>
<string name="license_name_cc_by_sa_3_0_lu">CC BY-SA 3.0 (Luxembourg)</string>
<string name="license_name_cc_by_sa_3_0_nl">CC BY-SA 3.0 (Netherlands)</string>
<string name="license_name_cc_by_sa_3_0_no">CC BY-SA 3.0 (Norway)</string>
<string name="license_name_cc_by_sa_3_0_pl">CC BY-SA 3.0 (Poland)</string>
<string name="license_name_cc_by_sa_3_0_ro">CC BY-SA 3.0 (Romania)</string>
<string name="license_name_cc_by_3_0">CC BY 3.0</string>
<string name="license_name_cc_zero">CC Zero</string>
<string name="license_name_own_pd">own-pd</string>
<string name="license_name_cc_by_sa_2_5">CC BY-SA 2.5</string>
<string name="license_name_cc_by_2_5">CC BY 2.5</string>
<string name="license_name_cc_by_sa_2_0">CC BY-SA 2.0</string>
<string name="license_name_cc_by_2_0">CC BY-SA 2.0</string>
<string name="license_name_cc_2_0">CC BY 2.0</string>
<string name="license_name_fal">Free Art License</string>
<string name="license_name_pd_old_100">Public domain (author died over 100 years ago)</string>
<string name="license_name_pd_old">Public domain (copyright expired)</string>
<string name="license_name_pd_art">Public domain (art)</string>
<string name="license_name_pd_us">Public domain (US)</string>
<string name="license_name_pd_usgov">Public domain (US government)</string>
<string name="license_name_pd_usgov_nasa">Public domain (NASA)</string>
<string name="license_name_pd_ineligible">Public domain (ineligible for copyright)</string>
<string name="license_name_attribution">Attribution</string>
<string name="license_name_gfdl">GNU Free Documentation License</string>
<string name="welcome_wikipedia_text">Contribute your images. Help Wikipedia articles come to life!</string>
<string name="welcome_wikipedia_subtext">Images on Wikipedia come from Wikimedia Commons.</string>
<string name="welcome_copyright_text">Your images help educate people around the world.</string>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<licenses xmlns="https://www.mediawiki.org/wiki/Extension:UploadWizard/xmlns/licenses">
<license id="cc-by-sa-3.0" template="cc-by-sa-3.0" url="https://creativecommons.org/licenses/by-sa/3.0/deed.$lang"/>
<license id="cc-by-sa-3.0-at" template="cc-by-sa-3.0-at" url="https://creativecommons.org/licenses/by-sa/3.0/at/deed.$lang"/>
<license id="cc-by-sa-3.0-de" template="cc-by-sa-3.0-de" url="https://creativecommons.org/licenses/by-sa/3.0/de/deed.$lang"/>
<license id="cc-by-sa-3.0-ee" template="cc-by-sa-3.0-ee" url="https://creativecommons.org/licenses/by-sa/3.0/ee/deed.$lang"/>
<license id="cc-by-sa-3.0-es" template="cc-by-sa-3.0-es" url="https://creativecommons.org/licenses/by-sa/3.0/es/deed.$lang"/>
<license id="cc-by-sa-3.0-hr" template="cc-by-sa-3.0-hr" url="https://creativecommons.org/licenses/by-sa/3.0/hr/deed.$lang"/>
<license id="cc-by-sa-3.0-lu" template="cc-by-sa-3.0-lu" url="https://creativecommons.org/licenses/by-sa/3.0/lu/deed.$lang"/>
<license id="cc-by-sa-3.0-nl" template="cc-by-sa-3.0-nl" url="https://creativecommons.org/licenses/by-sa/3.0/nl/deed.$lang"/>
<license id="cc-by-sa-3.0-no" template="cc-by-sa-3.0-no" url="https://creativecommons.org/licenses/by-sa/3.0/no/deed.$lang"/>
<license id="cc-by-sa-3.0-pl" template="cc-by-sa-3.0-pl" url="https://creativecommons.org/licenses/by-sa/3.0/pl/deed.$lang"/>
<license id="cc-by-sa-3.0-ro" template="cc-by-sa-3.0-ro" url="https://creativecommons.org/licenses/by-sa/3.0/ro/deed.$lang"/>
<license id="cc-by-3.0" template="cc-by-3.0" url="https://creativecommons.org/licenses/by/3.0/deed.$lang"/>
<license id="cc-zero" template="cc-zero" url="https://creativecommons.org/publicdomain/zero/1.0/deed.$lang"/>
<license id="own-pd" template="cc-zero"/>
<license id="cc-by-sa-2.5" template="cc-by-sa-2.5" url="https://creativecommons.org/licenses/by-sa/2.5/deed.$lang"/>
<license id="cc-by-2.5" template="cc-by-2.5" url="https://creativecommons.org/licenses/by/2.5/deed.$lang"/>
<license id="cc-by-sa-2.0" template="cc-by-sa-2.0" url="https://creativecommons.org/licenses/by-sa/2.0/deed.$lang"/>
<license id="cc-by-2.0" template="cc-by-2.0" url="https://creativecommons.org/licenses/by/2.0/deed.$lang"/>
<license id="fal" template="FAL"/>
<license id="pd-old-100" template="PD-old-100"/>
<license id="pd-old" template="PD-old"/>
<license id="pd-art" template="PD-Art"/>
<license id="pd-us" template="PD-US"/>
<license id="pd-usgov" template="PD-USGov"/>
<license id="pd-usgov-nasa" template="PD-USGov-NASA"/>
<license id="pd-ineligible" template="pd-ineligible"/>
<license id="attribution" template="attribution"/>
<license id="gfdl" template="GFDL"/>
</licenses>

View file

@ -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);
}
}
}

View file

@ -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<String, License> licenses = new HashMap<String, License>();
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<String> keySet() {
return licenses.keySet();
}
public Collection<License> 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;
}
}

View file

@ -33,16 +33,19 @@ public class MediaDataExtractor {
private Map<String, String> 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<String>();
descriptions = new HashMap<String, String>();
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
}

View file

@ -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;
}
}
}

View file

@ -59,6 +59,7 @@ public class MediaDetailFragment extends SherlockFragment {
private TextView title;
private TextView desc;
private TextView license;
private ListView listView;
private ArrayList<String> 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<Void, Void, Boolean>() {
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() {

View file

@ -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

View file

@ -0,0 +1,68 @@
<?php
// Stubs for enough of the MediaWiki environment to run UploadWizard.config.php
global $wgFileExtensions, $wgServer, $wgScriptPath, $wgAPIModules, $wgMaxUploadSize, $wgLang, $wgMemc, $wgUploadWizardConfig;
class FakeLang {
function getCode() {
return 'en';
}
}
$wgLang = new FakeLang();
function wfMemcKey() {
return 'fake-key';
}
class FakeMemc {
function get() {
return array( 'en' => '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();

View file

@ -0,0 +1,71 @@
<?php
// Quick hack to extract default license list from UploadWizard configuration.
// In future, try to export this info via the API on wiki so we can pull dynamically.
//
// Brion Vibber <brion@pobox.com>
// 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 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
echo "<licenses xmlns=\"https://www.mediawiki.org/wiki/Extension:UploadWizard/xmlns/licenses\">\n";
foreach( $licenseList as $key => $licenseInfo ) {
$encId = htmlspecialchars( $key );
echo " <license id=\"$encId\"";
$encTemplate = htmlspecialchars( $licenseInfo['template'] );
echo " template=\"$encTemplate\"";
if ( isset( $licenseInfo['url'] ) ) {
$encUrl = htmlspecialchars( $licenseInfo['url'] );
echo " url=\"$encUrl\"";
}
echo "/>\n";
}
echo "</licenses>\n";