Module:Commons link

From Zoophilia Wiki
Revision as of 06:54, 20 March 2020 by meta>Hike395 (add function to check whether article has any corresponding gallery or category)
Jump to navigationJump to search

Documentation for this module may be created at Module:Commons link/doc

-- Module to find commons galleries and categories based on wikidata entries
local getArgs = require('Module:Arguments').getArgs
local p = {}

-- Check if string is a valid QID
-- Argument: QID to check
-- Returns: valid (bool)
local function _validQID(qid)
	return qid and mw.ustring.find(qid,"^[Qq]%d+$")
end

-- Check if string is a valid wikidata property string
-- Argument: property string to check
-- Returns: valid (bool)
local function _validProp(prop)
	return prop and mw.ustring.find(prop,"^[Pp]%d+$")
end

-- Get title, namespace, and QID for current page
-- Arguments:
--   qid = testing only: get title of alternative page with QID=qid
-- Returns:
--   title, namespace (number), qid of current page (or test page)
local function _getTitleQID(qid)
	local titleObject = mw.title.getCurrentTitle()
	-- look up qid for current page (if not testing)
	if not _validQID(qid) then
		qid = mw.wikibase.getEntityIdForCurrentPage()
		return titleObject.text, titleObject.namespace, qid
	end
	-- testing-only path: given a qid, determine title
	-- always use namespace from current page (to suppress tracking cat)
	qid = qid:upper()
	local title = mw.wikibase.getSitelink(qid) or ""
	-- strip any namespace from sitelink
	local firstColon = mw.ustring.find(title,':',1,true)
	if firstColon then
		title = mw.ustring.sub(title,firstColon+1)
	end
	return title, titleObject.namespace, qid
end

-- Lookup Commons gallery in Wikidata
-- Arguments:
--   qid = QID of current article
--   fetch = whether to lookup Commons sitelink (bool)
--   commonsSitelink = default value for Commons sitelink
-- Returns:
--   categoryLink = name of Commons category, nil if nothing is found
--   consistent = multiple wikidata fields are examined: are they consistent?
--   commonsSitelink = commons sitelink for current article
local function _lookupGallery(qid,fetch,commonsSitelink)
	if not _validQID(qid) then
		return nil, true, nil
	end
	qid = qid:upper()
	local galleryLink = nil
	local consistent = true
	-- look up commons sitelink for article, use if not category
	if fetch then
		commonsSitelink = mw.wikibase.getSitelink(qid,"commonswiki") or commonsSitelink
	end
	if commonsSitelink and mw.ustring.sub(commonsSitelink,1,9) ~= "Category:" then
		galleryLink = commonsSitelink
	end
	-- P935 is the "commons gallery" property for this article
	local P935 = mw.wikibase.getBestStatements(qid, "P935")[1]
	if P935 and P935.mainsnak.datavalue then
		local gallery = P935.mainsnak.datavalue.value
		if galleryLink and galleryLink ~= gallery then
			consistent = false
		else
			galleryLink = gallery
		end
	end
	return galleryLink, consistent, commonsSitelink
end

-- Find fallback category by looking up Commons sitelink of different page
-- Arguments:
--    qid = QID for current article
--    property = property that refers to other article whose sitelink to return
-- Returns: either category-stripped name of article, or nil
local function _lookupFallback(qid,property)
	if not _validQID(qid) or not _validProp(property) then
		return nil
	end
	qid = qid:upper()
	property = property:upper()
	-- If property exists on current article, get value (other article qid)
	local value = mw.wikibase.getBestStatements(qid, property)[1]
	if value and value.mainsnak.datavalue and value.mainsnak.datavalue.value.id then
		-- Look up Commons sitelink of other article
		local sitelink = mw.wikibase.getSitelink(value.mainsnak.datavalue.value.id,"commonswiki")
		-- Check to see if it starts with "Category:". If so, strip it and return
		if sitelink and mw.ustring.sub(sitelink,1,9) == "Category:" then
			return mw.ustring.sub(sitelink,10)
		end
	end
	return nil
end

-- Find Commons category by looking in wikidata
-- Arguments:
--   qid = QID of current article
--   fetch = whether to lookup Commons sitelink (bool)
--   commonsSitelink = default value for Commons sitelink
-- Returns:
--   categoryLink = name of Commons category, nil if nothing is found
--   consistent = multiple wikidata fields are examined: are they consistent?
--   commonsSitelink = commons sitelink for current article
local function _lookupCategory(qid, fetch, commonsSitelink)
	if not _validQID(qid) then
		return nil, true, nil
	end
	qid = qid:upper()
	local categoryLink = nil
	local consistent = true
	-- look up commons sitelink for article, use if starts with "Category:"
	if fetch then
		commonsSitelink = mw.wikibase.getSitelink(qid,"commonswiki") or commonsSitelink
	end
	if commonsSitelink and mw.ustring.sub(commonsSitelink,1,9) == "Category:" then
		categoryLink = mw.ustring.sub(commonsSitelink,10)
	end
	-- P373 is the "commons category" property for this article
	local P373 = mw.wikibase.getBestStatements(qid, "P373")[1]
	if P373 and P373.mainsnak.datavalue then
		P373 = P373.mainsnak.datavalue.value
		if categoryLink and categoryLink ~= P373 then
			consistent = false
			qid = nil  -- stop searching on inconsistent data
		else
			categoryLink = P373
		end
	end
	-- P910 is the "topic's main category". Look for commons sitelink there
	local fallback = _lookupFallback(qid,"P910")
	if fallback then
		if categoryLink and categoryLink ~= fallback then
			consistent = false
			qid = nil
		else
			categoryLink = fallback
		end
	end
	-- P1754 is the "list's main category". Look for commons sitelink there
	fallback = _lookupFallback(qid,"P1754")
	if fallback then
		if categoryLink and categoryLink ~= fallback then
			consistent = false
		else
			categoryLink = fallback
		end
	end
	return categoryLink, consistent, commonsSitelink
