Skip to content

Instantly share code, notes, and snippets.

@soupi
Last active July 21, 2020 05:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save soupi/09db4a67afa96f356d7676e438f161c2 to your computer and use it in GitHub Desktop.
Save soupi/09db4a67afa96f356d7676e438f161c2 to your computer and use it in GitHub Desktop.
Fancily write to file which song is playing in cmus (can be read from obs using textmonitor script)
#!/usr/bin/env stack
-- stack --resolver lts-15.7 script --package text --package process
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad
import qualified Data.Text as T
import qualified Data.Text.IO as T
import System.Process
import Control.Exception
import Control.Concurrent
main :: IO ()
main = forever $ do
run `catch` \(SomeException e) -> pure ()
threadDelay 2000000
run :: IO ()
run = do
current <- readTextFile
text <- getSong
unless (current == text) $ do
deleteFromFile current
threadDelay delay
writeToFile "" =<< getSong
deleteFromFile :: T.Text -> IO ()
deleteFromFile current = do
unless (T.null current) $ do
let
temp
| T.drop (T.length current - 2) current == " " =
T.take (T.length current - 2) current
| otherwise =
T.take (T.length current - 1) current
T.writeFile file (prefix <> temp)
threadDelay delay
deleteFromFile temp
writeToFile :: T.Text -> T.Text -> IO ()
writeToFile current full = do
unless (current == full) $ do
let
temp
| T.drop (T.length current) full == " " =
T.take (T.length current + 2) full
| otherwise =
T.take (T.length current + 1) full
T.writeFile file (prefix <> temp)
threadDelay delay
writeToFile temp full
getSong :: IO T.Text
getSong =
fmap
(T.unwords . T.lines . T.pack)
(readCreateProcess (shell "cmus-remote -C \"format_print %A - %t\"") "")
readTextFile :: IO T.Text
readTextFile =
catch
(T.drop (T.length prefix) <$> T.readFile file)
(\(SomeException _) -> pure "")
file :: FilePath
file = "/tmp/cmus_playing.txt"
prefix :: T.Text
prefix = "Now Playing: "
delay = 95000
@soupi
Copy link
Author

soupi commented Apr 15, 2020

I modified this script https://obsproject.com/forum/resources/text-monitor.825/ with:

This in the update function:

local function update(text)
	if debug then obs.script_log(obs.LOG_INFO, string.format("changed to %s", text)) end
	local source = obs.obs_get_source_by_name("playing now")
	if source ~= nil then
		local settings = obs.obs_data_create()
		obs.obs_data_set_string(settings, "text", text)
		obs.obs_source_update(source, settings)
		obs.obs_data_release(settings)
		obs.obs_source_release(source)
	end

end

and modified the checkFile function like this:

local function checkFile(id)
	-- if the script has reloaded then stop any old timers
	if id < activeId then
		obs.remove_current_callback()
		return
	end

	if debug then obs.script_log(obs.LOG_INFO, string.format("(%d) Checking text file...(%d)", id, interval)) end
	local f, err = io.open(textFile, "rb")
	if f then
		local line
		for line in f:lines() do
			if line then
				-- success : now check if the value has changed
				if current ~= line then
					current = line
					update(line)
				end
			end
		end
		f:close()
	else
		if debug then obs.script_log(obs.LOG_INFO, string.format("Error reading text file : ", err)) end
	end
end

And the intervals:

-- define properties that user can change
function script_properties()
	local props = obs.obs_properties_create()
	obs.obs_properties_add_path(props, "textFile", "Text File", obs.OBS_PATH_FILE, "", nil)
	obs.obs_properties_add_int(props, "interval", "Interval (ms)", 50, 2000, 10)
	obs.obs_properties_add_bool(props, "debug", "Debug")
	return props
end


-- set default values
function script_defaults(settings)
	obs.obs_data_set_default_string(settings, "textFile", "")
	obs.obs_data_set_default_int(settings, "interval", 100)
	obs.obs_data_set_default_bool(settings, "debug", false)
end

So that now I can update text faster than the default which is 1 second.

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