Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy-text-to-clipboard function for scripts #7361

Open
wareya opened this issue Jan 14, 2020 · 9 comments
Open

Copy-text-to-clipboard function for scripts #7361

wareya opened this issue Jan 14, 2020 · 9 comments

Comments

@wareya
Copy link

wareya commented Jan 14, 2020

Expected behavior of the wanted feature

Desired feature

I want a function that copies a string containing unicode text to the clipboard, including newlines. This can of course be used to implement #4695 in a script much more gracefully than the solution the responses to it came up with, but I'm not asking for what's described in #4695, just a function for scripts to use.

I last looked for a function like this several months ago. If one was silently added in the meantime without an issue being created for it then this feature request doesn't really mean anything, I guess!

Motivation

I wrote a script that automatically copies subtitles to the clipboard so that they can be access more easily by "clipboard grabbers".

Copying text to the clipboard automatically (not after a hotkey press) is an accessibility design pattern that's started appearing in games, having options to copy onscreen text to the clipboard so that screen readers can verbalize it.

This idea is not limited to disability accessibility, though; it's also used when consuming media that uses very difficult vocabulary or is in foreign languages. Having access to plain text on the clipboard makes looking up words that you don't know extremely easy, to the point where it's becoming increasingly common for people who start learning Japanese to set up clipboard reading systems and mouseover dictionaries when playing games in Japanese just so that they never have to worry about manually looking up kanji.

In turn, that's the motivation for my script. I don't personally need it, but some of my friends did, and they found it helpful.

It has a few problems, though:

  • It only works on Windows (entirely different scripts are needed on different platforms)
  • It's laggy, because it involves invoking a new process, and AV software (including windows defender) can block it for several seconds
  • It's locale sensitive, because it involves invoking a shell
  • It's incredibly hacky, because safely invoking processes through the shell containing arbitrary strings for arguments is hard on windows

The third point is the biggest problem. The script doesn't just work, and it's not possible for it to just work. It needs to be edited if the user is using certain locales for non-unicode programs, and using strange locales is very common among people who are learning Japanese.

It would be much, much simpler, more stable, and more reliable if there were just a function for copying text to the clipboard made available to scripts.

@rubyFeedback
Copy link

Makes sense to me personally. My only regret would be if it is limited to a single operating system - also because I am almost exclusively using linux these days. :-)

@ghost
Copy link

ghost commented Jan 17, 2020

mpv's internal console.lua has some minor clipboard support, but also does it by invoking new processes (see get_clipboard(), pasting only).

@wiiaboo
Copy link
Member

wiiaboo commented Feb 20, 2020

At least in Windows, I've been using this lua code to make it work. Probably easy to adapt it to work for macOS and Linux too.

local utils = require 'mp.utils'

function set_clipboard(text)
    utils.subprocess(
        { args = {
            'powershell', '-NoProfile', '-Command', string.format([[& {
                Trap {
                    Write-Error -ErrorRecord $_
                    Exit 1
                }
                Add-Type -AssemblyName PresentationCore
                [System.Windows.Clipboard]::SetText('%s')
            }]], text)
        }, playback_only = false
    })
end

mp.add_key_binding("ctrl+c", "copy-url-to-clipboard", function()
    local text = mp.get_property_native('path', '')
    if (text:find("http://") == 1) or (text:find("https://") == 1)
        or (text:find("ytdl://") == 1) then
        set_clipboard(text)
    end
end)

@wareya
Copy link
Author

wareya commented Feb 20, 2020

The whole point of this is wanting something that doesn't have to be adapted for different systems and doesn't involve passing things to a shell.

@siikamiika
Copy link

Not sure if this is any better, but I found it easier to just write the clipboard contents to a file and read it from there: siikamiika/scripts@6235d22

+1 to the clipboard copy utility function

@lucy
Copy link
Contributor

lucy commented Dec 4, 2021

