ml_vpc: added options to use cookies from browsers and enable/disable the mod completely

This commit is contained in:
kafeijao 2025-11-18 14:53:59 +00:00
parent da9dc508d0
commit 7ada4c4d86
No known key found for this signature in database
GPG key ID: E99978723E454B4C
7 changed files with 302 additions and 3 deletions

View file

@ -1,3 +1,4 @@
using System;
using ABI_RC.VideoPlayer;
using System.Reflection;
using System.IO;
@ -10,6 +11,7 @@ namespace ml_vpc
public override void OnInitializeMelon()
{
Settings.Init();
HarmonyInstance.Patch(typeof(YoutubeDl).GetMethod("GetVideoMetaDataAsync", BindingFlags.NonPublic | BindingFlags.Static),
new HarmonyLib.HarmonyMethod(typeof(VideoPlayerCookies).GetMethod(nameof(OnGetYoutubeVideoMetaData_Prefix), BindingFlags.NonPublic | BindingFlags.Static))
);
@ -19,8 +21,52 @@ namespace ml_vpc
static void OnGetYoutubeVideoMetaData_Prefix(ref string parameter)
{
try
{
if (!Settings.Enabled)
return;
switch (Settings.Mode)
{
case Settings.CookieMode.File:
if (File.Exists(ms_cookiesPath))
parameter += string.Format(" --cookies \"{0}\"", ms_cookiesPath);
else
MelonLoader.MelonLogger.Warning("Cookies file not found in: '" + ms_cookiesPath + "'");
break;
case Settings.CookieMode.BrowserFirefox:
parameter += " --cookies-from-browser firefox";
break;
case Settings.CookieMode.BrowserBrave:
parameter += " --cookies-from-browser brave";
break;
case Settings.CookieMode.BrowserChrome:
parameter += " --cookies-from-browser chrome";
break;
case Settings.CookieMode.BrowserChromium:
parameter += " --cookies-from-browser chromium";
break;
case Settings.CookieMode.BrowserEdge:
parameter += " --cookies-from-browser edge";
break;
case Settings.CookieMode.BrowserOpera:
parameter += " --cookies-from-browser opera";
break;
case Settings.CookieMode.BrowserSafari:
parameter += " --cookies-from-browser safari";
break;
case Settings.CookieMode.BrowserVivaldi:
parameter += " --cookies-from-browser vivaldi";
break;
case Settings.CookieMode.BrowserWhale:
parameter += " --cookies-from-browser whale";
break;
}
}
catch(Exception e)
{
MelonLoader.MelonLogger.Warning(e);
}
}
}
}

View file

