Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux improvements & development builds #216

Merged
merged 13 commits into from
Jun 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 88 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,102 @@ jobs:

- name: Create release folder
run: |
$FolderName = "Twitch Drops Miner"
if (!(Test-Path $FolderName)) {
New-Item $FolderName -ItemType Directory
}
Copy-Item dist\*.exe -Destination $FolderName
$FolderName = 'Twitch Drops Miner'
New-Item $FolderName -ItemType Directory
Copy-Item dist\*.exe $FolderName
Copy-Item manual.txt $FolderName
Compress-Archive -Path $FolderName -DestinationPath Twitch.Drops.Miner.zip
Compress-Archive -Path $FolderName -DestinationPath Twitch.Drops.Miner.Windows.zip

- name: Upload build artifact
uses: actions/upload-artifact@v3
with:
if-no-files-found: error
name: Twitch.Drops.Miner
path: Twitch.Drops.Miner.zip
name: Twitch.Drops.Miner.Windows
path: Twitch.Drops.Miner.Windows.zip

linux:
name: Linux
runs-on: ubuntu-20.04

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up variables
id: vars
run: |
echo "sha_short=$(git rev-parse --short HEAD)" >> "${GITHUB_OUTPUT}"

- name: Append git revision to project version
run: |
sed -ri "s/^__version__\s*=\s*\"[^\"]+/\0.${{ steps.vars.outputs.sha_short }}/" version.py

# NOTE: We're only use a custom version of Python here because truststore requires at least Python 3.10, but Ubuntu 20.04 has Python 3.8.
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'

- name: Install system dependencies
run: |
sudo apt update
sudo apt install gir1.2-appindicator3-0.1 libgirepository1.0-dev python3-tk

- name: Set up Python virtual environment
run: |
python3 -m venv env

- name: Install project dependencies
run: |
source ./env/bin/activate
python3 -m pip install wheel -r requirements.txt

- name: Install PyInstaller
run: |
source ./env/bin/activate
python3 -m pip install pyinstaller

# NOTE: Remove this step if/once libxft gets updated to 2.3.5 or newer on Ubuntu 20.04, which currently has 2.3.3.
- name: Build a recent version of libXft
run: |
mkdir -p /tmp/libXft
cd /tmp/libXft
curl -L https://xorg.freedesktop.org/releases/individual/lib/libXft-2.3.8.tar.xz -o libXft.tar.xz
tar xvf libXft.tar.xz
cd libXft-*
./configure --prefix=/tmp/libXft --sysconfdir=/etc --disable-static
make
make install-strip

- name: Create portable executable
run: |
source ./env/bin/activate
LD_LIBRARY_PATH=/tmp/libXft/lib xvfb-run --auto-servernum pyinstaller build.spec

- name: Show PyInstaller warnings
run: |
cat build/build/warn-build.txt || true

