16 Commits

Author SHA1 Message Date
Axel Nicolas
b321a1d164 Merge pull request #45 from MasterAcnolo/linux-version
1.6.0 - Linux version
2026-07-28 21:38:03 +02:00
MasterAcnolo
89e6fcf9bc fix: snap Store package.json arguments 2026-07-28 20:43:04 +02:00
MasterAcnolo
ba2f317551 fix: snap Store mention in SECURITY.md 2026-07-28 20:42:51 +02:00
MasterAcnolo
553e383c94 refactor: rpm package publish 2026-07-27 22:40:30 +02:00
MasterAcnolo
89cc0b85a3 refactor: rpm package publish 2026-07-27 22:40:22 +02:00
MasterAcnolo
abd0bf9006 refactor: rpm package publish 2026-07-27 22:40:19 +02:00
MasterAcnolo
653f73805e fix: enhance package.json and rename linux package to freedom-loader 2026-07-27 22:15:19 +02:00
Axel Nicolas
4f03c5876f Merge pull request #44 from MasterAcnolo/sync
Sync
2026-07-26 15:15:52 +02:00
MasterAcnolo
a5f05f32af fix: readme missing items and [!TIP] 2026-07-26 11:21:23 +02:00
MasterAcnolo
0d1b1e4919 refactor: security.md 2026-07-26 09:37:39 +02:00
MasterAcnolo
0e77a94ec7 feat: enhance logger by displaying systeminfo at start of the app 2026-07-26 09:37:27 +02:00
MasterAcnolo
7f481d20b2 sync: update dependencies and this is ready for windows 2026-07-25 12:49:36 +02:00
MasterAcnolo
1ff32ca021 sync: to work on windows 2026-07-25 11:32:48 +02:00
MasterAcnolo
90d8a9f65d fix: correct use of logger for path.helpers.js 2026-07-22 20:41:54 +02:00
MasterAcnolo
d5965c2ce0 fix: bring back theme features for Linux 2026-07-22 18:44:30 +02:00
MasterAcnolo
15f59a6093 fix: bring back theme features for Linux 2026-07-22 18:16:33 +02:00
14 changed files with 1731 additions and 1003 deletions

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@
# Build Output Folder # Build Output Folder
/dist /dist
/out /out
/srpm-out
# Config JSON File. Create it and fill it if you want to have dev only settings # Config JSON File. Create it and fill it if you want to have dev only settings
config/config.dev.json config/config.dev.json

View File