@ -7,6 +7,21 @@ This mod allows yt-dlp to use cookies for playing YouTube videos.
* Put `VideoPlayerCookies.dll` in `Mods` folder of game
# Usage
Available mod's settings in `Settings - General - Video Player Cookies`:
* **Enabled:** Whether this mod adds cookie parameters or not; `true` by default.
* **Cookie fetch mode:** cookies fetch method; `Cookie text file` by default.
* **Cookie text file** *(default)* fetches cookies from your `cookies.txt` file, check [How to create cookies.txt](#how-to-create-cookiestxt)
* **Browser Firefox** fetches cookies directly from FireFox browser. *requires to be logged-in on YouTube in FireFox*
* **Browser Brave** fetches cookies directly from Brave browser. *requires to be logged-in on YouTube in Brave*
* **Browser Chrome** fetches cookies directly from Chrome browser. *requires to be logged-in on YouTube in Chrome*
* **Browser Chromium** fetches cookies directly from Chromium browser. *requires to be logged-in on YouTube in Chromium*
* **Browser Edge** fetches cookies directly from Edge browser. *requires to be logged-in on YouTube in Edge*
* **Browser Opera** fetches cookies directly from Opera browser. *requires to be logged-in on YouTube in Opera*
* **Browser Safari** fetches cookies directly from Safari browser. *requires to be logged-in on YouTube in Safari*
* **Browser Vivaldi** fetches cookies directly from Vivaldi browser. *requires to be logged-in on YouTube in Vivaldi*
* **Browser Whale** fetches cookies directly from Whale browser. *requires to be logged-in on YouTube in Whale*
# How to create cookies.txt
* Acquire cookies for YouTube from your browser:
* Chromium-based browsers: [Get cookies.txt LOCALLY](https://chromewebstore.google.com/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc) extension
* Firefox-based browsers: [cookies.txt](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt) extension

View file

@ -0,0 +1,30 @@
using System;
using System.IO;
using System.Reflection;
namespace ml_vpc
{
static class ResourcesHandler
{
readonly static string ms_namespace = typeof(ResourcesHandler).Namespace;
public static string GetEmbeddedResource(string p_name)
{
string l_result = "";
Assembly l_assembly = Assembly.GetExecutingAssembly();
try
{
Stream l_libraryStream = l_assembly.GetManifestResourceStream(ms_namespace + ".resources." + p_name);
StreamReader l_streadReader = new StreamReader(l_libraryStream);
l_result = l_streadReader.ReadToEnd();
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
return l_result;
}
}
}

144
ml_vpc/Settings.cs Normal file
View file

@ -0,0 +1,144 @@
using ABI_RC.Core.InteractionSystem;
using System;
using System.Collections.Generic;
namespace ml_vpc
{
static class Settings
{
internal class SettingEvent<T>
{
event Action<T> m_action;
public void AddListener(Action<T> p_listener) => m_action += p_listener;
public void RemoveListener(Action<T> p_listener) => m_action -= p_listener;
public void Invoke(T p_value) => m_action?.Invoke(p_value);
}
public enum CookieMode
{
File = 0,
BrowserFirefox,
BrowserBrave,
BrowserChrome, // This one might not work
BrowserChromium,
BrowserEdge,
BrowserOpera,
BrowserSafari,
BrowserVivaldi,
BrowserWhale,
}
private enum ModSetting
{
Enabled = 0,
Mode,
}
public static bool Enabled { get; private set; } = true;
public static CookieMode Mode { get; private set; } = CookieMode.File;
static MelonLoader.MelonPreferences_Category ms_category = null;
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
public static readonly SettingEvent<bool> OnEnabledChanged = new SettingEvent<bool>();
public static readonly SettingEvent<CookieMode> OnModeChanged = new SettingEvent<CookieMode>();
internal static void Init()
{
ms_category = MelonLoader.MelonPreferences.CreateCategory("VPC", null, true);
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
{
ms_category.CreateEntry(nameof(ModSetting.Enabled), Enabled),
ms_category.CreateEntry(nameof(ModSetting.Mode), (int)CookieMode.File),
};
Enabled = (bool)ms_entries[(int)ModSetting.Enabled].BoxedValue;
Mode = (CookieMode)ms_entries[(int)ModSetting.Mode].BoxedValue;
MelonLoader.MelonCoroutines.Start(WaitMainMenuUi());
}
private static System.Collections.IEnumerator WaitMainMenuUi()
{
while(ViewManager.Instance == null)
yield return null;
while(ViewManager.Instance.cohtmlView == null)
yield return null;
while(ViewManager.Instance.cohtmlView.Listener == null)
yield return null;
ViewManager.Instance.cohtmlView.Listener.ReadyForBindings += () =>
{
ViewManager.Instance.cohtmlView.View.BindCall("OnToggleUpdate_" + ms_category.Identifier, new Action<string, string>(OnToggleUpdate));
ViewManager.Instance.cohtmlView.View.BindCall("OnDropdownUpdate_" + ms_category.Identifier, new Action<string, string>(OnDropdownUpdate));
};
ViewManager.Instance.cohtmlView.Listener.FinishLoad += (_) =>
{
ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mods_extension.js"));
ViewManager.Instance.cohtmlView.View.ExecuteScript(ResourcesHandler.GetEmbeddedResource("mod_menu.js"));
MelonLoader.MelonCoroutines.Start(UpdateMenuSettings());
};
}
private static System.Collections.IEnumerator UpdateMenuSettings()
{
while(!ViewManager.Instance.IsReady || !ViewManager.Instance.IsViewShown)
yield return null;
foreach(var l_entry in ms_entries)
ViewManager.Instance.cohtmlView.View.TriggerEvent("updateModSetting", ms_category.Identifier, l_entry.DisplayName, l_entry.GetValueAsString());
}
private static void OnToggleUpdate(string p_name, string p_value)
{
try
{
if(Enum.TryParse(p_name, out ModSetting l_setting) && bool.TryParse(p_value, out bool l_value))
{
switch(l_setting)
{
case ModSetting.Enabled:
{
Enabled = l_value;
OnEnabledChanged.Invoke(Enabled);
}
break;
}
ms_entries[(int)l_setting].BoxedValue = l_value;
}
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
private static void OnDropdownUpdate(string p_name, string p_value)
{
try
{
if(Enum.TryParse(p_name, out ModSetting l_setting) && int.TryParse(p_value, out int l_value))
{
switch(l_setting)
{
case ModSetting.Mode:
{
Mode = (CookieMode)l_value;
OnModeChanged.Invoke(Mode);
}
break;
}
ms_entries[(int)l_setting].BoxedValue = l_value;
}
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
}
}

12
ml_vpc/Utils.cs Normal file
View file

@ -0,0 +1,12 @@
using ABI_RC.Core.UI;
using System.Reflection;
namespace ml_vpc
{
static class Utils
{
static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.Instance | BindingFlags.NonPublic);
public static void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => (ms_view?.GetValue(p_instance) as cohtml.Net.View)?.ExecuteScript(p_script);
}
}

View file

@ -18,6 +18,11 @@
<Exec Command="copy /y &quot;$(TargetPath)&quot; &quot;$(CVRPath)/Mods/&quot;" />
</Target>
<ItemGroup>
<EmbeddedResource Include="../js/mods_extension.js" Link="resources/mods_extension.js" />
<EmbeddedResource Include="resources/mod_menu.js" />
</ItemGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>$(CVRPath)/MelonLoader/net35/0Harmony.dll</HintPath>
@ -29,6 +34,16 @@
<Private>false</Private>
<SpecificVersion>false</SpecificVersion>
</Reference>
<Reference Include="cohtml.Net">
<HintPath>$(CVRPath)/ChilloutVR_Data/Managed/cohtml.Net.dll</HintPath>
<Private>false</Private>
<SpecificVersion>false</SpecificVersion>
</Reference>
<Reference Include="Cohtml.Runtime">
<HintPath>$(CVRPath)/ChilloutVR_Data/Managed/Cohtml.Runtime.dll</HintPath>
<Private>false</Private>
<SpecificVersion>false</SpecificVersion>
</Reference>
<Reference Include="MelonLoader">
<HintPath>$(CVRPath)/MelonLoader/net35/MelonLoader.dll</HintPath>
<Private>false</Private>

View file

@ -0,0 +1,37 @@
{
let l_block = document.createElement('div');
l_block.innerHTML = `
<div class ="settings-subcategory">
<div class ="subcategory-name">Video Player Cookies</div>
<div class ="subcategory-description"></div>
</div>
<div class ="row-wrapper">
<div class ="option-caption" data-tooltip="Whether the mod is enabled or not">Enabled: </div>
<div class ="option-input">
<div id="Enabled" class ="inp_toggle no-scroll" data-current="true"></div>
</div>
</div>
<div class ="row-wrapper">
<div class ="option-caption" data-tooltip="The way cookies are fetched">Cookie fetch mode: </div>
<div class ="option-input">
<div id="Mode" class ="inp_dropdown no-scroll" data-options="0:Cookie text file,1:Browser Firefox,2:Browser Brave,3:Browser Chrome,4:Browser Chromium,5:Browser Edge,6:Browser Opera,7:Browser Safari,8:Browser Vivaldi,9:Browser Whale" data-current="0"></div>
</div>
</div>
`;
document.getElementById('settings-general').appendChild(l_block);
// Toggles
for (let l_toggle of l_block.querySelectorAll('.inp_toggle'))
modsExtension.addSetting('VPC', l_toggle.id, modsExtension.createToggle(l_toggle, 'OnToggleUpdate_VPC'));
// Sliders
for (let l_slider of l_block.querySelectorAll('.inp_slider'))
modsExtension.addSetting('VPC', l_slider.id, modsExtension.createSlider(l_slider, 'OnSliderUpdate_VPC'));
// Dropdowns
for (let l_dropdown of l_block.querySelectorAll('.inp_dropdown'))
modsExtension.addSetting('VPC', l_dropdown.id, modsExtension.createDropdown(l_dropdown, 'OnDropdownUpdate_VPC'));
}