From 58f0037becb372dff3dfde6f770f84af1d67eda3 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Thu, 21 Aug 2014 14:07:24 +0200 Subject: Initial commit. --- mediawiki.lrdevplugin/Info.lua | 27 +++ mediawiki.lrdevplugin/MediaWikiApi.lua | 194 +++++++++++++++ .../MediaWikiExportServiceProvider.lua | 266 +++++++++++++++++++++ mediawiki.lrdevplugin/MediaWikiInterface.lua | 85 +++++++ mediawiki.lrdevplugin/TranslatedStrings_de.txt | 32 +++ 5 files changed, 604 insertions(+) create mode 100755 mediawiki.lrdevplugin/Info.lua create mode 100755 mediawiki.lrdevplugin/MediaWikiApi.lua create mode 100755 mediawiki.lrdevplugin/MediaWikiExportServiceProvider.lua create mode 100755 mediawiki.lrdevplugin/MediaWikiInterface.lua create mode 100755 mediawiki.lrdevplugin/TranslatedStrings_de.txt (limited to 'mediawiki.lrdevplugin') diff --git a/mediawiki.lrdevplugin/Info.lua b/mediawiki.lrdevplugin/Info.lua new file mode 100755 index 0000000..5636a42 --- /dev/null +++ b/mediawiki.lrdevplugin/Info.lua @@ -0,0 +1,27 @@ +-- This file is part of the LrMediaWiki project and distributed under the terms +-- of the MIT license (see LICENSE.txt file in the project root directory or +-- [0]). See [1] for more information about LrMediaWiki. +-- +-- Copyright (C) 2014 by the LrMediaWiki team (see CREDITS.txt file in the +-- project root directory or [2]) +-- +-- [0] +-- [1] +-- [2] + +return { + LrSdkVersion = 5.0, + LrToolkitIdentifier = 'org.ireas.lightroom.mediawiki', + LrPluginName = LOC '$$$/LrMediaWiki/PluginName=MediaWiki for Lightroom', + + LrExportServiceProvider = { + title = LOC '$$$/LrMediaWiki/MediaWiki=MediaWiki', + file = 'MediaWikiExportServiceProvider.lua', + }, + + VERSION = { + major = 0, + minor = 1, + revision = 0, + }, +} \ No newline at end of file diff --git a/mediawiki.lrdevplugin/MediaWikiApi.lua b/mediawiki.lrdevplugin/MediaWikiApi.lua new file mode 100755 index 0000000..420ab9f --- /dev/null +++ b/mediawiki.lrdevplugin/MediaWikiApi.lua @@ -0,0 +1,194 @@ +-- This file is part of the LrMediaWiki project and distributed under the terms +-- of the MIT license (see LICENSE.txt file in the project root directory or +-- [0]). See [1] for more information about LrMediaWiki. +-- +-- Copyright (C) 2014 by the LrMediaWiki team (see CREDITS.txt file in the +-- project root directory or [2]) +-- +-- [0] +-- [1] +-- [2] + +-- Code status: +-- doc: partly +-- i18n: complete + +local LrErrors = import 'LrErrors' +local LrHttp = import 'LrHttp' +local LrPathUtils = import 'LrPathUtils' +local LrXml = import 'LrXml' + +local Info = require 'Info' + +local MediaWikiApi = { + userAgent = string.format('LrMediaWiki %d.%d', Info.VERSION.major, Info.VERSION.minor), + apiPath = nil, +} + +--- URL-encode a string according to RFC 3986. +-- Based on http://lua-users.org/wiki/StringRecipes +-- @param str the string to encode +-- @return the URL-encoded string +function MediaWikiApi.urlEncode(str) + if str then + str = string.gsub(str, '\n', '\r\n') + str = string.gsub (str, '([^%w %-%_%.%~])', + function(c) return string.format('%%%02X', string.byte(c)) end) + str = string.gsub(str, ' ', '+') + end + return str +end + +--- Convert HTTP arguments to a URL-encoded request body. +-- @param arguments (table) the arguments to convert +-- @return (string) a request body created from the URL-encoded arguments +function MediaWikiApi.createRequestBody(arguments) + local body = nil + for key, value in pairs(arguments) do + if body then + body = body .. '&' + else + body = '' + end + body = body .. MediaWikiApi.urlEncode(key) .. '=' .. MediaWikiApi.urlEncode(value) + end + return body +end + +function MediaWikiApi.parseXmlDom(xmlDomInstance) + local value = nil + if xmlDomInstance:type() == 'element' then + value = {} + for key, attribute in pairs(xmlDomInstance:attributes()) do + value[key] = attribute.value + end + for i = 1, xmlDomInstance:childCount() do + local child = xmlDomInstance:childAtIndex(i) + local childName, childNamespace = child:name() + value[childName] = MediaWikiApi.parseXmlDom(child) + end + elseif xmlDomInstance:type() == 'text' then + value = xmlDomInstance:text() + end + return value +end + +function MediaWikiApi.performRequest(arguments) + arguments.format = 'xml' + local requestBody = MediaWikiApi.createRequestBody(arguments) + local requestHeaders = { + { + field = 'User-Agent', + value = MediaWikiApi.userAgent, + }, + { + field = 'Content-Type', + value = 'application/x-www-form-urlencoded', + }, + } + + local resultBody, resultHeaders = LrHttp.post(MediaWikiApi.apiPath, requestBody, requestHeaders) + + if resultHeaders.status ~= 200 then + LrErrors.throwUserError(LOC('$$$/LrMediaWiki/Api/HttpError=Received HTTP status ^1.', resultHeaders.status)) + end + + local resultXml = MediaWikiApi.parseXmlDom(LrXml.parseXml(resultBody)) + if resultXml.error then + LrErrors.throwUserError(LOC('$$$/LrMediaWiki/Api/MediaWikiError=The MediaWiki error ^1 occured: ^2', resultXml.error.code, resultXml.error.info)) + end + return resultXml +end + +function MediaWikiApi.login(username, password, token) + local arguments = { + action = 'login', + lgname = username, + lgpassword = password, + } + if token then + arguments.lgtoken = token + end + local xml = MediaWikiApi.performRequest(arguments) + + local loginResult = xml.login.result + if loginResult == 'Success' then + return true + elseif not token and loginResult == 'NeedToken' then + return MediaWikiApi.login(username, password, xml.login.token) + end + + return loginResult +end + +function MediaWikiApi.getEditToken() + local arguments = { + action = 'tokens', + } + local xml = MediaWikiApi.performRequest(arguments) + return xml.tokens.edittoken +end + +function MediaWikiApi.existsFile(fileName) + local arguments = { + action = 'query', + titles = 'File:' .. fileName, + } + local xml = MediaWikiApi.performRequest(arguments) + return xml.query and xml.query.pages and xml.query.pages.page and not xml.query.pages.page.missing +end + +function MediaWikiApi.upload(fileName, sourceFilePath, text, comment, ignoreWarnings) + local sourceFileName = LrPathUtils.leafName(sourceFilePath) + + local arguments = { + action = 'upload', + filename = fileName, + text = text, + comment = comment, + token = MediaWikiApi.getEditToken(), + format = 'xml', + } + if ignoreWarnings then + arguments.ignorewarnings = 'true' + end + local requestHeaders = { + { + field = 'User-Agent', + value = MediaWikiApi.userAgent, + }, + } + local requestBody = {} + for key, value in pairs(arguments) do + requestBody[#requestBody + 1] = { + name = key, + value = value, + } + end + requestBody[#requestBody + 1] = { + name = 'file', + fileName = sourceFileName, + filePath = sourceFilePath, + contentType = 'application/octet-stream', + } + + local resultBody, resultHeaders = LrHttp.postMultipart(MediaWikiApi.apiPath, requestBody, requestHeaders) + + if resultHeaders.status ~= 200 then + LrErrors.throwUserError(LOC('$$$/LrMediaWiki/Api/HttpError=Received HTTP status ^1.', resultHeaders.status)) + end + + local resultXml = MediaWikiApi.parseXmlDom(LrXml.parseXml(resultBody)) + if resultXml.error then + LrErrors.throwUserError(LOC('$$$/LrMediaWiki/Api/MediaWikiError=The MediaWiki error ^1 occured: ^2', resultXml.error.code, resultXml.error.info)) + end + + local uploadResult = resultXml.upload.result + if uploadResult == 'Success' then + return true + else + return uploadResult + end +end + +return MediaWikiApi diff --git a/mediawiki.lrdevplugin/MediaWikiExportServiceProvider.lua b/mediawiki.lrdevplugin/MediaWikiExportServiceProvider.lua new file mode 100755 index 0000000..fb39619 --- /dev/null +++ b/mediawiki.lrdevplugin/MediaWikiExportServiceProvider.lua @@ -0,0 +1,266 @@ +-- This file is part of the LrMediaWiki project and distributed under the terms +-- of the MIT license (see LICENSE.txt file in the project root directory or +-- [0]). See [1] for more information about LrMediaWiki. +-- +-- Copyright (C) 2014 by the LrMediaWiki team (see CREDITS.txt file in the +-- project root directory or [2]) +-- +-- [0] +-- [1] +-- [2] + +-- Code status: +-- doc: missing +-- i18n: complete + +local LrDialogs = import 'LrDialogs' +local LrErrors = import 'LrErrors' +local LrFileUtils = import 'LrFileUtils' +local LrView = import 'LrView' + +local bind = LrView.bind + +local MediaWikiInterface = require 'MediaWikiInterface' + +local MediaWikiExportServiceProvider = {} + +local isStringEmpty = function(str) + return str == nil or string.match(str, '^%s*$') ~= nil +end + +MediaWikiExportServiceProvider.processRenderedPhotos = function(functionContext, exportContext) + -- configure progess display + local exportSession = exportContext.exportSession + local photoCount = exportSession:countRenditions() + local progressScope = exportContext:configureProgress{ + title = photoCount > 1 and LOC('$$$/LrMediaWiki/Export/Progress=Exporting ^1 photos to a MediaWiki', photoCount) or LOC '$$$/LrMediaWiki/Export/Progress/One=Exporting one photo to a MediaWiki', + } + + local exportSettings = assert(exportContext.propertyTable) + + -- require username, password, apipath, license, author, source + if isStringEmpty(exportSettings.username) then + LrErrors.throwUserError(LOC '$$$/LrMediaWiki/Export/NoUsername=No username given!') + end + if isStringEmpty(exportSettings.password) then + LrErrors.throwUserError(LOC '$$$/LrMediaWiki/Export/NoPassword=No password given!') + end + if isStringEmpty(exportSettings.api_path) then + LrErrors.throwUserError(LOC '$$$/LrMediaWiki/Export/NoApiPath=No API path given!') + end + if isStringEmpty(exportSettings.info_license) then + LrErrors.throwUserError(LOC '$$$/LrMediaWiki/Export/NoLicense=No license given!') + end + if isStringEmpty(exportSettings.info_author) then + LrErrors.throwUserError(LOC '$$$/LrMediaWiki/Export/NoAuthor=No author given!') + end + if isStringEmpty(exportSettings.info_source) then + LrErrors.throwUserError(LOC '$$$/LrMediaWiki/Export/NoSource=No source given!') + end + + MediaWikiInterface.prepareUpload(exportSettings.username, exportSettings.password, exportSettings.api_path) + + -- iterate over photos + for i, rendition in exportContext:renditions() do + -- render photo + local success, pathOrMessage = rendition:waitForRender() + if success then + -- do upload to MediaWiki + local photo = rendition.photo + + local fallbackDescription = exportSettings.fallback_description + local description = photo:getFormattedMetadata('caption') + if isStringEmpty(description) then + if fallbackDescription then + description = fallbackDescription + else + rendition:uploadFailed(LOC '$$$/LrMediaWiki/Export/NoDescription=No description given for this file!') + end + end + local source = exportSettings.info_source + local timestampSeconds = photo:getRawMetadata('dateTimeOriginal') + local timestamp = '' + if timestampSeconds then + timestamp = os.date("!%Y-%m-%d", timestampSeconds + 978307200) + end + local author = exportSettings.info_author + local license = exportSettings.info_license + local other = exportSettings.info_other + local categories = exportSettings.info_categories + + local fileDescription = MediaWikiInterface.buildFileDescription(description, source, timestamp, author, license, other, categories) + + MediaWikiInterface.uploadFile(pathOrMessage, fileDescription) + LrFileUtils.delete(pathOrMessage) + else + -- rendering failed --> report failure + rendition:uploadFailed(pathOrMessage) + end + end +end + +MediaWikiExportServiceProvider.sectionsForTopOfDialog = function(viewFactory, propertyTable) + return { + { + title = LOC '$$$/LrMediaWiki/Section/User/Title=Login Information', + synopsis = bind 'username', + + viewFactory:row { + spacing = viewFactory:control_spacing(), + + viewFactory:static_text { + title = LOC '$$$/LrMediaWiki/Section/User/Username=Username', + }, + + viewFactory:edit_field { + value = bind 'username', + immediate = true, + }, + }, + + viewFactory:row { + spacing = viewFactory:control_spacing(), + + viewFactory:static_text { + title = LOC '$$$/LrMediaWiki/Section/User/Password=Password', + }, + + viewFactory:password_field { + value = bind 'password', + }, + }, + + viewFactory:row { + spacing = viewFactory:control_spacing(), + + viewFactory:static_text { + title = LOC '$$$/LrMediaWiki/Section/User/ApiPath=API path', + }, + + viewFactory:edit_field { + value = bind 'api_path', + immediate = true, + width_in_chars = 30, + }, + + viewFactory:static_text { + title = LOC '$$$/LrMediaWiki/Section/User/ApiPath/Details=Path to the api.php file', + }, + }, + }, + { + title = LOC "$$$/LrMediaWiki/Section/Licensing/Title=Upload Information", + synopsis = bind 'info_license', + + viewFactory:row { + spacing = viewFactory:control_spacing(), + + viewFactory:static_text { + title = LOC '$$$/LrMediaWiki/Section/Licensing/DefaultDescription=Default description', + }, + + viewFactory:edit_field { + value = bind 'fallback_description', + immediate = true, + width_in_chars = 30, + height_in_lines = 3, + }, + }, + + viewFactory:row { + spacing = viewFactory:control_spacing(), + + viewFactory:static_text { + title = LOC '$$$/LrMediaWiki/Section/Licensing/Source=Source', + }, + + viewFactory:edit_field { + value = bind 'info_source', + immediate = true, + }, + }, + + viewFactory:row { + spacing = viewFactory:control_spacing(), + + viewFactory:static_text { + title = LOC '$$$/LrMediaWiki/Section/Licensing/Author=Author', + }, + + viewFactory:edit_field { + value = bind 'info_author', + immediate = true, + }, + }, + + viewFactory:row { + spacing = viewFactory:control_spacing(), + + viewFactory:static_text { + title = LOC '$$$/LrMediaWiki/Section/Licensing/License=License', + }, + + viewFactory:edit_field { + value = bind 'info_license', + immediate = true, + }, + }, + + viewFactory:row { + spacing = viewFactory:control_spacing(), + + viewFactory:static_text { + title = LOC '$$$/LrMediaWiki/Section/Licensing/Other=Other fields', + }, + + viewFactory:edit_field { + value = bind 'info_other', + immediate = true, + }, + }, + + viewFactory:row { + spacing = viewFactory:control_spacing(), + + viewFactory:static_text { + title = LOC '$$$/LrMediaWiki/Section/Licensing/Categories=Categories', + }, + + viewFactory:edit_field { + value = bind 'info_categories', + immediate = true, + width_in_chars = 30, + height_in_lines = 3, + }, + + viewFactory:static_text { + title = LOC '$$$/LrMediaWiki/Section/Licensing/Categories/Details=separate with ;', + }, + }, + }, + } +end + +MediaWikiExportServiceProvider.hidePrintResolution = true + +MediaWikiExportServiceProvider.showSections = {'fileNaming', 'metadata'} + +MediaWikiExportServiceProvider.allowFileFormats = {'JPEG', 'TIFF'} + +MediaWikiExportServiceProvider.allowColorSpaces = {'sRGB'} + +MediaWikiExportServiceProvider.canExportVideo = false + +MediaWikiExportServiceProvider.exportPresetFields = { + { key = 'username', default = '' }, + { key = 'password', default = '' }, + { key = 'api_path', default = 'https://commons.wikimedia.org/w/api.php' }, + { key = 'fallback_description', default = '' }, + { key = 'info_source', default = '{{own}}' }, + { key = 'info_author', default = '' }, + { key = 'info_license', default = '{{Cc-by-sa-4.0}}' }, + { key = 'info_other', default = '' }, + { key = 'info_categories', default = '' }, +} + +return MediaWikiExportServiceProvider \ No newline at end of file diff --git a/mediawiki.lrdevplugin/MediaWikiInterface.lua b/mediawiki.lrdevplugin/MediaWikiInterface.lua new file mode 100755 index 0000000..14ef24e --- /dev/null +++ b/mediawiki.lrdevplugin/MediaWikiInterface.lua @@ -0,0 +1,85 @@ +-- This file is part of the LrMediaWiki project and distributed under the terms +-- of the MIT license (see LICENSE.txt file in the project root directory or +-- [0]). See [1] for more information about LrMediaWiki. +-- +-- Copyright (C) 2014 by the LrMediaWiki team (see CREDITS.txt file in the +-- project root directory or [2]) +-- +-- [0] +-- [1] +-- [2] + +-- Code status: +-- doc: missing +-- i18n: complete + +local LrDialogs = import 'LrDialogs' +local LrErrors = import 'LrErrors' +local LrPathUtils = import 'LrPathUtils' + +local MediaWikiApi = require 'MediaWikiApi' + + +local MediaWikiInterface = { + username = nil, + password = nil, + loggedIn = false, + fileDescriptionPattern = [=[== {{int:filedesc}} == +{{Information +|Description=%s +|Source=%s +|Date=%s +|Author=%s +|Permission= +|other_versions= +|other_fields=%s +}} +== {{int:license-header}} == +%s +%s[[Category:Uploaded with LrMediaWiki]]]=], +} + +MediaWikiInterface.prepareUpload = function(username, password, apiPath) + if username and password then + MediaWikiInterface.username = username + MediaWikiInterface.password = password + MediaWikiApi.apiPath = apiPath + local loginResult = MediaWikiApi.login(username, password) + if loginResult ~= true then + LrErrors.throwUserError(LOC('$$$/LrMediaWiki/Interface/LoginFailed=Login failed: ^1.', loginResult)) + end + MediaWikiInterface.loggedIn = true + else + LrErrors.throwUserError(LOC '$$$/LrMediaWiki/Interface/UsernameOrPasswordMissing=Username or password missing') + end +end + +MediaWikiInterface.uploadFile = function(filePath, description) + if not MediaWikiInterface.loggedIn then + LrErrors.throwUserError(LOC '$$$/LrMediaWiki/Interface/Internal/NotLoggedIn=Internal error: not logged in before upload.') + end + local targetFileName = LrPathUtils.leafName(filePath) + local ignorewarnings = false + if MediaWikiApi.existsFile(targetFileName) then + local continue = LrDialogs.confirm(LOC '$$$/LrMediaWiki/Interface/InUse=File name already in use', LOC('$$$/LrMediaWiki/Interface/InUse/Details=There already is a file with the name ^1. Overwrite? (File description won\'t be changed.)', targetFileName)) + if continue == 'ok' then + ignorewarnings = true + else + return + end + end + local uploadResult = MediaWikiApi.upload(targetFileName, filePath, description, 'Uploaded with LrMediaWiki', ignorewarnings) + if uploadResult ~= true then + LrErrors.throwUserError(LOC('$$$/LrMediaWiki/Interface/UploadFailed=Upload failed: ^1', uploadResult)) + end +end + +MediaWikiInterface.buildFileDescription = function(description, source, timestamp, author, license, other, categories) + local categoriesString = '' + for category in string.gmatch(categories, '[^;]+') do + categoriesString = categoriesString .. string.format('[[Category:%s]]\n', category) + end + return string.format(MediaWikiInterface.fileDescriptionPattern, description, source, timestamp, author, other, license, categoriesString) +end + +return MediaWikiInterface \ No newline at end of file diff --git a/mediawiki.lrdevplugin/TranslatedStrings_de.txt b/mediawiki.lrdevplugin/TranslatedStrings_de.txt new file mode 100755 index 0000000..e5ffbb8 --- /dev/null +++ b/mediawiki.lrdevplugin/TranslatedStrings_de.txt @@ -0,0 +1,32 @@ +"$$$/LrMediaWiki/PluginName=MediaWiki für Lightroom" +"$$$/LrMediaWiki/MediaWiki=MediaWiki" +"$$$/LrMediaWiki/Export/Progress=Exportiere ^1 Bilder in ein MediaWiki" +"$$$/LrMediaWiki/Export/Progress/One=Exportiere ein Bild in ein MediaWiki" +"$$$/LrMediaWiki/Export/NoUsername=Kein Benutzername angegeben!" +"$$$/LrMediaWiki/Export/NoPassword=Keine Passwort angegeben!" +"$$$/LrMediaWiki/Export/NoApiPath=Kein API-Pfad angegeben!" +"$$$/LrMediaWiki/Export/NoLicense=Keine Lizenz angegeben!" +"$$$/LrMediaWiki/Export/NoAuthor=Kein Urheber angegeben!" +"$$$/LrMediaWiki/Export/NoSource=Keine Quelle angegeben!" +"$$$/LrMediaWiki/Export/NoDescription=Für diese Datei ist keine Beschreibung angegeben!" +"$$$/LrMediaWiki/Section/User/Title=Login-Informationen" +"$$$/LrMediaWiki/Section/User/Username=Benutzername" +"$$$/LrMediaWiki/Section/User/Password=Passwort" +"$$$/LrMediaWiki/Section/User/ApiPath=API-Pfad" +"$$$/LrMediaWiki/Section/User/ApiPath/Details=Pfad zur api.php-Datei" +"$$$/LrMediaWiki/Section/Licensing/Title=Upload-Informationen" +"$$$/LrMediaWiki/Section/Licensing/DefaultDescription=Standard-Beschreibung" +"$$$/LrMediaWiki/Section/Licensing/Source=Quelle" +"$$$/LrMediaWiki/Section/Licensing/Author=Urheber" +"$$$/LrMediaWiki/Section/Licensing/License=Lizenz" +"$$$/LrMediaWiki/Section/Licensing/Other=Andere Felder" +"$$$/LrMediaWiki/Section/Licensing/Categories=Kategorien" +"$$$/LrMediaWiki/Section/Licensing/Categories/Details=mit ; trennen" +"$$$/LrMediaWiki/Api/HttpError=HTTP-Status ^1 erhalten." +"$$$/LrMediaWiki/Api/MediaWikiError=Der MediaWiki-Fehler ^1 ist aufgetreten: ^2" +"$$$/LrMediaWiki/Interface/LoginFailed=Login fehlgeschlagen: ^1." +"$$$/LrMediaWiki/Interface/UsernameOrPasswordMissing=Nutzername oder Password nicht angegeben +"$$$/LrMediaWiki/Interface/Internal/NotLoggedIn=Interner Fehler: vor dem Upload nicht angemeldet." +"$$$/LrMediaWiki/Interface/InUse=Dateiname schon verwendet" +"$$$/LrMediaWiki/Interface/InUse/Details=Es gibt bereits eine Datei mit dem Namen ^1. Überschreiben? (Die Dateibeschreibung wird nicht verändert.)" +"$$$/LrMediaWiki/Interface/UploadFailed=Upload fehlgeschlagen: ^1" \ No newline at end of file -- cgit v1.2.3