コンテンツにスキップ

モジュール:Cite

提供: Undertale Wiki

このモジュールについての説明文ページを モジュール:Cite/doc に作成できます

--- Generates citations across the wiki to ensure standard formatting.
--  The module accepts several different types of citations and processes each
--  differently, based on the <code>f</code> table's functions.
--  @module             cite
--  @alias              p
--  @require            Module:Date
--  @require            Module:User error
--  @require            Module:Yesno
--  @require            Module:Tags
--  @require            Module:Cite/data
--  @author             [[User:KockaAdmiralac|KockaAdmiralac]]
--  @author             [[User:Ceruleanwarbler2|Ceruleanwarbler2]]
--  @author             [[User:Jacky720|Jacky720]]
--  @see                [[:Category:Citation templates]]
--  <nowiki>
local p = {}

require('strict')

-- Module dependencies
local Date = require('Module:Date')
local yesno = require('Module:Yesno')
local tags = require('Module:Tags')
local data = mw.loadData('Module:Cite/data')

--  Private logic.

local DATE_FORMAT = '%B %d, %Y.'

--- Wrapper for <code>userError</code> that places the page under the Pages with
--  user errors category.
--  @function           err
--  @param              {string} text Text to display as an error
--  @return             {string} Wikitext with the error and category
--  @local
local function err(text)
    return require('Module:User error')(text, 'Pages with user errors')
end

--- Checks whether a given date string is a valid date.
--  @function           valid_date
--  @param              {string} d Date string to check
--  @return             {bool} Whether the string is a valid date
--  @local
local function valid_date(d)
    return pcall(function()
        Date(d)
    end)
end

--- Table of possible citation types and the way they are processed.
--  Each type has a function associated with it that gets passed the arguments
--  after the type, does validation of these arguments and returns the whole
--  citation text.
--  @table              cite_functions
--  @alias              f
local f = {}

--- Handles Twitter citations.
--  @function           f.twitter
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
--  @see                [[Template:Cite twitter]]
--  @see                [[github:client9/snowflake2time]]
function f.twitter(args)
    -- Check validity of arguments
    if not args.id or not tonumber(args.id) then
        return err('Tweet snowflake invalid or not specified')
    end
    if not args.author or not args['text'] then
        return err('Tweet author or citation not specified')
    end
    if args.wayback and not tonumber(args.wayback) then
    	return('Archive ID invalid')
    end
    if args.archivetoday and (not args.archivetimestamp or not valid_date(args.archivetimestamp)) then
		return err('Date of archivation not specified')
    end
    -- Twitter snowflake date extraction
    local snowflake = tonumber(args.id)
    local epoch = math.floor(snowflake / 4194304 + 1288834974657)
    local date1 = Date(math.floor(epoch / 1000))
    -- Format citation
    local date2
    if args.archivetimestamp then
    	date2 = Date(args.archivetimestamp):fmt(DATE_FORMAT)
    elseif args.wayback then
    	date2 = Date(args.wayback):fmt(DATE_FORMAT)
    end
    local deadurl = yesno(args['deleted'], false)
    local str = {
        '\'\'',
        args.text,
        '\'\' - ['
    }
    if deadurl and args.archivetoday then
	    table.insert(str, 'https://archive.today/')
	    table.insert(str, args.archivetoday)
	    table.insert(str, '/')
    else
    	if deadurl and args.wayback then
	    	table.insert(str, 'https://web.archive.org/web/')
	    	table.insert(str, args.wayback)
	    	table.insert(str, '/')
    	end
	    table.insert(str, 'https://twitter.com/')
	    table.insert(str, args.author)
	    table.insert(str, '/status/')
	    table.insert(str, args.id)
    end
    if data.twitter[args.author] then
        table.insert(str, ' ')
        table.insert(str, data.twitter[args.author])
        table.insert(str, ' (@')
        table.insert(str, args.author)
        table.insert(str, ')')
    else
        table.insert(str, ' @')
        table.insert(str, args.author)
    end
    table.insert(str, ' on Twitter,] ')
    table.insert(str, date1:fmt(DATE_FORMAT))
    if deadurl then
        if args.wayback or args.archivetoday then
            table.insert(str, ' Archived on ')
            table.insert(str, date2)
        else
            table.insert(str, ' \'\'\'[deleted]\'\'\'')
        end
    end
    return table.concat(str)
end

--- Handles Bluesky citations.
--  @function           f.bluesky
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
--  @see                [[Template:Cite bluesky]]
function f.bluesky(args)
    if not args.author or not args.text then
        return err('Author or quote not specified')
    end
    if not args.id then
        return err('Post ID not specified')
    end
    if not args.timestamp or not valid_date(args.timestamp) then
        return err('Date invalid or not specified')
    end
    return table.concat({
        '\'\'',
        tags.replace(args['text']),
        '\'\' - [https://bsky.app/profile/',
        args['author'],
        '/post/',
        args['id'],
        ' @',
        args['author'],
        ' on Bluesky,] ',
        Date(args.timestamp):fmt(DATE_FORMAT)
    })
end

--- Handles citations of text in the game.
--  @function           f.game
--  @param              {table} frame_args Citation type arguments
--  @return             {string} Citation text
--  @see                [[Template:Cite game]]
function f.game(frame_args)
    local args = {}
    for i, v in ipairs(frame_args) do
        -- frame.args is a metatable, so we cannot use #args or table.concat
        -- on it before we convert it to a real table.
        args[i] = v
    end
    local num_args = #args
    if num_args == 0 then
        return err('Quote not specified')
    end
    if num_args == 1 then
        return err('Quote author not specified')
    end
    local author = args[num_args]
    args[num_args] = nil
    return table.concat({
        '\'\'',
        tags.replace(table.concat(args, '<br />')),
        '\'\' - ',
        author
    })