@@ -7,7 +7,7 @@
### **A clean, open-source multimedia downloader for Windows and Linux** ### **A clean, open-source multimedia downloader for Windows and Linux**
[![Release](https://img.shields.io/badge/Release-1.6.0-blue?style=for-the-badge)](https://github.com/MasterAcnolo/Freedom-Loader/releases) [![Release](https://img.shields.io/github/v/release/MasterAcnolo/Freedom-Loader?style=for-the-badge&color=blue)](https://github.com/MasterAcnolo/Freedom-Loader/releases)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-red.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-red.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0)
[![Website](https://img.shields.io/badge/Website-Visit-404040?style=for-the-badge)](https://masteracnolo.github.io/Freedom-Loader-Site/) [![Website](https://img.shields.io/badge/Website-Visit-404040?style=for-the-badge)](https://masteracnolo.github.io/Freedom-Loader-Site/)
[![Workshop](https://img.shields.io/badge/Worshop-Visit-0E05A1?style=for-the-badge)](https://masteracnolo.github.io/Freedom-Loader-Workshop/) [![Workshop](https://img.shields.io/badge/Worshop-Visit-0E05A1?style=for-the-badge)](https://masteracnolo.github.io/Freedom-Loader-Workshop/)
@@ -88,8 +88,7 @@ The primary goal is to make media downloading accessible to users who want offli
[![Fedora Copr](https://img.shields.io/badge/Fedora-Copr-294172?style=for-the-badge&logo=fedora&logoColor=white)](https://copr.fedorainfracloud.org/coprs/masteracnolo/freedom-loader/) [![Fedora Copr](https://img.shields.io/badge/Fedora-Copr-294172?style=for-the-badge&logo=fedora&logoColor=white)](https://copr.fedorainfracloud.org/coprs/masteracnolo/freedom-loader/)
[![Debian/Ubuntu](https://img.shields.io/badge/.deb-Debian%2FUbuntu-A81D33?style=for-the-badge&logo=debian&logoColor=white)](https://github.com/MasterAcnolo/Freedom-Loader/releases) [![Debian/Ubuntu](https://img.shields.io/badge/.deb-Debian%2FUbuntu-A81D33?style=for-the-badge&logo=debian&logoColor=white)](https://github.com/MasterAcnolo/Freedom-Loader/releases)
[![Snap Store](https://img.shields.io/badge/Snap-Store-82BEA0?style=for-the-badge&logo=snapcraft&logoColor=white)](https://snapcraft.io/freedom-loader)
[//]: # ([![Snap Store](https://img.shields.io/badge/Snap-Store-82BEA0?style=for-the-badge&logo=snapcraft&logoColor=white)](https://snapcraft.io/freedom-loader))
[![AppImage](https://img.shields.io/badge/AppImage-Universal-1E88E5?style=for-the-badge&logo=linux&logoColor=white)](https://github.com/MasterAcnolo/Freedom-Loader/releases) [![AppImage](https://img.shields.io/badge/AppImage-Universal-1E88E5?style=for-the-badge&logo=linux&logoColor=white)](https://github.com/MasterAcnolo/Freedom-Loader/releases)
### Requirements ### Requirements
@@ -122,18 +121,16 @@ sudo dnf install freedom-loader
sudo apt install ./freedom-loader_1.x.x_amd64.deb sudo apt install ./freedom-loader_1.x.x_amd64.deb
``` ```
[//]: # (#### Snap (any distro with snapd)) #### Snap (any distro with snapd)
[//]: # () ```bash
[//]: # (```bash) sudo snap install freedom-loader
```
[//]: # (sudo snap install freedom-loader)
[//]: # (```)
#### RPM (Fedora/RHEL/openSUSE, without Copr) #### RPM (Fedora/RHEL/openSUSE, without Copr)
```bash ```bash
# Download the latest .rpm from the Releases page, then:
sudo dnf install ./freedom-loader-1.x.y.x86_64.rpm sudo dnf install ./freedom-loader-1.x.y.x86_64.rpm
``` ```
@@ -162,7 +159,8 @@ freedom-loader
## Usage ## Usage
> [!TIP] On Linux, you can start Freedom Loader using `freedom-loader` command > [!TIP]
> On Linux, you can start Freedom Loader using `freedom-loader` command
### Basic Download ### Basic Download
@@ -541,7 +539,7 @@ You are free to use, modify, and redistribute this software under the terms of t
- [yt-dlp](https://github.com/yt-dlp/yt-dlp) for the robust download engine - [yt-dlp](https://github.com/yt-dlp/yt-dlp) for the robust download engine
- [FFmpeg](https://ffmpeg.org/) for media processing capabilities - [FFmpeg](https://ffmpeg.org/) for media processing capabilities
- [Deno](https://deno.com/) for helping me bypassing challenges - [Deno](https://deno.com/) for helping me to bypass challenges
- [Electron](https://www.electronjs.org/) for the desktop application framework - [Electron](https://www.electronjs.org/) for the desktop application framework
- The open-source community for continuous support and contributions - The open-source community for continuous support and contributions
- [@SpicyFire21](https://github.com/SpicyFire21) to be the spiciest one - [@SpicyFire21](https://github.com/SpicyFire21) to be the spiciest one

View File

@@ -2,15 +2,14 @@
## Supported Versions ## Supported Versions
We actively maintain and provide security updates for the following versions of Freedom Loader: Freedom Loader follows a **latest-only** support model. Security fixes are applied to the current release only — no backports to older versions.
| Version | Supported | | Version | Supported |
|---------|--------------------| | ------------- | ------------------ |
| 1.4.x | :white_check_mark: | | Latest stable | :white_check_mark: |
| 1.3.x | :white_check_mark: | | Older versions | :x: |
| < 1.3.0 | :x: |
**Note**: We recommend always using the latest version to benefit from the most recent security patches and features. I recommend always running the latest version. The built-in auto-updater will notify you when a new release is available. Older versions will not receive security patches regardless of severity.
## Reporting a Vulnerability ## Reporting a Vulnerability
@@ -32,37 +31,40 @@ Instead, please report security issues privately by:
### What to Expect ### What to Expect
- **Acknowledgment**: We will acknowledge receipt of your report within 48 hours - **Acknowledgment**: I will acknowledge receipt of your report within 48 hours
- **Assessment**: We will assess the vulnerability and determine its severity - **Assessment**: I will assess the vulnerability and determine its severity
- **Updates**: We will keep you informed of our progress - **Updates**: I will keep you informed of our progress
- **Resolution**: We aim to release a fix within 7-14 days for critical vulnerabilities - **Resolution**: I aim to release a fix within 7-14 days for critical vulnerabilities
- **Credit**: We will credit you in the release notes (unless you prefer to remain anonymous) - **Credit**: I will credit you in the release notes (unless you prefer to remain anonymous)
## Security Best Practices for Users ## Security Best Practices for Users
When using Freedom Loader, we recommend: When using Freedom Loader, I recommend:
### General Security ### General Security
- **Keep Updated**: Always use the latest version of Freedom Loader - **Keep Updated**: Always use the latest version of Freedom Loader — older versions receive no security patches
- **Official Sources**: Download only from official releases on [GitHub](https://github.com/MasterAcnolo/Freedom-Loader/releases) - **Official Sources**: Download only from official sources:
- **Verify Downloads**: Check that installers are properly signed (Windows SmartScreen may show warnings for new releases) - [GitHub Releases](https://github.com/MasterAcnolo/Freedom-Loader/releases)
- [Fedora COPR](https://copr.fedorainfracloud.org/coprs/masteracnolo/freedom-loader/)
- [Snap Store](https://snapcraft.io/freedom-loader)
- **Verify Downloads**: Check that installers are from one of the above sources
- **Antivirus**: Keep your antivirus software up to date - **Antivirus**: Keep your antivirus software up to date
### Configuration Security ### Configuration Security
- **Download Path**: Only set download paths within your user directory (`C:\Users\[USERNAME]\...`) - **Download Path**: Only set download paths within your user directory
- **Cookies**: Be aware that Firefox cookies are used for authenticationkeep Firefox secure - **Cookies**: Be aware that Firefox cookies are used for authenticationkeep Firefox secure
- **Logs**: Logs may contain sensitive informationavoid sharing them publicly without review - **Logs**: Logs may contain sensitive information such as URLs or local paths — avoid sharing them publicly without review
### Privacy Considerations ### Privacy Considerations
Freedom Loader respects your privacy: Freedom Loader respects your privacy:
- **No Data Collection**: We don't collect, store, or transmit your personal data - **No Data Collection**: I don't collect, store, or transmit your personal data
- **No Telemetry**: No usage tracking or analytics - **No Telemetry**: No usage tracking or analytics
- **Local Operation**: All downloads are processed locally on your machine - **Local Operation**: All downloads are processed locally on your machine
- **Optional Features**: Discord RPC is optional and can be disabled - **Optional Features**: Discord RPC is optional and can be disabled in settings
## Known Security Considerations ## Known Security Considerations
@@ -71,16 +73,16 @@ Freedom Loader respects your privacy:
Freedom Loader accesses Firefox cookies to download protected content. This is: Freedom Loader accesses Firefox cookies to download protected content. This is:
- **By Design**: Required for age-restricted or member-only content - **By Design**: Required for age-restricted or member-only content
- **Local Only**: Cookies are read locally and never transmitted - **Local Only**: Cookies are read locally and never transmitted outside your machine
- **User Controlled**: You can control what content you download - **User Controlled**: You control what content you download
### Native Dependencies ### Native Dependencies
Freedom Loader bundles native binaries: Freedom Loader bundles the following official binaries:
- **yt-dlp**: Official builds from [yt-dlp/yt-dlp](https://github.com/yt-dlp/yt-dlp) - **yt-dlp**: Official builds from [yt-dlp/yt-dlp](https://github.com/yt-dlp/yt-dlp) — auto-updated on each launch
- **FFmpeg**: Official builds from [FFmpeg.org](https://ffmpeg.org/) - **FFmpeg**: Official builds from [FFmpeg.org](https://ffmpeg.org/)
- **Deno**: Official builds from [Deno.land](https://deno.land/) - **Deno**: Official builds from [Deno.com](https://deno.com/)
These dependencies are verified and updated regularly. These dependencies are verified and updated regularly.
@@ -91,13 +93,13 @@ New releases may trigger Windows Defender warnings because:
- The application is not yet widely distributed - The application is not yet widely distributed
- Code signing certificates are expensive for open-source projects - Code signing certificates are expensive for open-source projects
This is expected behavior for new releases. The warning will decrease as more users download the software. This is expected behavior for new releases and will diminish as more users download the software.
## Vulnerability Disclosure Policy ## Vulnerability Disclosure Policy
### Our Commitment ### Our Commitment
We are committed to: I am committed to:
- Responding promptly to security reports - Responding promptly to security reports
- Working with security researchers to verify and address issues - Working with security researchers to verify and address issues
@@ -107,9 +109,9 @@ We are committed to:
### Disclosure Timeline ### Disclosure Timeline
1. **Day 0**: Vulnerability reported privately 1. **Day 0**: Vulnerability reported privately
2. **Day 1-2**: Acknowledgment sent to reporter 2. **Day 12**: Acknowledgment sent to reporter
3. **Day 3-7**: Vulnerability assessed and fix developed 3. **Day 37**: Vulnerability assessed and fix developed
4. **Day 7-14**: Fix released (critical vulnerabilities prioritized) 4. **Day 714**: Fix released (critical vulnerabilities prioritized)
5. **Day 14+**: Public disclosure (coordinated with reporter) 5. **Day 14+**: Public disclosure (coordinated with reporter)
### Scope ### Scope
@@ -129,16 +131,16 @@ The following are generally not considered security vulnerabilities:
- Issues requiring physical access to the user's machine - Issues requiring physical access to the user's machine
- Social engineering attacks - Social engineering attacks
- Denial of service against third-party services - Denial of service against third-party services
- Issues in third-party dependencies (report to upstream projects) - Issues in third-party dependencies (report to upstream projects directly)
- Missing security headers on local HTTP server (no remote access) - Missing security headers on the local HTTP server (not exposed remotely)
## Security Updates ## Security Updates
Security updates are released as: Security updates are released as:
- **Patch Releases**: For critical security fixes (e.g., 1.4.1 1.4.2) - **Patch Releases**: For critical security fixes (e.g., 1.6.0 → 1.6.1)
- **Automatic Updates**: Users are notified via the built-in update system - **Automatic Updates**: Users are notified via the built-in update system
- **Release Notes**: Security fixes are clearly marked in changelog - **Release Notes**: Security fixes are clearly marked in the changelog
## Additional Resources ## Additional Resources
@@ -150,6 +152,7 @@ Security updates are released as:
For security-related questions or concerns: For security-related questions or concerns:
- **Email**: masteracnolo25@gmail.com
- **GitHub**: [@MasterAcnolo](https://github.com/MasterAcnolo) - **GitHub**: [@MasterAcnolo](https://github.com/MasterAcnolo)
--- ---

18
main.js
View File

@@ -37,7 +37,7 @@ app.setAppUserModelId("com.masteracnolo.freedomloader");
/** /**
* Load the app dependencies for hardware choice * Load the app dependencies for hardware choice
*/ */
const { logger, logSessionStart, logSessionEnd } = require("./server/logger"); const { logger, logSessionStart, logSessionEnd, logDir } = require("./server/logger");
const { configFeatures } = require("./config"); const { configFeatures } = require("./config");
/** /**
@@ -79,7 +79,7 @@ const { updateYtDlp } = require("./app/ytDlpUpdater");
const { createMainWindow, getMainWindow } = require("./app/windowManager"); const { createMainWindow, getMainWindow } = require("./app/windowManager");
const { registerIpcHandlers } = require("./app/ipcHandlers"); const { registerIpcHandlers } = require("./app/ipcHandlers");
const { createSplashWindow, closeSplashWindow, setSplashProgress } = require("./app/splashManager"); const { createSplashWindow, closeSplashWindow, setSplashProgress } = require("./app/splashManager");
const { userThemesPath, initUserThemes, isWindows } = require("./server/helpers/path.helpers"); const { userThemesPath, initUserThemes, isWindows, validateBinaries, defaultDownloadFolder } = require("./server/helpers/path.helpers");
/** /**
@@ -99,7 +99,7 @@ app.on("second-instance", () => {
}); });
app.whenReady().then(async () => { app.whenReady().then(async () => {
logSessionStart(); logSessionStart(logDir, defaultDownloadFolder);
createSplashWindow(); createSplashWindow();
@@ -117,14 +117,10 @@ app.whenReady().then(async () => {
setSplashProgress(2); // Loading themes setSplashProgress(2); // Loading themes
// TODO: Patch this, i disable this features for the moment validateBinaries();
// Themes are currently disabled if we are not on Windows
if(isWindows){ initUserThemes();
initUserThemes(); await initThemes(userThemesPath);
await initThemes(userThemesPath);
} else {
logger.info(`OS is ${process.platform}, Skipping themes loading`)
}
setSplashProgress(3); // Almost ready setSplashProgress(3); // Almost ready
await createMainWindow(); await createMainWindow();

2203
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,16 @@
"productName": "Freedom Loader", "productName": "Freedom Loader",
"version": "1.6.0", "version": "1.6.0",
"author": "MasterAcnolo <MasterAcnolo@users.noreply.github.com>", "author": "MasterAcnolo <MasterAcnolo@users.noreply.github.com>",
"description": "Freedom Loader", "description": "Free and open-source GUI for yt-dlp — download video and audio from hundreds of platforms",
"homepage": "https://masteracnolo.github.io/Freedom-Loader-Site/",
"repository": {
"type": "git",
"url": "https://github.com/MasterAcnolo/Freedom-Loader.git"
},
"license": "GPL-3.0-only",
"bugs": {
"url": "https://github.com/MasterAcnolo/Freedom-Loader/issues"
},
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
"start": "electron --trace-warnings .", "start": "electron --trace-warnings .",
@@ -11,6 +20,7 @@
"build": "electron-builder", "build": "electron-builder",
"build:win": "electron-builder --win", "build:win": "electron-builder --win",
"build:linux": "electron-builder --linux", "build:linux": "electron-builder --linux",
"build:rpm": "bash scripts/create-copr-package.sh",
"build:all": "electron-builder -wl", "build:all": "electron-builder -wl",
"update": "npm update" "update": "npm update"
}, },
@@ -27,9 +37,9 @@
"winston-daily-rotate-file": "^5.0.0" "winston-daily-rotate-file": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"@electron/devtron": "^2.1.1",
"electron": "^41.2.0", "electron": "^41.2.0",
"electron-builder": "^26.8.1", "electron-builder": "^25.1.8"
"@electron/devtron": "^2.1.1"
}, },
"build": { "build": {
"appId": "com.masteracnolo.freedomloader", "appId": "com.masteracnolo.freedomloader",
@@ -53,22 +63,52 @@
}, },
"asar": true, "asar": true,
"extraResources": [ "extraResources": [
{ "from": "theme", "to": "theme" }, {
{ "from": "build/confirm-icon.png", "to": "confirm-icon.png" }, "from": "theme",
{ "from": "build/banner.bmp", "to": "banner.bmp" }, "to": "theme"
{ "from": "build/banner.png", "to": "banner.png" }, },
{ "from": "build/error.png", "to": "error.png" }, {
{ "from": "config/config.default.json", "to": "config/config.default.json" } "from": "build/confirm-icon.png",
"to": "confirm-icon.png"
},
{
"from": "build/banner.bmp",
"to": "banner.bmp"
},
{
"from": "build/banner.png",
"to": "banner.png"
},
{
"from": "build/error.png",
"to": "error.png"
},
{
"from": "config/config.default.json",
"to": "config/config.default.json"
}
], ],
"win": { "win": {
"target": "nsis", "target": "nsis",
"icon": "build/app-icon.ico", "icon": "build/app-icon.ico",
"artifactName": "${productName}-Setup-${version}.${ext}", "artifactName": "${productName}-Setup-${version}.${ext}",
"extraResources": [ "extraResources": [
{ "from": "resources/binaries/win-32/yt-dlp.exe", "to": "binaries/yt-dlp.exe" }, {
{ "from": "resources/binaries/win-32/ffmpeg.exe", "to": "binaries/ffmpeg.exe" }, "from": "resources/binaries/win-32/yt-dlp.exe",
{ "from": "resources/binaries/win-32/ffprobe.exe", "to": "binaries/ffprobe.exe" }, "to": "binaries/yt-dlp.exe"
{ "from": "resources/binaries/win-32/deno.exe", "to": "binaries/deno.exe" } },
{
"from": "resources/binaries/win-32/ffmpeg.exe",
"to": "binaries/ffmpeg.exe"
},
{
"from": "resources/binaries/win-32/ffprobe.exe",
"to": "binaries/ffprobe.exe"
},
{
"from": "resources/binaries/win-32/deno.exe",
"to": "binaries/deno.exe"
}
] ]
}, },
"nsis": { "nsis": {
@@ -83,14 +123,31 @@
"shortcutName": "Freedom Loader" "shortcutName": "Freedom Loader"
}, },
"linux": { "linux": {
"target": ["AppImage", "deb","rpm", "snap"], "target": [
"AppImage",
"deb",
"snap"
],
"category": "Utility", "category": "Utility",
"icon": "build/app-icon.png", "icon": "build/app-icon.png",
"executableName": "freedom-loader",
"extraResources": [ "extraResources": [
{ "from": "resources/binaries/linux/yt-dlp", "to": "binaries/yt-dlp" }, {
{ "from": "resources/binaries/linux/ffmpeg", "to": "binaries/ffmpeg" }, "from": "resources/binaries/linux/yt-dlp",
{ "from": "resources/binaries/linux/ffprobe", "to": "binaries/ffprobe" }, "to": "binaries/yt-dlp"
{ "from": "resources/binaries/linux/deno", "to": "binaries/deno" } },
{
"from": "resources/binaries/linux/ffmpeg",
"to": "binaries/ffmpeg"
},
{
"from": "resources/binaries/linux/ffprobe",
"to": "binaries/ffprobe"
},
{
"from": "resources/binaries/linux/deno",
"to": "binaries/deno"
}
] ]
}, },
"deb": { "deb": {
@@ -107,14 +164,7 @@
"confinement": "strict", "confinement": "strict",
"plugs": [ "plugs": [
"default", "default",
"home", "removable-media"
"removable-media",
"network",
"audio-playback",
"desktop",
"desktop-legacy",
"x11",
"wayland"
] ]
} }
} }

9
package/copr-build.sh Normal file
View File

@@ -0,0 +1,9 @@
#!/bin/sh -xe
git clone --depth 1 https://github.com/MasterAcnolo/Freedom-Loader.git src
cd src
npm ci
npx electron-builder --linux dir
VERSION=$(node -p "require('./package.json').version")
tar czf "$resultdir/freedom-loader-$VERSION.tar.gz" -C dist linux-unpacked
sed "s/__VERSION__/$VERSION/" package/freedom-loader.spec > "$resultdir/freedom-loader.spec"

View File

@@ -25,6 +25,3 @@ async function initPlatformRestrictions() {
} }
} }
document.addEventListener('DOMContentLoaded', function(){
initPlatformRestrictions();
})

Binary file not shown.

50
scripts/create-copr-package.sh Executable file
View File

@@ -0,0 +1,50 @@
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
VERSION=$(node -p "require('$ROOT_DIR/package.json').version")
RPM_OUT="$ROOT_DIR/dist/freedom-loader-${VERSION}.x86_64.rpm"
# Check that linux-unpacked exists
if [ ! -d "$ROOT_DIR/dist/linux-unpacked" ]; then
echo "Error: dist/linux-unpacked not found. Run 'npm run build:linux' first."
exit 1
fi
# Step 1 — Build .rpm from linux-unpacked via fpm
echo "Building RPM..."
fpm -s dir -t rpm --force \
--name freedom-loader \
--version "$VERSION" \
--architecture x86_64 \
--description "Free and open-source GUI for yt-dlp" \
--url "https://masteracnolo.github.io/Freedom-Loader-Site/" \
--maintainer "MasterAcnolo <MasterAcnolo@users.noreply.github.com>" \
--license "GPL-3.0-only" \
--depends gtk3 \
--depends nss \
--depends libXScrnSaver \
--depends at-spi2-core \
--package "$RPM_OUT" \
"$ROOT_DIR/dist/linux-unpacked/=/opt/freedom-loader" \
"$ROOT_DIR/build/app-icon.png=/usr/share/icons/hicolor/512x512/apps/freedom-loader.png" \
"$ROOT_DIR/package/com.masteracnolo.freedomloader.metainfo.xml=/usr/share/metainfo/com.masteracnolo.freedomloader.metainfo.xml"
echo "RPM built: $RPM_OUT"
# Step 2 — Build SRPM for COPR (wraps the .rpm above)
echo "Building SRPM for COPR..."
mkdir -p "$ROOT_DIR/srpm-out"
TMP_DIR="$ROOT_DIR/.copr-build-tmp"
mkdir -p "$TMP_DIR"
TMP_SPEC="$TMP_DIR/freedom-loader.spec"
sed "s/__VERSION__/$VERSION/g" "$ROOT_DIR/package/freedom-loader.spec" > "$TMP_SPEC"
rpmbuild -bs "$TMP_SPEC" \
--define "_sourcedir $ROOT_DIR/dist" \
--define "_srcrpmdir $ROOT_DIR/srpm-out"
rm -rf "$TMP_DIR"
echo "SRPM built: $ROOT_DIR/srpm-out/freedom-loader-$VERSION-1*.src.rpm"

View File

@@ -1,20 +0,0 @@
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
VERSION=$(node -p "require('$ROOT_DIR/package.json').version")
mkdir -p "$ROOT_DIR/srpm-out"
TMP_DIR="$ROOT_DIR/.copr-build-tmp"
mkdir -p "$TMP_DIR"
TMP_SPEC="$TMP_DIR/freedom-loader.spec"
sed "s/__VERSION__/$VERSION/g" "$ROOT_DIR/package/freedom-loader.spec" > "$TMP_SPEC"
rpmbuild -bs "$TMP_SPEC" \
--define "_sourcedir $ROOT_DIR/dist" \
--define "_srcrpmdir $ROOT_DIR/srpm-out"
rm -rf "$TMP_DIR"
echo "SRPM généré : $ROOT_DIR/srpm-out/freedom-loader-$VERSION-1*.src.rpm"

View File

@@ -3,8 +3,6 @@ const fs = require("fs");
const { app } = require("electron"); const { app } = require("electron");
const config = require("../../config.js"); const config = require("../../config.js");
const { logger } = require("../logger.js");
/** /**
* Is the OS windows * Is the OS windows
*/ */
@@ -104,7 +102,7 @@ if (config.devMode) {
try { try {
fs.chmodSync(userYtDlp, 0o755); fs.chmodSync(userYtDlp, 0o755);
} catch (err) { } catch (err) {
logger.warn(`Failed to chmod yt-dlp: ${err.message}`); getLogger().warn(`Failed to chmod yt-dlp: ${err.message}`);
} }
} }
} }
@@ -165,48 +163,48 @@ function initUserThemes() {
try { try {
if (!fs.existsSync(userThemesPath)) { if (!fs.existsSync(userThemesPath)) {
fs.mkdirSync(userThemesPath, { recursive: true }); fs.mkdirSync(userThemesPath, { recursive: true });
// Ensure folder is writable
fs.chmodSync(userThemesPath, 0o777); fs.chmodSync(userThemesPath, 0o777);
logger.info("Created user themes directory"); getLogger().info("Created user themes directory");
} }
// Copy default themes from resources to user directory if they don't exist
if (fs.existsSync(defaultThemesSourcePath)) { if (fs.existsSync(defaultThemesSourcePath)) {
const defaultThemes = fs.readdirSync(defaultThemesSourcePath); const defaultThemes = fs.readdirSync(defaultThemesSourcePath);
for (const theme of defaultThemes) { for (const theme of defaultThemes) {
const srcPath = path.join(defaultThemesSourcePath, theme); const srcPath = path.join(defaultThemesSourcePath, theme);
const destPath = path.join(userThemesPath, theme); const destPath = path.join(userThemesPath, theme);
if (!fs.existsSync(destPath)) { const srcIsFile = !fs.statSync(srcPath).isDirectory();
try {
if (fs.existsSync(destPath)) {
const destIsDir = fs.statSync(destPath).isDirectory();
if (srcIsFile && destIsDir) {
getLogger().warn(`Corrupted theme entry: ${theme}, fixing...`);
fs.rmSync(destPath, { recursive: true, force: true });
} else {
continue;
}
}
try {
if (srcIsFile) {
fs.copyFileSync(srcPath, destPath);
fs.chmodSync(destPath, 0o666);
} else {
copyDirectory(srcPath, destPath); copyDirectory(srcPath, destPath);
fs.chmodSync(destPath, 0o777); fs.chmodSync(destPath, 0o777);
logger.info(`Copied default theme: ${theme}`);
} catch (copyErr) {
logger.warn(
`Failed to copy theme ${theme}: ${copyErr.message}. Theme folder will be created, add theme files manually.`
);
try {
fs.mkdirSync(destPath, { recursive: true });
fs.chmodSync(destPath, 0o777);
} catch (mkdirErr) {
logger.warn(
`Could not create theme directory ${theme}: ${mkdirErr.message}`
);
}
} }
getLogger().info(`Copied default theme: ${theme}`);
} catch (copyErr) {
getLogger().warn(`Failed to copy theme ${theme}: ${copyErr.message}`);
} }
} }
} else { } else {
logger.warn( getLogger().warn(`Default themes source path not found: ${defaultThemesSourcePath}`);
`Default themes source path not found: ${defaultThemesSourcePath}`
);
} }
} catch (err) { } catch (err) {
logger.error(`Failed to initialize user themes: ${err.message}`); getLogger().error(`Failed to initialize user themes: ${err.message}`);
} }
} }
/** /**
* Recursively copies a directory and its contents. * Recursively copies a directory and its contents.
* *
@@ -241,16 +239,31 @@ function copyDirectory(src, dest) {
} }
// Runtime validation of critical binaries // Runtime validation of critical binaries
if (!userYtDlp) { // if (!userYtDlp) {
logger.error("Missing yt-dlp binary"); // getLogger().error("Missing yt-dlp binary");
// }
// if (!ffmpegPath) {
// getLogger().error("Missing ffmpeg binary");
// }
// if (!denoPath) {
// getLogger().error("Missing deno binary");
// }
function validateBinaries() {
if (!userYtDlp) getLogger().error("Missing yt-dlp binary");
if (!ffmpegPath) getLogger().error("Missing ffmpeg binary");
if (!denoPath) getLogger().error("Missing deno binary");
} }
if (!ffmpegPath) { /**
logger.error("Missing ffmpeg binary"); * Helper to lazy load logger, avoid circular import
* @returns {winston.Logger}
*/
function getLogger() {
return require("../logger.js").logger;
} }
if (!denoPath) { module.exports = { userYtDlp, ffmpegPath, denoPath, iconPaths, binaryPaths, resourcesPath, defaultDownloadFolder, userThemesPath, initUserThemes, isWindows, validateBinaries };
logger.error("Missing deno binary");
}
module.exports = { userYtDlp, ffmpegPath, denoPath, iconPaths, binaryPaths, resourcesPath, defaultDownloadFolder, userThemesPath, initUserThemes, isWindows };

View File

@@ -5,6 +5,7 @@ const path = require("path");
const os = require("os"); const os = require("os");
const config = require("../config"); const config = require("../config");
const {isWindows} = require("./helpers/path.helpers"); const {isWindows} = require("./helpers/path.helpers");
const { logSystemInfo } = require("./sysinfo");
// Logs folder in Windows // Logs folder in Windows
const logDir = isWindows ? path.join(os.homedir(), "AppData", "Local", "FreedomLoader", "logs") : path.join(process.env.XDG_DATA_HOME || path.join(os.homedir(), ".local", "share"), "FreedomLoader", "logs"); const logDir = isWindows ? path.join(os.homedir(), "AppData", "Local", "FreedomLoader", "logs") : path.join(process.env.XDG_DATA_HOME || path.join(os.homedir(), ".local", "share"), "FreedomLoader", "logs");
@@ -52,9 +53,10 @@ const logger = createLogger({
/** /**
* Start Log Session * Start Log Session
*/ */
function logSessionStart() { function logSessionStart(logDir, downloadPath) {
logger.info(`--- Starting session: ${new Date().toISOString()} ---`); logger.info(`--- Starting session: ${new Date().toISOString()} ---`);
logger.info(`Application Version: ${config.version}`) logger.info(`Application Version: ${config.version}`)
logSystemInfo(logger, logDir, downloadPath)
} }
/** /**

142
server/sysinfo.js Normal file
View File

@@ -0,0 +1,142 @@
const os = require("os");
const fs = require("fs");
const { execSync } = require("child_process");
const { app } = require("electron");
/**
* Reads /etc/os-release to get the Linux distribution name
*/
function getLinuxDistro() {
try {
const content = fs.readFileSync("/etc/os-release", "utf-8");
const pretty = content.match(/^PRETTY_NAME="?(.+?)"?$/m);
if (pretty) return pretty[1];
const name = content.match(/^NAME="?(.+?)"?$/m);
return name ? name[1] : "Unknown Linux";
} catch {
return "Unknown Linux";
}
}
/**
* Reads the package-type file written by electron-builder
* to determine how the app was distributed (rpm, snap, AppImage, deb...)
*/
function getPackageType() {
try {
const pkgTypePath = require("path").join(process.resourcesPath, "package-type");
if (fs.existsSync(pkgTypePath)) {
return fs.readFileSync(pkgTypePath, "utf-8").trim();
}
} catch { /* ignore */ }
return "unknown";
}
/**
* Checks if Firefox is installed on the current platform
*/
function detectFirefox() {
const platform = process.platform;
if (platform === "win32") {
const paths = [
"C:\\Program Files\\Mozilla Firefox\\firefox.exe",
"C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe",
`${process.env.LOCALAPPDATA}\\Mozilla Firefox\\firefox.exe`,
];
return paths.some(p => fs.existsSync(p));
}
if (platform === "linux") {
const paths = [
"/usr/bin/firefox",
"/usr/bin/firefox-esr",
"/usr/local/bin/firefox",
"/snap/bin/firefox",
"/var/lib/flatpak/exports/bin/org.mozilla.firefox",
`${os.homedir()}/.local/share/flatpak/exports/bin/org.mozilla.firefox`,
];
if (paths.some(p => fs.existsSync(p))) return true;
try { execSync("which firefox", { stdio: "ignore" }); return true; } catch { return false; }
}
return false;
}
/**
* Builds the system info object logged at startup
*
* @param {string} logDir - path to the log directory
* @param {string} downloadPath - current configured download path
*/
function getSystemInfo(logDir, downloadPath) {
const platform = process.platform;
const cpus = os.cpus();
const totalMem = (os.totalmem() / 1024 / 1024 / 1024).toFixed(1);
const freeMem = (os.freemem() / 1024 / 1024 / 1024).toFixed(1);
let platformLabel;
if (platform === "win32") {
platformLabel = `Windows (${os.release()})`;
} else if (platform === "linux") {
platformLabel = `Linux — ${getLinuxDistro()}`;
} else {
platformLabel = `${platform} ${os.release()} (unsupported)`;
}
const info = {
"Platform": platformLabel,
"Architecture": os.arch(),
"CPU": cpus.length ? `${cpus[0].model.trim()} (${cpus.length} cores)` : "Unknown",
"Memory": `${freeMem} GB free / ${totalMem} GB total`,
"Locale": app.getLocale(),
"Electron": process.versions.electron,
"Node": process.versions.node,
"Packaged": String(app.isPackaged),
"Package type": app.isPackaged ? getPackageType() : "dev",
"Firefox present": detectFirefox() ? "Yes" : "No — cookie features unavailable",
"Log directory": logDir,
"Download path": downloadPath,
};
// Linux-specific extras
if (platform === "linux") {
const sessionType = process.env.XDG_SESSION_TYPE || "unknown";
const waylandDisplay = process.env.WAYLAND_DISPLAY;
const x11Display = process.env.DISPLAY;
info["Display server"] = waylandDisplay
? `Wayland (${waylandDisplay})`
: x11Display
? `X11 (${x11Display})`
: sessionType !== "unknown"
? sessionType
: "unknown";
info["Desktop env"] = process.env.XDG_CURRENT_DESKTOP || process.env.DESKTOP_SESSION || "unknown";
}
return info;
}
/**
* Logs system info at application startup
*
* @param {object} logger - winston logger instance
* @param {string} logDir - path to the log directory
* @param {string} downloadPath - current configured download path
*/
function logSystemInfo(logger, logDir, downloadPath) {
const info = getSystemInfo(logDir, downloadPath);
const maxKeyLen = Math.max(...Object.keys(info).map(k => k.length));
logger.info("=".repeat(60));
logger.info("SYSTEM INFO");
logger.info("=".repeat(60));
for (const [key, val] of Object.entries(info)) {
logger.info(` ${key.padEnd(maxKeyLen)} : ${val}`);
}
logger.info("=".repeat(60));
}
module.exports = { logSystemInfo };