end


-- Create Commons link corresponding to current article
-- Arguments:
--   namespace = namespace in Commons ("" for galleries)
--   default = use as Commons link, don't access wikidata
--   linktext = text to display in link
--   search = string to search for
--   qid = QID to lookup in wikidata (for testing only)
-- Returns:
--   formatted wikilink to Commons in specified namespace
function p._getCommons(namespace,default,linktext,search,qid)
	local nsColon
	if not namespace or namespace == "" then
		nsColon = ""
	else
		nsColon = namespace..":"
	end
	if default then
		return "[[Commons:"..nsColon..default.."|"..(linktext or default).."]]"
	end
	if search then
		return "[[Commons:Special:Search/"..nsColon..search.."|"..(linktext or search).."]]"
	end
	local wp_title, wp_ns
	wp_title, wp_ns, qid = _getTitleQID(qid)
	-- construct default result (which searches for title)
	local searchResult = "[[Commons:Special:Search/"..nsColon..wp_title.."|"..(linktext or wp_title).."]]"
	local commonsLink = nil
	local consistent = true
	if nsColon == "" then
		commonsLink, consistent = _lookupGallery(qid,true)
	elseif namespace:lower() == "category" then
		commonsLink, consistent = _lookupCategory(qid,true)
	end
	-- use wikidata if consistent
	if commonsLink and consistent then
		return "[[Commons:"..nsColon..commonsLink.."|"..(linktext or commonsLink).."]]"
	end
	-- if not consistent, fall back to search and add to tracking cat
	if not consistent and wp_ns == 0 then
		local friendlyNS
		if nsColon == "" then
			friendlyNS = "gallery"
		else
			friendlyNS = namespace:lower()
		end
		searchResult = searchResult.."[[Category:Inconsistent wikidata for Commons "..friendlyNS.."]]"
	end
	return searchResult
end

-- Returns "best" Commons link: first look for gallery, then try category
-- Arguments:
--   default = use as Commons link, don't access wikidata
--   linktext = text to display in link
--   search = string to search for
--   qid = QID to lookup in wikidata (for testing only)
-- Returns:
--   formatted wikilink to Commons "best" landing page
function p._getGalleryOrCategory(default,linktext,search,qid)
	if default then
		return "[[Commons:"..default.."|"..(linktext or default).."]]"
	end
	if search then
		return "[[Commons:Special:Search/"..search.."|"..(linktext or search).."]]"
	end
	local wp_title, wp_ns
	wp_title, wp_ns, qid = _getTitleQID(qid)
	-- construct default result (which searches for title)
	local searchResult = "[[Commons:Special:Search/"..wp_title.."|"..(linktext or wp_title).."]]"
	local trackingCats = ""
	local galleryLink, consistent, commonsSitelink = _lookupGallery(qid,true)
	-- use wikidata if either sitelink or P935 exist, and they both agree
	if galleryLink and consistent then
		return "[[Commons:"..galleryLink.."|"..(linktext or galleryLink).."]]"
	end
	if not consistent and wp_ns == 0 then
		trackingCats = "[[Category:Inconsistent wikidata for Commons gallery]]"
	end
	-- if gallery is not good, fall back looking for category
	local categoryLink
	categoryLink, consistent = _lookupCategory(qid,false,commonsSitelink)
	if categoryLink and consistent then
		return "[[Commons:Category:"..categoryLink.."|"..(linktext or categoryLink).."]]"..trackingCats
	end
	if not consistent and wp_ns == 0 then
		trackingCats = trackingCats.."[[Category:Inconsistent wikidata for Commons category]]"
	end
	return searchResult..trackingCats
end

-- Does the article have a corresponding Commons gallery or category?
-- Arguments:
--   qid = QID to lookup in wikidata (for testing only)
-- Returns:
--   "yes" if so, blank if not
function p._hasGalleryOrCategory(qid)
	local wp_title, wp_ns
	wp_title, wp_ns, qid = _getTitleQID(qid)
	local galleryLink, consistent, commonsSitelink = _lookupGallery(qid,true)
	if galleryLink and consistent then
		return "yes"
	end
	local categoryLink
	categoryLink, consistent = _lookupCategory(qid,false,commonsSitelink)
	if categoryLink and consistent then
		return "yes"
	end
	return ""
end


-- Testing-only entry point for _getTitleQID
function p.getTitleQID(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	local text, ns, qid = _getTitleQID(args[1])
	return text..","..ns..","..(qid or "nil")
end

-- Testing-only entry point for _lookupFallback
function p.lookupFallback(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	local fallback = _lookupFallback(args[1],args[2])
	return fallback or "nil"
end

-- Find the Commons gallery page associated with article
function p.getGallery(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	return p._getCommons("",args[1],args.linktext,args.search,args.qid)
end

-- Find the Commons category page associated with article
function p.getCategory(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	return p._getCommons("Category",args[1],args.linktext,args.search,args.qid)
end

function p.getGalleryOrCategory(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	return p._getGalleryOrCategory(args[1],args.linktext,args.search,args.qid)
end

function p.hasGalleryOrCategory(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	return p._hasGalleryOrCategory(args.qid)
end


return p