end

--- Handles citations of YouTube videos.
--  @function           f.youtube
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
--  @see                [[Template:Cite youtube]]
function f.youtube(args)
    if not args.id or not args.title then
        return err('Video ID or title not specified')
    end
    local str = {
        '\'\'',
        args.title,
        '\'\' - [https://youtu.be/',
        args.id
    }
    if args.timestamp then
        table.insert(str, '?t=')
        table.insert(str, args.timestamp)
    end
    table.insert(str, ' YouTube]')
    local seconds = tonumber(args.timestamp)
    if seconds ~= nil then
        local minutes = math.floor(seconds / 60)
        seconds = seconds - minutes * 60
        local hours = math.floor(minutes / 60)
        minutes = minutes - hours * 60
        if hours > 0 then
            table.insert(str, string.format(
                ' (%02d:%02d:%02d)',
                hours,
                minutes,
                seconds
            ))
        else
            table.insert(str, string.format(
                ' (%02d:%02d)',
                minutes,
                seconds
            ))
        end
    end
    return table.concat(str)
end

--- Handles Tumblr citations.
--  @function           f.tumblr
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
--  @see                [[Template:Cite tumblr]]
function f.tumblr(args)
    if not args.author or not args.text then
        return err('Author or quote not specified')
    end
    if not args.id or not tonumber(args.id) then
        return err('Post ID invalid or not specified')
    end
    if not args.timestamp or not valid_date(args.timestamp) then
        return err('Date invalid or not specified')
    end
    return table.concat({
        '\'\'',
        tags.replace(args.text),
        '\'\' - [https://',
        -- Temporary solution to avoid showing reblogger's name as author name
        -- on inaccessible posts.
        -- To be replaced by proper archival parameters.
        args.reblogger or args.author,
        '.tumblr.com/post/',
        args.id,
        ' ',
        args.author,
        ' on Tumblr,] ',
        Date(args.timestamp):fmt(DATE_FORMAT)
    })
end

--- Handles citations of the game's code.
--  @function           f.code
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
--  @see                [[Template:Cite code]]
--  @see                [[code:|Code repository]]
function f.code(args)
    local str = {}
    local hasLink = args.chapter == nil or tonumber(args.chapter) < 3
    if not args.script then
        return err('Script name not specified')
    end
    if args.line and not tonumber(args.line) then
        return err('Starting line number is not a number')
    end
    if args.line2 and not tonumber(args.line2) then
        return err('Ending line number is not a number')
    end
    if args.chapter == nil then
        str = {
            '[[code:',
            args.script,
        }
    elseif hasLink then
        str = {
            '[[code:',
            'ch',
            args.chapter,
            '/',
            args.script,
        }
    end
    if hasLink then
        if args.line then
            table.insert(str, '#L')
            table.insert(str, args.line)
        end
        table.insert(str, '|')
    end
    table.insert(str, args.script)
    table.insert(str, ' script')
    if hasLink then
        table.insert(str, ']]')
    end
    if args.line then
        table.insert(str, ', line')
        if args.line2 then
            table.insert(str, 's ')
            table.insert(str, args.line)
            table.insert(str, '–')
            table.insert(str, args.line2)
        else
            table.insert(str, ' ')
            table.insert(str, args.line)
        end
    end
    if args.chapter ~= nil then
        table.insert(str, ', Chapter ')
        table.insert(str, args.chapter)
    end
    return table.concat(str)
end

--- Handles citations from news sources.
--  @function           f.news
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
--  @see                [[Template:Cite news]]
function f.news(args)
    if not args.text then
        return err('Relevant news post excerpt not specified')
    end
    if not args.title then
        return err('News post title not specified')
    end
    if not args.site then
        return err('News site name not specified')
    end
    if not args.url then
        return err('News post URL not specified')
    end
    if not args.timestamp or not valid_date(args.timestamp) then
        return err('News post date invalid or not specified')
    end
    local author = {}
    if args.firstname then
        if args.lastname then
            table.insert(author, args.lastname)
            table.insert(author, ', ')
        end
        table.insert(author, args.firstname)
        table.insert(author, ', ')
    end
    return table.concat({
        '\'\'',
        tags.replace(args.text),
        '\'\' - [',
        args.url,
        ' ',
        args.title,
        '] (',
        table.concat(author),
        Date(args.timestamp):fmt(DATE_FORMAT),
        ') \'\'',
        args.site,
        '\'\'.'
    })
end

--- Handles citations from Twitch clips.
--  @function           f.twitch
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
--  @see                [[uty:Template:Cite twitch]]
function f.twitch(args)
	local id = args[1] or args.id
	local title = args[2] or args.title
	local author = args[3] or args.author
	local timestamp = args[4] or args.timestamp
    if not id then
        return err('Clip URL segment not specified')
    end
    if not title then
        return err('Clip title not specified')
    end
    if not author then
        return err('Streamer username not specified')
    end
    if not timestamp or not valid_date(timestamp) then
        return err('Stream date invalid or not specified')
    end
    return table.concat({
        '"\'\'[https://clips.twitch.tv/',
        id,
        ' "',
        title,
        ',]\'\'" a clip from [https://twitch.tv/',
        mw.ustring.lower(author),
        ' @',
        name,
        '\'s] Twitch stream on ',
        Date(timestamp):fmt(DATE_FORMAT)
    })
end

-- Package items.

for mname, method in pairs(f) do
    p[mname] = function(frame)
        return method(frame:getParent().args)
    end
end

return p