Compare commits

..

16 commits

Author SHA1 Message Date
Zarg
da0783dfd8 Added fullscreen-on-launch webmod 2025-12-15 23:56:38 +01:00
Zarg
adb360bd4a Choco push 5.0.21 2025-12-09 11:14:18 +01:00
Zarg
f6b08f6267 Bump to 5.0.21 and updated readme
- Bump to 5.0.21
- Updated Readme Animejanai section, added video guide and updated build link
- Updated App errors with more common issues
2025-12-09 11:12:28 +01:00
Zarg
90f8961641
Typo fixes - PR #99 from Dyras/patch-1
Spelling fixes in the readme
2025-12-08 01:08:38 +01:00
Zarg
be66d6be39
Added Winget Install Option - PR #175 from YusufKhalifadev/webview-windows-Winget
Added Winget Install Option
2025-12-08 01:05:53 +01:00
Zarg
3725f0b53d
Update installation instructions in README.md
- Added winget install
- Added (Recommended) note
2025-12-08 01:02:22 +01:00
Zarg
38349f0741 Updated ublock description and added 4.20.15 stremio runtime 2025-12-08 00:10:57 +01:00
Zarg
e197d8cc99 Server version bump to 4.20.15 2025-12-07 20:40:11 +01:00
YusufKhalifadev
4390983608 change icon 2025-12-06 14:07:00 +02:00
YusufKhalifadev
bca250f8dd Update README.md 2025-12-06 14:00:27 +02:00
Zarg
b4cad35041 Updated animejanai script to work with multi part releases
- Updated Script to work with multi part releases.
2025-10-22 17:29:08 +02:00
Zarg
7d1b63c993 Version Bump 5.0.20 2025-10-22 16:39:31 +02:00
Zarg
7add3f622b Added WebMods feature
- Added WebMods feature, allows loading custom js and css
2025-10-08 07:25:29 +02:00
Zarg
c5a6a7fb64 Choco 5.0.19 2025-08-20 23:11:59 +02:00
Zarg
a87bec252f Version Bump 5.0.19 2025-08-20 22:42:25 +02:00
Johan
5665603bf2
Spelling fixes in the readme 2025-07-09 15:56:54 +02:00
21 changed files with 418 additions and 197 deletions

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16)
project(stremio VERSION "5.0.18")
project(stremio VERSION "5.0.21")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

View file

