diff --git a/.github/workflows/ci_macos.yaml b/.github/workflows/ci_macos.yaml index 2dc99ca96..dd0de04ca 100644 --- a/.github/workflows/ci_macos.yaml +++ b/.github/workflows/ci_macos.yaml @@ -46,7 +46,7 @@ jobs: curl \ -L \ -o "${{ runner.temp }}/boost.tar.bz2" \ - "https://boostorg.jfrog.io/artifactory/main/release/1.80.0/source/boost_1_80_0.tar.bz2" + "https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.tar.bz2" tar -xf "${{ runner.temp }}/boost.tar.bz2" -C "${{ github.workspace }}/.." mv "${{ github.workspace }}/.."/boost_* "${{ env.boost_path }}" diff --git a/.github/workflows/ci_ubuntu.yaml b/.github/workflows/ci_ubuntu.yaml index 1caa0c1fa..053077ef4 100644 --- a/.github/workflows/ci_ubuntu.yaml +++ b/.github/workflows/ci_ubuntu.yaml @@ -78,7 +78,7 @@ jobs: cmake --build build --target qbt_update_translations cmake --build build cmake --build build --target check - DESTDIR="qbittorrent" cmake --install build + DESTDIR="qbittorrent" cmake --install build --strip - name: Build qBittorrent (Qt6) if: ${{ startsWith(matrix.qt_version, 6) }} @@ -97,7 +97,7 @@ jobs: cmake --build build --target qbt_update_translations cmake --build build cmake --build build --target check - DESTDIR="qbittorrent" cmake --install build + DESTDIR="qbittorrent" cmake --install build --strip - name: Prepare build artifacts run: | @@ -107,8 +107,35 @@ jobs: mkdir upload/cmake/libtorrent cp libtorrent/build/compile_commands.json upload/cmake/libtorrent + - name: 'AppImage: Prepare env' + run: | + sudo apt install libfuse2 + wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage + wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage + wget https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage + chmod +x linuxdeploy-x86_64.AppImage + chmod +x linuxdeploy-plugin-qt-x86_64.AppImage + chmod +x linuxdeploy-plugin-appimage-x86_64.AppImage + + - name: 'AppImage: Prepare nox' + if: matrix.qbt_gui == 'GUI=OFF' + run: | + mkdir -p qbittorrent/usr/share/icons/hicolor/scalable/apps/ + mkdir -p qbittorrent/usr/share/applications/ + cp dist/unix/menuicons/scalable/apps/qbittorrent.svg qbittorrent/usr/share/icons/hicolor/scalable/apps/qbittorrent.svg + cp .github/workflows/helper/appimage/org.qbittorrent.qBittorrent.desktop qbittorrent/usr/share/applications/org.qbittorrent.qBittorrent.desktop + + - name: 'AppImage: Package' + run: | + ./linuxdeploy-x86_64.AppImage --appdir=qbittorrent --plugin qt + rm qbittorrent/apprun-hooks/* + cp .github/workflows/helper/appimage/export_vars.sh qbittorrent/apprun-hooks/export_vars.sh + NO_APPSTREAM=1 \ + OUTPUT=upload/qbittorrent-CI_Ubuntu_x86_64.AppImage \ + ./linuxdeploy-x86_64.AppImage --appdir=qbittorrent --output appimage + - name: Upload build artifacts uses: actions/upload-artifact@v3 with: - name: build-info_ubuntu-x64_${{ matrix.qbt_gui }}_libtorrent-${{ matrix.libt_version }}_Qt-${{ matrix.qt_version }} + name: qBittorrent-CI_Ubuntu-x64_${{ matrix.qbt_gui }}_libtorrent-${{ matrix.libt_version }}_Qt-${{ matrix.qt_version }} path: upload diff --git a/.github/workflows/ci_windows.yaml b/.github/workflows/ci_windows.yaml index a384aa344..bca52a8e1 100644 --- a/.github/workflows/ci_windows.yaml +++ b/.github/workflows/ci_windows.yaml @@ -67,7 +67,7 @@ jobs: - name: Install boost run: | aria2c ` - "https://boostorg.jfrog.io/artifactory/main/release/1.80.0/source/boost_1_80_0.7z" ` + "https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.7z" ` -d "${{ runner.temp }}" ` -o "boost.7z" 7z x "${{ runner.temp }}/boost.7z" -o"${{ github.workspace }}/.." diff --git a/.github/workflows/helper/appimage/export_vars.sh b/.github/workflows/helper/appimage/export_vars.sh new file mode 100644 index 000000000..cbedc852e --- /dev/null +++ b/.github/workflows/helper/appimage/export_vars.sh @@ -0,0 +1,11 @@ +# this file is called from AppRun so 'root_dir' will point to where AppRun is +root_dir="$(readlink -f "$(dirname "$0")")" + +# Insert the default values because after the test we prepend our path +# and it will create problems with DEs (eg KDE) that don't set the variable +# and rely on the default paths +if [[ -z ${XDG_DATA_DIRS} ]]; then + XDG_DATA_DIRS="/usr/local/share/:/usr/share/" +fi + +export XDG_DATA_DIRS="${root_dir}/usr/share:${XDG_DATA_DIRS}" diff --git a/.github/workflows/helper/appimage/org.qbittorrent.qBittorrent.desktop b/.github/workflows/helper/appimage/org.qbittorrent.qBittorrent.desktop new file mode 100644 index 000000000..a00bf46df --- /dev/null +++ b/.github/workflows/helper/appimage/org.qbittorrent.qBittorrent.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Name=qBittorrent +Exec=qbittorrent-nox %U +Icon=qbittorrent +Type=Application +Categories=Network diff --git a/dist/docker/.env b/dist/docker/.env deleted file mode 100644 index 27246a6b4..000000000 --- a/dist/docker/.env +++ /dev/null @@ -1,8 +0,0 @@ -# refer to Readme.md for an explanation of the variables - -QBT_EULA= -QBT_VERSION=devel -QBT_WEBUI_PORT=8080 - -QBT_CONFIG_PATH=/config -QBT_DOWNLOADS_PATH=/downloads diff --git a/dist/docker/Dockerfile b/dist/docker/Dockerfile deleted file mode 100644 index e5111d4dd..000000000 --- a/dist/docker/Dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -# image for building -FROM alpine:latest AS builder - -ARG QBT_VERSION - -# alpine linux qbittorrent package: https://git.alpinelinux.org/aports/tree/community/qbittorrent/APKBUILD - -RUN \ - apk --update-cache add \ - boost-dev \ - cmake \ - g++ \ - libtorrent-rasterbar-dev \ - ninja \ - qt6-qtbase-dev \ - qt6-qttools-dev - -RUN \ - if [ "$QBT_VERSION" = "devel" ]; then \ - wget https://github.com/qbittorrent/qBittorrent/archive/refs/heads/master.zip && \ - unzip master.zip && \ - cd qBittorrent-master ; \ - else \ - wget "https://github.com/qbittorrent/qBittorrent/archive/refs/tags/release-${QBT_VERSION}.tar.gz" && \ - tar -xf "release-${QBT_VERSION}.tar.gz" && \ - cd "qBittorrent-release-${QBT_VERSION}" ; \ - fi && \ - cmake \ - -B build \ - -G Ninja \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DGUI=OFF \ - -DQT6=ON \ - -DSTACKTRACE=OFF && \ - cmake --build build && \ - cmake --install build - -# image for running -FROM alpine:latest - -RUN \ - apk --no-cache add \ - doas \ - libtorrent-rasterbar \ - python3 \ - qt6-qtbase \ - tini - -RUN \ - adduser \ - -D \ - -H \ - -s /sbin/nologin \ - -u 1000 \ - qbtUser && \ - echo "permit nopass :root" >> "/etc/doas.d/doas.conf" - -COPY --from=builder /usr/local/bin/qbittorrent-nox /usr/bin/qbittorrent-nox - -COPY entrypoint.sh /entrypoint.sh - -ENTRYPOINT ["/sbin/tini", "-g", "--", "/entrypoint.sh"] diff --git a/dist/docker/Readme.md b/dist/docker/Readme.md deleted file mode 100644 index b4e2a73d1..000000000 --- a/dist/docker/Readme.md +++ /dev/null @@ -1,101 +0,0 @@ -# qBittorrent-nox Docker Image - -This Dockerfile allows you to build a Docker Image containing qBittorrent-nox - -## Prerequisites - -In order to build/run this image you'll need Docker installed: https://docs.docker.com/get-docker/ - -If you don't need the GUI, you can just install Docker Engine: https://docs.docker.com/engine/install/ - -It is also recommended to install Docker Compose as it can significantly ease the process: https://docs.docker.com/compose/install/ - -## Building Docker Image - -* If you are using Docker (not Docker Compose) then run the following commands in this folder: - ```shell - export \ - QBT_VERSION=devel - docker build \ - --build-arg QBT_VERSION \ - -t qbittorrent-nox:"$QBT_VERSION" \ - . - ``` - -* If you are using Docker Compose then you should edit `.env` file first. - You can find an explanation of the variables in the following [Parameters](#parameters) section. \ - Then run the following commands in this folder: - ```shell - docker compose build \ - --build-arg QBT_VERSION - ``` - -### Parameters - -#### Environment variables - -* `QBT_EULA` \ - This environment variable defines whether you accept the end-user license agreement (EULA) of qBittorrent. \ - **Put `accept` only if you understand and accepted the EULA.** You can find - the EULA [here](https://github.com/qbittorrent/qBittorrent/blob/56667e717b82c79433ecb8a5ff6cc2d7b315d773/src/app/main.cpp#L320-L323). -* `QBT_VERSION` \ - This environment variable specifies the version of qBittorrent-nox to be built. \ - For example, `4.4.0` is a valid entry. You can find all tagged versions [here](https://github.com/qbittorrent/qBittorrent/tags). \ - Or you can put `devel` to build the latest development version. -* `QBT_WEBUI_PORT` \ - This environment variable sets the port number which qBittorrent WebUI will be binded to. - -#### Volumes - -There are some paths involved: -* `/config` \ - Full path to a folder on your host machine which will store qBittorrent configurations. - Using relative path won't work. -* `/downloads` \ - Full path to a folder on your host machine which will store the files downloaded by qBittorrent. - Using relative path won't work. - -## Running container - -* Using Docker (not Docker Compose), simply run: - ```shell - export \ - QBT_EULA=accept \ - QBT_VERSION=devel \ - QBT_WEBUI_PORT=8080 \ - QBT_CONFIG_PATH="/tmp/bbb/config" - QBT_DOWNLOADS_PATH="/tmp/bbb/downloads" - docker run \ - -t \ - --read-only \ - --rm \ - --tmpfs /tmp \ - --name qbittorrent-nox \ - -e QBT_EULA \ - -e QBT_WEBUI_PORT \ - -p "$QBT_WEBUI_PORT":"$QBT_WEBUI_PORT"/tcp \ - -p 6881:6881/tcp \ - -p 6881:6881/udp \ - -v "$QBT_CONFIG_PATH":/config \ - -v "$QBT_DOWNLOADS_PATH":/downloads \ - qbittorrent-nox:"$QBT_VERSION" - ``` - -* Using Docker Compose: - ```shell - docker compose up - ``` - -Then you can login at: `http://127.0.0.1:8080` - -## Stopping container - -* Using Docker (not Docker Compose): - ```shell - docker stop -t 1800 qbittorrent-nox - ``` - -* Using Docker Compose: - ```shell - docker compose down - ``` diff --git a/dist/docker/docker-compose.yml b/dist/docker/docker-compose.yml deleted file mode 100644 index c5cab9846..000000000 --- a/dist/docker/docker-compose.yml +++ /dev/null @@ -1,25 +0,0 @@ -version: "3.9" - -services: - qbittorrent-nox: - build: . - container_name: qbittorrent-nox - environment: - - QBT_EULA=${QBT_EULA} - - QBT_VERSION=${QBT_VERSION} - - QBT_WEBUI_PORT=${QBT_WEBUI_PORT} - image: qbittorrent-nox:${QBT_VERSION} - ports: - # for bittorrent traffic - - 6881:6881/tcp - - 6881:6881/udp - # for WebUI - - ${QBT_WEBUI_PORT}:${QBT_WEBUI_PORT}/tcp - read_only: true - stop_grace_period: 30m - tmpfs: - - /tmp - tty: true - volumes: - - ${QBT_CONFIG_PATH}:/config - - ${QBT_DOWNLOADS_PATH}:/downloads diff --git a/dist/docker/entrypoint.sh b/dist/docker/entrypoint.sh deleted file mode 100755 index c49f0b76c..000000000 --- a/dist/docker/entrypoint.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -downloadsPath="/downloads" -profilePath="/config" -qbtConfigFile="$profilePath/qBittorrent/config/qBittorrent.conf" - -if [ ! -f "$qbtConfigFile" ]; then - mkdir -p "$(dirname $qbtConfigFile)" - cat << EOF > "$qbtConfigFile" -[BitTorrent] -Session\DefaultSavePath=/downloads -Session\Port=6881 -Session\TempPath=/downloads/temp - -[LegalNotice] -Accepted=false -EOF - - if [ "$QBT_EULA" = "accept" ]; then - sed -i '/^\[LegalNotice\]$/{$!{N;s|\(\[LegalNotice\]\nAccepted=\).*|\1true|}}' "$qbtConfigFile" - else - sed -i '/^\[LegalNotice\]$/{$!{N;s|\(\[LegalNotice\]\nAccepted=\).*|\1false|}}' "$qbtConfigFile" - fi -fi - -# those are owned by root by default -# don't change existing files owner in `$downloadsPath` -chown qbtUser:qbtUser "$downloadsPath" -chown qbtUser:qbtUser -R "$profilePath" - -doas -u qbtUser \ - qbittorrent-nox \ - --profile="$profilePath" \ - --webui-port="$QBT_WEBUI_PORT" \ - "$@" diff --git a/dist/windows/installer-translations/lithuanian.nsi b/dist/windows/installer-translations/lithuanian.nsi index e69ed294f..b46782b9e 100644 --- a/dist/windows/installer-translations/lithuanian.nsi +++ b/dist/windows/installer-translations/lithuanian.nsi @@ -3,7 +3,7 @@ ;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)" LangString inst_qbt_req ${LANG_LITHUANIAN} "qBittorrent (reikalingas)" ;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut" -LangString inst_dekstop ${LANG_LITHUANIAN} "Sukurti darbalaukyje nuorodą" +LangString inst_dekstop ${LANG_LITHUANIAN} "Sukurti nuorodą darbalaukyje" ;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut" LangString inst_startmenu ${LANG_LITHUANIAN} "Sukurti Pradėti meniu nuorodą" ;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up" @@ -13,27 +13,27 @@ LangString inst_torrent ${LANG_LITHUANIAN} "Atidaryti .torrent failus su qBittor ;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent" LangString inst_magnet ${LANG_LITHUANIAN} "Atidaryti magneto nuorodas su qBittorrent" ;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule" -LangString inst_firewall ${LANG_LITHUANIAN} "Sukurti Windows užkardos leidimą" +LangString inst_firewall ${LANG_LITHUANIAN} "Sukurti Windows interneto užkardos leidimą" ;LangString inst_pathlimit ${LANG_ENGLISH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)" -LangString inst_pathlimit ${LANG_LITHUANIAN} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)" +LangString inst_pathlimit ${LANG_LITHUANIAN} "Išjungti Windows path ilgio limitaciją (260 ženklų MAX_PATH limitacija, reikalinga versija yra Windows 10 1607 ar naujesnė)" ;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule" LangString inst_firewallinfo ${LANG_LITHUANIAN} "Pridedu Windows užkardos leidimą" ;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing." -LangString inst_warning ${LANG_LITHUANIAN} "qBittorrent yra paleistas. Prašau uždaryti programą prieš įdiegiant." +LangString inst_warning ${LANG_LITHUANIAN} "qBittorrent yra paleistas. Prašome uždaryti programą prieš įdiegiant." ;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact." -LangString inst_uninstall_question ${LANG_LITHUANIAN} "Current version will be uninstalled. User settings and torrents will remain intact." +LangString inst_uninstall_question ${LANG_LITHUANIAN} "Dabartinė versija bus pašalinta. Naudotojo nustatymai ir torrentai liks nepakeisti." ;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version." -LangString inst_unist ${LANG_LITHUANIAN} "Šalinu ankstesnę versiją." +LangString inst_unist ${LANG_LITHUANIAN} "Šalinama ankstesnė versija." ;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent." LangString launch_qbt ${LANG_LITHUANIAN} "Paleisti qBittorrent." ;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions." -LangString inst_requires_64bit ${LANG_LITHUANIAN} "This installer works only in 64-bit Windows versions." +LangString inst_requires_64bit ${LANG_LITHUANIAN} "Šis įdiegėjas veikia tik su 64 bitų Windows versija." ;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7." -LangString inst_requires_win7 ${LANG_LITHUANIAN} "This qBittorrent version requires at least Windows 7." +LangString inst_requires_win7 ${LANG_LITHUANIAN} "Ši qBittorent versija reikalauja bent Windows 7." ;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809." -LangString inst_requires_win10 ${LANG_LITHUANIAN} "This installer requires at least Windows 10 1809." +LangString inst_requires_win10 ${LANG_LITHUANIAN} "Šis įdiegėjas reikalauja bent Windows 10 1809." ;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent" -LangString inst_uninstall_link_description ${LANG_LITHUANIAN} "Uninstall qBittorrent" +LangString inst_uninstall_link_description ${LANG_LITHUANIAN} "Pašalinti qBittorrent" ;------------------------------------ ;Uninstaller strings @@ -49,14 +49,14 @@ LangString remove_registry ${LANG_LITHUANIAN} "Pašalinti registro raktus" ;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files" LangString remove_conf ${LANG_LITHUANIAN} "Pašalinti nustatymų failus" ;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule" -LangString remove_firewall ${LANG_LITHUANIAN} "Pašalinti Windows užkardos leidimą" +LangString remove_firewall ${LANG_LITHUANIAN} "Pašalinti Windows interneto užkardos leidimą" ;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule" -LangString remove_firewallinfo ${LANG_LITHUANIAN} "Šalinu Windows užkardos leidimą" +LangString remove_firewallinfo ${LANG_LITHUANIAN} "Šalinamas Windows interneto užkardos leidimas" ;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data" -LangString remove_cache ${LANG_LITHUANIAN} "Pašalinti torentus ir podėlio duomenis" +LangString remove_cache ${LANG_LITHUANIAN} "Pašalinti torentus ir talpyklos duomenis" ;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling." -LangString uninst_warning ${LANG_LITHUANIAN} "qBittorrent yra paleistas. Prašau uždarykite programą prieš išdiegiant." +LangString uninst_warning ${LANG_LITHUANIAN} "qBittorrent yra paleistas. Prašome uždaryti programą prieš išdiegiant." ;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:" -LangString uninst_tor_warn ${LANG_LITHUANIAN} "Negaliu pašalinti .torrent asociacijos. Ji yra susieti su:" +LangString uninst_tor_warn ${LANG_LITHUANIAN} "Neįmanoma pašalinti .torrent asociacijos. Ji yra susieta su:" ;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:" -LangString uninst_mag_warn ${LANG_LITHUANIAN} "Negaliu pašalinti magneto asociacijos. Jis susietas su:" +LangString uninst_mag_warn ${LANG_LITHUANIAN} "Neįmanoma pašalinti magneto asociacijos. Ji yra susieta su:" diff --git a/dist/windows/installer-translations/swedish.nsi b/dist/windows/installer-translations/swedish.nsi index b5912d741..674c4ee44 100644 --- a/dist/windows/installer-translations/swedish.nsi +++ b/dist/windows/installer-translations/swedish.nsi @@ -27,11 +27,11 @@ LangString inst_unist ${LANG_SWEDISH} "Avinstallerar tidigare version." ;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent." LangString launch_qbt ${LANG_SWEDISH} "Kör qBittorrent." ;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions." -LangString inst_requires_64bit ${LANG_SWEDISH} "Installationsprogrammet fungerar endast i 64-bitars Windows-versioner." +LangString inst_requires_64bit ${LANG_SWEDISH} "Det här installationsprogrammet fungerar endast i 64-bitars Windows-versioner." ;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7." LangString inst_requires_win7 ${LANG_SWEDISH} "Den här qBittorrent-versionen kräver minst Windows 7." ;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809." -LangString inst_requires_win10 ${LANG_SWEDISH} "This installer requires at least Windows 10 1809." +LangString inst_requires_win10 ${LANG_SWEDISH} "Det här installationsprogrammet kräver minst Windows 10 1809." ;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent" LangString inst_uninstall_link_description ${LANG_SWEDISH} "Avinstallera qBittorrent" diff --git a/dist/windows/installer.nsi b/dist/windows/installer.nsi index 75f2a0f95..95d002a6c 100644 --- a/dist/windows/installer.nsi +++ b/dist/windows/installer.nsi @@ -35,6 +35,8 @@ Section $(inst_qbt_req) ;"qBittorrent (required)" SetOutPath "$INSTDIR\translations" ; Put files there File /r "translations\qt*.qm" + ; Restore output path because it affects `CreateShortCut`. It affects the "Start in" field. + SetOutPath $INSTDIR ; Write the installation path into the registry WriteRegStr HKLM "Software\qBittorrent" "InstallLocation" "$INSTDIR" diff --git a/src/app/application.cpp b/src/app/application.cpp index 988543098..7908a9540 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -88,6 +88,7 @@ #include "base/version.h" #include "applicationinstancemanager.h" #include "filelogger.h" +#include "upgrade.h" #ifndef DISABLE_GUI #include "gui/addnewtorrentdialog.h" @@ -171,6 +172,18 @@ Application::Application(int &argc, char **argv) SettingsStorage::initInstance(); Preferences::initInstance(); + const bool firstTimeUser = !Preferences::instance()->getAcceptedLegal(); + if (!firstTimeUser) + { + if (!upgrade()) + throw RuntimeError(u"Failed migration of old settings"_qs); // Not translatable. Translation isn't configured yet. + handleChangedDefaults(DefaultPreferencesMode::Legacy); + } + else + { + handleChangedDefaults(DefaultPreferencesMode::Current); + } + initializeTranslation(); connect(this, &QCoreApplication::aboutToQuit, this, &Application::cleanup); diff --git a/src/app/main.cpp b/src/app/main.cpp index 97e6869a1..bbb293479 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -118,6 +118,17 @@ int main(int argc, char *argv[]) // Create Application auto app = std::make_unique(argc, argv); +#ifdef Q_OS_WIN + // QCoreApplication::applicationDirPath() needs an Application object instantiated first + // Let's hope that there won't be a crash before this line + const char *envName = "_NT_SYMBOL_PATH"; + const QString envValue = qEnvironmentVariable(envName); + if (envValue.isEmpty()) + qputenv(envName, Application::applicationDirPath().toLocal8Bit()); + else + qputenv(envName, u"%1;%2"_qs.arg(envValue, Application::applicationDirPath()).toLocal8Bit()); +#endif + const QBtCommandLineParameters params = app->commandLineArgs(); if (!params.unknownParameter.isEmpty()) { @@ -221,26 +232,6 @@ int main(int argc, char *argv[]) app->setAttribute(Qt::AA_DontShowIconsInMenus); #endif - if (!firstTimeUser) - { - handleChangedDefaults(DefaultPreferencesMode::Legacy); - -#ifndef DISABLE_GUI - if (!upgrade()) return EXIT_FAILURE; -#elif defined(Q_OS_WIN) - if (!upgrade(_isatty(_fileno(stdin)) - && _isatty(_fileno(stdout)))) return EXIT_FAILURE; -#else - if (!upgrade(!params.shouldDaemonize - && isatty(fileno(stdin)) - && isatty(fileno(stdout)))) return EXIT_FAILURE; -#endif - } - else - { - handleChangedDefaults(DefaultPreferencesMode::Current); - } - #if defined(DISABLE_GUI) && !defined(Q_OS_WIN) if (params.shouldDaemonize) { @@ -274,6 +265,11 @@ int main(int argc, char *argv[]) displayBadArgMessage(er.message()); return EXIT_FAILURE; } + catch (const RuntimeError &er) + { + qDebug() << er.message(); + return EXIT_FAILURE; + } } #if !defined(DISABLE_GUI) diff --git a/src/app/upgrade.cpp b/src/app/upgrade.cpp index 9a22515c5..6644c0182 100644 --- a/src/app/upgrade.cpp +++ b/src/app/upgrade.cpp @@ -384,9 +384,21 @@ namespace } } #endif + + void migrateChineseLocale() + { + auto *settingsStorage = SettingsStorage::instance(); + const auto key = u"Preferences/General/Locale"_qs; + if (settingsStorage->hasKey(key)) + { + const auto locale = settingsStorage->loadValue(key); + if (locale.compare(u"zh"_qs, Qt::CaseInsensitive) == 0) + settingsStorage->storeValue(key, u"zh_CN"_qs); + } + } } -bool upgrade(const bool /*ask*/) +bool upgrade() { CachedSettingValue version {MIGRATION_VERSION_KEY, 0}; @@ -413,6 +425,9 @@ bool upgrade(const bool /*ask*/) migrateMemoryPrioritySettings(); #endif + { + migrateChineseLocale(); + } version = MIGRATION_VERSION; } diff --git a/src/app/upgrade.h b/src/app/upgrade.h index 4271f5a19..0ef24fae8 100644 --- a/src/app/upgrade.h +++ b/src/app/upgrade.h @@ -35,5 +35,5 @@ enum class DefaultPreferencesMode }; void handleChangedDefaults(DefaultPreferencesMode mode); -bool upgrade(bool ask = true); +bool upgrade(); void setCurrentMigrationVersion(); diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index ad781f3a9..5fd86649c 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -50,10 +50,6 @@ #include #include -#ifdef QBT_USES_CUSTOMDBUSNOTIFICATIONS -#include "notifications/dbusnotifier.h" -#endif - #include "base/bittorrent/session.h" #include "base/bittorrent/sessionstatus.h" #include "base/global.h" diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h index aace1fd12..e7af3d2e0 100644 --- a/src/gui/mainwindow.h +++ b/src/gui/mainwindow.h @@ -68,11 +68,6 @@ namespace Ui class MainWindow; } -#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB) -#define QBT_USES_CUSTOMDBUSNOTIFICATIONS -class DBusNotifier; -#endif - class MainWindow final : public QMainWindow, public GUIApplicationComponent { Q_OBJECT diff --git a/src/gui/transferlistfilterswidget.cpp b/src/gui/transferlistfilterswidget.cpp index 0a62098ac..e024e535c 100644 --- a/src/gui/transferlistfilterswidget.cpp +++ b/src/gui/transferlistfilterswidget.cpp @@ -188,7 +188,7 @@ StatusFilterWidget::StatusFilterWidget(QWidget *parent, TransferListWidget *tran resumed->setData(Qt::DecorationRole, UIThemeManager::instance()->getIcon(u"torrent-start"_qs, u"media-playback-start"_qs)); auto *paused = new QListWidgetItem(this); paused->setData(Qt::DisplayRole, tr("Paused (0)")); - paused->setData(Qt::DecorationRole, UIThemeManager::instance()->getIcon(u"torrent-stop"_qs, u"media-playback-pause"_qs)); + paused->setData(Qt::DecorationRole, UIThemeManager::instance()->getIcon(u"stopped"_qs, u"media-playback-pause"_qs)); auto *active = new QListWidgetItem(this); active->setData(Qt::DisplayRole, tr("Active (0)")); active->setData(Qt::DecorationRole, UIThemeManager::instance()->getIcon(u"filter-active"_qs, u"filteractive"_qs)); diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 4547935d1..71edfab78 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -162,7 +162,7 @@ TransferListModel::TransferListModel(QObject *parent) , m_completedIcon {UIThemeManager::instance()->getIcon(u"checked-completed"_qs, u"completed"_qs)} , m_downloadingIcon {UIThemeManager::instance()->getIcon(u"downloading"_qs)} , m_errorIcon {UIThemeManager::instance()->getIcon(u"error"_qs)} - , m_pausedIcon {UIThemeManager::instance()->getIcon(u"torrent-stop"_qs, u"media-playback-pause"_qs)} + , m_pausedIcon {UIThemeManager::instance()->getIcon(u"stopped"_qs, u"media-playback-pause"_qs)} , m_queuedIcon {UIThemeManager::instance()->getIcon(u"queued"_qs)} , m_stalledDLIcon {UIThemeManager::instance()->getIcon(u"stalledDL"_qs)} , m_stalledUPIcon {UIThemeManager::instance()->getIcon(u"stalledUP"_qs)} diff --git a/src/icons/icons.qrc b/src/icons/icons.qrc index 68d214309..30bb4f8f0 100644 --- a/src/icons/icons.qrc +++ b/src/icons/icons.qrc @@ -336,6 +336,7 @@ splash.png stalledDL.svg stalledUP.svg + stopped.svg system-log-out.svg tags.svg task-complete.svg diff --git a/src/icons/stopped.svg b/src/icons/stopped.svg new file mode 100644 index 000000000..06140f883 --- /dev/null +++ b/src/icons/stopped.svg @@ -0,0 +1 @@ + diff --git a/src/icons/torrent-stop.svg b/src/icons/torrent-stop.svg index 48141141c..6a6f574f0 100644 --- a/src/icons/torrent-stop.svg +++ b/src/icons/torrent-stop.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index e998cbc7a..6ede337e5 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -104,6 +104,7 @@ const QString KEY_PROP_CREATION_DATE = u"creation_date"_qs; const QString KEY_PROP_SAVE_PATH = u"save_path"_qs; const QString KEY_PROP_DOWNLOAD_PATH = u"download_path"_qs; const QString KEY_PROP_COMMENT = u"comment"_qs; +const QString KEY_PROP_ISPRIVATE = u"is_private"_qs; // File keys const QString KEY_FILE_INDEX = u"index"_qs; @@ -387,6 +388,10 @@ void TorrentsController::infoAction() // - "save_path": Torrent save path // - "download_path": Torrent download path // - "comment": Torrent comment +// - "infohash_v1": Torrent v1 infohash (or empty string for v2 torrents) +// - "infohash_v2": Torrent v2 infohash (or empty string for v1 torrents) +// - "hash": Torrent TorrentID (infohashv1 for v1 torrents, truncated infohashv2 for v2/hybrid torrents) +// - "name": Torrent name void TorrentsController::propertiesAction() { requireParams({u"hash"_qs}); @@ -400,6 +405,8 @@ void TorrentsController::propertiesAction() dataDict[KEY_TORRENT_INFOHASHV1] = torrent->infoHash().v1().toString(); dataDict[KEY_TORRENT_INFOHASHV2] = torrent->infoHash().v2().toString(); + dataDict[KEY_TORRENT_NAME] = torrent->name(); + dataDict[KEY_TORRENT_ID] = torrent->id().toString(); dataDict[KEY_PROP_TIME_ELAPSED] = torrent->activeTime(); dataDict[KEY_PROP_SEEDING_TIME] = torrent->finishedTime(); dataDict[KEY_PROP_ETA] = static_cast(torrent->eta()); @@ -430,6 +437,7 @@ void TorrentsController::propertiesAction() dataDict[KEY_PROP_PIECE_SIZE] = torrent->pieceLength(); dataDict[KEY_PROP_PIECES_HAVE] = torrent->piecesHave(); dataDict[KEY_PROP_CREATED_BY] = torrent->creator(); + dataDict[KEY_PROP_ISPRIVATE] = torrent->isPrivate(); dataDict[KEY_PROP_ADDITION_DATE] = static_cast(torrent->addedTime().toSecsSinceEpoch()); if (torrent->hasMetadata()) { diff --git a/src/webui/www/private/images/stopped.svg b/src/webui/www/private/images/stopped.svg new file mode 100644 index 000000000..06140f883 --- /dev/null +++ b/src/webui/www/private/images/stopped.svg @@ -0,0 +1 @@ + diff --git a/src/webui/www/private/images/torrent-stop.svg b/src/webui/www/private/images/torrent-stop.svg index 48141141c..6a6f574f0 100644 --- a/src/webui/www/private/images/torrent-stop.svg +++ b/src/webui/www/private/images/torrent-stop.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/src/webui/www/private/rename_file.html b/src/webui/www/private/rename_file.html index 93bcf4334..49cdbada8 100644 --- a/src/webui/www/private/rename_file.html +++ b/src/webui/www/private/rename_file.html @@ -85,7 +85,7 @@

QBT_TR(New name:)QBT_TR[CONTEXT=TorrentContentTreeView]

- +
diff --git a/src/webui/www/private/scripts/client.js b/src/webui/www/private/scripts/client.js index d9e4bc2b8..c1e3a2c68 100644 --- a/src/webui/www/private/scripts/client.js +++ b/src/webui/www/private/scripts/client.js @@ -1350,14 +1350,26 @@ new Keyboard({ defaultEventType: 'keydown', events: { 'ctrl+a': function(event) { + if (event.target.nodeName == "INPUT" || event.target.nodeName == "TEXTAREA") + return; + if (event.target.isContentEditable) + return; torrentsTable.selectAll(); event.preventDefault(); }, 'delete': function(event) { + if (event.target.nodeName == "INPUT" || event.target.nodeName == "TEXTAREA") + return; + if (event.target.isContentEditable) + return; deleteFN(); event.preventDefault(); }, 'shift+delete': (event) => { + if (event.target.nodeName == "INPUT" || event.target.nodeName == "TEXTAREA") + return; + if (event.target.isContentEditable) + return; deleteFN(true); event.preventDefault(); } diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 6f72009ab..89191a257 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -970,7 +970,7 @@ window.qBittorrent.DynamicTable = (function() { break; case "pausedDL": state = "torrent-stop"; - img_path = "images/torrent-stop.svg"; + img_path = "images/stopped.svg"; break; case "pausedUP": state = "checked-completed"; diff --git a/src/webui/www/private/scripts/prop-files.js b/src/webui/www/private/scripts/prop-files.js index 3381c5b00..2242fd81f 100644 --- a/src/webui/www/private/scripts/prop-files.js +++ b/src/webui/www/private/scripts/prop-files.js @@ -561,11 +561,11 @@ window.qBittorrent.PropFiles = (function() { contentURL: 'rename_file.html?hash=' + hash + '&isFolder=' + node.isFolder + '&path=' + encodeURIComponent(path), scrollbars: false, - resizable: false, + resizable: true, maximizable: false, paddingVertical: 0, paddingHorizontal: 0, - width: 250, + width: 400, height: 100 }); }, diff --git a/src/webui/www/private/views/filters.html b/src/webui/www/private/views/filters.html index b87fd552e..3e07e09d2 100644 --- a/src/webui/www/private/views/filters.html +++ b/src/webui/www/private/views/filters.html @@ -8,7 +8,7 @@
  • SeedingQBT_TR(Seeding (0))QBT_TR[CONTEXT=StatusFilterWidget]
  • CompletedQBT_TR(Completed (0))QBT_TR[CONTEXT=StatusFilterWidget]
  • ResumedQBT_TR(Resumed (0))QBT_TR[CONTEXT=StatusFilterWidget]
  • -
  • PausedQBT_TR(Paused (0))QBT_TR[CONTEXT=StatusFilterWidget]
  • +
  • PausedQBT_TR(Paused (0))QBT_TR[CONTEXT=StatusFilterWidget]
  • ActiveQBT_TR(Active (0))QBT_TR[CONTEXT=StatusFilterWidget]
  • InactiveQBT_TR(Inactive (0))QBT_TR[CONTEXT=StatusFilterWidget]
  • StalledQBT_TR(Stalled (0))QBT_TR[CONTEXT=StatusFilterWidget]
  • diff --git a/src/webui/www/private/views/properties.html b/src/webui/www/private/views/properties.html index bd505f318..dc3a3bf83 100644 --- a/src/webui/www/private/views/properties.html +++ b/src/webui/www/private/views/properties.html @@ -1,7 +1,7 @@
    - +
    QBT_TR(Progress:)QBT_TR[CONTEXT=PropertiesWidget]QBT_TR(Progress:)QBT_TR[CONTEXT=PropertiesWidget]
    diff --git a/src/webui/www/private/views/search.html b/src/webui/www/private/views/search.html index cefb4654c..b37ca8541 100644 --- a/src/webui/www/private/views/search.html +++ b/src/webui/www/private/views/search.html @@ -80,7 +80,7 @@
    - + diff --git a/src/webui/www/translations/webui_hr.ts b/src/webui/www/translations/webui_hr.ts index e50221a75..bf7b0dc39 100644 --- a/src/webui/www/translations/webui_hr.ts +++ b/src/webui/www/translations/webui_hr.ts @@ -1598,8 +1598,7 @@ Use ';' to split multiple entries. Can use wildcard '*'. U svrhu obrane od napada ponovnog povezivanja DNS-a, trebali biste unijeti nazive domena koje koristi WebUI poslužitelj. -Koristite ';' za razdvajanje više unosa. Može koristiti zamjenski znak '*'. - +Koristite ';' za razdvajanje više unosa. Može koristiti zamjenski znak '*'. Run external program on torrent added diff --git a/src/webui/www/webui.qrc b/src/webui/www/webui.qrc index 597453128..07ee4474a 100644 --- a/src/webui/www/webui.qrc +++ b/src/webui/www/webui.qrc @@ -345,6 +345,7 @@ private/images/spinner.gif private/images/stalledDL.svg private/images/stalledUP.svg + private/images/stopped.svg private/images/system-log-out.svg private/images/tabs.gif private/images/tags.svg