You can use the env parameter to avoid janky shell quoting. Not sure how robust it is but it's probably better than that at least.

local env = utils.get_env_list()
table.insert(env, "TEXT="..text)
mp.command_native_async({
    name = "subprocess",
    playback_only = false,
    args = {"powershell", "-nop", "-c", "Set-Clipboard -Value $env:TEXT"},
    env = env,
}, function(success, result, error)
    -- ...
end)                                 

edit: nvm this is really flaky and I can't tell why, seems like env passing just makes it fail randomly

dexeonify referenced this issue in dexeonify/mpv-config Dec 24, 2021
This allows seek-to.lua to accept and paste timestamps from copyTime.lua
directly. The format accepted is HH:MM:SS.SSS and it can be invoked with
ctrl+v by default. The copy from clipboard code is for Windows only, but
it can be modified to accept clipboard on other OS too, see below.

Psst... occivink/mpv-scripts#43

Getting data from clipboard is harder than it looks, there isn't a
native and unified command to communicate with the clipboard for all OS.
Instead, you have to call a function/program specific to your OS through
a shell to get your clipboard data. Here is how mpv officially does it:
https://github.com/mpv-player/mpv/blob/master/player/lua/console.lua#L619-L672

Here is some issues related to it:
`https://github.com/mpv-player/mpv/issues/7361`
`https://github.com/mpv-player/mpv/issues/4695`
`https://github.com/mpv-player/mpv/issues/4653`
(backticks around it so I don't create a reference to all of them)
dexeonify added a commit to dexeonify/mpv-config that referenced this issue Dec 24, 2021
This allows seek-to.lua to accept and paste timestamps from copyTime.lua
directly. The format accepted is HH:MM:SS.SSS and it can be invoked with
ctrl+v by default. The copy from clipboard code is for Windows only, but
it can be modified to accept clipboard on other OS too, see below.

Psst... occivink/mpv-scripts#43

Getting data from clipboard is harder than it looks, there isn't a
native and unified command to communicate with the clipboard for all OS.
Instead, you have to call a function/program specific to your OS through
a shell to get your clipboard data. Here is how mpv officially does it:
https://github.com/mpv-player/mpv/blob/master/player/lua/console.lua#L619-L672

Here is some issues related to it:
mpv-player/mpv#7361
mpv-player/mpv#4695
mpv-player/mpv#4653
@Dudemanguy
Copy link
Member

I suppose one could generalize what console.lua does and expose it as part of the API. It would necessitate calling new processes though (pretty much unavoidable) and would of course error if the clipboard programs aren't available for whatever reason. The upside is that I guess it would make the life for scripters nicer.

@Anonymity
Copy link

Anonymity commented Jan 10, 2025

edit: nvm, they added clipboard function for windows and wayland in Nov 2024. Grab a recent build and use this:

mp.set_property('clipboard/text', txt)

Instead of escaping quotes, I think it's probably more reliable to encode the text with base64 before passing into shell, and decode it within the shell.

Here's what I use now:

-- base64 implementation taken from http://lua-users.org/wiki/BaseSixtyFour
local b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

local function base64_encode(data)
    return ((data:gsub('.', function(x) 
        local r,b='',x:byte()
        for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
        return r;
    end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
        if (#x < 6) then return '' end
        local c=0
        for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
        return b:sub(c+1,c+1)
    end)..({ '', '==', '=' })[#data%3+1])
end

local function set_clipboard(txt)
    txt = base64_encode(txt)
    local cmd = string.format('[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("%s")) | Set-Clipboard', txt)
    mp.commandv("run", "powershell.exe", "-NoProfile", "-Command", cmd)
end

local function copy_sub()
    local txt = mp.get_property('sub-text')
    set_clipboard(txt)
end

mp.add_key_binding('ctrl+c', 'copy_sub', copy_sub)

@guidocella
Copy link
Contributor

The builtin clipboard function has already been added.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants