-- If the file "../script-opts/360plugin.conf" (or name of this script) is present,
-- and enabled=yes is written to it,
-- or the command line argument "--script-opts=360plugin-enabled=yes" is passed,
-- the features of this script will be running without having to use the toggle key.
-- The following default key bindings can also be reconfigured in the same way
-- (including via CLI) without editing this script at all.
local opts = {
	["enabled"]=false,
	["toggle_vr360"]="v",
	["cycle_input"]="1",
	["cycle_output"]="2",
	["roll_left"]="u",
	["roll_right"]="o",
	["write_log"]="w",
	["pitch_up"]="i",
	["pitch_down"]="k",
	["yaw_up"]="l",
	["yaw_down"]="j",
	["easy_crop"]="c",
	["res_up"]="y",
	["res_down"]="h",
	["zoom_in"]="=",
	["zoom_out"]="-",
	["wzoom_out"]="WHEEL_DOWN",
	["wzoom_in"]="WHEEL_UP",
	["reset_view"]="0",
	["switch_stereo"]="r",
	["switch_eye"]="t",
	["switch_scaler"]="e",
	["switch_output_sbs"]="p",
	["toggle_smooth"]="g",
	["switch_bounds"]="b",
	["new_log_session"]="n",
	["grab_mouse"]="mouse_btn0",
	["mouse_pan"]="mouse_move",
	["show_help"]="?",
	["osc"]="no",
	["fullscreen"]="yes",
	["osd-font-size"]=30
}
(require 'mp.options').read_options(opts)

local saved_props = {
	["hwdec"] 			= "NIL",
	["fullscreen"] 		= "NIL",
	["osc"] 			= "NIL",
	["osd-font-size"] 	= "NIL",
	["cursor-autohide"] = "NIL"
}

local yaw   = 0.0
local last_yaw = 0.0
local init_yaw = 0.0

local pitch = 0.0
local last_pitch = 0.0
local init_pitch = 0.0

local roll  = 0.0
local last_roll  = 0.0
local init_roll = 0.0

local inputProjections = {
	"hequirect",
	"equirect",
	"fisheye",
	"pannini",
	"cylindrical",
	"sg"
}
local inputProjectionInd = 0
local inputProjection    = "hequirect"

local outputProjections = {
	"flat",
	"sg"
}

local outputProjectionInd = 0
local outputProjection    = "flat"



local idfov=180.0
local dfov=110.0
local last_dfov  = 110.0
local init_dfov = 0.0


local doit = 0.0
local res  = 1.0
local dragging = false

local smoothMouse = true

local scaling   = 'linear'

 
local in_stereo  = 'sbs'
local outputMode = '2d'
local out_stereo = '2d'
local anaglyph_filter = ""
local sarOutput = 1.0

local h_flip    = '0'
local in_flip   = ''

local interp    = 'cubic'

local startTime = nil

local filterIsOn = false

local mousePos = {}
local lasttimePos = nil
local filename = nil

local fileobjectNumber = 0
local fileobjectFilename = ''
local videofilename = ''
local file_object      = nil

local ffmpegCommandList = {}

local openNewLogFile = function()
	if lasttimePos ~= nil then
		fileobjectNumber = fileobjectNumber+1
	end
	videofilename = mp.get_property('filename')
	fileobjectFilename = string.format('%s_3dViewHistory_%s.txt',videofilename,fileobjectNumber)
	file_object = io.open(fileobjectFilename, 'w')
	lasttimePos = nil
end

local SecondsToClock = function(seconds)
	local seconds = tonumber(seconds)
	if seconds <= 0 then
		return "00:00:00";
	else
	hours = string.format("%02.f", math.floor(seconds/3600));
	mins = string.format("%02.f", math.floor(seconds/60 - (hours*60)));
	secs = string.format("%02.2f", seconds - hours*3600 - mins *60);
		return hours .. ":" .. mins .. ":" .. secs
	end
end