@ -73,7 +73,7 @@
<img src="https://i.imgur.com/rLTmFC2.png" alt="Stremio Web Desktop Screenshot" width="600" />
</p>
<p align="center">
<small><i>Anime4k + Auto HDR vs Offical Stremio v5.</i></small>
<small><i>Anime4k + Auto HDR vs Official Stremio v5.</i></small>
</p>
<p align="center">
@ -100,11 +100,20 @@
## 🔧 Installation
1. 🪟 **Windows x64 and x86**
1. 📥 **Installer**
1. 📥 **Installer (Recommended)**
- **Install using the** `Installer`. Download `stremio-5.0.0-x64.exe` or `stremio-5.0.0-x86.exe` and run it.
2. 💼 **Portable Version**
- **Install using the** `Archive`. Download `stremio-5.0.0-x64.7z` or `stremio-5.0.0-x86.7z` extract it and run `stremio.exe`
3. 🥄 **Scoop.sh**
3. 📦 **Winget**
```shell
# Install
winget install Zaarrg.StremioCommunity
# Update
winget upgrade Zaarrg.StremioCommunity
# Uninstall
winget uninstall Zaarrg.StremioCommunity
```
4. 🥄 **Scoop.sh**
```shell
# Install
scoop bucket add zarg https://github.com/zaarrg/scoop
@ -115,7 +124,7 @@
# Uninstall
scoop uninstall stremio-desktop-v5
```
4. ~~🍫 **Chocolatey**~~
5. ~~🍫 **Chocolatey**~~
```shell
⚠️ Note: Chocolatey is not updated use scoop or a other installation method!
# Install
@ -125,14 +134,14 @@
# Uninstall
choco uninstall stremio-desktop-v5 -y
```
> **⏳ Note:** If you have stremio-desktop v4.x.x installed make sure to uninstall it first. Otherwise there might be issues.
2. 🚀 **Linux, macOS**
- Coming soon!
> **⏳ Note:** Linux and Mac release will take considerable time as they need their own build with os specific technology's
> **⏳ Note:** Linux and Mac release will take considerable time as they need their own build with OS specific technologies
## 🔍 **Mpv Upscalers**
@ -143,7 +152,7 @@
- 🎨 **[AnimeJaNai](https://github.com/the-database/mpv-upscale-2x_animejanai)**
- ❌ Not included by default.
- 📥 Download from the **Stremio-Desktop-v5** [release tab](https://github.com/Zaarrg/stremio-desktop-v5/releases/5.0.0-beta.7) the `stremio-animejanai-3.x.x.7z` for Stremio and drop the content of the 7z into `%localAppData%\Programs\LNV\Stremio-5\` and `replace all`
- 📥 Download from the **Stremio-Desktop-v5** [release tab](https://github.com/Zaarrg/stremio-community-v5/releases/tag/5.0.0-beta.20) the `stremio-animejanai-3.x.x.7z.001` and `stremio-animejanai-3.x.x.7z.002` for Stremio and drop the content of the 7z into `%localAppData%\Programs\LNV\Stremio-5\` and `replace all`
- 🛠️ **Changes made:**
- Removed `mpvnet.exe` as Stremio is used as the player.
- Adjusted `mpv.conf` to work with Stremio.
@ -155,6 +164,8 @@
- 🔢 `SHIFT+1` - `SHIFT+3` Select Quality, Balanced or Performance Profiles
- ⚙️ `CTRL+1` - `CTRL+9` Switch between Custom Profiles
- 🔗 For more, check [AnimeJaNai](https://github.com/the-database/mpv-upscale-2x_animejanai)
- 📺 **Installation Guide**
- See: [AnimeJaNai Youtube Installation Guide](https://www.youtube.com/watch?v=ZlPJ-M3kkdM)
> **⏳ Note:** When using AnimeJaNai on first playback Stremio will be unresponsive and a console will open to build the model via e.g. TensorRT. You will need to wait until the console closes for playback to start. This happens only once per model.
@ -166,7 +177,7 @@
## 🔍 **Mpv Addons**
- 🎥 **[ThumbFast](https://github.com/po5/thumbfast)**
- 🔧 Go in the `Stremio-Dekstop-v5` Repo to ``utils/mpv/thumbfast`` or [direct-link](https://github.com/Zaarrg/stremio-desktop-v5/tree/webview-windows/utils/mpv/thumbfast) and download ``thumbfast.7z``. Drag and Drop the archive contents into ``%localAppData%\Programs\LNV\Stremio-5``
- 🔧 Go in the `Stremio-Desktop-v5` Repo to ``utils/mpv/thumbfast`` or [direct-link](https://github.com/Zaarrg/stremio-desktop-v5/tree/webview-windows/utils/mpv/thumbfast) and download ``thumbfast.7z``. Drag and Drop the archive contents into ``%localAppData%\Programs\LNV\Stremio-5``
- 📁 Works best with local files as there is no **network bottleneck**. U can `Drag and Drop` any local file into **Stremio** or right click ``Open With > Stremio``
> **⏳ Note:** For more details visit [mpv-portable-configs](https://github.com/Zaarrg/stremio-desktop-v5/blob/webview-windows/utils/mpv/README.md)
@ -200,13 +211,31 @@
- 🔍 ``AllowZoom`` Allow zoom via `pinch action` or ``CTRL+Scroll``
- ❌ **App Errors**
- If the app does not start and instantly closes, check the error log in ``portable_config\errors-{date}.txt``
- ⚠️ **Common Issues**
- ❗ [WebView2](https://developer.microsoft.com/de-de/microsoft-edge/webview2/#download) not installed Installed by default using the installer but may have failed
- 🌎 Unreachable Web UI. Make sure you can reach the web ui hosted [here](https://zaarrg.github.io/stremio-web-shell-fixes/).
- ⚙️ Invalid MPV configuration like ``mpv.conf``, ``input.conf`` or ``scripts``
- 📄 Invalid ``stremio-settings.ini``
- 🧩 Invalid ``extensions``
- If the app does not start and instantly closes, check the error log in ``portable_config\errors-{date}.txt``
* ⚠️ **Common Issues**
* ❗ **WebView2 not available**
* The **installer** requires [WebView2](https://developer.microsoft.com/de-de/microsoft-edge/webview2/#download) to be installed.
* The **portable version** includes its own WebView2 runtime and does **not** require system installation.
* If a WebView-related error appears, install WebView2 or use the portable build.
* 🌎 **Unreachable Web UI**
The app loads the UI in the following order:
1. [https://stremio.zarg.me/](https://stremio.zarg.me/)
2. [https://zaarrg.github.io/stremio-web-shell-fixes/](https://zaarrg.github.io/stremio-web-shell-fixes/)
3. [https://web.stremio.com/](https://web.stremio.com/)
* If the UI appears stuck, press **F5** to reload.
* If the cached UI is outdated, use **Ctrl+F5** to clear cache and reload.
* ⚙️ **Invalid MPV configuration**
Invalid or unsupported config in `mpv.conf`, `input.conf`, or `scripts/` may prevent MPV from initializing.
* 📄 **Invalid `stremio-settings.ini`**
A default configuration is available:
[stremio-settings.ini](https://github.com/Zaarrg/stremio-desktop-v5/blob/webview-windows/utils/stremio/stremio-settings.ini)
* If corrupted, delete the file to let the app regenerate it.
* 🧩 **Invalid or incompatible extensions**
Extensions under `portable_config/extensions` may prevent startup.
* **uBlock** or similar blockers can cause infinite loading loops → remove them (see *Browser Extensions* section above).
* 🔁 **Server not running after sleep / incomplete restart**
If the PC went to sleep, the internal stremio server stops.
* Fully close the app via **Task Manager** and restart it.
> **⏳ Note:** A default stremio-settings.ini can be found [here](https://github.com/Zaarrg/stremio-desktop-v5/blob/webview-windows/utils/stremio/stremio-settings.ini)
@ -239,7 +268,7 @@ Enhance your Stremio experience by customizing the MPV player settings. Below ar
CTRL+4 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl;~~/shaders/Anime4K_Restore_CNN_VL.glsl;~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl;~~/shaders/Anime4K_Restore_CNN_M.glsl;~~/shaders/Anime4K_AutoDownscalePre_x2.glsl;~~/shaders/Anime4K_AutoDownscalePre_x4.glsl;~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode A+A (HQ)"
CTRL+5 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl;~~/shaders/Anime4K_Restore_CNN_Soft_VL.glsl;~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl;~~/shaders/Anime4K_AutoDownscalePre_x2.glsl;~~/shaders/Anime4K_AutoDownscalePre_x4.glsl;~~/shaders/Anime4K_Restore_CNN_Soft_M.glsl;~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode B+B (HQ)"
CTRL+6 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl;~~/shaders/Anime4K_Upscale_Denoise_CNN_x2_VL.glsl;~~/shaders/Anime4K_AutoDownscalePre_x2.glsl;~~/shaders/Anime4K_AutoDownscalePre_x4.glsl;~~/shaders/Anime4K_Restore_CNN_M.glsl;~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode C+A (HQ)"
CTRL+0 no-osd change-list glsl-shaders clr ""; show-text "GLSL shaders cleared"
```
> **⏳ Note:** Some keys might not work as key presses are converted from js event.codes to literal values for mpv
@ -247,7 +276,7 @@ Enhance your Stremio experience by customizing the MPV player settings. Below ar
- **🔡 Subtitle Customization:**
- Subtitles can be full customized in the ``mpv.conf`` by adding the following:
```shell
# Adjust as needed -
# Adjust as needed -
sub-font="Comic Sans MS"
osd-font="Comic Sans MS"
osd-font-size=43
@ -272,12 +301,12 @@ Enhance your Stremio experience by customizing the MPV player settings. Below ar
'subtitlesTextColor': 'sub-color',
'subtitlesBackgroundColor': 'sub-back-color',
'subtitlesOutlineColor': 'sub-border-color',
# Affected mpv sub settings by this are:
sub-color
sub-back-color # + Alias sub-shadow-color
sub-border-color # + Alias sub-outline-color
# All these need to be set via the web ui instead
```
@ -299,8 +328,8 @@ If you want to build this app yourself, check the “[docs](https://github.com/Z
## ⚠️ **Disclaimer**
This project is not affiliated with **Stremio** in any way.
This fork is provided solely for educational and lawful use. **It does not support piracy or any form of copyright infringement.**
It is the users responsibility to ensure that any content accessed is fully compliant with the DMCA and all applicable copyright laws.
This fork is provided solely for educational and lawful use. **It does not support piracy or any form of copyright infringement.**
It is the users responsibility to ensure that any content accessed is fully compliant with the DMCA and all applicable copyright laws.
The project maintainers do not condone or support any illegal activities.
## 🤝 **Support Development**
@ -314,4 +343,4 @@ If you enjoy this project and want to support further development, consider [buy
<p align="center">
<strong>⭐ Made with ❤️ by <a href="https://github.com/Zaarrg">Zaarrg</a></strong>
</p>
</p>

View file

@ -235,27 +235,52 @@ function find7zExecutable() {
const version = releaseJson.tag_name || 'latest';
console.log(`Latest version: ${version}`);
// Step 2: Find the 'full-package' .7z asset
const assets = releaseJson.assets;
const fullPackageAsset = assets.find(asset => asset.name.includes('full-package') && asset.name.endsWith('.7z'));
// Step 2: Locate and download the 'full-package' asset(s) (single or multi-part)
const assets = releaseJson.assets || [];
const fullPackageCandidates = assets.filter(a =>
a.name.includes('full-package') &&
(a.name.endsWith('.7z') || /\.7z\.\d+$/.test(a.name))
);
if (!fullPackageAsset) {
throw new Error("No 'full-package' .7z asset found in the latest release.");
if (fullPackageCandidates.length === 0) {
throw new Error("No 'full-package' .7z or .7z.NNN assets found in the latest release.");
}
const downloadUrl = fullPackageAsset.browser_download_url;
const assetName = fullPackageAsset.name;
const downloadedFilePath = path.join(TEMP_DIR, assetName);
// Group by base name (strip .7z or .7z.NNN)
const groups = fullPackageCandidates.reduce((acc, a) => {
const base = a.name.replace(/\.7z(\.\d+)?$/, '');
(acc[base] ||= []).push(a);
return acc;
}, {});
console.log(`Downloading asset: ${assetName}`);
await downloadFile(downloadUrl, downloadedFilePath);
console.log(`Downloaded to ${downloadedFilePath}`);
// Pick the group with the most parts (typically only one group exists in a release)
const [selectedBase, selectedGroup] = Object.entries(groups)
.sort((a, b) => b[1].length - a[1].length)[0];
// Step 3: Extract the .7z archive
// Sort deterministically: .7z (treated like part 0) or .7z.001, .002, ...
const sortedAssets = selectedGroup.slice().sort((a, b) => {
const pa = (/\.7z\.(\d+)$/.exec(a.name)?.[1]) ? parseInt(/\.7z\.(\d+)$/.exec(a.name)[1], 10) : 0;
const pb = (/\.7z\.(\d+)$/.exec(b.name)?.[1]) ? parseInt(/\.7z\.(\d+)$/.exec(b.name)[1], 10) : 0;
return pa - pb;
});
// Download all parts into TEMP_DIR
const downloadedParts = [];
for (const asset of sortedAssets) {
const dest = path.join(TEMP_DIR, asset.name);
console.log(`Downloading asset: ${asset.name}`);
await downloadFile(asset.browser_download_url, dest);
downloadedParts.push(dest);
}
// For extraction: if multipart, 7-Zip expects we point at the .7z.001; if single, the .7z file itself
const archiveToExtract = downloadedParts[0];
// Step 3: Extract the archive (7-Zip will auto-detect and read all parts if .001 is used)
const extractDir = path.join(TEMP_DIR, 'extracted');
fs.mkdirSync(extractDir, { recursive: true });
console.log(`Extracting ${downloadedFilePath} to ${extractDir}...`);
execCommand(`${sevenZipPath} x "${downloadedFilePath}" -o"${extractDir}" -y`, TEMP_DIR);
console.log(`Extracting ${path.basename(archiveToExtract)} to ${extractDir}...`);
execCommand(`${sevenZipPath} x "${archiveToExtract}" -o"${extractDir}" -y`, TEMP_DIR);
console.log('Extraction complete.');
// Step 4: Identify the root directory inside the extracted folder
@ -346,7 +371,7 @@ function find7zExecutable() {
console.log('Cleanup complete.');
console.log('=== Build AnimeJaNai Script Completed Successfully ===');
process.exit(1);
process.exit(0);
} catch (error) {
console.error('Error during build:', error.message);
process.exit(1);

View file

@ -37,7 +37,7 @@ const DEFAULT_SETTINGS_FOLDER = path.join(SOURCE_DIR, 'utils', 'stremio');
const DEFAULT_NSIS = 'C:\\Program Files (x86)\\NSIS\\makensis.exe';
//VCPKG
const VCPKG_TRIPLET = ARCH === 'x86' ? 'x86-windows-static' : 'x64-windows-static';
const VCPKG_CMAKE = 'C:/bin/vcpkg/scripts/buildsystems/vcpkg.cmake';
const VCPKG_CMAKE = 'G:\\Documents\\Github\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake';
// ---------------------------------------------------------------------
// Main

View file

@ -3,7 +3,7 @@
"name": "uBlock Origin",
"extension_name": "ublock",
"logo": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/UBlock_Origin.svg/2048px-UBlock_Origin.png",
"description": "uBlock Origin is not just an “ad blocker“, it's a wide-spectrum content blocker with CPU and memory efficiency as a primary feature.",
"description": "uBlock Origin is not just an “ad blocker“, it's a wide-spectrum content blocker with CPU and memory efficiency as a primary feature. If stremio does not start and loads infinitely remove this extension.",
"types": ["Browser Extension", "other"],
"behaviorHints": {
"configurable": true,

View file

@ -27,7 +27,7 @@ using json = nlohmann::json;
#define APP_TITLE "Stremio - Freedom to Stream"
#define APP_NAME "Stremio"
#define APP_CLASS L"Stremio"
#define APP_VERSION "5.0.18"
#define APP_VERSION "5.0.21"
// -----------------------------------------------------------------------------
// Globals

View file

@ -1,178 +1,176 @@
#pragma comment(linker, "/SUBSYSTEM:WINDOWS")
#pragma comment(linker, "/ENTRY:mainCRTStartup")
#include "discord_rpc.h"
#include <windows.h>
#include <shellscalingapi.h>
#include <VersionHelpers.h>
#include <gdiplus.h>
#include <iostream>
#include <shellscalingapi.h>
#include <sstream>
#include <VersionHelpers.h>
#include "discord_rpc.h"
#include "ui/mainwindow.h"
#include "core/globals.h"
#include "utils/crashlog.h"
#include "utils/config.h"
#include "tray/tray.h"
#include "mpv/player.h"
#include "node/server.h"
#include "tray/tray.h"
#include "ui/mainwindow.h"
#include "ui/splash.h"
#include "webview/webview.h"
#include "updater/updater.h"
#include "utils/helpers.h"
#include "utils/config.h"
#include "utils/crashlog.h"
#include "utils/discord.h"
#include "utils/helpers.h"
#include "webview/webview.h"
// This started as 1-week project so please don't take the code to seriously
int main(int argc, char* argv[])
{
// Catch unhandled exceptions
SetUnhandledExceptionFilter([](EXCEPTION_POINTERS* info) -> LONG
{
std::wstringstream ws;
ws << L"Unhandled exception! Code=0x" << std::hex << info->ExceptionRecord->ExceptionCode;
AppendToCrashLog(ws.str());
Cleanup();
return EXCEPTION_EXECUTE_HANDLER;
});
atexit(Cleanup);
int main(int argc, char *argv[]) {
// Catch unhandled exceptions
SetUnhandledExceptionFilter([](EXCEPTION_POINTERS *info) -> LONG {
std::wstringstream ws;
ws << L"Unhandled exception! Code=0x" << std::hex
<< info->ExceptionRecord->ExceptionCode;
AppendToCrashLog(ws.str());
Cleanup();
return EXCEPTION_EXECUTE_HANDLER;
});
atexit(Cleanup);
// DPI
if (IsWindowsVersionOrGreater(10, 0, 14393)){
typedef BOOL(WINAPI *SetDpiCtxFn)(DPI_AWARENESS_CONTEXT);
auto setDpiAwarenessContext = (SetDpiCtxFn)GetProcAddress(GetModuleHandleW(L"user32.dll"), "SetProcessDpiAwarenessContext");
if(setDpiAwarenessContext){
setDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
} else {
// Fallback for Windows 8.1 and Windows 10 before 1607:
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
// DPI
if (IsWindowsVersionOrGreater(10, 0, 14393)) {
typedef BOOL(WINAPI * SetDpiCtxFn)(DPI_AWARENESS_CONTEXT);
auto setDpiAwarenessContext = (SetDpiCtxFn)GetProcAddress(
GetModuleHandleW(L"user32.dll"), "SetProcessDpiAwarenessContext");
if (setDpiAwarenessContext) {
setDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
} else {
// Fallback for Windows 8.1 and Windows 10 before 1607:
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
}
// parse cmd line
for(int i=1; i<argc; i++){
std::string arg(argv[i]);
if(arg.rfind("--webui-url=", 0)==0){
g_webuiUrls.insert(g_webuiUrls.begin(), Utf8ToWstring(arg.substr(12)));
} else if(arg.rfind("--autoupdater-endpoint=",0)==0){
g_updateUrl = arg.substr(23);
} else if(arg=="--streaming-server-disabled"){
g_streamingServer=false;
} else if(arg=="--autoupdater-force-full"){
g_autoupdaterForceFull=true;
}
// parse cmd line
for (int i = 1; i < argc; i++) {
std::string arg(argv[i]);
if (arg.rfind("--webui-url=", 0) == 0) {
g_webuiUrls.insert(g_webuiUrls.begin(), Utf8ToWstring(arg.substr(12)));
} else if (arg.rfind("--autoupdater-endpoint=", 0) == 0) {
g_updateUrl = arg.substr(23);
} else if (arg == "--streaming-server-disabled") {
g_streamingServer = false;
} else if (arg == "--autoupdater-force-full") {
g_autoupdaterForceFull = true;
}
}
// single instance
std::wstring launchProtocol;
if(!CheckSingleInstance(argc, argv, launchProtocol)){
return 0;
}
g_launchProtocol = launchProtocol;
// single instance
std::wstring launchProtocol;
if (!CheckSingleInstance(argc, argv, launchProtocol)) {
return 0;
}
g_launchProtocol = launchProtocol;
// check stremio-runtime duplicates
std::vector<std::wstring> processesToCheck={L"stremio.exe", L"stremio-runtime.exe"};
if(IsDuplicateProcessRunning(processesToCheck)){
MessageBoxW(nullptr,
L"An older version of Stremio or Stremio server may be running. There could be issues.",
L"Stremio Already Running", MB_OK|MB_ICONWARNING);
}
// check stremio-runtime duplicates
std::vector<std::wstring> processesToCheck = {L"stremio.exe",
L"stremio-runtime.exe"};
if (IsDuplicateProcessRunning(processesToCheck)) {
MessageBoxW(nullptr,
L"An older version of Stremio or Stremio server may be "
L"running. There could be issues.",
L"Stremio Already Running", MB_OK | MB_ICONWARNING);
}
// init GDI+
Gdiplus::GdiplusStartupInput gpsi;
if(Gdiplus::GdiplusStartup(&g_gdiplusToken, &gpsi, nullptr)!=Gdiplus::Ok){
AppendToCrashLog(L"[BOOT]: GdiplusStartup failed.");
return 1;
}
// init GDI+
Gdiplus::GdiplusStartupInput gpsi;
if (Gdiplus::GdiplusStartup(&g_gdiplusToken, &gpsi, nullptr) != Gdiplus::Ok) {
AppendToCrashLog(L"[BOOT]: GdiplusStartup failed.");
return 1;
}
// Load config
LoadSettings();
// Load config
LoadSettings();
// Initialize Discord RPC
InitializeDiscord();
// Initialize Discord RPC
InitializeDiscord();
// Updater
g_updaterThread=std::thread(RunAutoUpdaterOnce);
g_updaterThread.detach();
// Updater
g_updaterThread = std::thread(RunAutoUpdaterOnce);
g_updaterThread.detach();
g_hInst = GetModuleHandle(nullptr);
g_darkBrush = CreateSolidBrush(RGB(0,0,0));
g_hInst = GetModuleHandle(nullptr);
g_darkBrush = CreateSolidBrush(RGB(0, 0, 0));
// Register main window class
WNDCLASSEX wcex={0};
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW|CS_VREDRAW;
wcex.lpfnWndProc=WndProc;
wcex.hInstance=g_hInst;
wcex.hCursor=LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground=g_darkBrush;
wcex.lpszClassName=szWindowClass;
if(!RegisterClassEx(&wcex)){
AppendToCrashLog(L"[BOOT]: RegisterClassEx failed!");
return 1;
}
// Register main window class
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = g_hInst;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = g_darkBrush;
wcex.lpszClassName = szWindowClass;
if (!RegisterClassEx(&wcex)) {
AppendToCrashLog(L"[BOOT]: RegisterClassEx failed!");
return 1;
}
g_hWnd = CreateWindow(szWindowClass, szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
1200, 900,
nullptr, nullptr,
g_hInst, nullptr);
if(!g_hWnd){
AppendToCrashLog(L"[BOOT]: CreateWindow failed!");
return 1;
}
g_hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 1200, 900, nullptr,
nullptr, g_hInst, nullptr);
if (!g_hWnd) {
AppendToCrashLog(L"[BOOT]: CreateWindow failed!");
return 1;
}
//Add PlayPause Hotkey
if (!RegisterHotKey(g_hWnd, 1, 0, VK_MEDIA_PLAY_PAUSE)) {
AppendToCrashLog(L"[BOOT]: Failed to register hotkey!");
}
// Add PlayPause Hotkey
if (!RegisterHotKey(g_hWnd, 1, 0, VK_MEDIA_PLAY_PAUSE)) {
AppendToCrashLog(L"[BOOT]: Failed to register hotkey!");
}
// Scale Values with DPI
ScaleWithDPI();
LoadCustomMenuFont();
// Scale Values with DPI
ScaleWithDPI();
LoadCustomMenuFont();
// Load Saved position
WINDOWPLACEMENT wp;
if (LoadWindowPlacement(wp)) {
SetWindowPlacement(g_hWnd, &wp);
ShowWindow(g_hWnd, wp.showCmd);
UpdateWindow(g_hWnd);
} else {
ShowWindow(g_hWnd,SW_SHOW);
UpdateWindow(g_hWnd);
}
// Load Saved position
WINDOWPLACEMENT wp;
if (LoadWindowPlacement(wp)) {
SetWindowPlacement(g_hWnd, &wp);
ShowWindow(g_hWnd, wp.showCmd);
UpdateWindow(g_hWnd);
} else {
ShowWindow(g_hWnd, SW_SHOW);
UpdateWindow(g_hWnd);
}
// create splash
CreateSplashScreen(g_hWnd);
// create splash
CreateSplashScreen(g_hWnd);
// init mpv
if(!InitMPV(g_hWnd)){
DestroyWindow(g_hWnd);
return 1;
}
// init mpv
if (!InitMPV(g_hWnd)) {
DestroyWindow(g_hWnd);
return 1;
}
// node
if(g_streamingServer){
StartNodeServer();
}
// node
if (g_streamingServer) {
StartNodeServer();
}
// webview
InitWebView2(g_hWnd);
// webview
InitWebView2(g_hWnd);
// message loop
MSG msg;
while(GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
// message loop
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
// Run Discord RPC callbacks
Discord_RunCallbacks();
}
// Run Discord RPC callbacks
Discord_RunCallbacks();
}
if(g_darkBrush){
DeleteObject(g_darkBrush);
g_darkBrush=nullptr;
}
std::cout<<"Exiting...\n";
return (int)msg.wParam;
if (g_darkBrush) {
DeleteObject(g_darkBrush);
g_darkBrush = nullptr;
}
std::cout << "Exiting...\n";
return (int)msg.wParam;
}

View file

@ -1,5 +1,6 @@
#include "helpers.h"
#include <fstream>
#include <iostream>
#include <shellscalingapi.h>
#include <tlhelp32.h>
@ -244,4 +245,104 @@ void ScaleWithDPI() {
g_tray_sepH = ScaleValue(g_tray_sepH);
g_tray_w = ScaleValue(g_tray_w);
g_font_height = ScaleValue(g_font_height);
}
// ---- UTF-8 file read
bool ReadFileUtf8(const std::wstring& path, std::string& out)
{
std::ifstream f(path, std::ios::binary);
if (!f) return false;
f.seekg(0, std::ios::end);
std::streamsize size = f.tellg();
f.seekg(0, std::ios::beg);
out.resize(static_cast<size_t>(size));
if (size > 0) f.read(&out[0], size);
return true;
}
// ---- tiny Base64
std::string Base64Encode(const std::string& in)
{
static const char* T = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string out;
out.reserve(((in.size() + 2) / 3) * 4);
int val = 0, valb = -6;
for (uint8_t c : in) {
val = (val << 8) + c;
valb += 8;
while (valb >= 0) {
out.push_back(T[(val >> valb) & 0x3F]);
valb -= 6;
}
}
if (valb > -6) out.push_back(T[((val << 8) >> (valb + 8)) & 0x3F]);
while (out.size() % 4) out.push_back('=');
return out;
}
// ---- wrap CSS text into a safe injector (decodes UTF-8 from base64)
std::wstring MakeInjectCssScript(const std::wstring& idSafe, const std::string& cssUtf8)
{
const std::string b64 = Base64Encode(cssUtf8);
const std::wstring wb64 = Utf8ToWstring(b64);
std::wstringstream ss;
ss <<
L"(function(){try{"
L"if(window.top!==window)return;"
L"var id='webmods-css-" << idSafe << L"';"
L"function inject(){"
L"try{"
L"var root=document.head||document.documentElement||document.body;"
L"if(!root){"
L"document.addEventListener('DOMContentLoaded',inject,{once:true});"
L"document.addEventListener('readystatechange',function(){"
L"if(document.readyState==='interactive'||document.readyState==='complete')inject();"
L"},{once:true});"
L"setTimeout(inject,25);"
L"return;"
L"}"
L"if(document.getElementById(id))return;"
L"var bin=atob('" << wb64 << L"');"
L"var bytes=new Uint8Array(bin.length);"
L"for(var i=0;i<bin.length;i++)bytes[i]=bin.charCodeAt(i);"
L"var css='';"
L"try{css=new TextDecoder('utf-8').decode(bytes);}catch(e){css=decodeURIComponent(escape(bin));}"
L"var s=document.createElement('style');"
L"s.id=id;"
L"s.textContent=css;"
L"root.appendChild(s);"
L"}catch(e){console.error('webmods css inject tick failed:',e);setTimeout(inject,50);}"
L"}"
L"inject();"
L"}catch(e){console.error('webmods css inject failed:',e);}})();";
return ss.str();
}
// ---- wrap JS text into a safe executor
std::wstring MakeInjectJsScript(const std::wstring&,const std::string& jsUtf8)
{
const std::string b64 = Base64Encode(jsUtf8);
const std::wstring wb64 = Utf8ToWstring(b64);
std::wstringstream ss;
ss <<
L"(function(){try{"
L"if(window.top!==window)return;"
L"function run(){"
L"try{"
L"var bin=atob('" << wb64 << L"');"
L"var bytes=new Uint8Array(bin.length);"
L"for(var i=0;i<bin.length;i++)bytes[i]=bin.charCodeAt(i);"
L"var js='';"
L"try{js=new TextDecoder('utf-8').decode(bytes);}catch(e){js=decodeURIComponent(escape(bin));}"
L"(0,eval)(js);"
L"}catch(e){console.error('webmods js exec tick failed:',e);setTimeout(run,25);}"
L"}"
L"run();"
L"}catch(e){console.error('webmods js exec failed:',e);}})();";
return ss.str();
}

View file

@ -11,6 +11,8 @@ std::wstring Utf8ToWstring(const std::string& utf8Str);
std::string decodeURIComponent(const std::string& encoded);
std::wstring GetExeDirectory();
std::wstring GetFirstReachableUrl();
std::wstring MakeInjectCssScript(const std::wstring& idSafe, const std::string& cssUtf8);
std::wstring MakeInjectJsScript(const std::wstring& idSafe, const std::string& jsUtf8);
bool FileExists(const std::wstring& path);
bool DirectoryExists(const std::wstring& dirPath);
bool IsDuplicateProcessRunning(const std::vector<std::wstring>& targetProcesses);
@ -18,5 +20,6 @@ bool isSubtitle(const std::wstring& filePath);
bool URLContainsAny(const std::wstring& url);
bool FetchAndParseWhitelist();
void ScaleWithDPI();
bool ReadFileUtf8(const std::wstring& path, std::string& out);
#endif // HELPERS_H

View file

@ -289,6 +289,8 @@ void InitWebView2(HWND hWnd)
g_webview->AddScriptToExecuteOnDocumentCreated(EXEC_SHELL_SCRIPT,nullptr);
g_webview->AddScriptToExecuteOnDocumentCreated(INJECTED_KEYDOWN_SCRIPT,nullptr);
SetupWebMods();
SetupExtensions();
SetupWebMessageHandler();
@ -627,6 +629,68 @@ static void SetupExtensions()
}
}
static void SetupWebMods()
{
if (!g_webview) return;
wchar_t buf[MAX_PATH];
GetModuleFileNameW(nullptr, buf, MAX_PATH);
std::wstring exeDir = buf;
size_t pos = exeDir.find_last_of(L"\\/");
if (pos != std::wstring::npos) exeDir.erase(pos);
const std::filesystem::path root = std::filesystem::path(exeDir) / L"portable_config" / L"webmods";
if (!std::filesystem::exists(root) || !std::filesystem::is_directory(root)) {
std::wcout << L"[WEBMODS] Folder not found: " << root.wstring() << std::endl;
return;
}
std::vector<std::filesystem::path> cssFiles, jsFiles;
for (const auto& e : std::filesystem::recursive_directory_iterator(root)) {
if (!e.is_regular_file()) continue;
auto ext = e.path().extension().wstring();
std::transform(ext.begin(), ext.end(), ext.begin(), ::towlower);
if (ext == L".map" || ext == L".bak" || ext == L".tmp") continue;
if (ext == L".css") cssFiles.push_back(e.path());
else if (ext == L".js") jsFiles.push_back(e.path());
}
auto relStr = [&](const std::filesystem::path& p){
try { return std::filesystem::relative(p, root).wstring(); }
catch(...) { return p.wstring(); }
};
auto sorter = [&](const std::filesystem::path& a, const std::filesystem::path& b){
auto ra = relStr(a), rb = relStr(b);
return _wcsicmp(ra.c_str(), rb.c_str()) < 0;
};
std::sort(cssFiles.begin(), cssFiles.end(), sorter);
std::sort(jsFiles.begin(), jsFiles.end(), sorter);
auto makeId = [&](const std::filesystem::path& p){
std::wstring id = relStr(p);
for (auto& ch : id) if (!iswalnum(ch)) ch = L'_';
return id;
};
for (const auto& p : cssFiles) {
std::string content;
if (!ReadFileUtf8(p.wstring(), content)) continue;
const std::wstring id = makeId(p);
const std::wstring script = MakeInjectCssScript(id, content);
g_webview->AddScriptToExecuteOnDocumentCreated(script.c_str(), nullptr);
std::wcout << L"[WEBMODS] CSS: " << relStr(p) << std::endl;
}
for (const auto& p : jsFiles) {
std::string content;
if (!ReadFileUtf8(p.wstring(), content)) continue;
const std::wstring id = makeId(p);
const std::wstring script = MakeInjectJsScript(id, content);
g_webview->AddScriptToExecuteOnDocumentCreated(script.c_str(), nullptr);
std::wcout << L"[WEBMODS] JS: " << relStr(p) << std::endl;
}
}
void refreshWeb(const bool refreshAll) {
if (g_webviewProfile && refreshAll)
{

View file

@ -9,5 +9,6 @@ void WaitAndRefreshIfNeeded();
void refreshWeb(bool refreshAll);
static void SetupWebMessageHandler();
static void SetupExtensions();
static void SetupWebMods();
#endif // WEBVIEW_H

Binary file not shown.

Binary file not shown.

View file

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>stremio-desktop-v5</id>
<version>5.0.18</version>
<version>5.0.21</version>
<title>Stremio Desktop v5</title>
<authors>Zarg</authors>
<owners>Zarg</owners>

View file

@ -11,12 +11,12 @@ $packageArgs = @{
if ([Environment]::Is64BitOperatingSystem) {
$packageArgs['url'] = 'https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.18/Stremio.5.0.18-x64.exe'
$packageArgs['checksum'] = '9a04f81d5ef6e76207e2af1d8fa567b1f6c5edd696b8c49fb5b94261ebf04ea9'
$packageArgs['url'] = 'https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.21/Stremio.5.0.21-x64.exe'
$packageArgs['checksum'] = '6b2597e3179355fb59b62df762d65dbe3e493f96471fa3cf17e1620fadd0a1d7'
$packageArgs['checksumType'] = 'sha256'
} else {
$packageArgs['url'] = 'https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.18/Stremio.5.0.18-x86.exe'
$packageArgs['checksum'] = '3633ad3eda25c26e4b213f5a93f845ed226a9fb5186df59293e8576fc2de2d32'
$packageArgs['url'] = 'https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.21/Stremio.5.0.21-x86.exe'
$packageArgs['checksum'] = 'f2dfad202ae03b26a1d584d9a4e8747be6e0b078e6c6c5773d57632bdfe3aee0'
$packageArgs['checksumType'] = 'sha256'
}

View file

@ -1,12 +1,12 @@
{
"version": "5.0.18",
"version": "5.0.21",
"description": "Stremio Desktop v5 Community",
"homepage": "https://github.com/Zaarrg/stremio-desktop-v5",
"license": "GPL-3.0",
"architecture": {
"64bit": {
"url": "https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.18/Stremio.5.0.18-x64.exe",
"hash": "9a04f81d5ef6e76207e2af1d8fa567b1f6c5edd696b8c49fb5b94261ebf04ea9",
"url": "https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.21/Stremio.5.0.21-x64.exe",
"hash": "6b2597e3179355fb59b62df762d65dbe3e493f96471fa3cf17e1620fadd0a1d7",
"installer": {
"args": [
"/S"
@ -24,8 +24,8 @@
}
},
"32bit": {
"url": "https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.18/Stremio.5.0.18-x86.exe",
"hash": "3633ad3eda25c26e4b213f5a93f845ed226a9fb5186df59293e8576fc2de2d32",
"url": "https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.21/Stremio.5.0.21-x86.exe",
"hash": "f2dfad202ae03b26a1d584d9a4e8747be6e0b078e6c6c5773d57632bdfe3aee0",
"installer": {
"args": [
"/S"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,17 +1,17 @@
{
"shellVersion": "5.0.18",
"shellVersion": "5.0.21",
"files": {
"windows-x64": {
"url": "https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.18/Stremio.5.0.18-x64.exe",
"checksum": "9a04f81d5ef6e76207e2af1d8fa567b1f6c5edd696b8c49fb5b94261ebf04ea9"
"url": "https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.21/Stremio.5.0.21-x64.exe",
"checksum": "6b2597e3179355fb59b62df762d65dbe3e493f96471fa3cf17e1620fadd0a1d7"
},
"windows-x86": {
"url": "https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.18/Stremio.5.0.18-x86.exe",
"checksum": "3633ad3eda25c26e4b213f5a93f845ed226a9fb5186df59293e8576fc2de2d32"
"url": "https://github.com/Zaarrg/stremio-desktop-v5/releases/download/5.0.0-beta.21/Stremio.5.0.21-x86.exe",
"checksum": "f2dfad202ae03b26a1d584d9a4e8747be6e0b078e6c6c5773d57632bdfe3aee0"
},
"server.js": {
"url": "https://dl.strem.io/server/v4.20.11/desktop/server.js",
"checksum": "d900b0525bac3531aa6ce98e1a3c8a3b1d1b1daa069a7f6fcbddea5625f1f791"
"url": "https://dl.strem.io/server/v4.20.15/desktop/server.js",
"checksum": "fcc4c5e620effda04c9e1d29a76aa087ec86fd08a747cdcbdccc5bb8f0ec4818"
}
}
}

View file

@ -1,5 +1,5 @@
{
"upToDate": false,
"versionDesc": "https://raw.githubusercontent.com/Zaarrg/stremio-desktop-v5/refs/heads/webview-windows/version/version-details.json",
"signature": "lB0JmhHa6ig9Of0F/g0wQkNTRm9yAPchKHYHcwuDPS9LYI6mKIc292SkGDEV3o7fYqGz5aJKv8UN/hUwN4l6dso+/y3bL+L1GFyAwDcp8YkqncdIA9EZB/x+4X8/oTXTJjeo0pBSHmedTFhxfQcusj2rv/5bOsTkVCdxBqoPopfxOKm8Uj9icnz3eBkbY2dA3JZSYdxMRRxHuvPhSx57Cn2W7C9os0U4yAYvBJV0MV4CM/MPxnQDwflvrRYk1pvoHld2wZ/SBqelO66EegsMkt9yEth/LAOjOg8j3+/pTmc/9NS0FvLUoG7tY2jy+wZbGPGLn2S6pr1caF29F1zacQ=="
"signature": "DfGpCnyvD/jWmw+hhdaAlay2sYvSpPsmsMDOrplWbvBYqZtwrfXLuZXnL+HkEP6kVclwRPBE2Kg2/2+UN3BP44Zn2N8UtGEMQLgu8TIAeq51JPUzv8ab9dumS8OXRHFG+x2sK4EjyobnIKJBm0nhpHzZyVuIXUIQsniynFyXdvRJxerZS9zXivJ9WgXNSgpM5tJt2xKqkuJtZ+Ckt//G3SeseC/vn4TehVX9d+aLGVM3pdLAnVferq9VV9iMZw8pQ+tK6HrhwzGP+sFsEIQsPNxFaLV1K1ODxKChnH2cYdLEjF62QlBilZG/SARn5NNRxTTGGCa/Guy4VZ30OsUh8A=="
}