mirror of
https://github.com/KeksPirates/SoftwareManager.git
synced 2026-08-03 17:39:42 +02:00
Compare commits
38 Commits
9bc0e22-stable
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a4c6c3381a | |||
| 68a9e870cf | |||
| 02de32719d | |||
| c5a78a2da3 | |||
| 32f02d856d | |||
| 4edb1baa0b | |||
| 1ffa1cacb9 | |||
| 207eb70f11 | |||
| 64144e5ed7 | |||
| d05fae7e87 | |||
| 9abdec6c33 | |||
| fb5eb61d05 | |||
| eff2164ecc | |||
| d8aa206ea2 | |||
| 6de74303ff | |||
| 5eb6314cb2 | |||
| 179dd0af83 | |||
| 365700900f | |||
| babbccdc9a | |||
| 367ffab86a | |||
| 71bad60617 | |||
| 27758f794c | |||
| d82afe8577 | |||
| 8592b3058e | |||
| 7a82e948b9 | |||
| 782b0b6bc9 | |||
| 71cc0d9f1f | |||
| 675dead1d9 | |||
| 64ca3c76a2 | |||
| d378ee8258 | |||
| e9b01426f8 | |||
| 631f6592ac | |||
| 468faff16b | |||
| 6b45c40aad | |||
| d6302fc43f | |||
| e768c7518b | |||
| 49c390131a | |||
| 04aaff3b29 |
@@ -46,6 +46,21 @@ jobs:
|
|||||||
version: "0.9.7"
|
version: "0.9.7"
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
|
|
||||||
|
- name: Install system dependencies (Linux)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y \
|
||||||
|
libxcb-xinerama0 \
|
||||||
|
libxkbcommon-x11-0 \
|
||||||
|
libxcb-cursor0 \
|
||||||
|
libxcb-keysyms1 \
|
||||||
|
libxcb-render-util0 \
|
||||||
|
libxcb-icccm4 \
|
||||||
|
libxcb-image0 \
|
||||||
|
libxcb-shape0 \
|
||||||
|
libxcb-util1
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
uv pip install -r requirements.txt
|
uv pip install -r requirements.txt
|
||||||
@@ -141,7 +156,7 @@ jobs:
|
|||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
pyinstaller --onefile \
|
pyinstaller --windowed \
|
||||||
--add-data "build_info.json:." \
|
--add-data "build_info.json:." \
|
||||||
--exclude-module PyQt6 \
|
--exclude-module PyQt6 \
|
||||||
--exclude-module PyQt5 \
|
--exclude-module PyQt5 \
|
||||||
@@ -153,6 +168,10 @@ jobs:
|
|||||||
--name ${{ env.APP_NAME }} \
|
--name ${{ env.APP_NAME }} \
|
||||||
src/main.py
|
src/main.py
|
||||||
|
|
||||||
|
- name: Install create-dmg (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: brew install create-dmg
|
||||||
|
|
||||||
- name: Rename artifact
|
- name: Rename artifact
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
@@ -160,9 +179,20 @@ jobs:
|
|||||||
if [ "$RUNNER_OS" == "Windows" ]; then
|
if [ "$RUNNER_OS" == "Windows" ]; then
|
||||||
mv nuitka-build/main.dist dist-final/${{ env.APP_NAME }}
|
mv nuitka-build/main.dist dist-final/${{ env.APP_NAME }}
|
||||||
ls -la dist-final/${{ env.APP_NAME }}/
|
ls -la dist-final/${{ env.APP_NAME }}/
|
||||||
else
|
elif [ "$RUNNER_OS" == "Linux" ]; then
|
||||||
chmod +x dist/${{ env.APP_NAME }}
|
chmod +x dist/${{ env.APP_NAME }}
|
||||||
mv dist/${{ env.APP_NAME }} dist-final/${{ matrix.artifact_name }}
|
mv dist/${{ env.APP_NAME }} dist-final/${{ matrix.artifact_name }}
|
||||||
|
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||||
|
create-dmg \
|
||||||
|
--volname "${{ env.APP_NAME }}" \
|
||||||
|
--window-pos 200 120 \
|
||||||
|
--window-size 600 300 \
|
||||||
|
--icon-size 100 \
|
||||||
|
--icon "${{ env.APP_NAME }}.app" 150 150 \
|
||||||
|
--hide-extension "${{ env.APP_NAME }}.app" \
|
||||||
|
--app-drop-link 450 150 \
|
||||||
|
"dist-final/${{ matrix.artifact_name }}.dmg" \
|
||||||
|
"dist/"
|
||||||
fi
|
fi
|
||||||
ls -la dist-final/
|
ls -la dist-final/
|
||||||
|
|
||||||
@@ -203,7 +233,7 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.os }}-build
|
name: ${{ matrix.os }}-build
|
||||||
path: dist-final/${{ matrix.artifact_name }}
|
path: dist-final/${{ matrix.artifact_name }}*
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
release:
|
release:
|
||||||
@@ -225,8 +255,8 @@ jobs:
|
|||||||
cp artifacts/ubuntu-22.04-build/SoftwareManager-stable-*-linux release/SoftwareManager-stable-${SHORT_SHA}-linux
|
cp artifacts/ubuntu-22.04-build/SoftwareManager-stable-*-linux release/SoftwareManager-stable-${SHORT_SHA}-linux
|
||||||
cp artifacts/windows-latest-build/SoftwareManager-stable-*-windows.zip release/SoftwareManager-stable-${SHORT_SHA}-windows.zip
|
cp artifacts/windows-latest-build/SoftwareManager-stable-*-windows.zip release/SoftwareManager-stable-${SHORT_SHA}-windows.zip
|
||||||
cp artifacts/windows-latest-build/SoftwareManager-stable-*-windows-setup.exe release/SoftwareManager-stable-${SHORT_SHA}-windows-setup.exe
|
cp artifacts/windows-latest-build/SoftwareManager-stable-*-windows-setup.exe release/SoftwareManager-stable-${SHORT_SHA}-windows-setup.exe
|
||||||
cp artifacts/macos-latest-build/SoftwareManager-stable-*-macos release/SoftwareManager-stable-${SHORT_SHA}-macos
|
cp artifacts/macos-latest-build/SoftwareManager-stable-*-macos.dmg release/SoftwareManager-stable-${SHORT_SHA}-macos.dmg
|
||||||
chmod +x release/SoftwareManager-stable-*-linux release/SoftwareManager-stable-*-macos
|
chmod +x release/SoftwareManager-stable-*-linux
|
||||||
ls -la release/
|
ls -la release/
|
||||||
|
|
||||||
- name: Generate checksums
|
- name: Generate checksums
|
||||||
@@ -236,7 +266,7 @@ jobs:
|
|||||||
cat SHA256SUMS.txt
|
cat SHA256SUMS.txt
|
||||||
|
|
||||||
- name: Create Release (Public)
|
- name: Create Release (Public)
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v3
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.RELEASE_TOKEN }}
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
tag_name: ${{ needs.build.outputs.version }}
|
tag_name: ${{ needs.build.outputs.version }}
|
||||||
@@ -246,5 +276,5 @@ jobs:
|
|||||||
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-linux
|
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-linux
|
||||||
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-windows.zip
|
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-windows.zip
|
||||||
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-windows-setup.exe
|
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-windows-setup.exe
|
||||||
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-macos
|
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-macos.dmg
|
||||||
release/SHA256SUMS.txt
|
release/SHA256SUMS.txt
|
||||||
|
|||||||
@@ -51,6 +51,21 @@ jobs:
|
|||||||
version: "0.9.7"
|
version: "0.9.7"
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
|
|
||||||
|
- name: Install system dependencies (Linux)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y \
|
||||||
|
libxcb-xinerama0 \
|
||||||
|
libxkbcommon-x11-0 \
|
||||||
|
libxcb-cursor0 \
|
||||||
|
libxcb-keysyms1 \
|
||||||
|
libxcb-render-util0 \
|
||||||
|
libxcb-icccm4 \
|
||||||
|
libxcb-image0 \
|
||||||
|
libxcb-shape0 \
|
||||||
|
libxcb-util1
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
uv pip install -r requirements.txt
|
uv pip install -r requirements.txt
|
||||||
@@ -58,6 +73,15 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
UV_SYSTEM_PYTHON: 1
|
UV_SYSTEM_PYTHON: 1
|
||||||
|
|
||||||
|
- name: Install dependencies (Linux)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y \
|
||||||
|
libxcb-cursor0 libxcb-render-util0 libxcb-xkb1 \
|
||||||
|
libxcb-icccm4 libxcb-keysyms1 libxcb-image0 \
|
||||||
|
libxcb-shape0 libxcb-util1 libxkbcommon-x11-0
|
||||||
|
|
||||||
- name: Install Nuitka (Windows only)
|
- name: Install Nuitka (Windows only)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
run: uv pip install nuitka
|
run: uv pip install nuitka
|
||||||
@@ -266,7 +290,7 @@ jobs:
|
|||||||
cat release_notes.md
|
cat release_notes.md
|
||||||
|
|
||||||
- name: Create Release (Public)
|
- name: Create Release (Public)
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v3
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ needs.build.outputs.version }}
|
tag_name: ${{ needs.build.outputs.version }}
|
||||||
name: ${{ needs.build.outputs.version }}
|
name: ${{ needs.build.outputs.version }}
|
||||||
@@ -278,4 +302,4 @@ jobs:
|
|||||||
release/SoftwareManager-dev-${{ needs.build.outputs.short_sha }}-macos
|
release/SoftwareManager-dev-${{ needs.build.outputs.short_sha }}-macos
|
||||||
release/SHA256SUMS.txt
|
release/SHA256SUMS.txt
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
name: Build ${{ matrix.os }}
|
name: Build ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false # keep other platforms building even if one fails
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-22.04
|
- os: ubuntu-22.04
|
||||||
@@ -41,6 +41,21 @@ jobs:
|
|||||||
version: "0.9.7"
|
version: "0.9.7"
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
|
|
||||||
|
- name: Install system dependencies (Linux)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y \
|
||||||
|
libxcb-xinerama0 \
|
||||||
|
libxkbcommon-x11-0 \
|
||||||
|
libxcb-cursor0 \
|
||||||
|
libxcb-keysyms1 \
|
||||||
|
libxcb-render-util0 \
|
||||||
|
libxcb-icccm4 \
|
||||||
|
libxcb-image0 \
|
||||||
|
libxcb-shape0 \
|
||||||
|
libxcb-util1
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
uv pip install -r requirements.txt
|
uv pip install -r requirements.txt
|
||||||
@@ -138,7 +153,7 @@ jobs:
|
|||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
pyinstaller --onefile \
|
pyinstaller --windowed \
|
||||||
--add-data "build_info.json:." \
|
--add-data "build_info.json:." \
|
||||||
--exclude-module PyQt6 \
|
--exclude-module PyQt6 \
|
||||||
--exclude-module PyQt5 \
|
--exclude-module PyQt5 \
|
||||||
@@ -150,15 +165,30 @@ jobs:
|
|||||||
--name ${{ env.APP_NAME }} \
|
--name ${{ env.APP_NAME }} \
|
||||||
src/main.py
|
src/main.py
|
||||||
|
|
||||||
|
- name: Install create-dmg (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: brew install create-dmg
|
||||||
|
|
||||||
- name: Stage artifact
|
- name: Stage artifact
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
mkdir -p dist-final
|
mkdir -p dist-final
|
||||||
if [ "$RUNNER_OS" == "Windows" ]; then
|
if [ "$RUNNER_OS" == "Windows" ]; then
|
||||||
mv nuitka-build/main.dist dist-final/${{ env.APP_NAME }}
|
mv nuitka-build/main.dist dist-final/${{ env.APP_NAME }}
|
||||||
else
|
elif [ "$RUNNER_OS" == "Linux" ]; then
|
||||||
chmod +x dist/${{ env.APP_NAME }}
|
chmod +x dist/${{ env.APP_NAME }}
|
||||||
mv dist/${{ env.APP_NAME }} dist-final/${{ matrix.artifact_name }}
|
mv dist/${{ env.APP_NAME }} dist-final/${{ matrix.artifact_name }}
|
||||||
|
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||||
|
create-dmg \
|
||||||
|
--volname "${{ env.APP_NAME }} Test" \
|
||||||
|
--window-pos 200 120 \
|
||||||
|
--window-size 600 300 \
|
||||||
|
--icon-size 100 \
|
||||||
|
--icon "${{ env.APP_NAME }}.app" 150 150 \
|
||||||
|
--hide-extension "${{ env.APP_NAME }}.app" \
|
||||||
|
--app-drop-link 450 150 \
|
||||||
|
"dist-final/${{ matrix.artifact_name }}.dmg" \
|
||||||
|
"dist/"
|
||||||
fi
|
fi
|
||||||
ls -la dist-final/
|
ls -la dist-final/
|
||||||
|
|
||||||
@@ -181,5 +211,5 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.os }}-build
|
name: ${{ matrix.os }}-build
|
||||||
path: dist-final/${{ matrix.artifact_name }}
|
path: dist-final/${{ matrix.artifact_name }}*
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|||||||
@@ -41,11 +41,11 @@ SoftwareManager is a Python-based GUI tool that simplifies searching and downloa
|
|||||||
|
|
||||||
<!-- python-dependencies:start -->
|
<!-- python-dependencies:start -->
|
||||||
```text
|
```text
|
||||||
requests (2.33.1)
|
requests (2.34.2)
|
||||||
PySide6-Essentials (6.11.0)
|
PySide6-Essentials (6.11.1)
|
||||||
beautifulsoup4 (4.14.3)
|
beautifulsoup4 (4.14.3)
|
||||||
darkdetect (0.7.1)
|
darkdetect (0.7.1)
|
||||||
pyinstaller (6.19.0)
|
pyinstaller (6.20.0)
|
||||||
PyQtDarkTheme-fork (2.3.6)
|
PyQtDarkTheme-fork (2.3.6)
|
||||||
plyer (2.1.0)
|
plyer (2.1.0)
|
||||||
psutil (7.2.2)
|
psutil (7.2.2)
|
||||||
@@ -55,10 +55,6 @@ SoftwareManager is a Python-based GUI tool that simplifies searching and downloa
|
|||||||
```
|
```
|
||||||
<!-- python-dependencies:end -->
|
<!-- python-dependencies:end -->
|
||||||
|
|
||||||
## Activity
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Star History
|
## Star History
|
||||||
|
|
||||||
<a href="https://www.star-history.com/#KeksPirates/SoftwareManager&type=date&legend=top-left">
|
<a href="https://www.star-history.com/#KeksPirates/SoftwareManager&type=date&legend=top-left">
|
||||||
|
|||||||
+51
-5
@@ -39,9 +39,10 @@
|
|||||||
<h1>KeksPirates</h1>
|
<h1>KeksPirates</h1>
|
||||||
</div>
|
</div>
|
||||||
<nav class="tab">
|
<nav class="tab">
|
||||||
<a class="tablinks" onclick="openTab(event, 'start')" id="defaultOpen">Home</a>
|
<a class="tablinks" onclick="openTab(event, 'start')" id="navHome">Home</a>
|
||||||
<a class="tablinks" onclick="openTab(event, 'api')">API</a>
|
<a class="tablinks" onclick="openTab(event, 'api')" id="navApi">API</a>
|
||||||
<a class="tablinks" onclick="openTab(event, 'docs')">Docs</a>
|
<a class="tablinks" onclick="openTab(event, 'docs')" id="navDocs">Docs</a>
|
||||||
|
<a class="tablinks" id="navVst" href="https://vstsearch.softwaremanager.xyz">VST Search</a>
|
||||||
<!-- <a class="tablinks" onclick="openTab(event, 'notfound')">404</a> -->
|
<!-- <a class="tablinks" onclick="openTab(event, 'notfound')">404</a> -->
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
@@ -187,6 +188,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="vstsearch" class="tabcontent">
|
||||||
|
<div class="cse-search">
|
||||||
|
<h3 class="vst-logo"><span style="color: #db65d5">VST Search</span></h3>
|
||||||
|
<div class="gcse-searchbox"></div>
|
||||||
|
|
||||||
|
<div class="gcse-searchresults"></div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="notfound" class="tabcontent">
|
<div id="notfound" class="tabcontent">
|
||||||
<div class="notfound-frame">
|
<div class="notfound-frame">
|
||||||
<h1 class="notfound-title">404</h1>
|
<h1 class="notfound-title">404</h1>
|
||||||
@@ -203,6 +215,20 @@
|
|||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
const MAIN_ORIGIN = 'https://softwaremanager.xyz';
|
||||||
|
const VST_ORIGIN = 'https://vstsearch.softwaremanager.xyz';
|
||||||
|
const onVstDomain = window.location.hostname.startsWith('vstsearch.');
|
||||||
|
|
||||||
|
let cseLoaded = false;
|
||||||
|
function loadCSE() {
|
||||||
|
if (cseLoaded) return;
|
||||||
|
cseLoaded = true;
|
||||||
|
var s = document.createElement('script');
|
||||||
|
s.async = true;
|
||||||
|
s.src = 'https://cse.google.com/cse.js?cx=e7334cef72a8b42e7';
|
||||||
|
document.head.appendChild(s);
|
||||||
|
}
|
||||||
|
|
||||||
function openTab(evt, tabName, pushToHistory = true) {
|
function openTab(evt, tabName, pushToHistory = true) {
|
||||||
var i, tabcontent, tablinks;
|
var i, tabcontent, tablinks;
|
||||||
|
|
||||||
@@ -218,6 +244,8 @@
|
|||||||
|
|
||||||
var target = document.getElementById(tabName);
|
var target = document.getElementById(tabName);
|
||||||
target.style.display = "block";
|
target.style.display = "block";
|
||||||
|
|
||||||
|
if (tabName === 'vstsearch') loadCSE();
|
||||||
// restart animation
|
// restart animation
|
||||||
target.classList.remove('tab-animate');
|
target.classList.remove('tab-animate');
|
||||||
void target.offsetWidth;
|
void target.offsetWidth;
|
||||||
@@ -247,6 +275,10 @@
|
|||||||
|
|
||||||
// Determine the correct tab immediately (before full load) to prevent flash
|
// Determine the correct tab immediately (before full load) to prevent flash
|
||||||
(function() {
|
(function() {
|
||||||
|
if (onVstDomain) {
|
||||||
|
document.getElementById('vstsearch').style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
let currentPath = window.location.pathname;
|
let currentPath = window.location.pathname;
|
||||||
let tabName = 'start';
|
let tabName = 'start';
|
||||||
if (currentPath === '/api') tabName = 'api';
|
if (currentPath === '/api') tabName = 'api';
|
||||||
@@ -257,9 +289,23 @@
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
|
if (onVstDomain) {
|
||||||
|
document.getElementById('navHome').href = MAIN_ORIGIN + '/';
|
||||||
|
document.getElementById('navApi').href = MAIN_ORIGIN + '/api';
|
||||||
|
document.getElementById('navDocs').href = MAIN_ORIGIN + '/docs';
|
||||||
|
['navHome', 'navApi', 'navDocs'].forEach(function(id) {
|
||||||
|
document.getElementById(id).removeAttribute('onclick');
|
||||||
|
});
|
||||||
|
openTab(null, 'vstsearch', false);
|
||||||
|
document.getElementById('navVst').className += " active";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let currentPath = window.location.pathname;
|
let currentPath = window.location.pathname;
|
||||||
|
|
||||||
if (currentPath === '/api') {
|
if (currentPath === '/vstsearch') {
|
||||||
|
window.location.replace(VST_ORIGIN);
|
||||||
|
} else if (currentPath === '/api') {
|
||||||
openTab(null, 'api', false);
|
openTab(null, 'api', false);
|
||||||
} else if (currentPath === '/docs') {
|
} else if (currentPath === '/docs') {
|
||||||
openTab(null, 'docs', false);
|
openTab(null, 'docs', false);
|
||||||
|
|||||||
@@ -378,6 +378,84 @@ pre.api-response {
|
|||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cse-search {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 70vh;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cse-search .vst-logo {
|
||||||
|
font-family: var(--main-font);
|
||||||
|
font-size: 3.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cse-search .gsc-control-cse,
|
||||||
|
.cse-search .gsc-results-wrapper-overlay,
|
||||||
|
.cse-search .gsc-results-wrapper-visible {
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cse-search .gsc-input-box,
|
||||||
|
.cse-search .gsc-input-box.gsc-input-box-hover,
|
||||||
|
.cse-search .gsc-input-box.gsc-input-box-focus {
|
||||||
|
background: #1a1b1d !important;
|
||||||
|
border-color: #1a1b1d !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cse-search .gsc-input,
|
||||||
|
.cse-search input.gsc-input,
|
||||||
|
.cse-search .gsib_a input.gsc-input {
|
||||||
|
background: transparent !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cse-search .gsib_a {
|
||||||
|
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none'><path fill-rule='evenodd' clip-rule='evenodd' d='M14.76 13.27L20.49 19L19 20.49L13.27 14.76C12.2 15.53 10.91 16 9.5 16C5.91 16 3 13.09 3 9.5C3 5.91 5.91 3 9.5 3C13.09 3 16 5.91 16 9.5C16 10.91 15.53 12.2 14.76 13.27ZM9.5 5C7.01 5 5 7.01 5 9.5C5 11.99 7.01 14 9.5 14C11.99 14 14 11.99 14 9.5C14 7.01 11.99 5 9.5 5Z' fill='%23ffffff'/></svg>") !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cse-search .gsc-search-button-v2 {
|
||||||
|
background: #db65d5 !important;
|
||||||
|
border-color: #db65d5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cse-search .gsc-search-button-v2:hover {
|
||||||
|
background: #c94dc3 !important;
|
||||||
|
border-color: #c94dc3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cse-search .gcsc-more-maybe-branding-root,
|
||||||
|
.gcsc-find-more-on-google {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gsc-completion-container,
|
||||||
|
.gssb_c, .gssb_e,
|
||||||
|
table.gssb_c, table.gssb_e {
|
||||||
|
background: #1a1b1d !important;
|
||||||
|
border-color: #333 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gsc-completion-container td,
|
||||||
|
.gsc-completion-container .gsc-completion-suggestion,
|
||||||
|
.gssb_a, .gssb_a td, .gssb_i {
|
||||||
|
background: #1a1b1d !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gsc-completion-container .gsc-completion-selected,
|
||||||
|
.gsc-completion-container tr:hover td,
|
||||||
|
.gssb_a:hover td, .gssb_e-hover {
|
||||||
|
background: #2a2b2d !important;
|
||||||
|
}
|
||||||
|
|
||||||
@media(max-width: 560px) {
|
@media(max-width: 560px) {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// Cloudflare Pages middleware.
|
||||||
|
//
|
||||||
|
// Both softwaremanager.xyz and vstsearch.softwaremanager.xyz serve the same
|
||||||
|
// index.html. Crawlers (Discord, Twitter, etc.) read the raw HTML and do NOT
|
||||||
|
// run JavaScript, so we rewrite the <title> and Open Graph / Twitter meta tags
|
||||||
|
// server-side when the request is for the VST Search subdomain. This gives the
|
||||||
|
// subdomain its own link embed without a separate deploy.
|
||||||
|
|
||||||
|
const VST = {
|
||||||
|
title: "VST Search - SoftwareManager",
|
||||||
|
description: "Search for plugins easily",
|
||||||
|
url: "https://vstsearch.softwaremanager.xyz/",
|
||||||
|
};
|
||||||
|
|
||||||
|
class AttributeSetter {
|
||||||
|
constructor(attribute, value) {
|
||||||
|
this.attribute = attribute;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
element(element) {
|
||||||
|
element.setAttribute(this.attribute, this.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ContentSetter {
|
||||||
|
constructor(value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
element(element) {
|
||||||
|
element.setInnerContent(this.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function onRequest(context) {
|
||||||
|
const { request, next } = context;
|
||||||
|
const response = await next();
|
||||||
|
|
||||||
|
const onVstDomain = new URL(request.url).hostname.startsWith("vstsearch.");
|
||||||
|
const contentType = response.headers.get("content-type") || "";
|
||||||
|
|
||||||
|
// Leave everything untouched on the main domain and for non-HTML responses.
|
||||||
|
if (!onVstDomain || !contentType.includes("text/html")) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HTMLRewriter()
|
||||||
|
.on("title", new ContentSetter(VST.title))
|
||||||
|
.on("meta[name='description']", new AttributeSetter("content", VST.description))
|
||||||
|
.on("meta[property='og:title']", new AttributeSetter("content", VST.title))
|
||||||
|
.on("meta[property='og:description']", new AttributeSetter("content", VST.description))
|
||||||
|
.on("meta[property='og:url']", new AttributeSetter("content", VST.url))
|
||||||
|
.on("meta[name='twitter:title']", new AttributeSetter("content", VST.title))
|
||||||
|
.on("meta[name='twitter:description']", new AttributeSetter("content", VST.description))
|
||||||
|
.transform(response);
|
||||||
|
}
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
requests==2.33.1
|
requests==2.34.2
|
||||||
PySide6-Essentials==6.11.0
|
PySide6-Essentials==6.11.1
|
||||||
beautifulsoup4==4.14.3
|
beautifulsoup4==4.14.3
|
||||||
darkdetect==0.7.1
|
darkdetect==0.7.1
|
||||||
pyinstaller==6.19.0
|
pyinstaller==6.20.0
|
||||||
PyQtDarkTheme-fork==2.3.6
|
PyQtDarkTheme-fork==2.3.6
|
||||||
plyer==2.1.0
|
plyer==2.1.0
|
||||||
psutil==7.2.2
|
psutil==7.2.2
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ class SteamripScraper:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
consoleLog(f"Found download link: {best}")
|
consoleLog(f"Found download link: {best}")
|
||||||
if "buzzheavier" in best:
|
if "buzzheavier" or "bzzhr" in best:
|
||||||
link = scrape_buzzheavier(best)
|
link = scrape_buzzheavier(best)
|
||||||
return link
|
return link
|
||||||
elif "gofile" in best:
|
elif "gofile" in best:
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import threading
|
|||||||
import webbrowser
|
import webbrowser
|
||||||
import subprocess
|
import subprocess
|
||||||
import platform
|
import platform
|
||||||
import time
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -79,9 +79,8 @@ def settings_dialog(self):
|
|||||||
|
|
||||||
# Ignore Updates checkbox
|
# Ignore Updates checkbox
|
||||||
update_checkbox_container, update_checkbox = create_widget(QCheckBox, "Ignore Updates: ")
|
update_checkbox_container, update_checkbox = create_widget(QCheckBox, "Ignore Updates: ")
|
||||||
if platform.system() == "Windows":
|
update_checkbox.setChecked(state.ignore_updates)
|
||||||
update_checkbox.setChecked(state.ignore_updates)
|
update_checkbox.toggled.connect(lambda checked: setattr(state, 'ignore_updates', checked))
|
||||||
update_checkbox.toggled.connect(lambda checked: setattr(state, 'ignore_updates', checked))
|
|
||||||
|
|
||||||
# Autoresume Container Checkbox
|
# Autoresume Container Checkbox
|
||||||
autoresume_container, autoresume_checkbox = create_widget(QCheckBox, "Auto-Resume Downloads: ")
|
autoresume_container, autoresume_checkbox = create_widget(QCheckBox, "Auto-Resume Downloads: ")
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
|
from PySide6.QtWidgets import QDialog, QMessageBox, QCheckBox
|
||||||
from utils.network.update_checker import get_updates
|
from utils.network.update_checker import get_updates
|
||||||
from PySide6.QtWidgets import QDialog, QMessageBox
|
|
||||||
from utils.network.updater import download_update
|
from utils.network.updater import download_update
|
||||||
|
from utils.config.config import create_config
|
||||||
from utils.logging.logs import consoleLog
|
from utils.logging.logs import consoleLog
|
||||||
from utils.data.state import state
|
from utils.data.state import state
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import webbrowser
|
||||||
import platform
|
import platform
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
RELEASES_URL = "https://github.com/KeksPirates/SoftwareManager/releases/latest"
|
||||||
|
|
||||||
def _get_build_info_path() -> (Path | None):
|
def _get_build_info_path() -> (Path | None):
|
||||||
current_dir = Path(__file__).resolve().parent
|
current_dir = Path(__file__).resolve().parent
|
||||||
|
|
||||||
@@ -31,19 +35,49 @@ def get_version() -> None:
|
|||||||
else:
|
else:
|
||||||
consoleLog(f"Could not find build info file (Path: {build_info_path})")
|
consoleLog(f"Could not find build info file (Path: {build_info_path})")
|
||||||
|
|
||||||
|
|
||||||
|
def _show_notify_dialog(latest: str) -> None:
|
||||||
|
msg = QMessageBox()
|
||||||
|
msg.setIcon(QMessageBox.Icon.Information)
|
||||||
|
msg.setWindowTitle("Update Available")
|
||||||
|
msg.setText(f"A new version is available: <b>{latest}</b>")
|
||||||
|
msg.setInformativeText("Visit the releases page to download it.")
|
||||||
|
|
||||||
|
dont_show = QCheckBox("Don't show again")
|
||||||
|
msg.setCheckBox(dont_show)
|
||||||
|
|
||||||
|
open_btn = msg.addButton("Open Releases Page", QMessageBox.ButtonRole.AcceptRole)
|
||||||
|
msg.addButton("Dismiss", QMessageBox.ButtonRole.RejectRole)
|
||||||
|
|
||||||
|
msg.exec()
|
||||||
|
|
||||||
|
if dont_show.isChecked():
|
||||||
|
state.ignore_updates = True
|
||||||
|
create_config()
|
||||||
|
|
||||||
|
if msg.clickedButton() == open_btn:
|
||||||
|
webbrowser.open(RELEASES_URL)
|
||||||
|
|
||||||
|
|
||||||
class UpdateDialog(QDialog):
|
class UpdateDialog(QDialog):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
if state.ignore_updates is False and platform.system() == "Windows":
|
if state.ignore_updates:
|
||||||
|
return
|
||||||
|
|
||||||
assets, latest = get_updates()
|
assets, latest = get_updates()
|
||||||
if assets != None:
|
if assets is None:
|
||||||
msg = QMessageBox()
|
return
|
||||||
msg.setIcon(QMessageBox.Icon.Information)
|
|
||||||
msg.setWindowTitle("Update Available")
|
if platform.system() == "Windows":
|
||||||
msg.setText(f"A new version is available\n({latest})")
|
msg = QMessageBox()
|
||||||
msg.setInformativeText("Press Ok to download.")
|
msg.setIcon(QMessageBox.Icon.Information)
|
||||||
msg.setStandardButtons(QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Ignore)
|
msg.setWindowTitle("Update Available")
|
||||||
response = msg.exec_()
|
msg.setText(f"A new version is available\n({latest})")
|
||||||
if response == QMessageBox.StandardButton.Ok:
|
msg.setInformativeText("Press Ok to download.")
|
||||||
download_update(assets)
|
msg.setStandardButtons(QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Ignore)
|
||||||
|
response = msg.exec_()
|
||||||
|
if response == QMessageBox.StandardButton.Ok:
|
||||||
|
download_update(assets)
|
||||||
|
else:
|
||||||
|
_show_notify_dialog(latest)
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,14 @@ def add_direct_download(url: str, title: str, dl_path: Optional[str] = None, hea
|
|||||||
consoleLog(f"Download already active: {title}")
|
consoleLog(f"Download already active: {title}")
|
||||||
return
|
return
|
||||||
|
|
||||||
filename = (
|
raw_filename = (
|
||||||
detect_filename_from_headers(url, DirectDownloadHandle.USER_AGENT)
|
detect_filename_from_headers(url, DirectDownloadHandle.USER_AGENT)
|
||||||
or extract_filename_from_url(url)
|
or extract_filename_from_url(url)
|
||||||
or sanitize_filename(title) + ".zip"
|
or sanitize_filename(title) + ".zip"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
filename = sanitize_filename(raw_filename)
|
||||||
|
|
||||||
handle = DirectDownloadHandle(url, filename, dl_path, headers, single_threaded)
|
handle = DirectDownloadHandle(url, filename, dl_path, headers, single_threaded)
|
||||||
with state.downloads_lock:
|
with state.downloads_lock:
|
||||||
state.active_downloads[url] = handle
|
state.active_downloads[url] = handle
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import requests
|
|||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
@@ -231,8 +232,24 @@ class DirectDownloadHandle:
|
|||||||
def _preallocate_file(self, total_size: int):
|
def _preallocate_file(self, total_size: int):
|
||||||
if os.path.exists(self._file_path) and os.path.getsize(self._file_path) == total_size:
|
if os.path.exists(self._file_path) and os.path.getsize(self._file_path) == total_size:
|
||||||
return
|
return
|
||||||
|
|
||||||
with open(self._file_path, "wb") as f:
|
with open(self._file_path, "wb") as f:
|
||||||
f.truncate(total_size)
|
if sys.platform == "win32":
|
||||||
|
import msvcrt
|
||||||
|
import ctypes
|
||||||
|
from ctypes.wintypes import DWORD
|
||||||
|
|
||||||
|
handle = msvcrt.get_osfhandle(f.fileno())
|
||||||
|
kernel32 = ctypes.windll.kernel32
|
||||||
|
|
||||||
|
bytes_returned = DWORD()
|
||||||
|
kernel32.DeviceIoControl(
|
||||||
|
handle, 590020, None, 0, None, 0, ctypes.byref(bytes_returned), None
|
||||||
|
)
|
||||||
|
kernel32.SetFilePointerEx(handle, ctypes.c_int64(total_size), None, 0)
|
||||||
|
kernel32.SetEndOfFile(handle)
|
||||||
|
else:
|
||||||
|
f.truncate(total_size)
|
||||||
|
|
||||||
def _compute_chunks(self, total_size: int) -> list[ChunkSpec]:
|
def _compute_chunks(self, total_size: int) -> list[ChunkSpec]:
|
||||||
num_chunks = min(self.NUM_THREADS, max(1, total_size // self.MIN_CHUNK_SIZE))
|
num_chunks = min(self.NUM_THREADS, max(1, total_size // self.MIN_CHUNK_SIZE))
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ def detect_filename_from_headers(url: str, user_agent: str) -> Optional[str]:
|
|||||||
if "filename=" in cd:
|
if "filename=" in cd:
|
||||||
parts = cd.split("filename=")
|
parts = cd.split("filename=")
|
||||||
if len(parts) > 1:
|
if len(parts) > 1:
|
||||||
fname = parts[-1].strip().strip('"').strip("'")
|
fname = parts[1].split(";")[0].strip().strip('"').strip("'")
|
||||||
if fname:
|
if fname:
|
||||||
return fname
|
return fname
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ from PySide6.QtCore import QObject, QTimer
|
|||||||
from utils.data.state import state
|
from utils.data.state import state
|
||||||
from plyer import notification
|
from plyer import notification
|
||||||
import libtorrent as lt
|
import libtorrent as lt
|
||||||
import time
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user