local writeHeadPositionChange = function()
	if filename == nil then
		filename = mp.get_property("path")
	end

	if file_object == nil then
		return
	else		
		local initPass=false
		if lasttimePos == nil then
			lasttimePos = mp.get_property("time-pos")
			startTime   = lasttimePos
			initPass=true
			if lasttimePos == nil then
				return
			end
		end

		local newTimePos = mp.get_property("time-pos")

		if newTimePos == nil then
			return
		end

		local outputTs = string.format("%.3f-%.3f ",lasttimePos,newTimePos)
		local changedValues = {}
		local movementDuration = (newTimePos-lasttimePos)
		local maximumTimeoutReached = movementDuration > 5.0

		if initPass or pitch ~= last_pitch or maximumTimeoutReached then
			changedValues[#changedValues+1]= string.format(", [expr] v360 pitch 'lerp(%.3f,%.3f,(T-%.3f)/%.3f)'",last_pitch,pitch,lasttimePos,movementDuration)
		end 
		last_pitch=pitch

		if initPass or yaw ~= last_yaw or maximumTimeoutReached then
			changedValues[#changedValues+1]= string.format(", [expr] v360 yaw 'lerp(%.3f,%.3f,(T-%.3f)/%.3f)'",last_yaw,yaw,lasttimePos,movementDuration)
		end 
		last_yaw=yaw


		if initPass or roll ~= last_roll or maximumTimeoutReached then
			changedValues[#changedValues+1]= string.format(", [expr] v360 roll 'lerp(%.3f,%.3f,(T-%.3f)/%.3f)'",last_roll,roll,lasttimePos,movementDuration)
		end 
		last_roll=roll

		if initPass or dfov ~= last_dfov or maximumTimeoutReached then
			changedValues[#changedValues+1]= string.format(", [expr] v360 d_fov 'lerp(%.3f,%.3f,(T-%.3f)/%.3f)'",last_dfov,dfov,lasttimePos,movementDuration)
		end 
		last_dfov=dfov

		if initPass then
			init_pitch = pitch
			init_yaw   = yaw
			init_roll  = roll
			init_dfov  = dfov
		end

		if #changedValues > 0 then
			local commandString = ''
			for k,changedValue in pairs(changedValues) do
				commandString = commandString .. changedValue
			end

			commandString = commandString:sub(2)

			commandString = outputTs .. commandString .. ';'

			file_object:write(commandString .. '\n')	
			lasttimePos = newTimePos
		end
	end
end

local updateAwaiting = false

local updateComplete = function()
	updateAwaiting = false
end

local printRecordingStatus = function()
	lasttimePos = (mp.get_property("time-pos") or lasttimePos)
	if file_object ~= nil and lasttimePos ~= nil and startTime ~= nil then
		mp.osd_message(string.format("Recording:%s", SecondsToClock(lasttimePos - startTime)), 10)
	end
end

local updateFilters = function ()
	if not filterIsOn then
		mp.command_native_async({"no-osd", "vf", "add", string.format("@vrrev:%sv360=%s:%s:reset_rot=1:in_stereo=%s:out_stereo=%s:id_fov=%s:d_fov=%.3f:yaw=%.3f:pitch=%s:roll=%.3f:w=%s*192.0:h=%.3f*108.0:h_flip=%s:interp=%s,setsar=sar=%.3f%s",in_flip,inputProjection,outputProjection,in_stereo,out_stereo,idfov,dfov,yaw,pitch,roll,res,res,h_flip,scaling,sarOutput,anaglyph_filter)}, updateComplete)
		filterIsOn=true
	elseif not updateAwaiting then
		updateAwaiting=true
		mp.command_native_async({"no-osd", "vf", "set", string.format("@vrrev:%sv360=%s:%s:reset_rot=1:in_stereo=%s:out_stereo=%s:id_fov=%s:d_fov=%.3f:yaw=%.3f:pitch=%s:roll=%.3f:w=%s*192.0:h=%.3f*108.0:h_flip=%s:interp=%s,setsar=sar=%.3f%s",in_flip,inputProjection,outputProjection,in_stereo,out_stereo,idfov,dfov,yaw,pitch,roll,res,res,h_flip,scaling,sarOutput,anaglyph_filter)}, updateComplete)
	end
	writeHeadPositionChange()
end

local mouse_btn0_cb = function ()
	dragging = not dragging
	if dragging then
		mp.set_property("cursor-autohide", "always")
	else
		mp.set_property("cursor-autohide", saved_props["cursor-autohide"])
	end 
end

local mouse_pan = function ()
	if dragging then

		local MousePosx, MousePosy = mp.get_mouse_pos()
		local osd_w, osd_h = mp.get_property("osd-width"), mp.get_property("osd-height")


		local yawpc 	= ((MousePosx/osd_w)-0.5)*180
		local pitchpc   = -((MousePosy/osd_h)-0.5)*180

		local updateCrop = false

		if smoothMouse then
			if yaw ~= yawpc and math.abs(yaw-yawpc)<0.1 then
				yaw = yawpc
				updateCrop=true
				yaw = math.max(-180,math.min(180,yaw))
			elseif yaw ~= yawpc then
				yaw   = (yawpc+(yaw*5))/6
				yaw = math.max(-180,math.min(180,yaw))
				updateCrop=true
			end

			if pitch ~= pitchpc and math.abs(pitch-pitchpc)<0.1 then
				pitch = pitchpc
				pitch = math.max(-180,math.min(180,pitch))
				updateCrop=true
			elseif pitch ~= pitchpc then
				pitch = (pitchpc+(pitch*5))/6
				pitch = math.max(-180,math.min(180,pitch))
				updateCrop=true
			end
		else
			if yaw ~= yawpc then 
				yaw  = yawpc
				yaw = math.max(-180,math.min(180,yaw))
				updateCrop=true
			end
			if pitch ~= pitchpc then 
				pitch  = pitchpc
				pitch = math.max(-180,math.min(180,pitch))
				updateCrop=true
			end

		end

		if updateCrop then
			updateFilters()
		end

	end
end

local increment_res = function(inc)
	res = res+inc
	res = math.max(math.min(res, 20), 1)
	mp.osd_message(string.format("Out-Width: %spx", res*108.0), 0.5)
	updateFilters()
end

local increment_roll = function (inc)
	roll = roll + inc
	if roll > 180.0 then
		roll = 180.0
	elseif roll < -180.0 then
		roll = -180.0
	end
	mp.osd_message(string.format("Roll: %s°", roll), 0.5)
	updateFilters()
end

local increment_pitch = function (inc)
	pitch = pitch + inc
	if pitch > 180.0 then
		pitch = 180.0
	elseif pitch < -180.0 then
		pitch = -180.0
	end
	mp.osd_message(string.format("Pitch: %s°", pitch), 0.5)
	updateFilters()
end

local increment_yaw = function (inc)
	yaw = yaw+inc
	if yaw > 180.0 then
		yaw = 180.0
	elseif yaw < -180.0 then
		yaw = -180.0
	end
	mp.osd_message(string.format("Yaw: %s°", yaw), 0.5)
	updateFilters()
end

local increment_zoom = function (inc)
	dfov = dfov+inc
	dfov = math.max(math.min(150, dfov), 30)
	mp.osd_message(string.format("D-Fov: %s°", dfov), 0.5)
	updateFilters()
end

local reset_view = function()
	yaw = 0.0
	roll = 0.0
	pitch = 0.0
	mp.osd_message("Reset view.", 0.5)
	updateFilters()
end

local toggleSmoothMouse  = function()
	smoothMouse = not smoothMouse
	if smoothMouse then
		mp.osd_message("Mouse smothing On",0.5)
	else
		mp.osd_message("Mouse smothing Off",0.5)
	end
end

local switchoutputsbs = function()
	if outputMode == 'sbs2l:arcd' then
		out_stereo = '2d'
		outputMode = '2d'
		anaglyph_filter=""
		sarOutput = 1.0
		mp.osd_message("2d output mode")
	elseif outputMode == '2d' then
		out_stereo = 'sbs'
		outputMode = 'sbs'
		anaglyph_filter=""
		sarOutput = 1.0
		mp.osd_message("Side by side full width output mode")
	elseif outputMode == 'sbs' then
		out_stereo = 'sbs'
		outputMode = 'sbs-hw'
		anaglyph_filter=""
		sarOutput = 0.5
		mp.osd_message("side by side half width output mode")
	elseif outputMode == 'sbs-hw' then
		out_stereo = 'sbs'
		outputMode = 'sbs2l:arcg'
		anaglyph_filter=",stereo3d=sbs2l:arcg"
		sarOutput = 0.5
		mp.osd_message("Red cyan gray/monochrome anaglyph output mode")
	elseif outputMode == 'sbs2l:arcg' then
		out_stereo = 'sbs'
		outputMode = 'sbs2l:arbg'
		anaglyph_filter=",stereo3d=sbs2l:arbg"
		sarOutput = 0.5
		mp.osd_message("Red blue gray/monochrome anaglyph output mode")
	elseif outputMode == 'sbs2l:arbg' then
		out_stereo = 'sbs'
		outputMode = 'sbs2l:arcd'
		anaglyph_filter=",stereo3d=sbs2l:arcd"
		sarOutput = 0.5
		mp.osd_message("Red cyan dubois anaglyph output mode")
	end
	updateFilters()
end

local switchScaler = function()
	if scaling == 'nearest' then
		scaling = 'cubic'
	elseif scaling == 'cubic' then
		scaling = 'lagrange9'
	elseif scaling == 'lagrange9' then
		scaling = 'lanczos'
	elseif scaling == 'lanczos' then
		scaling = 'linear'
	elseif scaling == 'linear' then
		scaling = 'nearest'
	end
	mp.osd_message("Scaling algorithm: " .. scaling,5.5)
	updateFilters()
end

local switchEye = function()
	if h_flip == '0' then
		h_flip  = '1'
		in_flip = 'hflip,'
		mp.osd_message("Right eye",0.5)
	else
		h_flip  = '0'
		in_flip = ''
		mp.osd_message("Left eye",0.5)
	end
	print(in_flip,h_flip)
	updateFilters()
end


local cycleInputProjection = function()
	inputProjectionInd = ((inputProjectionInd+1) % (#inputProjections +1))
	inputProjection    = inputProjections[inputProjectionInd]
	mp.osd_message(string.format("Input projection: %s ",inputProjection),0.5)
	updateFilters()
end

local cycleOutputProjection = function()
	outputProjectionInd = ((outputProjectionInd+1) % (#outputProjections + 1))
	outputProjection    = outputProjections[outputProjectionInd]
	mp.osd_message(string.format("Output projection: %s",outputProjection),0.5)
	updateFilters()
end


local switchInputFovBounds = function()
	if idfov == 180.0 then
			idfov = 360.0
	elseif idfov == 360.0 then
		idfov = 90.0
	else
		idfov = 180.0
	end
	mp.osd_message(string.format("Input fov bounds: %s°",idfov),0.5)
	updateFilters()
end

local switchStereoMode = function()
	if in_stereo == 'sbs' then
		in_stereo = 'tb'
	else
		in_stereo = 'sbs'
	end
	mp.osd_message("Input format: " .. in_stereo,0.5)
	updateFilters()
end

local binding_by_name = function(lookup)
	for k, v in pairs(bindings) do
		if v["name"] == lookup then
			return k
		end
	end
end

local build_help_string = function()
	return table.concat({ "Default keyboard & mouse controls:\n",
	binding_by_name("show_help"), " = show help\n",
	binding_by_name("res_up"), ",", binding_by_name("res_down"), " = adjust quality\n",
	"Mouse Click = look around\n",
	binding_by_name("roll_left"), ",", binding_by_name("roll_right"), " = roll head\n",
	"Mouse Wheel = zoom\n",
	binding_by_name("switch_stereo"),	" = switch stereo Mode\n",
	binding_by_name("switch_eye"), 		" = switch eye side\n",
	binding_by_name("switch_scaler"), 	" = switch scaler\n",
	binding_by_name("switch_output_sbs"), 	" = toggle side by side output\n",
	binding_by_name("toggle_smooth"), 	" = toggle mouse smoothing\n",
	binding_by_name("new_log_session"),	" = start/stop motion recording\n",
	binding_by_name("cycle_input"), ",", binding_by_name("cycle_output"), " = cycle in and out projections\n",
	binding_by_name("reset_view"), " = center view\n"
	})
end

local help_string = nil

local showHelp = function()
	if help_string == nil then
		help_string = build_help_string()
	end
	mp.osd_message(help_string, 10)
end

local closeCurrentLog = function()
	commandForFinalLog=''
	if lasttimePos ~= nil and file_object ~= nil then

		finalTimeStamp = mp.get_property("time-pos")
		-- Can be nil while the player is shutting down and the file is already closed
		if finalTimeStamp == nil then
			finalTimeStamp = lasttimePos
		end

		file_object:write('#\n')

 		local stats = string.format('# Duration: %s-%s (total %s) %s seconds',
			SecondsToClock(startTime),
			SecondsToClock(finalTimeStamp),
			SecondsToClock(finalTimeStamp - startTime),
			finalTimeStamp - startTime
		)

		print('#')
		file_object:write(stats .. '\n')
		print(stats)

		file_object:write('# Suggested ffmpeg conversion command:\n')

		local closingCommandComment = string.format(
			'ffmpeg -y -ss %s -i "%s" -to %s -copyts -filter_complex "%sv360=%s:%s:in_stereo=%s:out_stereo=%s:reset_rot=1:id_fov=%s:d_fov=%.3f:yaw=%.3f:pitch=%.3f:roll=%.3f:w=1920.0:h=1080.0:interp=cubic:h_flip=%s,setsar=sar=%.3f,sendcmd=filename=%s_3dViewHistory_%s.txt" -avoid_negative_ts make_zero -preset slower -crf 17 "%s_2d_%03d.mp4"',
			startTime, filename, finalTimeStamp, in_flip, inputProjection, outputProjection, in_stereo, out_stereo, idfov, init_dfov, init_yaw, init_pitch, init_roll, h_flip, sarOutput, videofilename, fileobjectNumber, videofilename, fileobjectNumber
		)

				
		file_object:write('# ' .. closingCommandComment .. '\n')
		file_object:write('#\n')

		print(closingCommandComment)
		print('#')

		commandForFinalLog = closingCommandComment
	end
	lasttimePos = nil
	startTime = nil
	if file_object ~= nil then
		file_object:close()
		file_object = nil
	end
	return commandForFinalLog
end

local startNewLogSession = function()
	if file_object == nil then
		openNewLogFile()
		writeHeadPositionChange()
		mp.osd_message(string.format("Started Motion Record %s_3dViewHistory_%s.txt",videofilename,fileobjectNumber), 0.5)
	else
		mp.osd_message(string.format("Stopped Motion Record %s_3dViewHistory_%s.txt",videofilename,fileobjectNumber), 2.5)
		writeHeadPositionChange()
		local command = closeCurrentLog()
		if command then
			ffmpegCommandList[#ffmpegCommandList+1] = command
		end
	end
end

local onExit = function()
	closeCurrentLog()
	mergedCommand = ''
	for _, v in pairs(ffmpegCommandList) do
		if v ~= '' then
			mergedCommand = mergedCommand .. ' & ' .. v
		end
	end
	if mergedCommand ~= '' then
		mergedCommand = mergedCommand:sub(3)
		print(mergedCommand)
		batchfile = io.open('convert_3dViewHistory.bat', 'w')
		batchfile:write(mergedCommand)
		batchfile:close()
		print('Batch processing file created convert_3dViewHistory.bat')
	end
end

local save_props = function()
	for k, _ in pairs(saved_props) do
		local propv = (mp.get_property(k) or "NIL")
		saved_props[k] = propv

		if k == "hwdec" and propv ~= "no" then
			-- Workaround: hardware acceleration rarely works well, so we have to disable it.
			-- Error: [ffmpeg] Impossible to convert between the formats supported by 
			-- the filter 'mpv_src_default_in' and the filter 'auto_scaler_0'
			mp.osd_message("Temporarily turning off hardware decoding.", 1.5)
			mp.set_property("hwdec", "no")
		end
	end
end

local restore_props = function()
	for k, v in pairs(saved_props) do
		if v ~= "NIL" then
			if k == "hwdec" then
				-- Can also be displayed in osd console with "show-text ${hwdec-current}"
				mp.osd_message(string.format("Restoring hardware acceleration: %s", v), 1.5)
			end
			mp.set_property(k, v)
		end
	end

	for k, _ in pairs(saved_props) do
		saved_props[k] = "NIL"
	end
end

local restore_keybinds = function()
	-- There is no need to re-apply the previous key-bindings if they have been
	-- forcibly rebound by our script. They are still there after removal.
	for k,v in pairs(bindings) do
		if k == binding_by_name("toggle_vr360") then
			print("Keeping key bind to toggle vr360: " .. k)
		else
			mp.remove_key_binding(v["name"])
		end
	end
end

local recordingStatusTimer = nil

local initFunction = function()
	save_props()
	for key, pref in pairs(bindings) do
		mp.add_forced_key_binding(key, pref["name"], pref["fn"], pref["flags"])
	end

	mp.set_property("osc", opts["osc"])
	-- It seems not forcing fullscreen may cause minor issues. Use with caution.
	mp.set_property("fullscreen", opts["fullscreen"])
	mp.set_property("osd-font-size", opts["osd-font-size"])

	mp.register_event("end-file", onExit)
	mp.register_event("shutdown", onExit)

	recordingStatusTimer = mp.add_periodic_timer(0.1, printRecordingStatus)

	updateFilters()
end

local teardownFunction = function()
	if recordingStatusTimer ~= nil and recordingStatusTimer:is_enabled() then
		recordingStatusTimer:kill()
		recordingStatusTimer = nil
	end
	filterIsOn = false
	updateAwaiting = true
	mp.unregister_event(onExit)
	onExit()
	-- Remove bindings before to avoid updating the filter with mouse movements
	restore_keybinds()
	-- Remove filter before restoring hardware acceleration to avoid potential errors
	mp.command_native({"no-osd", "vf", "remove", "@vrrev"}, updateComplete)
	restore_props()
end

local toggleVR = function()
	if not opts.enabled then
		opts.enabled = true
		initFunction()
		return
	end
	teardownFunction()
	opts.enabled = false
end

bindings = {
	[opts.toggle_vr360]		=	{name="toggle_vr360",		fn=toggleVR				},
	[opts.cycle_input]		=	{name="cycle_input",		fn=cycleInputProjection },
	[opts.cycle_output]		=	{name="cycle_output",		fn=cycleOutputProjection },
	[opts.roll_left]		=	{name="roll_left",			fn=function() increment_roll(-1) end,	flags={repeatable=true}},
	[opts.roll_right]		=	{name="roll_right",			fn=function() increment_roll(1) end,	flags={repeatable=true}},
	[opts.write_log]		=	{name="write_log",			fn=writeHeadPositionChange },
	[opts.pitch_up]			=	{name="pitch_up",			fn=function() increment_pitch(1) end,	flags={repeatable=true}},
	[opts.pitch_down]		=	{name="pitch_down",			fn=function() increment_pitch(-1) end,	flags={repeatable=true}},
	[opts.yaw_up]			=	{name="yaw_up",				fn=function() increment_yaw(1) end,		flags={repeatable=true}},
	[opts.yaw_down]			=	{name="yaw_down",			fn=function() increment_yaw(-1) end,	flags={repeatable=true}},
	[opts.easy_crop]		=	{name="easy_crop",			fn=updateFilters,						flags={repeatable=true}},
	[opts.res_up]			=	{name="res_up",				fn=function() increment_res(1) end,		flags={repeatable=true}},
	[opts.res_down]			=	{name="res_down",			fn=function() increment_res(-1) end,	flags={repeatable=true}},
	[opts.zoom_in]			=	{name="zoom_in",			fn=function() increment_zoom(-1) end,	flags={repeatable=true}},
	[opts.zoom_out]			=	{name="zoom_out",			fn=function() increment_zoom(1) end,	flags={repeatable=true}},
	[opts.wzoom_out]		=	{name="wzoom_out",			fn=function() increment_zoom(1) end },
	[opts.wzoom_in] 		=	{name="wzoom_in",			fn=function() increment_zoom(-1) end },
	[opts.reset_view] 		=	{name="reset_view",			fn=reset_view 			},
	[opts.switch_stereo]	=	{name="switch_stereo",		fn=switchStereoMode		},
	[opts.switch_eye]		=	{name="switch_eye",			fn=switchEye			},
	[opts.switch_scaler]	=	{name="switch_scaler",		fn=switchScaler			},
	[opts.switch_output_sbs]=	{name="switch_output_sbs",	fn=switchoutputsbs		},	
	[opts.toggle_smooth]	=	{name="toggle_smooth",		fn=toggleSmoothMouse	},
	[opts.switch_bounds]	=	{name="switch_bounds",		fn=switchInputFovBounds	},
	[opts.new_log_session]	=	{name="new_log_session",	fn=startNewLogSession	},
	[opts.grab_mouse]		=	{name="grab_mouse",			fn=mouse_btn0_cb		},
	[opts.mouse_pan]		=	{name="mouse_pan",			fn=mouse_pan			},
	[opts.show_help]		=	{name="show_help",			fn=showHelp				}
}

local register_toggle_key = function ()
	-- mp.add_forced_key_binding("v", "toggle_vr360", toggleVR)
	for k,v in pairs(bindings) do
		if v["name"] == "toggle_vr360" then
			mp.add_forced_key_binding(k, "toggle_vr360", v["fn"])
			return
		end
	end
end

register_toggle_key()

if opts.enabled == true then
	initFunction()
end