- name: Create release folder
run: |
folder='Twitch Drops Miner'
mkdir "${folder}"
cp manual.txt dist/* "${folder}"
7z a Twitch.Drops.Miner.Linux.zip "${folder}"

- name: Upload build artifact
uses: actions/upload-artifact@v3
with:
if-no-files-found: error
name: Twitch.Drops.Miner.Linux
path: Twitch.Drops.Miner.Linux.zip

update_releases_page:
name: Upload build to Releases
name: Upload builds to Releases
if: github.event_name != 'pull_request'
needs: windows
needs:
- windows
- linux
runs-on: ubuntu-22.04
permissions:
contents: write
Expand All @@ -87,7 +164,7 @@ jobs:
with:
path: artifacts

- name: Upload build to Releases
- name: Upload builds to Releases
uses: ncipollo/release-action@v1
with:
allowUpdates: true
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ Every ~60 seconds, the application sends a "minute watched" event to the channel
- Successfully logging into your Twitch account in the application, may cause Twitch to send you a "New Login" notification email. This is normal - you can verify that it comes from your own IP address. The application uses the Twitch's SmartTV account linking process, so the detected browser during the login should signify that as well.
- The time remaining timer always countdowns a single minute and then stops - it is then restarted only after the application redetermines the remaining time. This "redetermination" can happen as early as at 10 seconds in a minute remaining, and as late as 20 seconds after the timer reaches zero (especially when finishing mining a drop), but is generally only an approximation and does not represent nor affect actual mining speed. The time variations are due to Twitch sometimes not reporting drop progress at all, or reporting progress for the wrong drop - these cases have all been accounted for in the application though.

### Notes about the Windows build:

- To achieve a portable-executable format, the application is packaged with PyInstaller into an `EXE`. Some non-mainstream antivirus engines might report the packaged executable as a trojan, because PyInstaller has been used by others to package malicious Python code in the past. These reports can be safely ignored. If you absolutely do not trust the executable, you'll have to install Python yourself and run everything from source.
- The executable uses the `%TEMP%` directory for temporary runtime storage of files, that don't need to be exposed to the user (like compiled code and translation files). For persistent storage, the directory the executable resides in is used instead.
- The autostart feature is implemented as a registry entry to the current user's (`HKCU`) autostart key. It is only altered when toggling the respective option. If you relocate the app to a different directory, the autostart feature will stop working, until you toggle the option off and back on again

### Notes about the Linux build:

- The Linux app is built and distributed in a portable-executable format (similar to [AppImages](https://appimage.org/)).
- The Linux app should work out of the box on any modern distribution (as long as it has `glibc>=2.31` and a working display server).
- Every feature of the app is expected to work on Linux just as well as it does on Windows. If you find something that's broken, please [open a new issue](https://github.com/DevilXD/TwitchDropsMiner/issues/new).
- The size of the Linux app is significantly larger than the Windows app due to the inclusion of the `gtk3` library (and its dependencies), which is required for proper system tray/notifications support.
- As an alternative to the native Linux app, you can run the Windows app via [Wine](https://www.winehq.org/) instead. It works really well!

### Support

<div align="center">
Expand Down
41 changes: 30 additions & 11 deletions build.spec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ from __future__ import annotations

import sys
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any, TYPE_CHECKING

SELF_PATH = str(Path(".").absolute())
if SELF_PATH not in sys.path:
Expand Down Expand Up @@ -34,28 +34,47 @@ for source_path, dest_path, required in to_add:
elif required:
raise FileNotFoundError(str(source_path))

hooksconfig: dict[str, Any] = {}
binaries: list[tuple[Path, str]] = []
hiddenimports: list[str] = [
"PIL._tkinter_finder",
"setuptools._distutils.log",
"setuptools._distutils.dir_util",
"setuptools._distutils.file_util",
"setuptools._distutils.archive_util",
]

if sys.platform == "linux":
# Needed files for better system tray support on Linux via pystray (AppIndicator backend).
datas.append((Path("/usr/lib/girepository-1.0/AppIndicator3-0.1.typelib"), "gi_typelibs"))
binaries.append((Path("/lib/x86_64-linux-gnu/libappindicator3.so.1"), "."))
hiddenimports.extend([
"gi.repository.Gtk",
"gi.repository.GObject",
])
hooksconfig = {
"gi": {
"icons": [],
"themes": [],
"languages": ["en_US"]
}
}

block_cipher = None
a = Analysis(
["main.py"],
pathex=[],
datas=datas,
binaries=[],
excludes=[],
hookspath=[],
hooksconfig={},
noarchive=False,
hiddenimports=[
"setuptools._distutils.log",
"setuptools._distutils.dir_util",
"setuptools._distutils.file_util",
"setuptools._distutils.archive_util",
"PIL._tkinter_finder",
],
runtime_hooks=[],
binaries=binaries,
cipher=block_cipher,
win_no_prefer_redirects=False,
hooksconfig=hooksconfig,
hiddenimports=hiddenimports,
win_private_assemblies=False,
win_no_prefer_redirects=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
Expand Down
Loading